diff --git a/.factorypath b/.factorypath deleted file mode 100644 index b4510fae..00000000 --- a/.factorypath +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 00000000..763ecc10 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,39 @@ +name: Java launcher + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + cache: maven + - name: Check code with linters + run: mvn -U checkstyle:check + - name: Download dependancies + env: + CLIENT_ID: ${{ secrets.CLIENT_ID }} + IMPERSONATED_USER_ID: ${{ secrets.IMPERSONATED_USER_ID }} + PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} + SIGNER_EMAIL: ${{ secrets.SIGNER_EMAIL }} + SIGNER_NAME: ${{ secrets.SIGNER_NAME }} + run: mvn install + - name: Build with Maven + env: + CLIENT_ID: ${{ secrets.CLIENT_ID }} + IMPERSONATED_USER_ID: ${{ secrets.IMPERSONATED_USER_ID }} + PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} + SIGNER_EMAIL: ${{ secrets.SIGNER_EMAIL }} + SIGNER_NAME: ${{ secrets.SIGNER_NAME }} + run: mvn -B package --file pom.xml diff --git a/.gitignore b/.gitignore index 23e56e0d..73ec87e5 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,16 @@ hs_err_pid* private.key application.properties +/target/ +src/main/resources/application.json +src/main/resources/application.properties +src/main/java/com/docusign/admin/ + +# according to gitignore.io this shouldnt be shared +.factorypath +src/main/resources/ExportedUserData.csv +app.config +Quick_ACG/target/* +JWT Console App/target/* +Quick_ACG/src/main/resources/application.json + diff --git a/.metadata/.plugins/org.eclipse.epp.logging.aeri.ide/org.eclipse.epp.logging.aeri.ide.server/server-config.json b/.metadata/.plugins/org.eclipse.epp.logging.aeri.ide/org.eclipse.epp.logging.aeri.ide.server/server-config.json index 867c06cd..879f1b33 100644 --- a/.metadata/.plugins/org.eclipse.epp.logging.aeri.ide/org.eclipse.epp.logging.aeri.ide.server/server-config.json +++ b/.metadata/.plugins/org.eclipse.epp.logging.aeri.ide/org.eclipse.epp.logging.aeri.ide.server/server-config.json @@ -33,7 +33,7 @@ "com.sun.*", "java.*", "javafx.*", - "javax.*", + "jakarta.*", "org.apache.*", "org.eclipse.*", "org.fordiac.*", diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..6fcb152c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "Launch App", + "request": "launch", + "mainClass": "com.docusign.App", + "projectName": "code-examples-java" + }, + { + "type": "java", + "name": "Launch Java Program", + "request": "launch", + "mainClass": "" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index e0f15db2..0be1c0c6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "java.configuration.updateBuildConfiguration": "automatic" + "java.configuration.updateBuildConfiguration": "automatic", + "java.compile.nullAnalysis.mode": "automatic" } \ No newline at end of file diff --git a/JWT Console App/app.config.example b/JWT Console App/app.config.example new file mode 100644 index 00000000..25f4225d --- /dev/null +++ b/JWT Console App/app.config.example @@ -0,0 +1,3 @@ +clientId={INTEGRATION_KEY_JWT} +userId={IMPERSONATED_USER_ID} +rsaKeyFile=private.key \ No newline at end of file diff --git a/JWT Console App/pom.xml b/JWT Console App/pom.xml new file mode 100644 index 00000000..50394bea --- /dev/null +++ b/JWT Console App/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + docusign.jwtconsoleapp + code-examples-java-JWT + 1.0-SNAPSHOT + + DocuSign Java JWT Console App + + + UTF-8 + 11 + 11 + 6.0.0 + + + + + + commons-cli + commons-cli + 1.7.0 + + + + org.apache.commons + commons-math3 + 3.6.1 + + + + com.docusign + docusign-esign-java + ${esignature.version} + shaded + + + + commons-io + commons-io + 2.16.1 + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + 11 + 11 + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.4.2 + + + + true + lib/ + com.docusign.jwtconsoleapp.JWTConsoleApp + + + + + + + + diff --git a/JWT Console App/src/main/java/com/docusign/JWTConsoleApp.java b/JWT Console App/src/main/java/com/docusign/JWTConsoleApp.java new file mode 100644 index 00000000..7f8f0f4b --- /dev/null +++ b/JWT Console App/src/main/java/com/docusign/JWTConsoleApp.java @@ -0,0 +1,146 @@ +package com.docusign.jwtconsoleapp; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.auth.OAuth; +import com.docusign.esign.client.auth.OAuth.OAuthToken; +import com.docusign.esign.client.auth.OAuth.UserInfo; +import com.docusign.esign.client.auth.OAuth.Account; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.Document; +import com.docusign.esign.model.CarbonCopy; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import com.docusign.esign.model.Recipients; +import com.docusign.esign.model.Signer; +import com.docusign.esign.model.Tabs; +import com.docusign.esign.model.SignHere; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.*; +import java.io.*; +import java.awt.Desktop; +import java.net.URI; + +/** + * Starter class for JWTConsoleApp application. + */ + +public class JWTConsoleApp { + + static String DevCenterPage = "https://developers.docusign.com/platform/auth/consent"; + /** + * Application entry point. + * + * @param args application command line arguments + */ + public static void main(String[] args) throws java.io.IOException { + + Scanner scanner = new Scanner(System. in); + System.out.println ("Welcome to the JWT Code example! "); + System.out.print("Enter the signer's email address: "); + String signerEmail = scanner. nextLine(); + System.out.print("Enter the signer's name: "); + String signerName = scanner. nextLine(); + System.out.print("Enter the carbon copy's email address: "); + String ccEmail = scanner. nextLine(); + System.out.print("Enter the carbon copy's name: "); + String ccName = scanner. nextLine(); + + // Get information fro app.config + Properties prop = new Properties(); + String fileName = "app.config"; + FileInputStream fis = new FileInputStream(fileName); + prop.load(fis); + try + { + // Get access token and accountId + ApiClient apiClient = new ApiClient("https://demo.docusign.net/restapi"); + apiClient.setOAuthBasePath("account-d.docusign.com"); + ArrayList scopes = new ArrayList(); + scopes.add("signature"); + scopes.add("impersonation"); + byte[] privateKeyBytes = Files.readAllBytes(Paths.get(prop.getProperty("rsaKeyFile"))); + OAuthToken oAuthToken = apiClient.requestJWTUserToken( + prop.getProperty("clientId"), + prop.getProperty("userId"), + scopes, + privateKeyBytes, + 3600); + String accessToken = oAuthToken.getAccessToken(); + UserInfo userInfo = apiClient.getUserInfo(accessToken); + String accountId = userInfo.getAccounts().get(0).getAccountId(); + + // Create envelopeDefinition object + EnvelopeDefinition envelope = new EnvelopeDefinition(); + envelope.setEmailSubject("Please sign this document set"); + envelope.setStatus("sent"); + + // Create tabs object + SignHere signHere = new SignHere(); + signHere.setDocumentId("1"); + signHere.setPageNumber("1"); + signHere.setXPosition("191"); + signHere.setYPosition("148"); + Tabs tabs = new Tabs(); + tabs.setSignHereTabs(Arrays.asList(signHere)); + // Set recipients + Signer signer = new Signer(); + signer.setEmail(signerEmail); + signer.setName(signerName); + signer.recipientId("1"); + signer.setTabs(tabs); + CarbonCopy cc = new CarbonCopy(); + cc.setEmail(ccEmail); + cc.setName(ccName); + cc.recipientId("2"); + Recipients recipients = new Recipients(); + recipients.setSigners(Arrays.asList(signer)); + recipients.setCarbonCopies(Arrays.asList(cc)); + envelope.setRecipients(recipients); + + // Add document + Document document = new Document(); + document.setDocumentBase64("VGhhbmtzIGZvciByZXZpZXdpbmcgdGhpcyEKCldlJ2xsIG1vdmUgZm9yd2FyZCBhcyBzb29uIGFzIHdlIGhlYXIgYmFjay4="); + document.setName("doc1.txt"); + document.setFileExtension("txt"); + document.setDocumentId("1"); + envelope.setDocuments(Arrays.asList(document)); + + // Send envelope + apiClient.addDefaultHeader("Authorization", "Bearer " + accessToken); + EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); + EnvelopeSummary results = envelopesApi.createEnvelope(accountId, envelope); + System.out.println("Successfully sent envelope with envelopeId " + results.getEnvelopeId()); + } + catch (ApiException exp) + { + if (exp.getMessage().contains("consent_required")) + { + try + { + System.out.println ("Consent required, please provide consent in browser window and then run this app again."); + Desktop.getDesktop().browse(new URI("https://account-d.docusign.com/oauth/auth?response_type=code&scope=impersonation%20signature&client_id=" + prop.getProperty("clientId") + "&redirect_uri=" + DevCenterPage)); + } + catch (Exception e) + { + System.out.print ("Error!!! "); + System.out.print (e.getMessage()); + } + } + } + catch (Exception e) + { + System.out.print ("Error!!! "); + System.out.print (e.getMessage()); + } + } +} \ No newline at end of file diff --git a/PAYMENTS_INSTALLATION.md b/PAYMENTS_INSTALLATION.md index 689be36d..d575c2c2 100644 --- a/PAYMENTS_INSTALLATION.md +++ b/PAYMENTS_INSTALLATION.md @@ -1,24 +1,21 @@ -# Configuring a DocuSign payments gateway +# Configure a payment gateway -DocuSign offers built-in connections to multiple payment -gateways. The payments example uses a demo account via the Stripe -gateway service. +DocuSign offers built-in connections to multiple payment gateways. The payments code example uses a developer account via the Stripe gateway service. -## Creating the payments gateway account -1. Login to demo.docusign.net and go to the Admin Tool. -1. On the Integrations / Payments screen, click Stripe. -1. For development, you can skip the Stripe account application - by using the `Skip this account form` link: +## Create a Stripe payment gateway + +1. Select the Stripe button on the [**Payments**](https://admindemo.docusign.com/authenticate?goTo=payments) page in your developer account. + +1. For development, you can skip the Stripe account application by using the **Skip this account form** link at the top of the page.
+ + ![Skipping the Stripe account form](docs/stripe_skip_account_form_link.png) + + An enabled Stripe payment gateway is now associated with your DocuSign developer account and is shown under **Payment Gateway**. + +1. Save the **Gateway Account ID** GUID to the code example launcher configuration file. - ![Skipping the Stripe account form](docs/stripe_skip_account_form_link.png) -1. Next, the Admin Tool will show that an enabled Stripe - payment gateway account has been associated with your - DocuSign demo sandbox account. -1. Configure the example launcher with the gateway account id shown in the Admin tool. ## Additional documentation -See the -[Managing Payment Gateways](https://support.docusign.com/en/guides/managing-payment-gateways) -documentation. - +* [Managing Payment Gateways](https://support.docusign.com/en/guides/managing-payment-gateways) +* [How to send a request for payment](https://developers.docusign.com/docs/esign-rest-api/how-to/request-a-payment) diff --git a/Quick_ACG/pom.xml b/Quick_ACG/pom.xml new file mode 100644 index 00000000..c38ee390 --- /dev/null +++ b/Quick_ACG/pom.xml @@ -0,0 +1,297 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.7.18 + + + + com.docusign + code-examples-java-acg + 1.0-SNAPSHOT + + Docusign Java Tutorial + + + 11 + 2.5.6 + 2.16.1 + 6.4.0 + 2.0.17 + + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-oauth2-client + + + + org.apache.commons + commons-lang3 + + + org.freemarker + freemarker + + + + + javax.servlet + jstl + + + + + org.apache.tomcat.embed + tomcat-embed-jasper + provided + + + + commons-io + commons-io + ${commonsio.version} + + + com.docusign + docusign-esign-java + ${esignature.version} + shaded + + + + org.projectlombok + lombok + RELEASE + compile + + + org.springframework.boot + spring-boot-autoconfigure + 2.7.18 + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + + org.slf4j + slf4j-simple + ${slf4j.version} + + + + + + + maven-resources-plugin + 3.2.0 + + + copy-resource-one + generate-sources + + copy-resources + + + ${basedir} + + + ${basedir}/src/main/resources + ../src/main/resources + + application.json + World_Wide_Corp_lorem.pdf + + + + ${basedir}/src/main/resources/META-INF + ../src/main/resources/META-INF + + spring.factories + + + + ${basedir}/src/main/resources/public/assets + ../src/main/resources/public/assets + + favicon.png + css.css + + + + ${basedir}/src/main/java/com/docusign + ../src/main/java/com/docusign + + JsonPropertySourceLoader.java + EG001ControllerEmbeddedSigning.java + + + + ${basedir}/src/main/java/com/docusign/common + ../src/main/java/com/docusign/common + + WorkArguments.java + + + + ${basedir}/src/main/java/com/docusign/controller/eSignature/examples + ../src/main/java/com/docusign/controller/eSignature/examples + + EnvelopeHelpers.java + ExampleException.java + + + + ${basedir}/src/main/java/com/docusign/controller/eSignature/services + ../src/main/java/com/docusign/controller/eSignature/services + + EmbeddedSigningService.java + + + + ${basedir}/src/main/java/com/docusign/core/model + ../src/main/java/com/docusign/core/model + + Locals.java + User.java + EnvelopeDocumentInfo.java + + + + ${basedir}/src/main/java/com/docusign/core/common + ../src/main/java/com/docusign/core/common + + Utils.java + DiffField.java + + + + ${basedir}/src/main/java/com/docusign/core/utils + ../src/main/java/com/docusign/core/utils + + AccountsConverter.java + + + + ${basedir}/src/main/java/com/docusign/core/model/manifestModels + ../src/main/java/com/docusign/core/model/manifestModels + + AdditionalPage.java + APIs.java + CodeExampleText.java + CustomErrorTexts.java + Forms.java + HelpingTexts.java + Inputs.java + LinkToAPIMethods.java + LoginPage.java + ManifestGroup.java + ManifestStructure.java + RedirectsToOtherCodeExamples.java + SelectAPIPage.java + SupportingTexts.java + + + + ${basedir}/src/main/java/com/docusign/core/security + ../src/main/java/com/docusign/core/security + + SecurityHelpers.java + JWTOAuth2User.java + CustomAuthenticationFailureHandler.java + + + + ${basedir}/src/main/java/com/docusign/core/security/acg + ../src/main/java/com/docusign/core/security/acg + + ACGAuthenticationMethod.java + + + + ${basedir}/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples + ../src/main/webapp/WEB-INF/templates/views/pages/esignature/examples + + quickEmbeddedSigning.jsp + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + + + + + + org.bouncycastle + bcprov-jdk15on + 1.78 + + + + org.yaml + snakeyaml + 2.2 + + + + net.minidev + json-smart + 2.5.1 + + + + com.nimbusds + nimbus-jose-jwt + 9.40 + + + + org.springframework.security + spring-security-core + 5.7.12 + + + + ch.qos.logback + logback-core + 1.5.6 + + + + ch.qos.logback + logback-classic + 1.5.6 + test + + + + diff --git a/Quick_ACG/src/main/java/com/docusign/App.java b/Quick_ACG/src/main/java/com/docusign/App.java new file mode 100644 index 00000000..18bc6638 --- /dev/null +++ b/Quick_ACG/src/main/java/com/docusign/App.java @@ -0,0 +1,58 @@ +package com.docusign; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.FileSystemAlreadyExistsException; +import java.nio.file.FileSystems; +import java.util.Collections; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; + +@Slf4j +@SpringBootApplication(exclude={JmxAutoConfiguration.class}) +public class App { + + public static void main(String[] args) throws IOException { + SpringApplication.run(App.class, args); + openHomePage(); + initFileSystem(); + } + + private static void openHomePage() throws IOException { + // Each operating system opens web browsers differently so we need to determine the user's + // OS and open a browser to the example homepage accordingly. + Runtime rt = Runtime.getRuntime(); + if (OSDetector.isMac()){ + String[] arguments = { "osascript", "-e", "open location \"" + "http://localhost:8080" + "\"" }; + rt.exec(arguments); + } + else if (OSDetector.isWindows()){ + rt.exec("rundll32 url.dll,FileProtocolHandler " + "http://localhost:8080"); + } + else if (OSDetector.isLinux()){ + String [] browsers = {"firefox", "safari", "chrome", "mozilla"}; + StringBuffer cmd = new StringBuffer(); + for (int i=0; i= HttpURLConnection.HTTP_BAD_REQUEST) { + throw new Exception(httpConnection.getResponseMessage()); + } + + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpConnection.getInputStream())); + StringBuilder stringBuilder = new StringBuilder(); + String temp; + while ((temp = bufferedReader.readLine()) != null) { + stringBuilder.append(temp); + } + bufferedReader.close(); + httpConnection.disconnect(); + + return stringBuilder.toString(); + } +} diff --git a/Quick_ACG/src/main/java/com/docusign/OSDetector.java b/Quick_ACG/src/main/java/com/docusign/OSDetector.java new file mode 100644 index 00000000..358aba40 --- /dev/null +++ b/Quick_ACG/src/main/java/com/docusign/OSDetector.java @@ -0,0 +1,25 @@ +package com.docusign; + +/* + * This class can be used to determine the user's operating system so that the + * application can successfully open a web browser to run the examples. + */ +public class OSDetector +{ + private static final boolean isWindows; + private static final boolean isLinux; + private static final boolean isMac; + + static + { + String os = System.getProperty("os.name").toLowerCase(); + isWindows = os.contains("win"); + isLinux = os.contains("nux") || os.contains("nix"); + isMac = os.contains("mac"); + } + + public static boolean isWindows() { return isWindows; } + public static boolean isLinux() { return isLinux; } + public static boolean isMac() { return isMac; } + +} \ No newline at end of file diff --git a/Quick_ACG/src/main/java/com/docusign/WebSecurityConfig.java b/Quick_ACG/src/main/java/com/docusign/WebSecurityConfig.java new file mode 100644 index 00000000..6770bd1d --- /dev/null +++ b/Quick_ACG/src/main/java/com/docusign/WebSecurityConfig.java @@ -0,0 +1,52 @@ +package com.docusign; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; +import org.springframework.security.web.savedrequest.HttpSessionRequestCache; +import org.springframework.security.web.savedrequest.RequestCache; +import com.docusign.core.security.CustomAuthenticationFailureHandler; + +@EnableWebSecurity +public class WebSecurityConfig { + + @Autowired + public DSConfiguration dsConfiguration; + + @Bean + public RequestCache requestCache() { + return new HttpSessionRequestCache(); + } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests(authorize -> { + try { + authorize + .antMatchers("/", "/error**", "/assets/**", "/ds/mustAuthenticate**", + "/ds/authenticate**", "/ds/selectApi**", "/pkce") + .permitAll() + .anyRequest().authenticated() + .and() + .exceptionHandling() + .authenticationEntryPoint( + new LoginUrlAuthenticationEntryPoint("/ds/mustAuthenticate")); + } catch (Exception e) { + throw new RuntimeException(e); + } + }) + .requestCache().requestCache(requestCache()).and() + .oauth2Login(login -> login.failureHandler(new CustomAuthenticationFailureHandler())) + .oauth2Client(Customizer.withDefaults()) + .logout(logout -> logout + .logoutSuccessUrl("/")) + .csrf().disable(); + + return http.build(); + } +} diff --git a/Quick_ACG/src/main/java/com/docusign/controller/eSignature/examples/AbstractEsignatureController.java b/Quick_ACG/src/main/java/com/docusign/controller/eSignature/examples/AbstractEsignatureController.java new file mode 100644 index 00000000..d033672a --- /dev/null +++ b/Quick_ACG/src/main/java/com/docusign/controller/eSignature/examples/AbstractEsignatureController.java @@ -0,0 +1,147 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.core.model.User; +import com.docusign.core.model.manifestModels.APIs; +import com.docusign.core.model.manifestModels.CodeExampleText; +import com.docusign.core.model.Session; +import com.docusign.core.model.manifestModels.ManifestGroup; +import com.docusign.esign.client.ApiClient; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; +import java.util.Objects; + +/** + * Abstract base class for all eSignature controllers. + */ +@Controller +public abstract class AbstractEsignatureController { + + protected static final String BEARER_AUTHENTICATION = "Bearer "; + + @Autowired + protected Session session; + + protected final String exampleName; + protected String title; + private final String pagePath; + protected final DSConfiguration config; + protected CodeExampleText codeExampleText; + private static final String EXAMPLE_PAGES_PATH = "pages/esignature/examples/"; + private static final String EXAMPLE_TEXT = "example"; + private static final String LAUNCHER_TEXTS = "launcherTexts"; + protected final User user; + + public AbstractEsignatureController(DSConfiguration config, String exampleName, Session session, User user) { + this.config = config; + this.session = session; + this.user = user; + this.exampleName = exampleName; + this.pagePath = this.getExamplePagesPath() + exampleName; + } + + protected String getExamplePagesPath() { + return AbstractEsignatureController.EXAMPLE_PAGES_PATH; + } + + /** + * Creates new instance of the eSignature API client. + * @param basePath URL to eSignature REST API + * @param userAccessToken user's access token + * @return an instance of the {@link ApiClient} + */ + protected static ApiClient createApiClient(String basePath, String userAccessToken) { + ApiClient apiClient = new ApiClient(basePath); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + userAccessToken); + return apiClient; + } + + @GetMapping + public String get(WorkArguments args, ModelMap model) { + try { + onInitModel(args, model); + return pagePath; + } catch (Exception exception) { + return handleException(exception, model); + } + } + + @PostMapping + public Object create(WorkArguments args, ModelMap model, HttpServletResponse response) { + try { + return doWork(args, model, response); + } catch (Exception exception) { + return handleException(exception, model); + } + } + + /** + * This method is called from the GET request and it should initialize a + * model. Override this method if it is necessary to add example specific + * attributes into the model. + * @param args + * @param model the model data + */ + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + this.codeExampleText = GetExampleText(); + this.title = this.codeExampleText.ExampleName; + + Class clazz = Objects.requireNonNullElse(getClass().getEnclosingClass(), getClass()); + String srcPath = String.join("", config.getExampleUrl(), clazz.getName().replace('.', '/'), ".java"); + model.addAttribute("csrfToken", ""); + model.addAttribute("title", title); + model.addAttribute("sourceFile", clazz.getSimpleName() + ".java"); + model.addAttribute("sourceUrl", srcPath); + model.addAttribute("documentation", config.getDocumentationPath() + exampleName); + model.addAttribute(EXAMPLE_TEXT, this.codeExampleText); + model.addAttribute(LAUNCHER_TEXTS, config.getCodeExamplesText().SupportingTexts); + } + + /** + * This method is called from the POST request. Example pages must override + * it. Overridden method should return an Object means URL to redirect. + * @param args the work arguments got from the current page + * @param model page model holder + * @param response for HTTP-specific functionality in sending a response + * @return {@link Object}. Possible types and values: null, + * {@link String} representation of the URL or Spring RedirectView object, + * (see {@link org.springframework.web.servlet.view.RedirectView RedirectView}) + * @throws Exception if calling API has failed or if I/O operation has failed + */ + protected abstract Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws Exception; + + private String handleException(Exception exception, ModelMap model) { + return ExceptionUtils.getStackTrace(exception); + } + + protected CodeExampleText GetExampleText() { + List eSignatureManifestGroups = config.getCodeExamplesText().APIs.stream() + .filter(x -> "esignature".contains(((APIs) x).Name.toLowerCase())) + .findFirst() + .orElse(null).Groups; + var exampleNumberToSearch = 1; + + for (ManifestGroup group : eSignatureManifestGroups) { + CodeExampleText codeExampleText = group.Examples.stream() + .filter(x -> ((CodeExampleText) x).ExampleNumber == exampleNumberToSearch) + .findFirst() + .orElse(null); + + if (codeExampleText != null) + { + return codeExampleText; + } + } + return null; + } +} diff --git a/Quick_ACG/src/main/java/com/docusign/core/controller/IndexController.java b/Quick_ACG/src/main/java/com/docusign/core/controller/IndexController.java new file mode 100644 index 00000000..33528727 --- /dev/null +++ b/Quick_ACG/src/main/java/com/docusign/core/controller/IndexController.java @@ -0,0 +1,213 @@ +package com.docusign.core.controller; + +import com.docusign.DSConfiguration; +import com.docusign.core.model.Locals; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import java.io.IOException; +import java.util.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import com.docusign.core.security.acg.ACGAuthenticationMethod; + +import com.docusign.core.utils.AccountsConverter; +import org.apache.commons.lang3.StringUtils; +import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.view.RedirectView; +import com.docusign.esign.client.auth.OAuth; +import java.util.stream.Collectors; +import org.springframework.security.core.Authentication; + +@Controller +@ControllerAdvice +@Scope(WebApplicationContext.SCOPE_SESSION) +public class IndexController { + private static final List ESIGNATURE_SCOPES = Arrays.asList("signature"); + private static final String ATTR_STATE = "state"; + private static final String ATTR_EVENT = "event"; + + private static final String ERROR_ACCOUNT_NOT_FOUND = "Could not find account information for the user"; + private final DSConfiguration config; + private final Session session; + private final User user; + private Optional account; + + @Autowired + private OAuth2AuthorizedClientService authorizedClientService; + + public IndexController(DSConfiguration config, Session session, User user, Optional account) { + this.config = config; + this.session = session; + this.user = user; + this.account = account; + } + + @GetMapping(path = "/") + public String index(ModelMap model, HttpServletResponse response) throws IOException { + String site = "/eg001"; + response.setStatus(response.SC_MOVED_TEMPORARILY); + response.setHeader("Location", site); + return null; + } + + @GetMapping(path = "/ds/mustAuthenticate") + public ModelAndView mustAuthenticateController(ModelMap model) throws IOException, Exception { + return new ModelAndView(getRedirectView()); + } + + @GetMapping(path = "/ds-return") + public String returnController(@RequestParam(value = ATTR_STATE, required = false) String state, + @RequestParam(value = ATTR_EVENT, required = false) String event, + @RequestParam(required = false) String envelopeId, ModelMap model, HttpServletResponse response) + throws IOException { + String site = "/eg001"; + response.setStatus(response.SC_MOVED_TEMPORARILY); + response.setHeader("Location", site); + return null; + } + + @GetMapping("/pkce") + public RedirectView pkce(String code, String state, HttpServletRequest req, HttpServletResponse resp) + throws Exception { + String redirectURL = "/"; + RedirectView redirect; + try { + redirect = new ACGAuthenticationMethod().exchangeCodeForToken(code, config, session, redirectURL, + ESIGNATURE_SCOPES); + } catch (Exception e) { + redirect = new RedirectView(getLoginPath()); + this.session.setIsPKCEWorking(false); + } + + return redirect; + } + + private RedirectView getRedirectView() throws Exception { + RedirectView redirect; + if (this.session.getIsPKCEWorking()) { + redirect = new ACGAuthenticationMethod().initiateAuthorization(config, ESIGNATURE_SCOPES); + } else { + redirect = new RedirectView(getLoginPath()); + } + + redirect.setExposeModelAttributes(false); + return redirect; + } + + private String getLoginPath() { + return config.getAcgRedirectURL(); + } + + @ModelAttribute("documentOptions") + public List populateDocumentOptions() { + return new ArrayList<>(); + } + + @ModelAttribute("showDoc") + public boolean populateShowDoc() { + return StringUtils.isNotBlank(config.getDocumentationPath()); + } + + @ModelAttribute("locals") + public Object populateLocals() throws IOException { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (!(authentication instanceof OAuth2AuthenticationToken)) { + return new RedirectView("/"); + } + + OAuth2AuthenticationToken oauth = (OAuth2AuthenticationToken) authentication; + OAuth2User oauthUser = oauth.getPrincipal(); + OAuth2AuthorizedClient oauthClient = authorizedClientService.loadAuthorizedClient( + oauth.getAuthorizedClientRegistrationId(), + oauthUser.getName()); + + if (oauth.isAuthenticated()) { + user.setName(oauthUser.getAttribute("name")); + + if (oauthClient != null) { + user.setAccessToken(oauthClient.getAccessToken().getTokenValue()); + } else { + user.setAccessToken(((OAuth.OAuthToken) oauthUser.getAttribute("access_token")).getAccessToken()); + } + + if (account.isEmpty()) { + account = Optional.ofNullable(getDefaultAccountInfo(getOAuthAccounts(oauthUser))); + } + + OAuth.Account oauthAccount = account.orElseThrow(() -> new NoSuchElementException(ERROR_ACCOUNT_NOT_FOUND)); + session.setAccountId(oauthAccount.getAccountId()); + session.setAccountName(oauthAccount.getAccountName()); + // TODO set this more efficiently with more APIs as they're added in + String basePath = this.getBaseUrl(oauthAccount) + "/restapi"; + session.setBasePath(basePath); + } + + return new Locals(config, session, user, ""); + } + + private String getBaseUrl(OAuth.Account oauthAccount) { + return oauthAccount.getBaseUri(); + } + + private static List getOAuthAccounts(OAuth2User user) { + List> oauthAccounts = user.getAttribute("accounts"); + if (oauthAccounts == null) { + return new ArrayList<>(); + } + + return oauthAccounts.stream() + .map(AccountsConverter::convert) + .collect(Collectors.toList()); + } + + private OAuth.Account getDefaultAccountInfo(List accounts) { + String targetAccountId = config.getTargetAccountId(); + if (StringUtils.isNotBlank(targetAccountId)) { + OAuth.Account account = getAccountById(accounts, targetAccountId); + if (account != null) { + return account; + } + } + return getDefaultAccount(accounts); + } + + private static OAuth.Account getDefaultAccount(List accounts) { + for (OAuth.Account oauthAccount : accounts) { + if ("true".equals(oauthAccount.getIsDefault())) { + return oauthAccount; + } + } + return null; + } + + private static OAuth.Account getAccountById(List accounts, String accountId) { + for (OAuth.Account oauthAccount : accounts) { + if (StringUtils.equals(oauthAccount.getAccountId(), accountId)) { + return oauthAccount; + } + } + return null; + } + + public static OAuth.Account convert(Map account) { + OAuth.Account res = new OAuth.Account(); + res.setAccountId((String) account.get("account_id")); + res.setIsDefault(String.valueOf(account.get("is_default"))); + res.setAccountName((String) account.get("account_name")); + res.setBaseUri((String) account.get("base_uri")); + return res; + } +} diff --git a/src/main/java/com/docusign/model/Session.java b/Quick_ACG/src/main/java/com/docusign/core/model/Session.java similarity index 58% rename from src/main/java/com/docusign/model/Session.java rename to Quick_ACG/src/main/java/com/docusign/core/model/Session.java index a68e730d..0fc6fafb 100644 --- a/src/main/java/com/docusign/model/Session.java +++ b/Quick_ACG/src/main/java/com/docusign/core/model/Session.java @@ -1,31 +1,33 @@ -package com.docusign.model; +package com.docusign.core.model; +import com.docusign.esign.client.auth.OAuth; import lombok.Data; - -import java.io.Serializable; -import java.util.List; - import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.stereotype.Component; import org.springframework.web.context.WebApplicationContext; +import java.io.Serializable; +import java.util.List; +import java.util.UUID; @Component -@Scope(value = WebApplicationContext.SCOPE_SESSION, - proxyMode = ScopedProxyMode.TARGET_CLASS) +@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) @Data public class Session implements Serializable { private static final long serialVersionUID = 2695379118371574037L; + public Long tokenExpirationTime; + private String accountId; + private String accountName; + private String basePath; + private String envelopeId; - private String templateName; - private List envelopeDocuments; - private String permissionProfileId; - private String permissionProfileName; - private AuthType authTypeSelected = AuthType.AGC; - private boolean refreshToken = false; + + private String statusCFR; + + private Boolean isPKCEWorking = true; } diff --git a/Quick_ACG/src/main/resources/application.example.json b/Quick_ACG/src/main/resources/application.example.json new file mode 100644 index 00000000..6bb5d0e3 --- /dev/null +++ b/Quick_ACG/src/main/resources/application.example.json @@ -0,0 +1,41 @@ +{ + "quickstart" :"{QUICKSTART_VALUE}", + "quickACG": "{QUICK_ACG_VALUE}", + "DS_SIGNER_NAME": "{SIGNER_NAME}", + "DS_SIGNER_EMAIL": "{SIGNER_EMAIL}", + "DS_APP_URL": "http://localhost:8080", + "DS_TARGET_ACCOUNT_ID": "{IMPERSONATED_USER_ID}", + "DS_BASE_PATH": "https://demo.docusign.net", + "DS_ROOMS_BASE_PATH": "https://demo.rooms.docusign.com", + "DS_CLICK_BASE_PATH": "https://demo.docusign.net", + "DS_MONITOR_BASE_PATH": "https://lens-d.docusign.net", + "DS_ADMIN_BASE_PATH": "https://api-d.docusign.net", + + "Gateway_Name": "{DS_PAYMENT_GATEWAY_NAME}", + "Gateway_Account_Id": "{GATEWAY_ACCOUNT_ID}", + "Gateway_Display_Name": "{DS_PAYMENT_GATEWAY_DISPLAY_NAME}", + + "authorization.code.grant.client.scope": "signature", + "authorization.code.grant.sso.redirect-url": "&type=acg", + "authorization.code.grant.client.client-id": "{INTEGRATION_KEY_AUTH_CODE}", + "authorization.code.grant.client.client-secret": "{SECRET_KEY}", + "authorization.code.grant.client.access-token-uri": "https://account-d.docusign.com/oauth/token", + "authorization.code.grant.client.user-authorization-uri": "https://account-d.docusign.com/oauth/auth?prompt=login", + + "common.client.resource.user-info-uri": "https://account-d.docusign.com/oauth/userinfo", + "com.docusign.github.example-uri": "https://github.com/docusign/code-examples-java/blob/master/src/main/java/", + "com.docusign.documentation-path": "", + + "ESignatureManifest": "https://raw.githubusercontent.com/docusign/code-examples-csharp/master/manifest/eSignatureManifest.json", + + "server.tomcat.additional-tld-skip-patterns": "*jaxb*.jar", + "server.servlet.session.tracking-modes": "cookie", + "server.servlet.session.persistent": false, + "server.error.include-stacktrace": "always", + "server.error.whitelabel.enabled": false, + + "spring.session.store-type": "none", + "spring.mvc.view.prefix": "/WEB-INF/templates/views/", + "spring.mvc.view.suffix": ".jsp", + "spring.jmx.enabled": false +} \ No newline at end of file diff --git a/README.md b/README.md index f054c89d..d106c9c0 100644 --- a/README.md +++ b/README.md @@ -1,205 +1,247 @@ # Java Launcher Code Examples -### Github repo: [code-examples-java](./) +> +>### PLEASE! Share your feedback in a [two-question survey](https://docs.google.com/forms/d/e/1FAIpQLScPa74hwhJwi7XWDDj4-XZVOQTF9jJWgbIFEpulXokCqYWT4A/viewform?usp=pp_url&entry.680551577=Java). +> +> +### GitHub repo: [code-examples-java](./README.md) + +If you downloaded this project using the [Quickstart](https://developers.docusign.com/docs/esign-rest-api/quickstart/) tool, it may be configured in one of three ways: + +* **[JWT Grant remote signing example](#jwt-grant-remote-signing-example)**–demonstrates how to implement JSON Web Token authentication. It includes a single remote signing workflow. +* **[Authorization Code Grant embedded signing example](#authorization-code-grant-embedded-signing-example)**–demonstrates how to implement Authorization Code Grant authentication. It includes a single embedded signing workflow. +* **[Multiple code examples, Authorization Code Grant and JWT Grant](#multiple-code-examples-authorization-code-grant-and-jwt-grant)**–includes the full range of examples and authentication types. + +***Installation and running instructions vary depending on the configuration. Follow the link that matches your project type to get started.*** + +This GitHub repo includes code examples for the [Web Forms API](https://developers.docusign.com/docs/web-forms-api/), [Docusign Admin API](https://developers.docusign.com/docs/admin-api/), [Click API](https://developers.docusign.com/docs/click-api/), [eSignature REST API](https://developers.docusign.com/docs/esign-rest-api/), [Monitor API](https://developers.docusign.com/docs/monitor-api/), and [Rooms API](https://developers.docusign.com/docs/rooms-api/). + + ## Introduction -This repo is a Java Spring Boot application that demonstrates: - -1. **Embedded Signing Ceremony.** - [Source.](./src/main/java/com/docusign/controller/examples/EG001ControllerEmbeddedSigning.java) - This example sends an envelope, and then uses an embedded signing ceremony for the first signer. - With embedded signing, the DocuSign signing ceremony is initiated from your website. -1. **Send an envelope with a remote (email) signer and cc recipient.** - [Source.](./src/main/java/com/docusign/controller/examples/EG002ControllerSigningViaEmail.java) - The envelope includes a pdf, Word, and HTML document. - Anchor text ([AutoPlace](https://support.docusign.com/en/guides/AutoPlace-New-DocuSign-Experience)) is used to position the signing fields in the documents. -1. **List envelopes in the user's account.** - [Source.](./src/main/java/com/docusign/controller/examples/EG003ControllerListEnvelopes.java) -1. **Get an envelope's basic information.** - [Source.](./src/main/java/com/docusign/controller/examples/EG004ControllerEnvelopeInfo.java) - The example lists the basic information about an envelope, including its overall status. -1. **List an envelope's recipients and their current status.** - [Source.](./src/main/java/com/docusign/controller/examples/EG005ControllerEnvelopeRecipients.java) -1. **List an envelope's documents.** - [Source.](./src/main/java/com/docusign/controller/examples/EG006ControllerEnvelopeDocs.java) -1. **Download an envelope's documents.** The example can download individual - documents, the documents concatenated together, or a zip file of the documents. - [Source.](./src/main/java/com/docusign/controller/examples/EG007ControllerEnvelopeGetDoc.java) -1. **Programmatically create a template.** - [Source.](./src/main/java/com/docusign/controller/examples/EG008ControllerCreateTemplate.java) -1. **Send an envelope using a template.** - [Source.](./src/main/java/com/docusign/controller/examples/EG009ControllerUseTemplate.java) -1. **Send an envelope and upload its documents with multipart binary transfer.** - [Source.](./src/main/java/com/docusign/controller/examples/EG010ControllerSendBinaryDocs.java) - Binary transfer is 33% more efficient than using Base64 encoding. -1. **Embedded sending.** - [Source.](./src/main/java/com/docusign/controller/examples/EG011ControllerEmbeddedSending.java) -1. **Embedded DocuSign web tool (NDSE).** - [Source.](./src/main/java/com/docusign/controller/examples/EG012ControllerEmbeddedConsole.java) -1. **Embedded Signing Ceremony from a template with an added document.** - [Source.](./src/main/java/com/docusign/controller/examples/EG013ControllerAddDocToTemplate.java) - This example sends an envelope based on a template. - In addition to the template's document(s), the example adds an - additional document to the envelope by using the - [Composite Templates](https://developers.docusign.com/esign-rest-api/guides/features/templates#composite-templates) - feature. -1. **Payments example: an order form, with online payment by credit card.** - [Source.](./src/main/java/com/docusign/controller/examples/EG014ControllerCollectPayment.java) -1. **Get the envelope tab data.** - Retrieve the tab (field) values for all of the envelope's recipients. - [Source.](./src/main/java/com/docusign/controller/examples/EG015ControllerGetTabValues.java) -1. **Set envelope tab values.** - The example creates an envelope and sets the initial values for its tabs (fields). Some of the tabs - are set to be read-only, others can be updated by the recipient. The example also stores - metadata with the envelope. - [Source.](./src/main/java/com/docusign/controller/examples/EG016ControllerSetTabValues.java) -1. **Set template tab values.** - The example creates an envelope using a template and sets the initial values for its tabs (fields). - The example also stores metadata with the envelope. - [Source.](./src/main/java/com/docusign/controller/examples/EG017ControllerSetTemplateTabValues.java) -1. **Get the envelope custom field data (metadata).** - The example retrieves the custom metadata (custom data fields) stored with the envelope. - [Source.](./src/main/java/com/docusign/controller/examples/EG018ControllerEnvelopeCustomFieldValues.java) -1. **Requiring an Access Code for a Recipient** - [Source.](./src/main/java/com/docusign/controller/examples/EG019ControllerAccessCodeAuthentication.java) - This example sends and envelope that requires an access-code for the purpose of multi-factor authentication. -1. **Requiring SMS authentication for a recipient** - [Source.](./src/main/java/com/docusign/controller/examples/EG020ControllerSmsAuthentication.java) - This example sends and envelope that requires entering in a six digit code from an text message for the purpose of multi-factor authentication. -1. **Requiring Phone authentication for a recipient** - [Source.](./src/main/java/com/docusign/controller/examples/EG021ControllerPhoneAuthentication.java) - This example sends and envelope that requires entering in a voice-based response code for the purpose of multi-factor authentication. -1. **Requiring Knowledge-Based Authentication (KBA) for a Recipient** - [Source.](./src/main/java/com/docusign/controller/examples/EG022ControllerKBAAuthentication.java) - This example sends and envelope that requires passing a Public records check to validate identity for the purpose of multi-factor authentication. -1. **Requiring ID Verification (IDV) for a recipient** - [Source.](./src/main/java/com/docusign/controller/examples/EG023ControllerIdvAuthentication.java) - This example sends and envelope that requires the recipient to upload a government issued id. - **Creating a permission profile** - [Source.](./src/main/java/com/docusign/controller/examples/EG024ControllerPermissionCreate.java) - This code example demonstrates how to create a user group's permission profile using the [Create Profile](https://developers.docusign.com/esign-rest-api/reference/UserGroups/Groups/create) method. -1. **Setting a permission profile** - [Source.](./src/main/java/com/docusign/controller/examples/EG025ControllerPermissionSetUserGroups.java) - This code example demonstrates how to set a user group's permission profile using the [Update Group](https://developers.docusign.com/esign-rest-api/reference/UserGroups/Groups/update) method. - You must have already created permissions profile and group of users. -1. **Updating individual permission settings** - [Source.](./src/main/java/com/docusign/controller/examples/EG026ControllerPermissionChangeSingleSetting.java) - This code example demonstrates how to update individual settings for a specific permission profile using the [Update Permission Profile](https://developers.docusign.com/esign-rest-api/reference/Accounts/AccountPermissionProfiles/update) method. - You must have already created permissions profile and group of users. -1. **Deleting a permission profile** - [Source.](./src/main/java/com/docusign/controller/examples/EG027ControllerPermissionDelete.java) - This code example demonstrates how to an account's permission profile using the [Delete AccountPermissionProfiles](https://developers.docusign.com/esign-rest-api/reference/Accounts/AccountPermissionProfiles/delete) method. -1. **Creating a brand** - [Source.](./src/main/java/com/docusign/controller/examples/EG028ControllerCreateBrand.java) - This example creates brand profile for an account using the [Create Brand](https://developers.docusign.com/esign-rest-api/reference/Accounts/AccountBrands/create) method. -1. **Applying a brand to an envelope** - [Source.](./src/main/java/com/docusign/controller/examples/EG029ControllerApplyBrandToEnvelope.java) - This code example demonstrates how to apply a brand you've created to an envelope using the [Create Envelope](https://developers.docusign.com/esign-rest-api/reference/Envelopes/Envelopes/create) method. - First, creates the envelope and then applies brand to it. - Anchor text ([AutoPlace](https://support.docusign.com/en/guides/AutoPlace-New-DocuSign-Experience)) is used to position the signing fields in the documents. -1. **Applying a brand to a template** - [Source.](./src/main/java/com/docusign/controller/examples/EG030ControllerApplyBrandToTemplate.java) - This code example demonstrates how to apply a brand you've created to a template using using the [Create Envelope](https://developers.docusign.com/esign-rest-api/reference/Envelopes/Envelopes/create) method. - You must have at least one created template and brand. - -1. **Bulk sending envelopes to multiple recipients** - [Source.](./src/main/java/com/docusign/controller/examples/EG031ControllerBulkSendEnvelopes.java) - This example creates and sends a bulk envelope by generating a bulk recipient list and initiating a bulk send. - - - -## Included OAuth grant types: - -* Authentication with Docusign via [Authorization Code Grant flow](https://developers.docusign.com/esign-rest-api/guides/authentication/oauth2-code-grant) . -When the token expires, the user is asked to re-authenticate. -The **refresh token** is not used in this example. - -* Authentication with DocuSign via the [JSON Web Token (JWT) Grant](https://developers.docusign.com/esign-rest-api/guides/authentication/oauth2-jsonwebtoken). + +This repo is a Java Spring Boot application that supports the following authentication workflows: + +* Authentication with Docusign via [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode). +When the token expires, the user is asked to re-authenticate. The refresh token is not used. + +* Authentication with Docusign via [JSON Web Token (JWT) Grant](https://developers.docusign.com/platform/auth/jwt/). When the token expires, it updates automatically. +The [Spring Boot security Oauth2 boot autoconfigure package](https://github.com/spring-projects/spring-security-oauth2-boot/blob/master/spring-security-oauth2-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/UserInfoRestTemplateCustomizer.java) is used for authentication. -## Installation +The OAuth library is used in the file [WebSecurityConfig.java](https://github.com/docusign/code-examples-java/blob/master/src/main/java/com/docusign/WebSecurityConfig.java). + + +## eSignature API + +For more information about the scopes used for obtaining authorization to use the eSignature API, see [Required scopes](https://developers.docusign.com/docs/esign-rest-api/esign101/auth#required-scopes). + +For a list of code examples that use the eSignature API, see the [How-to guides overview](https://developers.docusign.com/docs/esign-rest-api/how-to/) on the Docusign Developer Center. -### Prerequisites -1. A DocuSign Developer Sandbox account (email and password) on [demo.docusign.net](https://demo.docusign.net). - Create a [free account](https://go.docusign.com/sandbox/productshot/?elqCampaignId=16533). -1. A DocuSign Integration Key (a client ID) that is configured to use the - OAuth Authorization Code flow. - You will need the **Integration Key** itself, and its **secret**. To - use JSON Web token, you will need the **Integration Key** itself, the - **RSA Secret Key** and an API user ID for the user you are impersonating. - - If you use this example on your own workstation, - the Integration key must include following **Redirect URI**s: - * http://localhost:8080/login&type=acg - * http://localhost:8080/login&type=jwt - If you will not be running the example on your own workstation, - use the appropriate DNS name and port instead of `localhost:8080`. - An example Redirect URI: http://myserver.it.mycompany.com/login +## Rooms API -1. Java 11. -1. A name and email for a signer, and a name and email for a cc recipient. - The signer and the cc email cannot be the same. -1. Maven +**Note:** To use the Rooms API, you must also [create your Rooms developer account](https://developers.docusign.com/docs/rooms-api/rooms101/create-account). Examples 4 and 6 require that you have the Docusign Forms feature enabled in your Rooms for Real Estate account. +For more information about the scopes used for obtaining authorization to use the Rooms API, see [Required scopes](https://developers.docusign.com/docs/rooms-api/rooms101/auth/). -### Short installation instructions -* Download or clone this repository. -* The project includes a Maven pom file. -* Create a file `code-examples-java/src/main/resources/application-dev.properties` and configure the project by overriding necessary properties from the `application.properties` file. **Don't add this file into the Git index.** -* Add VM argument `-Dspring.profiles.active=dev` to your IDE -* Note that IntelliJ Community Edition does not directly support - Spring Boot applications. +For a list of code examples that use the Rooms API, see the [How-to guides overview](https://developers.docusign.com/docs/rooms-api/how-to/) on the Docusign Developer Center. -### Build and run -Examples are built as a dedicated application with embedded TomCat server. Build: -``` bash -$ cd code-examples-java -$ mvn package -``` -Run: -``` bash -$ cd target -$ java -Dspring.profiles.active=dev -jar code-examples-java-1.0-SNAPSHOT.war -``` -### IntelliJ Ultimate installation +## Click API +For more information about the scopes used for obtaining authorization to use the Click API, see [Required scopes](https://developers.docusign.com/docs/click-api/click101/auth/#required-scopes) -See the [IntelliJ Ultimate instructions](https://github.com/docusign/eg-03-java-auth-code-grant/blob/master/docs/Readme_IntelliJ_Ultimate.md). +For a list of code examples that use the Click API, see the [How-to guides overview](https://developers.docusign.com/docs/click-api/how-to/) on the Docusign Developer Center. -## Configure the example -Configure the example via the properties file: -`eg-03-java-auth-code-grant/src/main/resources/application-dev.properties`. +## Monitor API -Add the client id, secret, signer name and email to the file. -Also add the URL that the application will use (the **DS_APP_URL** setting). -By default, this is http://localhost:8080 +**Note:** To use the Monitor API, you must also [enable Docusign Monitor for your organization](https://developers.docusign.com/docs/monitor-api/how-to/enable-monitor/). -You must also add a **Redirect URI** to the client id's settings in -DocuSign. The Redirect URIs are `/login&type=acg` and `/login&type=jwt` appended to the DS_APP_URL setting. -Eg http://localhost:8080/login&type=acg +For information about the scopes used for obtaining authorization to use the Monitor API, see the [scopes section](https://developers.docusign.com/docs/monitor-api/monitor101/auth/). -### Payments code example -To use the payments example, create a -test payments gateway for your developer sandbox account. +For a list of code examples that use the Monitor API, see the [How-to guides overview](https://developers.docusign.com/docs/monitor-api/how-to/) on the Docusign Developer Center. -See the -[PAYMENTS_INSTALLATION.md](https://github.com/docusign/eg-03-java-auth-code-grant/blob/master/PAYMENTS_INSTALLATION.md) -file for instructions. -Then add the payment gateway account id to the **application.properties** file. +## Admin API -## Using the examples with other authentication flows +**Note:** To use the Admin API, you must [create an organization](https://support.docusign.com/en/guides/org-admin-guide-create-org) in your Docusign developer account. Also, to run the Docusign CLM code example, [CLM must be enabled for your organization](https://support.docusign.com/en/articles/DocuSign-and-SpringCM). -The examples in this repository can also be used with the -JWT OAuth flow. -See the [Authentication guide](https://developers.docusign.com/esign-rest-api/guides/authentication) -for information on choosing the right authentication flow for your application. +For information about the scopes used for obtaining authorization to use the Admin API, see the [scopes section](https://developers.docusign.com/docs/admin-api/admin101/auth/). -## License and additional information +For a list of code examples that use the Admin API, see the [How-to guides overview](https://developers.docusign.com/docs/admin-api/how-to/) on the Docusign Developer Center. + + +## Web Forms API + +The Web Forms API is available in all developer accounts, but only in certain production account plans. Contact [Docusign Support](https://support.docusign.com/) or your account manager to find out whether the Web Forms API is available for your production account plan. + +For more information about the scopes used for obtaining authorization to use the Rooms API, see [Required scopes](https://developers.docusign.com/docs/web-forms-api/plan-integration/authentication/). + +For a list of code examples that use the Web Forms API, see the [How-to guides overview](https://developers.docusign.com/docs/web-forms-api/how-to/) on the Docusign Developer Center. + + +## Installation + +### Prerequisites +**Note:** If you downloaded this code using [Quickstart](https://developers.docusign.com/docs/esign-rest-api/quickstart/) from the Docusign Developer Center, skip items 1 and 2 as they were automatically performed for you. + +1. A free [Docusign developer account](https://go.docusign.com/o/sandbox/); create one if you don't already have one. +1. A Docusign app and integration key that is configured to use either [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) or [JWT Grant](https://developers.docusign.com/platform/auth/jwt/) authentication. + + This [video](https://www.youtube.com/watch?v=eiRI4fe5HgM) demonstrates how to obtain an integration key. + + To use [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/), you will need an integration key and a secret key. See [Installation steps](#installation-steps) for details. + + To use [JWT Grant](https://developers.docusign.com/platform/auth/jwt/), you will need an integration key, an RSA key pair, and the User ID GUID of the impersonated user. See [Installation steps for JWT Grant authentication](#installation-steps-for-jwt-grant-authentication) for details. + + For both authentication flows: + + If you use this launcher on your own workstation, the integration key must include redirect URIs of + + * http://localhost:8080/login&type=acg + * http://localhost:8080/login&type=jwt -### License -This repository uses the MIT License. See the LICENSE file for more information. + If you host this launcher on a remote web server, set your redirect URI as + + {base_url}/login + + where {base_url} is the URL for the web app. + +1. Download [JDK 11](https://jdk.java.net/java-se-ri/11) or later and extract to C:\Program Files\Java +1. Download [Maven](https://maven.apache.org/download.cgi) and extract to C: + * Follow these [instructions](https://maven.apache.org/install.html) to add both Java and Maven to the `PATH` environment variable. +1. [Git Bash command line](https://gitforwindows.org/), macOS Terminal, or Linux shell + + +### Installation steps + +**Note:** If you downloaded this code using [Quickstart](https://developers.docusign.com/docs/esign-rest-api/quickstart/) from the Docusign Developer Center, skip step 4 as it was automatically performed for you. + +1. Extract the Quickstart ZIP file or download or clone the code-examples-java repository. +1. In your command-line environment, switch to the : + `cd ` or `cd code-examples-java` +1. Package the code: `mvn package -Dmaven.test.skip=true` +1. To configure the launcher for [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) authentication, create a copy of the file src/main/resources/application.example.json and save the copy as src/main/resources/application.json. + 1. Add your User ID. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **My Account Information**, copy the **User ID** GUID and save it in application.json as your `DS_TARGET_ACCOUNT_ID`. + 1. Add your integration key. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **Apps and Integration Keys**, choose the app to use, then select **Actions > Edit**. Under **General Info**, copy the **Integration Key** GUID and save it in application.json as your `authorization.code.grant.client.client-id`. + 1. Generate a secret key, if you don’t already have one. Under **Authentication**, select **+ ADD SECRET KEY**. Copy the secret key and save it in application.json as your `authorization.code.grant.client.client-secret`. + 1. Add the launcher’s redirect URI. Under **Additional settings**, select **+ ADD URI**, and set a redirect URI of http://localhost:8080/login&type=acg. Select **SAVE**. + 1. Set a name and email address for the signer. In application.json, save an email address as `DS_SIGNER_EMAIL` and a name as `DS_SIGNER_NAME`. +**Note:** Protect your personal information. Please make sure that application.json will not be stored in your source code repository. + +#### Multiple code examples, Authorization Code Grant, and JWT Grant: +1. $ `cd ` +1. $ `mvn spring-boot:run` + +#### Authorization Code Grant embedded signing example: + +1. $ `cd /Quick_ACG` +1. $ `mvn spring-boot:run -Drun.profiles=dev` +For Windows: +1. $ `mvn spring-boot:run -D"run.profiles"="dev"` + +#### JWT grant remote signing example: +1. $ `cd /'JWT Console App'` +1. $ `mvn compile` +1. $ `mvn exec:java -Dexec.mainClass="com.docusign.jwtconsoleapp.JWTConsoleApp"` + For Windows +1. $ `mvn exec:java -D"exec.mainClass"="com.docusign.jwtconsoleapp.JWTConsoleApp"` + + +### Installation steps for JWT Grant authentication + +**Note:** If you downloaded this code using [Quickstart](https://developers.docusign.com/docs/esign-rest-api/quickstart/) from the Docusign Developer Center, skip step 4 as it was automatically performed for you. +Also, in order to select JSON Web Token authentication in the launcher, in src/main/resources/application.json, change the `quickstart` setting to `false`. + +1. Extract the Quickstart ZIP file or download or clone the code-examples-java repository. +1. In your command-line environment, switch to the folder: `cd ` or `cd code-examples-java` +1. Package the code: `mvn package` +1. To configure the launcher for [JWT Grant](https://developers.docusign.com/platform/auth/jwt/) authentication, create a copy of the file src/main/resources/application.example.json and save the copy as src/main/resources/application.json. + 1. Add your User ID. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **My Account Information**, copy the **User ID** GUID and save it in application.json as your `DS_TARGET_ACCOUNT_ID` and as your `jwt.grant.client.impersonated-user-guid`. + 1. Add your integration key. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **Apps and Integration Keys**, choose the app to use, then select **Actions > Edit**. Under **General Info**, copy the **Integration Key** GUID and save it in application.json as your `jwt.grant.client.client-id`. + 1. Generate an RSA key pair, if you don’t already have one. Under **Authentication**, select **+ GENERATE RSA**. Copy the private key, and save it in a new file named src/main/resources/private.key. + 1. Add the launcher’s redirect URI. Under **Additional settings**, select **+ ADD URI**, and set a redirect URI of http://localhost:8080/login&type=jwt. Select **SAVE**. + 1. Set a name and email address for the signer. In application.json, save an email address as `DS_SIGNER_EMAIL` and a name as `DS_SIGNER_NAME`. +**Note:** Protect your personal information. Please make sure that application.json will not be stored in your source code repository. +1. Run the launcher: `mvn exec:java -Dexec.mainClass="com.docusign.jwtconsoleapp.JWTConsoleApp"` (`mvn exec:java -D"exec.mainClass"="com.docusign.jwtconsoleapp.JWTConsoleApp"`) + The launcher automatically opens. +1. On the black navigation bar, select **Login**. +1. From the picklist, select **JSON Web Token (JWT) grant** > **Authenticate with Docusign**. +1. When prompted, log in to your DocuSign developer account. If this is your first time using the app, select **ACCEPT** at the consent window. +3. Select your desired code example. + + +## IntelliJ Ultimate instructions for Windows + +IntelliJ IDEA can be used with the launcher. The [IntelliJ IDEA Ultimate edition](https://www.jetbrains.com/idea/download/#section=windows) is required due to its support for Spring Boot and JSP view pages. + +**Note:** If you downloaded this code using [Quickstart](https://developers.docusign.com/docs/esign-rest-api/quickstart/) from the Docusign Developer Center, skip step 2 as it was automatically performed for you. + +1. Extract the Quickstart ZIP file or download or clone the code-examples-java repository. +1. To configure the launcher for [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) authentication, create a copy of the file src/main/resources/application.example.json and save the copy as src/main/resources/application.json. + 1. Add your User ID. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **My Account Information**, copy the **User ID** GUID and save it in application.json as your `DS_TARGET_ACCOUNT_ID`. + 1. Add your integration key. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **Apps and Integration Keys**, choose the app to use, then select **Actions > Edit**. Under **General Info**, copy the **Integration Key** GUID and save it in application.json as your `authorization.code.grant.client.client-id`. + 1. Generate a secret key, if you don’t already have one. Under **Authentication**, select **+ ADD SECRET KEY**. Copy the secret key and save it in application.json as your `authorization.code.grant.client.client-secret`. + 1. Add the launcher’s redirect URI. Under **Additional settings**, select **+ ADD URI**, and set a redirect URI of http://localhost:8080/login&type=acg. Select **SAVE**. + 1. Set a name and email address for the signer. In application.json, save an email address as `DS_SIGNER_EMAIL` and a name as `DS_SIGNER_NAME`. +**Note:** Protect your personal information. Please make sure that application.json will not be stored in your source code repository. +1. Start IntelliJ IDEA Ultimate. In the **Welcome to IntelliJ IDEA** dialog box, select **Open**. + 1. In the **Open File or Project** dialog box, select your Quickstart folder or code-examples-java, then select **OK**. + 1. In **Open or Import Project** dialog box, select **Maven project**, then select **OK**. +1. Create a Java application configuration: In the top navigation bar, select **Run** > **Edit configurations**. + 1. In the far left corner, select **+** > **Spring Boot**. + 1. To the right of **Main class**, select **... > App (com.docusign) code-examples-java**, then select **OK**. + 1. Under **Spring Boot**, select the **Enable debug output** checkbox, then select **OK**. +1. Run the launcher: In the top navigation bar, select **Run > Run 'App'**. The launcher automatically opens. + When prompted, log in to your Docusign developer account. If this is your first time using the app, select **ACCEPT** at the consent window. +1. [Optional] To install Lombok, select **File > Settings > Plugins > Marketplace** tab. To the right of the magnifying glass icon, input: `Lombok` + It should have an author named Michail Plushnikov. Select **Install**, then restart IntelliJ. + + +## Eclipse instructions for Windows + +**Note:** If you downloaded this code using [Quickstart](https://developers.docusign.com/docs/esign-rest-api/quickstart/) from the Docusign Developer Center, skip step 2 as it was automatically performed for you. + +1. Extract the Quickstart ZIP file or download or clone the code-examples-java repository. +1. To configure the launcher for [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) authentication, create a copy of the file src/main/resources/application.example.json and save the copy as src/main/resources/application.json. + 1. Add your User ID. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **My Account Information**, copy the **User ID** GUID and save it in application.json as your `DS_TARGET_ACCOUNT_ID`. + 1. Add your integration key. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **Apps and Integration Keys**, choose the app to use, then select **Actions > Edit**. Under **General Info**, copy the **Integration Key** GUID and save it in application.json as your `authorization.code.grant.client.client-id`. + 1. Generate a secret key, if you don’t already have one. Under **Authentication**, select **+ ADD SECRET KEY**. Copy the secret key and save it in application.json as your `authorization.code.grant.client.client-secret`. + 1. Add the launcher’s redirect URI. Under **Additional settings**, select **+ ADD URI**, and set a redirect URI of http://localhost:8080/login&type=acg. Select **SAVE**. + 1. Set a name and email address for the signer. In application.json, save an email address as `DS_SIGNER_EMAIL` and a name as `DS_SIGNER_NAME`. +**Note:** Protect your personal information. Please make sure that application.json will not be stored in your source code repository. + +1. Open Eclipse and select **File > Import**. In the **Import** dialog box, select **Existing Maven Project > Next > Browse**, browse for your Quickstart folder or code-examples-java, then **Select Folder**. + 1. Under **Projects**, the `pom.xml` file should be selected. + 1. To save the project link to your Eclipse workspace, select the **Add project(s) to working set** checkbox. Select **Finish**. +1. Next, select **Run**, then **Run Configurations**, and right-click **Maven Build**, then **New Configuration** to clean and compile the package. + 1. In the **Name** field, input: `build` + 1. In **Base directory**, input: `${workspace_loc:/code-examples-java}` + 1. In **Goals**, input: `clean package` + 1. Select the **JRE** tab. Under **Runtime JRE**, ensure it lists jdk-11 or higher. Select **Apply** to save. +1. In the **Run Configurations** dialog box, in the left sidebar, right-click **Java Application**, then select **New Configuration**. + 1. In the **Name** field, input: `App` + 1. In the **Project** field, input: `code-examples-java` + 1. In the **Main class** field, input: `com.docusign.App` + 1. Select the **JRE** tab. Under **Runtime JRE**, ensure it lists jdk-11 or higher. Select **Apply** to save. + 1. Select **Run** to run the launcher. The launcher automatically opens. + When prompted, log in to your Docusign developer account. If this is your first time using the app, select **ACCEPT** at the consent window. +1. [Optional] Download [lombok.jar](https://projectlombok.org/downloads/lombok.jar) to your local machine, then run the following command to install Lombok: `java -jar lombok.jar` + +## JWT grant remote signing project +See [Docusign Quickstart overview](https://developers.docusign.com/docs/esign-rest-api/quickstart/overview/) on the Docusign Developer Center for more information on how to run the JWT grant remote signing project. + +## Payments code example + +To use the payments code example, create a test payment gateway on the [**Payments**](https://admindemo.docusign.com/authenticate?goTo=payments) page in your developer account. See [Configure a payment gateway](./PAYMENTS_INSTALLATION.md) for details. + +Once you've created a payment gateway, save the **Gateway Account ID** GUID to application.json. + + +## License and additional information + +### License +This repository uses the MIT License. See [LICENSE](./LICENSE) for details. ### Pull Requests Pull requests are welcomed. Pull requests will only be considered if their content diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 00000000..3b9b1a89 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,137 @@ +# Starter pipeline +# Start with a minimal pipeline that you can customize to build and deploy your code. +# Add steps that build, run tests, deploy, and more: +# https://aka.ms/yaml +resources: + repositories: + - repository: launcher-automation + type: github + name: docusign/launcher-automation + ref: main + endpoint: launcherAutomationServiceConnection + +pr: +- master +- releases/* + +pool: + name: launcher-automation-pool + +steps: +- script: echo Hello, world! + displayName: 'Run a one-line script' +- checkout: self +- checkout: launcher-automation + +- script: dir $(Build.SourcesDirectory) + +- task: DownloadSecureFile@1 + name: java_dockerfile + displayName: 'download Dockerfile' + inputs: + secureFile: 'java.Dockerfile' + +- script: | + echo "place java.Dockerfile" + echo $(java_dockerfile.secureFilePath) + cp $(java_Dockerfile.secureFilePath) code-examples-java-private/Dockerfile + displayName: 'place Dockerfile' + +- script: | + allure –-version + java --version + javac --version + mvn --version + docker --version + +- task: DownloadSecureFile@1 + name: tests_config_properties + displayName: 'download config.properties' + inputs: + secureFile: 'java.config.properties' + + +- script: | + echo "place config.properties" + echo $(tests_config_properties.secureFilePath) + cp $(tests_config_properties.secureFilePath) launcher-automation/src/main/resources/config.properties + displayName: 'place config.properties' + +- task: DownloadSecureFile@1 + name: java_application + displayName: 'download application.json' + inputs: + secureFile: 'java.application.json' + + +- script: | + echo "place application.json" + cp $(java_application.secureFilePath) code-examples-java-private/src/main/resources/application.json + displayName: 'place application.json' + + +- task: DownloadSecureFile@1 + name: java_private_key + displayName: 'download private.key' + inputs: + secureFile: 'private.key' + + +- script: | + echo "place private.key" + cp $(java_private_key.secureFilePath) code-examples-java-private/src/main/resources/private.key + displayName: 'place private.key' + +- script: dir $(Build.SourcesDirectory) + +- script: dir $(Build.SourcesDirectory)/code-examples-java-private + +- script: dir $(Build.SourcesDirectory)/code-examples-java-private/src/main/resources + +- script: | + echo "Checking for running Docker containers..." + containers=$(docker ps -q) + if [ ! -z "$containers" ]; then + echo "Stopping running Docker containers..." + docker stop $(docker ps -q) + else + echo "No Docker containers are running." + fi + displayName: "check for running containers" + +- script: | + docker system prune -a --force + displayName: "cleanup docker files" + +- task: Docker@2 + displayName: Build java image + inputs: + command: build + repository: 'launcher-automation-java' + dockerfile: '$(Build.SourcesDirectory)/code-examples-java-private/Dockerfile' + buildContext: '$(Build.SourcesDirectory)/code-examples-java-private ' + tags: | + latest + +- script: | + docker run -p 8080:8080 -d launcher-automation-java:latest + displayName: 'start java app' + +- script: | + cd launcher-automation + mvn clean test -DsuiteXmlFile="java_suite.xml" + displayName: 'Java app tests' + +- script: | + docker stop $(docker ps -a -q) + docker rm $(docker ps -a -q) + displayName: 'stop java app' + +- script: | + allure generate --clean --output $(Build.SourcesDirectory)/java-allure-output '$(Build.SourcesDirectory)/launcher-automation/target/allure-results' + displayName: generate allure html reports + +- task: PublishAllureReport@1 + displayName: 'Publish Allure Report' + inputs: + reportDir: '$(Build.SourcesDirectory)/java-allure-output' \ No newline at end of file diff --git a/checkstyle.xml b/checkstyle.xml new file mode 100644 index 00000000..57627a62 --- /dev/null +++ b/checkstyle.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/code-examples-java.iml b/code-examples-java.iml index 6d509eea..23cbefe9 100644 --- a/code-examples-java.iml +++ b/code-examples-java.iml @@ -1,16 +1,24 @@ - + + + - - - + + + + + + + @@ -18,91 +26,162 @@ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/Adding_examples.md b/docs/Adding_examples.md index 757641a8..dd9b40aa 100644 --- a/docs/Adding_examples.md +++ b/docs/Adding_examples.md @@ -25,11 +25,11 @@ Examples should be self-contained within the scope of the launcher. For example, if your example operates on a template, -then either use the template created by example number 8, -or modify the template created by example 8 (eg add a field), +then either use the template created by Create a template, +or modify the template created by Create a template (eg add a field), or programmatically create a new template. -If you plan to change example 8, first discuss with the +If you plan to change Create a template, first discuss with the Examples Manager via apihelp@docusign.com. Do not require a user to create or modify a template by diff --git a/docs/IntelliJ_import_highlight.jpg b/docs/IntelliJ_import_highlight.jpg new file mode 100644 index 00000000..0ca31bba Binary files /dev/null and b/docs/IntelliJ_import_highlight.jpg differ diff --git a/docs/Readme_IntelliJ_Ultimate.md b/docs/Readme_IntelliJ_Ultimate.md deleted file mode 100644 index 071ab7e4..00000000 --- a/docs/Readme_IntelliJ_Ultimate.md +++ /dev/null @@ -1,58 +0,0 @@ -# IntelliJ installation - -The [IntelliJ IDE Ultimate edition](https://www.jetbrains.com/idea/) -can be used with the example. The IntelliJ Ultimate edition is -required due to its support for Spring Boot and JSP view pages. - -**Step 1.** Download or clone the -[eg-03-java-auth-code-grant](https://github.com/docusign/eg-03-java-auth-code-grant) - repository - -**Step 2.** Start IntelliJ Ultimate and choose the **Import Project** option. - -![IntelliJ Import project](install_fig_1.png) - -**Step 3.** Use the popup file chooser to select the -**code-examples-java** directory. - -**Step 4.** The **Import Project** wizard will open. It's a -series of screens. On the first screen, select -**Import project from external model** and **Maven**. - -![IntelliJ Import Maven project](install_fig_2.png) - -**Step 5.** Click **Finish** and the project will -be displayed in the IDE. - -## Configuring the project -Configure the example as discussed in the repository's Readme. - -## Running the example - -### Configuring the IDE's *Run/Debug Configuration* -IntelliJ uses **Run/Debug Configurations** to manage -settings for running the example. - -**One time:** setup a Run/Debug Configuration for the example: - -Step 1. Use the menu command **Run / Edit configurations...** -to open the configuration manager. - -Step 2. Click the **+** (plus) sign to add a new configuration. -The configuration type is **Spring Boot**. You may need to -open the additional templates section of the template chooser. - -Step 3. Update the form with the **Name** of the -configuration and the **Main class** for the configuration, -`com.docusign.App` **Tip:** use the **...** (ellipses) button next to the field to choose the Main class. - -Tip: check the **Enable debug output** checkbox. - -![Configure a Run configuration](install_fig_7.png) - -### Running or debugging the example - -Use a **Run** menu option to run or debug the example. - -After the application is ready for requests, open your -browser to http://localhost:8080 diff --git a/docs/ds-java-auth-final.zip b/docs/ds-java-auth-final.zip new file mode 100644 index 00000000..c18317e4 Binary files /dev/null and b/docs/ds-java-auth-final.zip differ diff --git a/docs/lombok_errors.png b/docs/lombok_errors.png new file mode 100644 index 00000000..bbe873cb Binary files /dev/null and b/docs/lombok_errors.png differ diff --git a/pom.xml b/pom.xml index a8236905..d224749a 100644 --- a/pom.xml +++ b/pom.xml @@ -1,12 +1,14 @@ - + 4.0.0 org.springframework.boot spring-boot-starter-parent - 2.2.1.RELEASE - + 2.7.18 + com.docusign @@ -17,10 +19,23 @@ Docusign Java Tutorial + src/main + src/test/java + 11 - 2.1.1.RELEASE - 2.6 - 3.5.0 + 2.5.6 + 2.16.1 + + 6.4.0 + 1.4.3 + 1.5.0 + 1.4.0 + 2.0.0 + 2.1.0 + 1.0.0-beta.9 + 2.2.22 + 2.17.2 + 3.1.10 @@ -28,44 +43,105 @@ org.springframework.boot spring-boot-starter-security + org.springframework.boot spring-boot-starter-web + - org.springframework.security.oauth.boot - spring-security-oauth2-autoconfigure - ${oauth2.version} + org.springframework.boot + spring-boot-starter-oauth2-client + + + + io.github.cdimascio + dotenv-java + 3.2.0 org.projectlombok lombok - true + 1.18.38 + provided + org.apache.commons commons-lang3 + org.freemarker freemarker + com.google.code.gson gson - + + com.fasterxml.jackson.datatype + jackson-datatype-joda + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + io.swagger.core.v3 + swagger-annotations + ${swagger-core-version} + + + + com.fasterxml.jackson.jakarta.rs + jackson-jakarta-rs-base + ${jackson-version} + + + + jakarta.ws.rs + jakarta.ws.rs-api + 3.1.0 + + + + javax.ws.rs + javax.ws.rs-api + 2.0.1 + + + + javax.servlet + javax.servlet-api + + + + commons-codec + commons-codec + 1.18.0 + + javax.servlet jstl + + + org.json + json + 20250517 + + org.apache.tomcat.embed tomcat-embed-jasper - provided @@ -73,15 +149,81 @@ commons-io ${commonsio.version} + com.docusign docusign-esign-java - ${docusign.version} + ${esignature.version} + + + + com.docusign + docusign-rooms-java + ${rooms.version} + shaded + + + + com.docusign + iam-sdk + ${iam.version} + + + + com.docusign + docusign-click-java + ${click.version} + + + + com.docusign + docusign-monitor-java + ${monitor.version} + + + + com.docusign + docusign-admin-java + ${admin.version} + + + + com.docusign + docusign-webforms-java + ${webforms.version} + + + + org.springframework.boot + spring-boot-autoconfigure + + + + org.glassfish.jersey.media + jersey-media-json-jackson + ${jersey2.version} + + + + org.junit.jupiter + junit-jupiter-api + test + + + + org.junit.jupiter + junit-jupiter-params + test + + org.apache.maven.plugins + maven-surefire-plugin + + org.springframework.boot spring-boot-maven-plugin @@ -89,7 +231,103 @@ true + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + org.projectlombok + lombok + 1.18.38 + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.6.0 + + checkstyle.xml + warning + true + + - + + + + org.bouncycastle + bcprov-jdk15on + + + + com.fasterxml.jackson.core + jackson-databind + 2.13.5 + + + + org.yaml + snakeyaml + 2.4 + + + + net.minidev + json-smart + 2.5.2 + + + + com.nimbusds + nimbus-jose-jwt + 10.3 + + + + org.springframework.security + spring-security-core + 5.7.12 + + + + org.glassfish.jersey.core + jersey-client + ${jersey2.version} + + + + org.glassfish.jersey.inject + jersey-hk2 + ${jersey2.version} + + + + org.glassfish.jersey.core + jersey-common + ${jersey2.version} + + + + ch.qos.logback + logback-core + 1.5.18 + + + + ch.qos.logback + logback-classic + 1.5.18 + test + + + + \ No newline at end of file diff --git a/src/main/java/com/docusign/App.java b/src/main/java/com/docusign/App.java index 9c829ef7..9598d85d 100644 --- a/src/main/java/com/docusign/App.java +++ b/src/main/java/com/docusign/App.java @@ -1,16 +1,85 @@ package com.docusign; +import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; +import java.awt.*; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.FileSystemAlreadyExistsException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; + +@Slf4j +@SpringBootApplication(exclude = {JmxAutoConfiguration.class}) +@ComponentScan(basePackages = "com.docusign") +@Import(WebSecurityConfig.class) -@SpringBootApplication -@EnableAutoConfiguration(exclude={JmxAutoConfiguration.class}) public class App { - public static void main(String[] args) { - SpringApplication.run(App.class, args); + public static void main(String[] args) throws IOException, URISyntaxException { + initFileSystem(); + + ClassLoader classLoader = App.class.getClassLoader(); + URL applicationJsonURL = classLoader.getResource("application.json"); + + if (applicationJsonURL != null) { + SpringApplication.run(App.class, args); + openHomePage(); + } else { + InputStream inputStream = classLoader.getResourceAsStream("applicationJsonMissingError.html"); + + if (inputStream.available() > 0) { + Path path = Files.createTempFile("applicationJsonMissingError", ".html"); + try (FileOutputStream out = new FileOutputStream(path.toFile())) { + byte[] buffer = new byte[1024]; + int len; + while ((len = inputStream.read(buffer)) != -1) { + out.write(buffer, 0, len); + } + } catch (IOException e) { + log.error("File applicationJsonMissingError.html could not be accessed."); + } + + Desktop.getDesktop().browse(path.toUri()); + } + + log.info(""); + log.info("Please, add the application.json file to the resources folder."); + log.info(""); + } + } + + private static void openHomePage() throws IOException { + System.setProperty("java.awt.headless", "false"); + try { + Desktop.getDesktop().browse(new URI("http://localhost:8080")); + } catch (URISyntaxException use) { + log.error("Invalid URI in App.openHomePage()"); + } + } + + private static void initFileSystem() { + try { + FileSystems.newFileSystem(new URI(""), Collections.emptyMap()); + log.info("FileSystem initialized successfully"); + } catch (Exception e) { + if (e instanceof FileSystemAlreadyExistsException) { + log.info("FileSystem is already initialized"); + } else { + log.info("Retrieving the default initialize context"); + FileSystems.getDefault(); + } + } } } diff --git a/src/main/java/com/docusign/DSConfiguration.java b/src/main/java/com/docusign/DSConfiguration.java index c536e46e..bcc35efa 100644 --- a/src/main/java/com/docusign/DSConfiguration.java +++ b/src/main/java/com/docusign/DSConfiguration.java @@ -1,26 +1,63 @@ package com.docusign; +import com.docusign.common.ApiIndex; +import com.docusign.core.model.ApiType; +import com.docusign.core.model.manifestModels.ManifestStructure; +import com.docusign.esign.client.auth.OAuth; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.ws.rs.HttpMethod; +import jakarta.ws.rs.core.HttpHeaders; import lombok.Getter; +import lombok.Setter; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; import org.springframework.stereotype.Component; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; @Component @Getter +@Setter public class DSConfiguration { + public Boolean isConsentRedirectActivated = false; + + public String apiTypeHeader = "ApiType"; + @Value("${com.docusign.github.example-uri}") private String exampleUrl; @Value("${com.docusign.documentation-path}") private String documentationPath; + private String selectedApiType; + + private ManifestStructure codeExamplesText; + + private boolean additionalRedirect; + + private boolean shareAccessExampleScenario; + + private String principalUserId; + @Value("${DS_TARGET_ACCOUNT_ID}") private String targetAccountId; @Value("${DS_APP_URL}") private String appUrl; + @Value("${DS_BASE_PATH}") + private String basePath; + + @Value("${DS_ROOMS_BASE_PATH}") + private String roomsBasePath; + + @Value("${DS_CLICK_BASE_PATH}") + private String clickBasePath; + @Value("${DS_SIGNER_EMAIL:{USER_EMAIL}}") private String signerEmail; @@ -30,12 +67,57 @@ public class DSConfiguration { @Value("${Gateway_Account_Id}") private String gatewayAccountId; + @Value("${spring.security.oauth2.client.registration.jwt.client-id}") + private String userId; + + @Value("${spring.security.oauth2.client.registration.acg.client-secret}") + private String secretUserId; + + @Value("${spring.security.oauth2.client.provider.acg.token-uri}") + private String tokenEndpoint; + + @Value("${spring.security.oauth2.client.provider.acg.authorization-uri}") + private String authorizationEndpoint; + + @Value("${jwt.grant.sso.redirect-url}") + private String jwtRedirectURL; + + @Value("${authorization.code.grant.sso.redirect-url}") + private String acgRedirectURL; + + @Value("${spring.security.oauth2.client.registration.jwt.private-key-path}") + private String privateKeyPath; + + @Value("${spring.security.oauth2.client.registration.jwt.impersonated-user-guid}") + private String impersonatedUserId; + + @Value("${jwt.grant.client.base-url}") + private String baseURL; + @Value("${Gateway_Name}") private String gatewayName; @Value("${Gateway_Display_Name}") private String gatewayDisplayName; + @Value("${quickstart:{quickstart}}") + private String quickstart; + + @Value("${quickACG:{quickACG}}") + private String quickACG; + + @Value("${DS_MONITOR_BASE_PATH}") + private String monitorBasePath; + + @Value("${DS_ADMIN_BASE_PATH}") + private String adminBasePath; + + @Value("${DS_WEBFORMS_BASE_PATH}") + private String webFormsBasePath; + + @Value("${CodeExamplesManifest}") + private String codeExamplesManifest; + public String getDsReturnUrl() { return appUrl + "/ds-return"; } @@ -43,4 +125,76 @@ public String getDsReturnUrl() { public String getDsPingUrl() { return appUrl + "/"; } -} + + public String getBaseUrl(ApiIndex apiIndex, OAuth.Account oauthAccount) { + if (ApiIndex.ROOMS.equals(apiIndex)) { + return roomsBasePath; + } else if (ApiIndex.CLICK.equals(apiIndex)) { + return clickBasePath; + } else if (ApiIndex.MONITOR.equals(apiIndex)) { + return monitorBasePath; + } else if (ApiIndex.ADMIN.equals(apiIndex)) { + return adminBasePath; + } + + return oauthAccount.getBaseUri(); + } + + public ApiType getSelectedApiType() { + if (selectedApiType == null) { + return ApiType.ESIGNATURE; + } + + return ApiType.valueOf(selectedApiType); + } + + public ApiIndex getSelectedApiIndex() { + if (selectedApiType == null) { + return ApiIndex.ESIGNATURE; + } + + return ApiIndex.valueOf(selectedApiType); + } + + public ManifestStructure getCodeExamplesText() { + if (codeExamplesText != null) { + return codeExamplesText; + } + + try { + codeExamplesText = new ObjectMapper().readValue(loadFileData(codeExamplesManifest), + ManifestStructure.class); + } catch (Exception e) { + e.printStackTrace(); + } + + return codeExamplesText; + } + + public String loadFileData(String linkToManifestFile) throws Exception { + URL fullRequestPath = new URL(linkToManifestFile); + HttpURLConnection httpConnection = (HttpURLConnection) fullRequestPath.openConnection(); + httpConnection.setRequestMethod(HttpMethod.GET); + + httpConnection.setRequestProperty( + HttpHeaders.CONTENT_TYPE, + String.valueOf(MediaType.APPLICATION_JSON)); + + int responseCode = httpConnection.getResponseCode(); + + if (responseCode < HttpURLConnection.HTTP_OK || responseCode >= HttpURLConnection.HTTP_BAD_REQUEST) { + throw new Exception(httpConnection.getResponseMessage()); + } + + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpConnection.getInputStream())); + StringBuilder stringBuilder = new StringBuilder(); + String temp; + while ((temp = bufferedReader.readLine()) != null) { + stringBuilder.append(temp); + } + bufferedReader.close(); + httpConnection.disconnect(); + + return stringBuilder.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/docusign/EG001ControllerEmbeddedSigning.java b/src/main/java/com/docusign/EG001ControllerEmbeddedSigning.java new file mode 100644 index 00000000..cce51831 --- /dev/null +++ b/src/main/java/com/docusign/EG001ControllerEmbeddedSigning.java @@ -0,0 +1,105 @@ +package com.docusign; + +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.examples.AbstractEsignatureController; +import com.docusign.controller.eSignature.services.EmbeddedSigningService; +import com.docusign.core.common.Utils; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.RecipientViewRequest; +import com.docusign.esign.model.ViewUrl; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.view.RedirectView; + +import javax.servlet.http.HttpServletResponse; + + +/** + * Use embedded signing. + * This example sends an envelope, and then uses embedded signing + * for the first signer. Embedded signing provides a smoother user experience + * for the signer: the DocuSign signing is initiated from your site. + */ +@Controller +@RequestMapping("/eg001") +public class EG001ControllerEmbeddedSigning extends AbstractEsignatureController { + + private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String DOCUMENT_NAME = "Lorem Ipsum"; + + private static final int ANCHOR_OFFSET_Y = 20; + + private static final int ANCHOR_OFFSET_X = 10; + + private static final String SIGNER_CLIENT_ID = "1000"; + + public EG001ControllerEmbeddedSigning(DSConfiguration config, Session session, User user) { + super(config, Boolean.valueOf(config.getQuickACG()) ? "quickEmbeddedSigning" : "eg001", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + if (Utils.isCfr(session.getBasePath(), user.getAccessToken(), session.getAccountId())) { + session.setStatusCFR("enabled"); + throw new Exception(config.getCodeExamplesText().getSupportingTexts().getCFRError()); + } + if (config.getQuickstart().equals("true")) { + config.setQuickstart("false"); + } + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws Exception { + String signerName = args.getSignerName(); + String signerEmail = args.getSignerEmail(); + String accountId = session.getAccountId(); + + // Create the envelope definition + //ds-snippet-start:eSign1Step3 + EnvelopeDefinition envelope = EmbeddedSigningService.makeEnvelope( + signerEmail, + signerName, + SIGNER_CLIENT_ID, + ANCHOR_OFFSET_Y, + ANCHOR_OFFSET_X, + DOCUMENT_FILE_NAME, + DOCUMENT_NAME); + + // Call DocuSign to create the envelope + ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); + + String envelopeId = EmbeddedSigningService.createEnvelope(apiClient, session.getAccountId(), envelope); + //ds-snippet-end + session.setEnvelopeId(envelopeId); + + // Create the recipient view, the embedded signing + //ds-snippet-start:eSign1Step5 + RecipientViewRequest viewRequest = EmbeddedSigningService.makeRecipientViewRequest( + signerEmail, + signerName, + SIGNER_CLIENT_ID, + config.getDsReturnUrl(), + config.getDsPingUrl()); + + ViewUrl viewUrl = EmbeddedSigningService.embeddedSigning( + apiClient, + accountId, + envelopeId, + viewRequest + ); + + // Redirect the user to the embedded signing + // Don't use an iFrame! + // State can be stored/recovered using the framework's session or a + // query parameter on the returnUrl (see the makeRecipientViewRequest method) + return new RedirectView(viewUrl.getUrl()); + //ds-snippet-end + } +} diff --git a/src/main/java/com/docusign/HttpsConnectWebhookhMacValidation.java b/src/main/java/com/docusign/HttpsConnectWebhookhMacValidation.java new file mode 100644 index 00000000..f71c891a --- /dev/null +++ b/src/main/java/com/docusign/HttpsConnectWebhookhMacValidation.java @@ -0,0 +1,58 @@ +package com.docusign; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +public class HttpsConnectWebhookhMacValidation { + + private static final Logger LOGGER = LoggerFactory.getLogger(HttpsConnectWebhookhMacValidation.class); + + /* + * Useful reference: + * https://docs.oracle.com/javase/10/docs/api/javax/crypto/Mac.html + * https://docs.oracle.com/javase/10/docs/specs/security/standard-names.html#mac + * -algorithms + */ + //ds-snippet-start:Connect1Step1 + private static String ComputeHash(String secret, byte[] payload) + throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException { + String digest = "HmacSHA256"; + Mac mac = Mac.getInstance(digest); + mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), digest)); + return Base64.getEncoder().encodeToString(mac.doFinal(payload)); + } + + public static boolean HashIsValid(String secret, byte[] payload, String verify) + throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException { + String computedHash = ComputeHash(secret, payload); + boolean isEqual = MessageDigest.isEqual(computedHash.getBytes(StandardCharsets.UTF_8), + verify.getBytes(StandardCharsets.UTF_8)); + return isEqual; + } + //ds-snippet-end:Connect1Step1 + + public static void main(String[] args) + { + LOGGER.info("DocuSign HMAC Tester"); + try { + Boolean response = HttpsConnectWebhookhMacValidation.HashIsValid("{DocuSign HMAC private key}", + Files.readAllBytes(Paths.get("payload.txt")), "{JSON response Signature}"); + LOGGER.info("is this HMAC Valid? "); + LOGGER.info(String.valueOf(response)); + } catch (Exception e) { + LOGGER.error("Error!!! "); + LOGGER.error(e.getMessage()); + } + } +} diff --git a/src/main/java/com/docusign/JsonPropertySourceLoader.java b/src/main/java/com/docusign/JsonPropertySourceLoader.java new file mode 100644 index 00000000..c25de2fe --- /dev/null +++ b/src/main/java/com/docusign/JsonPropertySourceLoader.java @@ -0,0 +1,10 @@ +package com.docusign; + +import org.springframework.boot.env.YamlPropertySourceLoader; + +public class JsonPropertySourceLoader extends YamlPropertySourceLoader { + @Override + public String[] getFileExtensions() { + return new String[]{"json"}; + } +} \ No newline at end of file diff --git a/src/main/java/com/docusign/WebSecurityConfig.java b/src/main/java/com/docusign/WebSecurityConfig.java index bcfd93d6..494a4b96 100644 --- a/src/main/java/com/docusign/WebSecurityConfig.java +++ b/src/main/java/com/docusign/WebSecurityConfig.java @@ -1,142 +1,53 @@ package com.docusign; -import com.docusign.security.OAuthProperties; -import com.docusign.security.jwt.JWTAuthorizationCodeResourceDetails; -import com.docusign.security.jwt.JWTOAuth2RestTemplate; -import com.docusign.security.jwt.JWTUserInfoTokenService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2SsoProperties; -import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties; -import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.SecurityConfigurerAdapter; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.oauth2.client.OAuth2ClientContext; -import org.springframework.security.oauth2.client.OAuth2RestTemplate; -import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter; -import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter; -import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails; -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client; -import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices; -import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; -import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter; -import org.springframework.web.filter.CompositeFilter; +import org.springframework.security.web.savedrequest.HttpSessionRequestCache; +import org.springframework.security.web.savedrequest.RequestCache; -import java.util.Arrays; -import java.util.List; -import javax.servlet.Filter; +import com.docusign.core.security.CustomAuthenticationFailureHandler; -@EnableOAuth2Client -@Configuration -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { +@EnableWebSecurity +public class WebSecurityConfig { @Autowired - private OAuth2ClientContext oAuth2ClientContext; + public DSConfiguration dsConfiguration; @Bean - @ConfigurationProperties("authorization.code.grant.sso") - public OAuthProperties authCodeGrantSso() { - return new OAuthProperties(); + public RequestCache requestCache() { + return new HttpSessionRequestCache(); } @Bean - @ConfigurationProperties("jwt.grant.sso") - public OAuthProperties jwtGrantSso() { - return new OAuthProperties(); - } - - @Bean - @ConfigurationProperties("authorization.code.grant.client") - public AuthorizationCodeResourceDetails authCodeGrantClient() { - return new AuthorizationCodeResourceDetails(); - } - - @Bean - @ConfigurationProperties("jwt.grant.client") - public JWTAuthorizationCodeResourceDetails jwtCodeGrantClient() { - return new JWTAuthorizationCodeResourceDetails(); - } - - @Bean - @ConfigurationProperties("common.client.resource") - public ResourceServerProperties userInfoResource() { - return new ResourceServerProperties(); - } - - @Bean - public FilterRegistrationBean oAuth2ClientFilterRegistration(OAuth2ClientContextFilter oAuth2ClientContextFilter) { - FilterRegistrationBean registration = new FilterRegistrationBean<>(); - registration.setFilter(oAuth2ClientContextFilter); - registration.setOrder(-100); - return registration; - } - - private OAuth2ClientAuthenticationProcessingFilter authCodeGrantFilter() { - OAuth2SsoProperties authCodeGrantSso = authCodeGrantSso(); - AuthorizationCodeResourceDetails authCodeGrantClient = authCodeGrantClient(); - ResourceServerProperties userInfoResource = userInfoResource(); - OAuth2ClientAuthenticationProcessingFilter filter = - new OAuth2ClientAuthenticationProcessingFilter(authCodeGrantSso.getLoginPath()); - OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(authCodeGrantClient, oAuth2ClientContext); - filter.setRestTemplate(restTemplate); - ResourceServerTokenServices tokenServices = new UserInfoTokenServices(userInfoResource.getUserInfoUri(), - authCodeGrantClient.getClientId()); - filter.setTokenServices(tokenServices); - return filter; - } - - private OAuth2ClientAuthenticationProcessingFilter jwtGrantFilter() { - OAuth2SsoProperties authCodeGrantSso = jwtGrantSso(); - JWTAuthorizationCodeResourceDetails jwtCodeGrantClient = jwtCodeGrantClient(); - OAuth2ClientAuthenticationProcessingFilter filter = - new OAuth2ClientAuthenticationProcessingFilter(authCodeGrantSso.getLoginPath()); - OAuth2RestTemplate restTemplate = new JWTOAuth2RestTemplate(jwtCodeGrantClient, oAuth2ClientContext); - filter.setRestTemplate(restTemplate); - ResourceServerTokenServices tokenServices = new JWTUserInfoTokenService(jwtCodeGrantClient); - filter.setTokenServices(tokenServices); - return filter; - } - - @Override - protected void configure(HttpSecurity http) throws Exception { - + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .antMatcher("/**") - .authorizeRequests() - .antMatchers( "/", "/login**", "/error**", "/assets/**","/ds/mustAuthenticate**", - "/ds/authenticate**") - .permitAll() - .anyRequest() - .authenticated() - .and() - .exceptionHandling() - .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/ds/mustAuthenticate")) - .and() - .logout().logoutSuccessUrl("/").permitAll() - .and() - .csrf().disable(); - http.apply(new CombinedAuthenticationConfigurer(Arrays.asList(authCodeGrantFilter(), - jwtGrantFilter()))); - } - - private static class CombinedAuthenticationConfigurer - extends SecurityConfigurerAdapter { - - CompositeFilter filter = new CompositeFilter(); - - CombinedAuthenticationConfigurer(List filters) { - filter.setFilters(filters); - } - - @Override - public void configure(HttpSecurity builder) { - builder.addFilterAfter(this.filter, - AbstractPreAuthenticatedProcessingFilter.class); - } - } -} + .authorizeHttpRequests(authorize -> { + try { + authorize + .antMatchers("/", "/error**", "/assets/**", "/ds/mustAuthenticate**", + "/ds/authenticate**", "/ds/selectApi**", "/con001", "/pkce") + .permitAll() + .anyRequest().authenticated() + .and() + .exceptionHandling() + .authenticationEntryPoint( + new LoginUrlAuthenticationEntryPoint("/ds/mustAuthenticate")); + } catch (Exception e) { + throw new RuntimeException(e); + } + }) + .requestCache().requestCache(requestCache()).and() + .oauth2Login(login -> login.failureHandler(new CustomAuthenticationFailureHandler())) + .oauth2Client(Customizer.withDefaults()) + .logout(logout -> logout + .logoutSuccessUrl("/")) + .csrf().disable(); + + return http.build(); + } +} \ No newline at end of file diff --git a/src/main/java/com/docusign/common/ApiIndex.java b/src/main/java/com/docusign/common/ApiIndex.java new file mode 100644 index 00000000..d17d9ea1 --- /dev/null +++ b/src/main/java/com/docusign/common/ApiIndex.java @@ -0,0 +1,49 @@ +package com.docusign.common; + +public enum ApiIndex { + ESIGNATURE("/pages/esignature/index", "/restapi", "/eg001", "/eg"), + ROOMS("/pages/rooms/index", "/restapi", "/r001", "/r"), + CLICK("/pages/click/index", "/clickapi", "/c001", "/c"), + MONITOR("/pages/monitor/index", "", "/m001", "/m"), + ADMIN("/pages/admin/index", "/management", "/a001", "/a"), + CONNECT("/pages/connect/index", "", "/con001", "/con"), + NAVIGATOR("/pages/navigator/index", "/restapi", "/nav001", "/nav"), + NOTARY("/pages/notary/index", "/restapi", "/n004", "/n"), + WEBFORMS("/pages/webforms/index", "/restapi", "/web001", "/web"), + MAESTRO("/pages/maestro/index", "/restapi", "/mae001", "/mae"), + CONNECTEDFIELDS("/pages/connectedfields/index", "/restapi", "/cf001", "/cf"), + WORKSPACES("/pages/workspaces/index", "/restapi", "/work001", "/work"); + + private final String indexPath; + + private final String baseUrlSuffix; + + private final String firstExamplePath; + + private final String examplesPathCode; + + ApiIndex(final String indexPath, final String baseUrlSuffix, final String firstExamplePath, + final String examplesPathCode) { + this.indexPath = indexPath; + this.baseUrlSuffix = baseUrlSuffix; + this.firstExamplePath = firstExamplePath; + this.examplesPathCode = examplesPathCode; + } + + public String getBaseUrlSuffix() { + return baseUrlSuffix; + } + + public String getPathOfFirstExample() { + return firstExamplePath; + } + + public String getExamplesPathCode() { + return examplesPathCode; + } + + @Override + public String toString() { + return this.indexPath; + } +} \ No newline at end of file diff --git a/src/main/java/com/docusign/common/WorkArguments.java b/src/main/java/com/docusign/common/WorkArguments.java new file mode 100644 index 00000000..eebb42d1 --- /dev/null +++ b/src/main/java/com/docusign/common/WorkArguments.java @@ -0,0 +1,197 @@ +package com.docusign.common; + +import lombok.Data; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; +import org.springframework.web.context.WebApplicationContext; + +import java.util.UUID; + +@Component +@Scope(value = WebApplicationContext.SCOPE_REQUEST) +@Data +public class WorkArguments { + private String item; + + private String quantity; + + private String signerEmail; + + private String signerName; + + private String ccEmail; + + private String ccName; + + private String clickwrapName; + + private String signerEmail2; + + private String signerName2; + + private String ccEmail2; + + private String ccName2; + + private String status; + + private String startingView; + + private String dsReturnUrl; + + private String dsPingUrl; + + private String signerClientId; + + private String signerCheckedEmail; + + private String signerCheckedName; + + private String signerNotCheckedEmail; + + private String signerNotCheckedName; + + private String docSelect; + + private String accessCode; + + private String brandName; + + private String language; + + private String brandId; + + private String templateId; + + private String profileId; + + private String appId; + + private String groupId; + + private String agreementId; + + private String envelopeId; + + private String permissionProfileName; + + private String phoneNumber; + + private Integer roleId; + + private String roomName; + + private Integer roomTemplateId; + + private Integer roomId; + + private Integer officeId; + + private UUID formId; + + private String formGroupName; + + private UUID formGroupId; + + private String startDate; + + private String endDate; + + private String deliveryMethod; + + private String ccPhoneNumber; + + private String countryCode; + + private String ccCountryCode; + + private String email; + + private String userName; + + private String firstName; + + private String lastName; + + private String clmProfileId; + + private UUID clmProductId; + + private String eSignProfileId; + + private UUID eSignProductId; + + private String PermissionProfileId; + + private UUID ProductId; + + private UUID dsGroupId; + + private UUID userId; + + private String resumeDate; + + private String delay; + + private String clickwrap; + + private String clickwrapId; + + private String documentId; + + private String hostEmail; + + private String hostName; + + private String fullName; + + private String company; + + private String title; + + private String date; + + private String candidateEmail; + + private String candidateName; + + private String managerName; + + private String jobTitle; + + private String salary; + + private String rsus; + + private String agentEmail; + + private String agentName; + + private String activationCode; + + private UUID sourceAccountId; + + private String targetAccountName; + + private String targetAccountFirstName; + + private String targetAccountLastName; + + private String targetAccountEmail; + + private String hmacSecret; + + private String jsonPayload; + + private String instanceName; + + private String folderName; + + private String workspaceName; + + private String documentName; + + private String documentPath; + + private String assigneeEmail; +} diff --git a/src/main/java/com/docusign/controller/IndexController.java b/src/main/java/com/docusign/controller/IndexController.java deleted file mode 100644 index ccee7808..00000000 --- a/src/main/java/com/docusign/controller/IndexController.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.docusign.controller; - -import com.docusign.model.AuthType; -import com.docusign.model.Session; -import com.docusign.security.OAuthProperties; -import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.servlet.ModelAndView; -import org.springframework.web.servlet.view.RedirectView; - - -@Controller -public class IndexController { - - private static final String ATTR_ENVELOPE_ID = "qpEnvelopeId"; - private static final String ATTR_STATE = "state"; - private static final String ATTR_EVENT = "event"; - private static final String ATTR_TITLE = "title"; - - @Autowired - private Session session; - - @Autowired - private OAuthProperties jwtGrantSso; - - @Autowired - private OAuthProperties authCodeGrantSso; - - @GetMapping(path = "/") - public String index(ModelMap model) { - model.addAttribute(ATTR_TITLE,"Home"); - return "pages/index"; - } - - @GetMapping(path = "/ds/mustAuthenticate") - public ModelAndView mustAuthenticateController(ModelMap model) { - model.addAttribute(ATTR_TITLE, "Authenticate with DocuSign"); - if (session.isRefreshToken()) { - return new ModelAndView(getRedirectView(session.getAuthTypeSelected())); - } - return new ModelAndView("pages/ds_must_authenticate"); - } - - @RequestMapping(path = "/ds/authenticate", method = RequestMethod.POST) - public RedirectView authenticate(ModelMap model, - @RequestBody MultiValueMap formParams) { - if (!formParams.containsKey("selectAuthType")) { - model.addAttribute("message", - "select option with selectAuthType name must be provided"); - return new RedirectView("pages/error"); - } - List selectAuthTypeObject = formParams.get("selectAuthType"); - AuthType authTypeSelected = AuthType.valueOf(selectAuthTypeObject.get(0)); - return getRedirectView(authTypeSelected); - } - - @GetMapping(path = "/ds-return") - public String returnController(@RequestParam(value=ATTR_STATE, required = false) String state, - @RequestParam(value=ATTR_EVENT, required = false) String event, - @RequestParam(value="envelopeId", required = false) String envelopeId, - ModelMap model) { - model.addAttribute(ATTR_TITLE , "Return from DocuSign"); - model.addAttribute(ATTR_EVENT, event); - model.addAttribute(ATTR_STATE, state); - model.addAttribute(ATTR_ENVELOPE_ID, envelopeId); - return "pages/ds_return"; - } - - private RedirectView getRedirectView(AuthType authTypeSelected) { - session.setAuthTypeSelected(authTypeSelected); - RedirectView redirect = new RedirectView(getLoginPath(authTypeSelected)); - redirect.setExposeModelAttributes(false); - return redirect; - } - - private String getLoginPath(AuthType authTypeSelected) { - OAuthProperties oAuth2SsoProperties = authCodeGrantSso; - if (authTypeSelected.equals(AuthType.JWT)) { - oAuth2SsoProperties = jwtGrantSso; - } - return oAuth2SsoProperties.getLoginPath(); - } -} diff --git a/src/main/java/com/docusign/controller/admin/examples/A001AddActiveUser.java b/src/main/java/com/docusign/controller/admin/examples/A001AddActiveUser.java new file mode 100644 index 00000000..08e519bc --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/examples/A001AddActiveUser.java @@ -0,0 +1,115 @@ +package com.docusign.controller.admin.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.api.UsersApi; +import com.docusign.admin.client.ApiException; +import com.docusign.admin.model.NewUserResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.admin.services.AddActiveUserService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.api.GroupsApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.model.GroupInformation; +import com.docusign.esign.model.PermissionProfileInformation; +import jakarta.ws.rs.core.HttpHeaders; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletResponse; +import java.util.UUID; + +/** + * Create new user + * This example demonstrates how to create a new user with methods from Admin API. + */ +@Controller +@RequestMapping("/a001") +public class A001AddActiveUser extends AbstractAdminController { + + private static final Logger LOGGER = LoggerFactory.getLogger(A001AddActiveUser.class); + + private static final String MODEL_LIST_PROFILES = "listProfiles"; + + private static final String MODEL_LIST_GROUPS = "listGroups"; + + public A001AddActiveUser(DSConfiguration config, Session session, User user) { + super(config, "a001", user, session); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + + try { + super.onInitModel(args, model); + LOGGER.info("super called"); + //ds-snippet-start:Admin1Step2 + ApiClient apiClient = new ApiClient("https://demo.docusign.net/restapi"); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + user.getAccessToken()); + //ds-snippet-end:Admin1Step2 + LOGGER.info("API client called"); + + //ds-snippet-start:Admin1Step3 + AccountsApi accountsApi = new AccountsApi(apiClient); + LOGGER.info(this.user.getAccessToken()); + LOGGER.info(this.session.getBasePath()); + + UUID orgId = this.getOrganizationId(this.user.getAccessToken(), this.session.getBasePath()); + LOGGER.info("we have an org id: " + orgId); + UUID accountId = this.getExistingAccountId(this.user.getAccessToken(), this.session.getBasePath(), orgId); + LOGGER.info("An accountID: " + accountId); + PermissionProfileInformation permissionsInfo = accountsApi.listPermissions(String.valueOf(accountId)); + //ds-snippet-end:Admin1Step3 + LOGGER.info("and permissions info too: " + permissionsInfo); + model.addAttribute(MODEL_LIST_PROFILES, permissionsInfo.getPermissionProfiles()); + + //ds-snippet-start:Admin1Step4 + GroupsApi groupsApi = new GroupsApi(apiClient); + GroupInformation groupInformation = groupsApi.listGroups(String.valueOf(accountId)); + //ds-snippet-end:Admin1Step4 + + model.addAttribute(MODEL_LIST_GROUPS, groupInformation.getGroups()); + } catch (ApiException e) { + LOGGER.info(String.valueOf(e)); + } + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + LOGGER.info("doWork function called"); + String accessToken = this.user.getAccessToken(); + String basePath = this.session.getBasePath(); + // Create a users api instance + UsersApi usersApi = createUsersApi(accessToken, basePath); + + // Collect ids needed for the request + UUID organizationId = this.getOrganizationId(accessToken, basePath); + + //ds-snippet-start:Admin1Step5 + UUID accountId = this.getExistingAccountId(accessToken, basePath, organizationId); + //ds-snippet-end:Admin1Step5 + NewUserResponse result = AddActiveUserService.createNewActiveUser( + args.getGroupId(), + args.getProfileId(), + args.getEmail(), + args.getUserName(), + args.getFirstName(), + args.getLastName(), + usersApi, + organizationId, + accountId); + + // Process results + DoneExample + .createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(result) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/admin/examples/A002CreateActiveCLMESignUser.java b/src/main/java/com/docusign/controller/admin/examples/A002CreateActiveCLMESignUser.java new file mode 100644 index 00000000..6a3bb078 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/examples/A002CreateActiveCLMESignUser.java @@ -0,0 +1,118 @@ +package com.docusign.controller.admin.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.api.DsGroupsApi; +import com.docusign.admin.api.ProductPermissionProfilesApi; +import com.docusign.admin.api.UsersApi; +import com.docusign.admin.client.ApiException; +import com.docusign.admin.model.AddUserResponse; +import com.docusign.admin.model.DSGroupListResponse; +import com.docusign.admin.model.ProductPermissionProfileResponse; +import com.docusign.admin.model.ProductPermissionProfilesResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.admin.services.CreateActiveCLMESignUserService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.util.UUID; + +/** + * Create new user This example demonstrates how to create a new user with + * methods from Admin API. + */ +@Controller +@RequestMapping("/a002") +public class A002CreateActiveCLMESignUser extends AbstractAdminController { + + public A002CreateActiveCLMESignUser(DSConfiguration config, Session session, User user) { + super(config, "a002", user, session); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + UUID organizationId = this.getOrganizationId(this.user.getAccessToken(), this.session.getBasePath()); + UUID accountId = this.getExistingAccountId(user.getAccessToken(), session.getBasePath(), organizationId); + + //ds-snippet-start:Admin2Step3 + ProductPermissionProfilesApi permissionsInfo = this.createProductPermissionProfilesApi(user.getAccessToken(), + session.getBasePath()); + ProductPermissionProfilesResponse profiles = permissionsInfo.getProductPermissionProfiles(organizationId, + accountId); + ProductPermissionProfileResponse clmProfiles = null; + ProductPermissionProfileResponse eSignProfiles = null; + UUID clmProductId = null; + UUID eSignProductId = null; + // filter by each type per response + for (ProductPermissionProfileResponse eachOne : profiles.getProductPermissionProfiles()) { + if (eachOne.getProductName().equals("CLM")) { + clmProductId = eachOne.getProductId(); + clmProfiles = eachOne; + } else { + eSignProductId = eachOne.getProductId(); + eSignProfiles = eachOne; + } + } + //ds-snippet-end:Admin2Step3 + + //ds-snippet-start:Admin2Step4 + DsGroupsApi groupsApi = this.createDSGroupsApi(user.getAccessToken(), session.getBasePath()); + DSGroupListResponse groups = groupsApi.getDSGroups(organizationId, accountId); + //ds-snippet-end:Admin2Step4 + + // set CLM permission profiles + model.addAttribute("listCLM", clmProfiles); + model.addAttribute("clmProductId", clmProductId); + + // set eSign permission profiles + model.addAttribute("listeSign", eSignProfiles); + model.addAttribute("eSignProductId", eSignProductId); + + model.addAttribute("listGroups", groups); + + if (groups.getTotalCount() == 0) { + throw new ApiException(getTextForCodeExampleByApiType().CustomErrorTexts.get(0).ErrorMessage); + } + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + String accessToken = this.user.getAccessToken(); + String basePath = this.session.getBasePath(); + // Create a users api instance + UsersApi usersApi = createUsersApi(accessToken, basePath); + + // Collect ids needed for the request + UUID organizationId = this.getOrganizationId(accessToken, basePath); + UUID accountId = this.getExistingAccountId(accessToken, basePath, organizationId); + + AddUserResponse result = CreateActiveCLMESignUserService.createNewActiveUser( + args.getClmProfileId(), + args.getClmProductId(), + args.getESignProfileId(), + args.getESignProductId(), + args.getDsGroupId(), + args.getUserName(), + args.getFirstName(), + args.getLastName(), + args.getEmail(), + usersApi, + organizationId, + accountId); + + this.session.setEmailAddress(result.getEmail()); + + // Process results + DoneExample + .createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(result) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/admin/examples/A003BulkExportUserData.java b/src/main/java/com/docusign/controller/admin/examples/A003BulkExportUserData.java new file mode 100644 index 00000000..cdd23e84 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/examples/A003BulkExportUserData.java @@ -0,0 +1,74 @@ +package com.docusign.controller.admin.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.api.BulkExportsApi; +import com.docusign.admin.model.OrganizationExportResponse; +import com.docusign.admin.model.OrganizationExportsResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.admin.services.BulkExportUserDataService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.util.concurrent.TimeUnit; + +/** + * How to bulk-export user data This example demonstrates how to bulk-export + * user data from Admin API. + */ +@Controller +@RequestMapping("/a003") +public class A003BulkExportUserData extends AbstractAdminController { + + private static final int BUFFER_SIZE = 4096; + + public A003BulkExportUserData(DSConfiguration config, Session session, User user) { + super(config, "a003", user, session); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + //ds-snippet-start:Admin3Step3 + BulkExportsApi bulkExportsApi = createBulkExportsApi(this.user.getAccessToken(), this.session.getBasePath()); + + OrganizationExportResponse bulkList = BulkExportUserDataService.createUserListExport( + bulkExportsApi, + this.getOrganizationId(this.user.getAccessToken(), this.session.getBasePath())); + //ds-snippet-end:Admin3Step3 + + TimeUnit.SECONDS.sleep(30); + + //ds-snippet-start:Admin3Step4 + OrganizationExportResponse data = BulkExportUserDataService.bulkExportUserData( + bulkExportsApi, + this.getOrganizationId(this.user.getAccessToken(), this.session.getBasePath()), + bulkList.getId()); + //ds-snippet-end:Admin3Step4 + + String saveFilePath = ""; + + if (data.getResults() != null && !data.getResults().isEmpty()) { + String csvUri = data.getResults().get(0).getUrl(); + saveFilePath = BulkExportUserDataService.moveUserListExportToFile( + csvUri, + BEARER_AUTHENTICATION, + this.user.getAccessToken(), + BUFFER_SIZE + ); + } + + OrganizationExportsResponse results = BulkExportUserDataService + .bulkExportsUserData(bulkExportsApi, this.getOrganizationId(this.user.getAccessToken(), this.session.getBasePath())); + // Process results + DoneExample + .createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText.replaceFirst("\\{0}", saveFilePath)) + .withJsonObject(results).addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + +} diff --git a/src/main/java/com/docusign/controller/admin/examples/A003aCheckRequestStatus.java b/src/main/java/com/docusign/controller/admin/examples/A003aCheckRequestStatus.java new file mode 100644 index 00000000..35bfb8dc --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/examples/A003aCheckRequestStatus.java @@ -0,0 +1,56 @@ +package com.docusign.controller.admin.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.api.BulkExportsApi; +import com.docusign.admin.model.OrganizationExportResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.admin.services.CheckRequestStatusService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.util.UUID; + +/** + * Check request status + * This example demonstrates how to check request status from the Admin API. + */ +@Controller +@RequestMapping("/a003a") +public class A003aCheckRequestStatus extends AbstractAdminController { + private static final String MODEL_EXPORT_OK = "exportOk"; + + public A003aCheckRequestStatus(DSConfiguration config, Session session, User user) { + super(config, "a003a", user, session); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + model.addAttribute(MODEL_EXPORT_OK, StringUtils.isNotBlank(this.session.getExportId())); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + // Create a bulk exports api instance + BulkExportsApi bulkExportsApi = createBulkExportsApi(this.user.getAccessToken(), this.session.getBasePath()); + + OrganizationExportResponse result = CheckRequestStatusService.checkRequestStatus( + bulkExportsApi, + this.getOrganizationId(this.user.getAccessToken(), this.session.getBasePath()), + UUID.fromString(this.session.getExportId())); + + // Process results + DoneExample + .createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().AdditionalPage.get(0).ResultsPageText) + .withJsonObject(result) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/admin/examples/A004BulkImportUserData.java b/src/main/java/com/docusign/controller/admin/examples/A004BulkImportUserData.java new file mode 100644 index 00000000..8f0d5eec --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/examples/A004BulkImportUserData.java @@ -0,0 +1,57 @@ +package com.docusign.controller.admin.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.api.BulkImportsApi; +import com.docusign.admin.model.OrganizationImportResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.admin.services.BulkImportUserDataService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.util.UUID; + + +/** + * How to add users via bulk import + * This example demonstrates how to add users via bulk import from the Admin API. + */ +@Controller +@RequestMapping("/a004") +public class A004BulkImportUserData extends AbstractAdminController { + + public A004BulkImportUserData(DSConfiguration config, Session session, User user) { + super(config, "a004", user, session); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + OrganizationImportResponse result = bulkImportUserData(this.user.getAccessToken()); + + this.session.setImportId(result.getId().toString()); + + // Process results + DoneExample + .createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(result) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + + protected OrganizationImportResponse bulkImportUserData(String accessToken) throws Exception { + // Collect ids and user data needed for the request + UUID organizationId = this.getOrganizationId(this.user.getAccessToken(), this.session.getBasePath()); + UUID accountId = this.getExistingAccountId(accessToken, this.session.getBasePath(), organizationId); + // Make sure you're using a verified domain for auto-activation to work properly + //ds-snippet-start:Admin4Step3 + BulkImportsApi bulkImportsApi = createBulkImportsApi(accessToken, this.session.getBasePath()); + + return BulkImportUserDataService.bulkImportUserData(bulkImportsApi, organizationId, accountId); + //ds-snippet-end:Admin4Step3 + } +} diff --git a/src/main/java/com/docusign/controller/admin/examples/A004CheckImportRequestStatus.java b/src/main/java/com/docusign/controller/admin/examples/A004CheckImportRequestStatus.java new file mode 100644 index 00000000..3c79f9aa --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/examples/A004CheckImportRequestStatus.java @@ -0,0 +1,80 @@ +package com.docusign.controller.admin.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.api.BulkImportsApi; +import com.docusign.admin.model.OrganizationImportResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.admin.services.CheckImportRequestStatusService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.view.RedirectView; + +import javax.servlet.http.HttpServletResponse; +import java.util.UUID; + + +/** + * Check request status + * This example demonstrates how to check request status from the Admin API. + */ +@Controller +@RequestMapping("/a004a") +public class A004CheckImportRequestStatus extends AbstractAdminController { + private static final String MODEL_IMPORT_OK = "importOk"; + + public A004CheckImportRequestStatus(DSConfiguration config, Session session, User user) { + super(config, "a004a", user, session); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + model.addAttribute(MODEL_IMPORT_OK, StringUtils.isNotBlank(this.session.getImportId())); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + // Redirects to the front facing example to avoid a Null Pointer Exception + if (this.session.getImportId() == null) { + return new RedirectView("a004"); + } + + OrganizationImportResponse result = checkRequestStatus(this.user.getAccessToken()); + if (result.getStatus().equals("queued")) { + // Return the refresh page + DoneExample.createDefault("Request not complete") + .withMessage("The request has not completed, please refresh this page") + .addToModel(model, config); + return EXAMPLE_PENDING_PAGE; + + } + + // Clear the import ID to remove 'Check Status link' from the results page + this.session.setImportId(null); + + // Process results + DoneExample + .createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(result) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + + protected OrganizationImportResponse checkRequestStatus(String accessToken) throws Exception { + // Create a bulk exports api instance + BulkImportsApi bulkImportsApi = createBulkImportsApi(accessToken, this.session.getBasePath()); + //ds-snippet-start:Admin4Step4 + return CheckImportRequestStatusService.checkRequestStatus( + bulkImportsApi, + this.getOrganizationId(this.user.getAccessToken(), this.session.getBasePath()), + UUID.fromString(this.session.getImportId())); + //ds-snippet-end:Admin4Step4 + } + +} diff --git a/src/main/java/com/docusign/controller/admin/examples/A005AuditUsers.java b/src/main/java/com/docusign/controller/admin/examples/A005AuditUsers.java new file mode 100644 index 00000000..753155bb --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/examples/A005AuditUsers.java @@ -0,0 +1,49 @@ +package com.docusign.controller.admin.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.api.UsersApi; +import com.docusign.admin.model.UserDrilldownResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.admin.services.AuditUsersService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.UUID; + +/** + * Create new user This example demonstrates how to create a new user with + * methods from Admin API. + */ +@Controller +@RequestMapping("/a005") +public class A005AuditUsers extends AbstractAdminController { + + public A005AuditUsers(DSConfiguration config, Session session, User user) { + super(config, "a005", user, session); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + // Collect ids needed for the request + UUID organizationId = this.getOrganizationId(this.user.getAccessToken(), this.session.getBasePath()); + UUID accountId = this.getExistingAccountId(this.user.getAccessToken(), this.session.getBasePath(), organizationId); + + UsersApi usersApi = createUsersApi(this.user.getAccessToken(), this.session.getBasePath()); + + ArrayList resultsArr = AuditUsersService.auditUsers(usersApi, organizationId, accountId); + + // Process results + DoneExample + .createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(resultsArr).addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + +} diff --git a/src/main/java/com/docusign/controller/admin/examples/A006RetrieveDocuSignProfileByEmailAddress.java b/src/main/java/com/docusign/controller/admin/examples/A006RetrieveDocuSignProfileByEmailAddress.java new file mode 100644 index 00000000..4ddf273d --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/examples/A006RetrieveDocuSignProfileByEmailAddress.java @@ -0,0 +1,44 @@ +package com.docusign.controller.admin.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.api.UsersApi; +import com.docusign.admin.model.UsersDrilldownResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.admin.services.RetrieveDocuSignProfileByEmailAddress; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.util.UUID; + +/** + * Get a DocuSign user by the email address using the methods from Admin API. + */ +@Controller +@RequestMapping("/a006") +public class A006RetrieveDocuSignProfileByEmailAddress extends AbstractAdminController { + + public A006RetrieveDocuSignProfileByEmailAddress(DSConfiguration config, User user, Session session) { + super(config, "a006", user, session); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + UUID organizationId = this.getOrganizationId(this.user.getAccessToken(), this.session.getBasePath()); + //ds-snippet-start:Admin6Step3 + UsersApi usersApi = createUsersApi(this.user.getAccessToken(), this.session.getBasePath()); + UsersDrilldownResponse usersResponse = RetrieveDocuSignProfileByEmailAddress + .getDocuSignProfileByEmailAddress(usersApi, organizationId, args.getEmail()); + //ds-snippet-end:Admin6Step3 + DoneExample + .createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(usersResponse.getUsers()).addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/admin/examples/A007RetrieveDocuSignProfileByUserID.java b/src/main/java/com/docusign/controller/admin/examples/A007RetrieveDocuSignProfileByUserID.java new file mode 100644 index 00000000..72857454 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/examples/A007RetrieveDocuSignProfileByUserID.java @@ -0,0 +1,47 @@ +package com.docusign.controller.admin.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.api.UsersApi; +import com.docusign.admin.model.UsersDrilldownResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.admin.services.RetrieveDocuSignProfileByUserId; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.util.UUID; + +/** + * Get a DocuSign user by the user ID using the methods from Admin API. + */ +@Controller +@RequestMapping("/a007") +public class A007RetrieveDocuSignProfileByUserID extends AbstractAdminController { + + public A007RetrieveDocuSignProfileByUserID(DSConfiguration config, User user, Session session) { + super(config, "a007", user, session); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + UUID organizationId = this.getOrganizationId(this.user.getAccessToken(), this.session.getBasePath()); + //ds-snippet-start:Admin7Step3 + UsersApi usersApi = createUsersApi(this.user.getAccessToken(), this.session.getBasePath()); + + UsersDrilldownResponse usersResponse = RetrieveDocuSignProfileByUserId. + getDocuSignProfileByUserId(usersApi, organizationId, args.getUserId()); + //ds-snippet-end:Admin7Step3 + + DoneExample + .createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(usersResponse).addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } + +} diff --git a/src/main/java/com/docusign/controller/admin/examples/A008UpdateUserProductPermissionProfile.java b/src/main/java/com/docusign/controller/admin/examples/A008UpdateUserProductPermissionProfile.java new file mode 100644 index 00000000..55f376a7 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/examples/A008UpdateUserProductPermissionProfile.java @@ -0,0 +1,133 @@ +package com.docusign.controller.admin.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.api.ProductPermissionProfilesApi; +import com.docusign.admin.api.UsersApi; +import com.docusign.admin.client.ApiException; +import com.docusign.admin.model.PermissionProfileResponse21; +import com.docusign.admin.model.ProductPermissionProfileResponse; +import com.docusign.admin.model.ProductPermissionProfilesResponse; +import com.docusign.admin.model.UserProductPermissionProfilesResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.admin.services.RetrieveDocuSignProfileByEmailAddress; +import com.docusign.controller.admin.services.UpdateUserProductPermissionProfileByEmail; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.servlet.http.HttpServletResponse; +import java.util.Hashtable; +import java.util.List; +import java.util.UUID; + +/** + * This example demonstrates how to update user product permission profiles using an email address. + */ +@Controller +@RequestMapping("/a008") +public class A008UpdateUserProductPermissionProfile extends AbstractAdminController { + + private final Hashtable products = new Hashtable<>(); + + private ProductPermissionProfilesResponse productPermissionProfiles; + + public A008UpdateUserProductPermissionProfile(DSConfiguration config, Session session, User user) { + super(config, "a008", user, session); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + UUID organizationId = this.getOrganizationId(this.user.getAccessToken(), this.session.getBasePath()); + UUID existingAccountId = this.getExistingAccountId(user.getAccessToken(), session.getBasePath(), organizationId); + String emailAddress = this.session.getEmailAddress(); + ProductPermissionProfileResponse permissionProfiles = null; + UUID clmProductId = null; + UUID eSignProductId = null; + + if (emailAddress != null) { + try { + UsersApi usersApi = createUsersApi(this.user.getAccessToken(), this.session.getBasePath()); + RetrieveDocuSignProfileByEmailAddress.getDocuSignProfileByEmailAddress(usersApi, organizationId, emailAddress); + + ProductPermissionProfilesApi productPermissionProfilesApi = this.createProductPermissionProfilesApi( + user.getAccessToken(), + session.getBasePath() + ); + productPermissionProfiles = productPermissionProfilesApi.getProductPermissionProfiles(organizationId, existingAccountId); + + for (ProductPermissionProfileResponse profileResponse : productPermissionProfiles.getProductPermissionProfiles()) { + if (profileResponse.getProductName().equals("CLM")) { + clmProductId = profileResponse.getProductId(); + } else { + permissionProfiles = profileResponse; + eSignProductId = profileResponse.getProductId(); + } + } + + products.put(eSignProductId, "eSignature"); + products.put(clmProductId, "CLM"); + + model.addAttribute("listPermissionProfiles", permissionProfiles); + model.addAttribute("listProducts", products); + model.addAttribute("emailAddress", emailAddress); + } catch (ApiException e) { + model.addAttribute("emailAddress", null); + } + } else { + model.addAttribute("emailAddress", null); + } + } + + @GetMapping(value = "/getPermissionProfiles", produces = MediaType.APPLICATION_JSON_VALUE) + public @ResponseBody + List getPermissionProfiles(@RequestParam UUID productId) { + List permissionProfiles = null; + for (ProductPermissionProfileResponse profileResponse : productPermissionProfiles.getProductPermissionProfiles()) { + if (profileResponse.getProductId().equals(productId)) { + permissionProfiles = profileResponse.getPermissionProfiles(); + } + } + + return permissionProfiles; + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + UUID organizationId = this.getOrganizationId(this.user.getAccessToken(), this.session.getBasePath()); + UUID existingAccountId = this.getExistingAccountId( + this.user.getAccessToken(), + this.session.getBasePath(), + organizationId + ); + + ProductPermissionProfilesApi productPermissionProfilesApi = createProductPermissionProfilesApi( + this.user.getAccessToken(), + this.session.getBasePath()); + + UserProductPermissionProfilesResponse productPermissionProfile = UpdateUserProductPermissionProfileByEmail + .updateUserProductPermissionProfile( + productPermissionProfilesApi, + args.getPermissionProfileId(), + args.getProductId(), + this.session.getEmailAddress(), + organizationId, + existingAccountId + ); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(productPermissionProfile) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } + +} diff --git a/src/main/java/com/docusign/controller/admin/examples/A009DeleteUserProductPermissionProfile.java b/src/main/java/com/docusign/controller/admin/examples/A009DeleteUserProductPermissionProfile.java new file mode 100644 index 00000000..1c9291ac --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/examples/A009DeleteUserProductPermissionProfile.java @@ -0,0 +1,136 @@ +package com.docusign.controller.admin.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.api.ProductPermissionProfilesApi; +import com.docusign.admin.api.UsersApi; +import com.docusign.admin.client.ApiException; +import com.docusign.admin.model.PermissionProfileResponse21; +import com.docusign.admin.model.ProductPermissionProfileResponse; +import com.docusign.admin.model.RemoveUserProductsResponse; +import com.docusign.admin.model.UserProductPermissionProfilesResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.admin.services.DeleteUserProductPermissionProfileById; +import com.docusign.controller.admin.services.RetrieveDocuSignProfileByEmailAddress; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.util.Hashtable; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * This example demonstrates how to delete user product permission profiles using an email address. + */ +@Controller +@RequestMapping("/a009") +public class A009DeleteUserProductPermissionProfile extends AbstractAdminController { + public static UUID clmProductId = UUID.fromString("37f013eb-7012-4588-8028-357b39fdbd00"); + + public static UUID eSignatureProductId = UUID.fromString("f6406c68-225c-4e9b-9894-64152a26fa83"); + + private final Hashtable products = new Hashtable<>(); + + private final String CLM_PROFILES_NOT_FOUND = "No CLM permission profiles are connected to this user"; + + private final String ESIGN_PROFILES_NOT_FOUND = "No eSignature permission profiles are connected to this user"; + + public A009DeleteUserProductPermissionProfile(DSConfiguration config, Session session, User user) { + super(config, "a009", user, session); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + UUID organizationId = this.getOrganizationId(this.user.getAccessToken(), this.session.getBasePath()); + UUID existingAccountId = this.getExistingAccountId(user.getAccessToken(), session.getBasePath(), organizationId); + String emailAddress = this.session.getEmailAddress(); + List clmProfiles = null; + List eSignProfiles = null; + + if (emailAddress != null) { + try { + + UsersApi usersApi = createUsersApi(this.user.getAccessToken(), this.session.getBasePath()); + RetrieveDocuSignProfileByEmailAddress.getDocuSignProfileByEmailAddress(usersApi, organizationId, emailAddress); + + //ds-snippet-start:Admin9Step3 + ProductPermissionProfilesApi productPermissionProfilesApi = this.createProductPermissionProfilesApi( + user.getAccessToken(), + session.getBasePath() + ); + ProductPermissionProfilesApi.GetUserProductPermissionProfilesByEmailOptions userProductPermissionProfilesByEmailOptions = + productPermissionProfilesApi.new GetUserProductPermissionProfilesByEmailOptions(); + userProductPermissionProfilesByEmailOptions.setEmail(emailAddress); + UserProductPermissionProfilesResponse userProductPermissionProfilesByEmail = productPermissionProfilesApi + .getUserProductPermissionProfilesByEmail(organizationId, existingAccountId, userProductPermissionProfilesByEmailOptions); + //ds-snippet-end:Admin9Step3 + for (ProductPermissionProfileResponse profileResponse : userProductPermissionProfilesByEmail.getProductPermissionProfiles()) { + if (profileResponse.getProductName().equals("CLM")) { + clmProfiles = profileResponse + .getPermissionProfiles() + .stream() + .map(PermissionProfileResponse21::getPermissionProfileName) + .collect(Collectors.toList()); + } else { + eSignProfiles = profileResponse + .getPermissionProfiles() + .stream() + .map(PermissionProfileResponse21::getPermissionProfileName) + .collect(Collectors.toList()); + } + } + + String clmProfilesFormatted = clmProfiles != null + ? String.join(",", clmProfiles) + : CLM_PROFILES_NOT_FOUND; + + String eSignProfilesFormatted = eSignProfiles != null + ? String.join(",", eSignProfiles) + : ESIGN_PROFILES_NOT_FOUND; + + products.put(eSignatureProductId, String.format("eSignature - %s", eSignProfilesFormatted)); + products.put(clmProductId, String.format("CLM - %s", clmProfilesFormatted)); + + model.addAttribute("listProducts", products); + + model.addAttribute("emailAddress", emailAddress); + } catch (ApiException e) { + model.addAttribute("emailAddress", null); + } + } else { + model.addAttribute("emailAddress", null); + } + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + UUID organizationId = this.getOrganizationId(this.user.getAccessToken(), this.session.getBasePath()); + UUID existingAccountId = this.getExistingAccountId(this.user.getAccessToken(), this.session.getBasePath(), organizationId); + + ProductPermissionProfilesApi productPermissionProfilesApi = createProductPermissionProfilesApi( + this.user.getAccessToken(), + this.session.getBasePath()); + + //ds-snippet-start:Admin9Step5 + RemoveUserProductsResponse removeUserProductsRepsonse = DeleteUserProductPermissionProfileById.deleteUserProductPermissionProfile( + productPermissionProfilesApi, + args.getProductId(), + this.session.getEmailAddress(), + organizationId, + existingAccountId); + //ds-snippet-end:Admin9Step5 + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(removeUserProductsRepsonse) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } + +} diff --git a/src/main/java/com/docusign/controller/admin/examples/A010DeleteUserDataFromOrganization.java b/src/main/java/com/docusign/controller/admin/examples/A010DeleteUserDataFromOrganization.java new file mode 100644 index 00000000..32aedf15 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/examples/A010DeleteUserDataFromOrganization.java @@ -0,0 +1,52 @@ +package com.docusign.controller.admin.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.api.OrganizationsApi; +import com.docusign.admin.api.UsersApi; +import com.docusign.admin.model.IndividualUserDataRedactionResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.admin.services.UserDataManagementService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.util.UUID; + +/** + * This example demonstrates how to delete user data from organization. + */ +@Controller +@RequestMapping("/a010") +public class A010DeleteUserDataFromOrganization extends AbstractAdminController { + + public A010DeleteUserDataFromOrganization(DSConfiguration config, User user, Session session) { + super(config, "a010", user, session); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + String accessToken = this.user.getAccessToken(); + String basePath = this.session.getBasePath(); + + UUID organizationId = this.getOrganizationId(accessToken, basePath); + UsersApi usersApi = createUsersApi(accessToken, basePath); + OrganizationsApi organizationsApi = createOrganizationsApi(accessToken, basePath); + + IndividualUserDataRedactionResponse individualUserDataRedactionResponse = (new UserDataManagementService()).deleteUserDataFromOrganizationByEmail( + usersApi, + organizationsApi, + args.getEmail(), + organizationId); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(individualUserDataRedactionResponse) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/admin/examples/A011DeleteUserDataFromAccount.java b/src/main/java/com/docusign/controller/admin/examples/A011DeleteUserDataFromAccount.java new file mode 100644 index 00000000..fcfaeac5 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/examples/A011DeleteUserDataFromAccount.java @@ -0,0 +1,50 @@ +package com.docusign.controller.admin.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.api.AccountsApi; +import com.docusign.admin.model.IndividualUserDataRedactionResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.admin.services.UserDataManagementService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.util.UUID; + +/** + * This example demonstrates how to delete user data from account. + */ +@Controller +@RequestMapping("/a011") +public class A011DeleteUserDataFromAccount extends AbstractAdminController { + + public A011DeleteUserDataFromAccount(DSConfiguration config, Session session, User user) { + super(config, "a011", user, session); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + String accessToken = this.user.getAccessToken(); + String basePath = this.session.getBasePath(); + + UUID organizationId = this.getOrganizationId(accessToken, basePath); + UUID existingAccountId = this.getExistingAccountId(accessToken, basePath, organizationId); + AccountsApi accountsApi = createAccountsApi(accessToken, basePath); + + IndividualUserDataRedactionResponse userDataRedactionResponse = (new UserDataManagementService()).deleteUserDataFromAccountByUserId( + accountsApi, + args.getUserId(), + existingAccountId); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(userDataRedactionResponse) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/admin/examples/A012CloneAccount.java b/src/main/java/com/docusign/controller/admin/examples/A012CloneAccount.java new file mode 100644 index 00000000..896820a6 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/examples/A012CloneAccount.java @@ -0,0 +1,63 @@ +package com.docusign.controller.admin.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.api.ProvisionAssetGroupApi; +import com.docusign.admin.model.AssetGroupAccountsResponse; +import com.docusign.admin.model.AssetGroupAccountClone; +import com.docusign.common.WorkArguments; +import com.docusign.controller.admin.services.CloneAccountService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.util.UUID; + +/** + * This example demonstrates how to clone the account. + */ +@Controller +@RequestMapping("/a012") +public class A012CloneAccount extends AbstractAdminController { + + public A012CloneAccount(DSConfiguration config, Session session, User user) { + super(config, "a012", user, session); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + UUID organizationId = this.getOrganizationId(this.user.getAccessToken(), this.session.getBasePath()); + ProvisionAssetGroupApi provisionAssetGroupApi = this.createProvisionAssetGroupApi(user.getAccessToken(), session.getBasePath()); + + AssetGroupAccountsResponse groupAccounts = (new CloneAccountService()).getGroupAccounts(provisionAssetGroupApi, organizationId); + model.addAttribute("groups", groupAccounts.getAssetGroupAccounts()); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + String accessToken = this.user.getAccessToken(); + String basePath = this.session.getBasePath(); + UUID organizationId = this.getOrganizationId(accessToken, basePath); + ProvisionAssetGroupApi provisionAssetGroupApi = this.createProvisionAssetGroupApi(accessToken, basePath); + + AssetGroupAccountClone assetGroupAccountClone =(new CloneAccountService()).getClonedAccount( + provisionAssetGroupApi, + organizationId, + args.getSourceAccountId(), + args.getTargetAccountName(), + args.getTargetAccountEmail(), + args.getTargetAccountFirstName(), + args.getTargetAccountLastName()); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(assetGroupAccountClone) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/admin/examples/A013CreateAccount.java b/src/main/java/com/docusign/controller/admin/examples/A013CreateAccount.java new file mode 100644 index 00000000..5a94a8cd --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/examples/A013CreateAccount.java @@ -0,0 +1,59 @@ +package com.docusign.controller.admin.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.api.ProvisionAssetGroupApi; +import com.docusign.admin.model.OrganizationSubscriptionResponse; +import com.docusign.admin.model.SubscriptionProvisionModelAssetGroupWorkResult; +import com.docusign.common.WorkArguments; +import com.docusign.controller.admin.services.CreateAccountService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.util.UUID; + +/** + * This example demonstrates how to create the account. + */ +@Controller +@RequestMapping("/a013") +public class A013CreateAccount extends AbstractAdminController { + + public A013CreateAccount(DSConfiguration config, Session session, User user) { + super(config, "a013", user, session); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + String accessToken = this.user.getAccessToken(); + String basePath = this.session.getBasePath(); + UUID organizationId = this.getOrganizationId(accessToken, basePath); + + ProvisionAssetGroupApi provisionAssetGroupApi = this.createProvisionAssetGroupApi(accessToken, basePath); + + OrganizationSubscriptionResponse planItems = CreateAccountService.getFirstPlanItem( + provisionAssetGroupApi, + organizationId); + + SubscriptionProvisionModelAssetGroupWorkResult createdAccount = CreateAccountService + .createAccountBySubscription( + provisionAssetGroupApi, + organizationId, + args.getEmail(), + args.getFirstName(), + args.getLastName(), + planItems.getSubscriptionId(), + planItems.getPlanId()); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(createdAccount) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/admin/examples/AbstractAdminController.java b/src/main/java/com/docusign/controller/admin/examples/AbstractAdminController.java new file mode 100644 index 00000000..df559474 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/examples/AbstractAdminController.java @@ -0,0 +1,260 @@ +package com.docusign.controller.admin.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.api.*; +import com.docusign.admin.api.UsersApi.GetUserProfilesOptions; +import com.docusign.admin.client.ApiClient; +import com.docusign.admin.client.ApiException; +import com.docusign.admin.model.OrganizationsResponse; +import com.docusign.admin.model.UsersDrilldownResponse; +import com.docusign.core.controller.AbstractController; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Controller; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.UUID; + +/** + * Abstract base class for all Admin controllers. + */ +@Controller +public abstract class AbstractAdminController extends AbstractController { + + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAdminController.class); + + private static final String EXAMPLE_PAGES_PATH = "pages/admin/examples/"; + + protected final User user; + + protected final Session session; + + private final DSConfiguration configuration; + + + public AbstractAdminController(DSConfiguration config, String exampleName, User user, Session session) { + super(config, exampleName); + this.configuration = config; + this.user = user; + this.session = session; + } + + /** + * Creates new instance of the Admin API client. + * + * @param accessToken user's access token + * @param basePath basePath to the server + * @return an instance of the {@link ApiClient} + */ + protected static ApiClient createApiClient( + String accessToken, + String basePath + ) { + //ds-snippet-start:AdminJavaStep2 + ApiClient apiClient = new ApiClient(basePath); + apiClient.addDefaultHeader( + HttpHeaders.AUTHORIZATION, + BEARER_AUTHENTICATION + accessToken); + //ds-snippet-end:AdminJavaStep2 + + return apiClient; + } + + /** + * Creates a new instance of the UsersApi. This method + * creates an instance of the UsersApi class silently. + * + * @param accessToken user's access token + * @param basePath basePath to the server + * @return an instance of the {@link UsersApi} + */ + protected static UsersApi createUsersApi( + String accessToken, + String basePath + ) { + ApiClient apiClient = createApiClient(accessToken, basePath); + apiClient.addDefaultHeader("Content-Type", "application/json"); + return new UsersApi(apiClient); + } + + /** + * Creates a new instance of the AccountsApi. This method + * creates an instance of the AccountsApi class silently. + * + * @param accessToken user's access token + * @param basePath basePath to the server + * @return an instance of the {@link AccountsApi} + */ + protected static AccountsApi createAccountsApi( + String accessToken, + String basePath + ) { + ApiClient apiClient = createApiClient(accessToken, basePath); + apiClient.addDefaultHeader("Content-Type", "application/json"); + return new AccountsApi(apiClient); + } + + /** + * Creates a new instance of the OrganizationsApi. This method + * creates an instance of the OrganizationsApi class silently. + * + * @param accessToken user's access token + * @param basePath basePath to the server + * @return an instance of the {@link OrganizationsApi} + */ + protected static OrganizationsApi createOrganizationsApi( + String accessToken, + String basePath + ) { + ApiClient apiClient = createApiClient(accessToken, basePath); + apiClient.addDefaultHeader("Content-Type", "application/json"); + return new OrganizationsApi(apiClient); + } + + /** + * Creates a new instance of the BulkExportsApi. This method + * creates an instance of the BulkExportsApi class silently. + * + * @param accessToken user's access token + * @param basePath basePath to the server + * @return an instance of the {@link BulkExportsApi} + */ + protected static BulkExportsApi createBulkExportsApi( + String accessToken, + String basePath + ) { + ApiClient apiClient = createApiClient(accessToken, basePath); + return new BulkExportsApi(apiClient); + } + + /** + * Creates a new instance of the BulkImportsApi. This method + * creates an instance of the BulkImportsApi class silently. + * + * @param accessToken user's access token + * @param basePath basePath to the server + * @return an instance of the {@link BulkImportsApi} + */ + protected static BulkImportsApi createBulkImportsApi( + String accessToken, + String basePath + ) { + ApiClient apiClient = createApiClient(accessToken, basePath); + return new BulkImportsApi(apiClient); + } + + protected String getExamplePagesPath() { + return AbstractAdminController.EXAMPLE_PAGES_PATH; + } + + /** + * Creates a request to get current user. + * + * @param accessToken user's access token + * @param basePath basePath to the server + * @param organizationId the ID of current organization + * @return the account Id + */ + protected UUID getExistingAccountId( + String accessToken, + String basePath, + UUID organizationId + ) throws Exception { + LOGGER.info("createUsers API called"); + UsersApi usersApi = createUsersApi(accessToken, basePath); + LOGGER.info("createUsers called succeeds"); + // set the signer email to get an information about that user + // new GetUsersOptions() will throw "an enclosing instance that contains com.docusign.admin.api.UsersApi.GetUserProfilesOptions is required" + // at compile time. I used this workaround from stackOverflow: + // https://stackoverflow.com/a/4297913/2226328 + LOGGER.info("what email are we feedin ya? hmm??? " + configuration.getSignerEmail()); + GetUserProfilesOptions userProfilesOptions = + usersApi.new GetUserProfilesOptions(); + userProfilesOptions.setEmail(configuration.getSignerEmail()); + LOGGER.info("getUserProfiles called"); + UsersDrilldownResponse user = usersApi.getUserProfiles( + organizationId, + userProfilesOptions + ); + LOGGER.info("getUserProfiles succeeded"); + if (user.getUsers().isEmpty()) { + throw new Exception("Could not get an account id from the request."); + } + + return user.getUsers().get(0).getDefaultAccountId(); + } + + protected UUID getOrganizationId(String accessToken, String basePath) + throws ApiException { + UUID orgId = null; + if (session.getOrgId() == null) { + + ApiClient apiClient = createApiClient(accessToken, basePath); + AccountsApi accounts = new AccountsApi(apiClient); + LOGGER.info("before Org id"); + OrganizationsResponse orgs = accounts.getOrganizations(); + LOGGER.info("after orgs call"); + if (orgs.getOrganizations().isEmpty()) { + throw new ApiException( + "No organizations found on this account, please create an organization first." + ); + } else { + LOGGER.info("we're looking for a specific org id"); + orgId = orgs.getOrganizations().get(0).getId(); + LOGGER.info("first found org id is: " + orgId); + session.setOrgId(orgId); + } + + } else { + LOGGER.info("nothing found? try a 2nd way"); + orgId = session.getOrgId(); + + LOGGER.info("we have an org id: " + orgId); + } + + return orgId; + } + + /** + * Creates a new instance of the ProductPermissionProfilesApi. This method + * creates an instance of the ProductPermissionProfilesApi class silently. + * @param accessToken user's access token + * @param basePath basePath to the server + * @return an instance of the {@link ProductPermissionProfilesApi} + */ + protected ProductPermissionProfilesApi createProductPermissionProfilesApi( + String accessToken, + String basePath + ) { + ApiClient apiClient = createApiClient(accessToken, basePath); + return new ProductPermissionProfilesApi(apiClient); + } + + /** + * Creates a new instance of the AdminGroupsApi. This method + * creates an instance of the AdminGroupsApi class silently. + * @param accessToken user's access token + * @param basePath basePath to the server + * @return an instance of the {@link DsGroupsApi} + */ + protected DsGroupsApi createDSGroupsApi(String accessToken, String basePath) { + ApiClient apiClient = createApiClient(accessToken, basePath); + return new DsGroupsApi(apiClient); + } + + /** + * Creates a new instance of the ProvisionAssetGroupApi. This method + * creates an instance of the ProvisionAssetGroupApi class silently. + * @param accessToken user's access token + * @param basePath basePath to the server + * @return an instance of the {@link ProvisionAssetGroupApi} + */ + protected ProvisionAssetGroupApi createProvisionAssetGroupApi(String accessToken, String basePath) { + //ds-snippet-start:AdminJavaAccountStep2 + ApiClient apiClient = createApiClient(accessToken, basePath); + return new ProvisionAssetGroupApi(apiClient); + //ds-snippet-end:AdminJavaAccountStep2 + } +} diff --git a/src/main/java/com/docusign/controller/admin/services/AddActiveUserService.java b/src/main/java/com/docusign/controller/admin/services/AddActiveUserService.java new file mode 100644 index 00000000..8b7071cc --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/services/AddActiveUserService.java @@ -0,0 +1,63 @@ +package com.docusign.controller.admin.services; + +import com.docusign.admin.api.UsersApi; +import com.docusign.admin.client.ApiResponse; +import com.docusign.admin.model.*; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class AddActiveUserService { + //ds-snippet-start:Admin1Step5 + public static NewUserResponse createNewActiveUser( + String groupId, + String profileId, + String email, + String userName, + String firstName, + String lastName, + UsersApi usersApi, + UUID organizationId, + UUID accountId) throws Exception { + java.util.List groups = new ArrayList<>(); + groups.add(new GroupRequest().id(Long.valueOf(groupId))); + + // Fill the request with data from the form + NewUserRequest accountUserRequest = new NewUserRequest() + .defaultAccountId(accountId) + .addAccountsItem( + new NewUserRequestAccountProperties() + .id(accountId) + .permissionProfile( + new PermissionProfileRequest() + .id(Long.valueOf( + profileId))) + .groups(groups)) + .email(email) + .userName(userName) + .firstName(firstName) + .lastName(lastName) + .autoActivateMemberships(true); + //ds-snippet-end:Admin1Step5 + + //ds-snippet-start:Admin1Step6 + ApiResponse response = usersApi.createUserWithHttpInfo(organizationId, + accountUserRequest); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + //ds-snippet-end:Admin1Step6 + } +} diff --git a/src/main/java/com/docusign/controller/admin/services/AuditUsersService.java b/src/main/java/com/docusign/controller/admin/services/AuditUsersService.java new file mode 100644 index 00000000..4302a4a3 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/services/AuditUsersService.java @@ -0,0 +1,81 @@ +package com.docusign.controller.admin.services; + +import com.docusign.admin.api.UsersApi; +import com.docusign.admin.client.ApiException; +import com.docusign.admin.client.ApiResponse; +import com.docusign.admin.model.OrganizationUserResponse; +import com.docusign.admin.model.OrganizationUsersResponse; +import com.docusign.admin.model.UserDrilldownResponse; +import com.docusign.admin.model.UsersDrilldownResponse; + +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import java.util.UUID; + +public class AuditUsersService { + private static final String timeZoneId = "UTC"; + + private static final String simpleDateFormat = "yyyy-MM-dd'T'HH:mm'Z'"; + + public static ArrayList auditUsers( + UsersApi usersApi, + UUID organizationId, + UUID accountId) throws ApiException { + ArrayList auditedUsers = new ArrayList<>(); + + //ds-snippet-start:Admin5Step3 + UsersApi.GetUsersOptions options = usersApi.new GetUsersOptions(); + options.setAccountId(accountId); + TimeZone tz = TimeZone.getTimeZone(timeZoneId); + SimpleDateFormat df = new SimpleDateFormat(simpleDateFormat); + // Quoted "Z" to indicate UTC, no timezone offset + df.setTimeZone(tz); + Integer tenDaysBeforeToday = 1000 * 60 * 60 * 24 * 10; + String nowAsISO = df.format(new Date(System.currentTimeMillis() - tenDaysBeforeToday)); + options.setLastModifiedSince(nowAsISO); + ApiResponse modifiedUsers = usersApi.getUsersWithHttpInfo(organizationId, options); + + Map> headers = modifiedUsers.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + //ds-snippet-end:Admin5Step3 + + //ds-snippet-start:Admin5Step5 + for (OrganizationUserResponse user : modifiedUsers.getData().getUsers()) { + //ds-snippet-end:Admin5Step5 + //ds-snippet-start:Admin5Step4 + UsersApi.GetUserProfilesOptions profilesOptions = usersApi.new GetUserProfilesOptions(); + profilesOptions.setEmail(user.getEmail()); + //ds-snippet-end:Admin5Step4 + //ds-snippet-start:Admin5Step5 + ApiResponse res = usersApi.getUserProfilesWithHttpInfo(organizationId, + profilesOptions); + + headers = res.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + auditedUsers.add(res.getData().getUsers().get(0)); + } + //ds-snippet-end:Admin5Step5 + + return auditedUsers; + } +} diff --git a/src/main/java/com/docusign/controller/admin/services/BulkExportUserDataService.java b/src/main/java/com/docusign/controller/admin/services/BulkExportUserDataService.java new file mode 100644 index 00000000..f4776a1a --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/services/BulkExportUserDataService.java @@ -0,0 +1,133 @@ +package com.docusign.controller.admin.services; + +import com.docusign.admin.api.BulkExportsApi; +import com.docusign.admin.client.ApiException; +import com.docusign.admin.client.ApiResponse; +import com.docusign.admin.model.OrganizationExportRequest; +import com.docusign.admin.model.OrganizationExportResponse; +import com.docusign.admin.model.OrganizationExportsResponse; +import jakarta.ws.rs.core.MediaType; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpHeaders; + +import javax.net.ssl.HttpsURLConnection; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Paths; +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +public class BulkExportUserDataService { + public static OrganizationExportsResponse bulkExportsUserData( + BulkExportsApi bulkExportsApi, + UUID organizationId) throws ApiException { + ApiResponse response = bulkExportsApi + .getUserListExportsWithHttpInfo(organizationId); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } + + public static OrganizationExportResponse bulkExportUserData( + BulkExportsApi bulkExportsApi, + UUID organizationId, + UUID exportId) throws ApiException { + ApiResponse response = bulkExportsApi.getUserListExportWithHttpInfo(organizationId, + exportId); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } + + public static OrganizationExportResponse createUserListExport( + BulkExportsApi bulkExportsApi, + UUID organizationId) throws ApiException { + OrganizationExportRequest request = new OrganizationExportRequest(); + request.setType("organization_memberships_export"); + ApiResponse response = bulkExportsApi + .createUserListExportWithHttpInfo(organizationId, request); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } + + public static String moveUserListExportToFile( + String csvUri, + String bearerAuthentication, + String accessToken, + Integer bufferSize) throws IOException, URISyntaxException { + //ds-snippet-start:Admin3Step5 + URL request_url = new URL(csvUri); + + // Send Web request to download and save the exported CSV data + HttpsURLConnection.setFollowRedirects(true); // Defaults to true + HttpsURLConnection http_conn = (HttpsURLConnection) request_url.openConnection(); + http_conn.setRequestProperty(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON); + http_conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, "mutlipart/form-data"); + http_conn.setRequestProperty(HttpHeaders.AUTHORIZATION, bearerAuthentication + accessToken); + http_conn.setInstanceFollowRedirects(true); + + ClassLoader rawPath = Thread.currentThread().getContextClassLoader(); + String rootDir = Paths.get(Objects.requireNonNull(rawPath.getResource("")).toURI()).toString(); + // Set the save file path in the project root instead of the compiled folder and + // force forward slash scheme + rootDir = StringUtils.remove(rootDir, "target\\classes"); + rootDir = StringUtils.remove(rootDir, "file:/"); + rootDir = StringUtils.replace(rootDir, "\\", "/"); + + // opens input stream from the HTTP connection + InputStream inputStream = http_conn.getInputStream(); + String saveFilePath = rootDir + "src/main/resources/ExportedUserData.csv"; + + // opens an output stream to save into file + FileOutputStream outputStream = FileUtils.openOutputStream(new File(saveFilePath)); + + int bytesRead; + byte[] buffer = new byte[bufferSize]; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + + outputStream.close(); + inputStream.close(); + http_conn.disconnect(); + //ds-snippet-end:Admin3Step5 + + return saveFilePath; + } +} diff --git a/src/main/java/com/docusign/controller/admin/services/BulkImportUserDataService.java b/src/main/java/com/docusign/controller/admin/services/BulkImportUserDataService.java new file mode 100644 index 00000000..22295eba --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/services/BulkImportUserDataService.java @@ -0,0 +1,41 @@ +package com.docusign.controller.admin.services; + +import com.docusign.admin.api.BulkImportsApi; +import com.docusign.admin.client.ApiResponse; +import com.docusign.admin.model.OrganizationImportResponse; + +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class BulkImportUserDataService { + private static final String BULK_IMPORT_TEXT = "AccountID,UserName,UserEmail,PermissionSet\n%s,FirstLast1,User1java@example.com,DS Admin\n%s,FirstLast2,User2java@example.com,DS Sender"; + + public static OrganizationImportResponse bulkImportUserData( + BulkImportsApi bulkImportsApi, + UUID organizationId, + UUID accountId) throws Exception { + // Make sure you're using a verified domain for auto-activation to work properly + //ds-snippet-start:Admin4Step3 + String csvUserData = String.format(BULK_IMPORT_TEXT, accountId, accountId); + byte[] csvDataInBytes = csvUserData.getBytes(StandardCharsets.UTF_8); + + ApiResponse response = bulkImportsApi + .createBulkImportSingleAccountAddUsersRequestWithHttpInfo(organizationId, accountId, csvDataInBytes); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + //ds-snippet-end:Admin4Step3 + } +} diff --git a/src/main/java/com/docusign/controller/admin/services/CheckImportRequestStatusService.java b/src/main/java/com/docusign/controller/admin/services/CheckImportRequestStatusService.java new file mode 100644 index 00000000..ebb63669 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/services/CheckImportRequestStatusService.java @@ -0,0 +1,34 @@ +package com.docusign.controller.admin.services; + +import com.docusign.admin.api.BulkImportsApi; +import com.docusign.admin.client.ApiResponse; +import com.docusign.admin.model.OrganizationImportResponse; + +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class CheckImportRequestStatusService { + public static OrganizationImportResponse checkRequestStatus( + BulkImportsApi bulkImportsApi, + UUID organizationId, + UUID importId) throws Exception { + // Step 4a start + ApiResponse response = bulkImportsApi + .getBulkUserImportRequestWithHttpInfo(organizationId, importId); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + // Step 4a end + } +} diff --git a/src/main/java/com/docusign/controller/admin/services/CheckRequestStatusService.java b/src/main/java/com/docusign/controller/admin/services/CheckRequestStatusService.java new file mode 100644 index 00000000..b5c220a8 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/services/CheckRequestStatusService.java @@ -0,0 +1,32 @@ +package com.docusign.controller.admin.services; + +import com.docusign.admin.api.BulkExportsApi; +import com.docusign.admin.client.ApiResponse; +import com.docusign.admin.model.OrganizationExportResponse; + +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class CheckRequestStatusService { + public static OrganizationExportResponse checkRequestStatus( + BulkExportsApi bulkExportsApi, + UUID organizationId, + UUID exportId) throws Exception { + ApiResponse response = bulkExportsApi.getUserListExportWithHttpInfo(organizationId, + exportId); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/admin/services/CloneAccountService.java b/src/main/java/com/docusign/controller/admin/services/CloneAccountService.java new file mode 100644 index 00000000..d4ef7de9 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/services/CloneAccountService.java @@ -0,0 +1,88 @@ +package com.docusign.controller.admin.services; + +import com.docusign.admin.api.ProvisionAssetGroupApi; +import com.docusign.admin.client.ApiException; +import com.docusign.admin.client.ApiResponse; +import com.docusign.admin.model.AssetGroupAccountClone; +import com.docusign.admin.model.AssetGroupAccountsResponse; +import com.docusign.admin.model.AssetGroupAccountCloneSourceAccount; +import com.docusign.admin.model.AssetGroupAccountCloneTargetAccount; +import com.docusign.admin.model.AssetGroupAccountCloneTargetAccountAdmin; + +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class CloneAccountService { + public AssetGroupAccountsResponse getGroupAccounts( + ProvisionAssetGroupApi provisionAssetGroupApi, + UUID organizationId) throws ApiException { + + //ds-snippet-start:Admin12Step3 + ProvisionAssetGroupApi.GetAssetGroupAccountsOptions options = provisionAssetGroupApi.new GetAssetGroupAccountsOptions(); + options.setCompliant(true); + ApiResponse response = provisionAssetGroupApi + .getAssetGroupAccountsWithHttpInfo(organizationId, options); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + //ds-snippet-end:Admin12Step3 + } + + public AssetGroupAccountClone getClonedAccount( + ProvisionAssetGroupApi provisionAssetGroupApi, + UUID organizationId, + UUID sourceAccountId, + String targetAccountName, + String targetAccountEmail, + String targetAccountFirstName, + String targetAccountLastName) throws ApiException { + //ds-snippet-start:Admin12Step4 + String countryCode = "US"; + + AssetGroupAccountClone accountData = new AssetGroupAccountClone(); + AssetGroupAccountCloneSourceAccount sourceAccount = new AssetGroupAccountCloneSourceAccount(); + sourceAccount.setId(sourceAccountId); + + AssetGroupAccountCloneTargetAccount targetAccount = new AssetGroupAccountCloneTargetAccount(); + targetAccount.setName(targetAccountName); + targetAccount.setCountryCode(countryCode); + + AssetGroupAccountCloneTargetAccountAdmin admin = new AssetGroupAccountCloneTargetAccountAdmin(); + admin.setEmail(targetAccountEmail); + admin.setFirstName(targetAccountFirstName); + admin.setLastName(targetAccountLastName); + + targetAccount.admin(admin); + accountData.setSourceAccount(sourceAccount); + accountData.setTargetAccount(targetAccount); + //ds-snippet-end:Admin12Step4 + + //ds-snippet-start:Admin12Step5 + ApiResponse response = provisionAssetGroupApi + .cloneAssetGroupAccountWithHttpInfo(organizationId, accountData); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + //ds-snippet-end:Admin12Step5 + } +} diff --git a/src/main/java/com/docusign/controller/admin/services/CreateAccountService.java b/src/main/java/com/docusign/controller/admin/services/CreateAccountService.java new file mode 100644 index 00000000..df1ebe68 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/services/CreateAccountService.java @@ -0,0 +1,108 @@ +package com.docusign.controller.admin.services; + +import com.docusign.admin.api.ProvisionAssetGroupApi; +import com.docusign.admin.client.ApiException; +import com.docusign.admin.client.ApiResponse; +import com.docusign.admin.model.OrganizationSubscriptionResponse; +import com.docusign.admin.model.SubAccountCreateRequest; +import com.docusign.admin.model.SubAccountCreateRequestSubAccountCreationSubscription; +import com.docusign.admin.model.SubAccountCreateRequestSubAccountCreationTargetAccountAdmin; +import com.docusign.admin.model.SubAccountCreateRequestSubAccountCreationTargetAccountDetails; +import com.docusign.admin.model.SubscriptionProvisionModelAssetGroupWorkResult; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.DynamicTest.stream; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.UUID; + +public class CreateAccountService { + + private static final String DEFAULT_ACCOUNT_NAME = "CreatedThroughAPI"; + + private static final String DEFAULT_COUNTRY_CODE = "US"; + + //ds-snippet-start:Admin13Step3 + public static OrganizationSubscriptionResponse getFirstPlanItem( + ProvisionAssetGroupApi provisionAssetGroupApi, + UUID orgId) throws ApiException { + ApiResponse> response = provisionAssetGroupApi + .getOrganizationPlanItemsWithHttpInfo(orgId); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData().stream().findFirst().orElse(null); + } + //ds-snippet-end:Admin13Step3 + + //ds-snippet-start:Admin13Step5 + public static SubscriptionProvisionModelAssetGroupWorkResult createAccountBySubscription( + ProvisionAssetGroupApi provisionAssetGroupApi, + UUID orgId, + String email, + String firstName, + String lastName, + String subscriptionId, + UUID planId) throws ApiException { + SubAccountCreateRequest subAccountRequest = buildSubAccountRequest(email, firstName, lastName, subscriptionId, + planId); + + ApiResponse response = provisionAssetGroupApi + .createAssetGroupAccountWithHttpInfo(orgId, subAccountRequest); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } + //ds-snippet-end:Admin13Step5 + + //ds-snippet-start:Admin13Step4 + private static SubAccountCreateRequest buildSubAccountRequest( + String email, + String firstName, + String lastName, + String subscriptionId, + UUID planId) { + List uuidList = new ArrayList<>(); + SubAccountCreateRequest subAccountRequest = new SubAccountCreateRequest(); + SubAccountCreateRequestSubAccountCreationSubscription subscriptionDetails = new SubAccountCreateRequestSubAccountCreationSubscription(); + subscriptionDetails.setId(subscriptionId); + subscriptionDetails.setPlanId(planId); + subscriptionDetails.setModules(uuidList); + + SubAccountCreateRequestSubAccountCreationTargetAccountDetails targetAccount = new SubAccountCreateRequestSubAccountCreationTargetAccountDetails(); + targetAccount.setName(DEFAULT_ACCOUNT_NAME); + targetAccount.setCountryCode(DEFAULT_COUNTRY_CODE); + + SubAccountCreateRequestSubAccountCreationTargetAccountAdmin admin = new SubAccountCreateRequestSubAccountCreationTargetAccountAdmin(); + admin.setEmail(email); + admin.setFirstName(firstName); + admin.setLastName(lastName); + admin.setLocale(SubAccountCreateRequestSubAccountCreationTargetAccountAdmin.LocaleEnum.EN); + + targetAccount.setAdmin(admin); + subAccountRequest.setSubscriptionDetails(subscriptionDetails); + subAccountRequest.setTargetAccount(targetAccount); + + return subAccountRequest; + } + //ds-snippet-end:Admin13Step4 +} diff --git a/src/main/java/com/docusign/controller/admin/services/CreateActiveCLMESignUserService.java b/src/main/java/com/docusign/controller/admin/services/CreateActiveCLMESignUserService.java new file mode 100644 index 00000000..524cde44 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/services/CreateActiveCLMESignUserService.java @@ -0,0 +1,71 @@ +package com.docusign.controller.admin.services; + +import com.docusign.admin.api.UsersApi; +import com.docusign.admin.client.ApiResponse; +import com.docusign.admin.model.AddUserResponse; +import com.docusign.admin.model.DSGroupRequest; +import com.docusign.admin.model.NewMultiProductUserAddRequest; +import com.docusign.admin.model.ProductPermissionProfileRequest; + +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class CreateActiveCLMESignUserService { + public static AddUserResponse createNewActiveUser( + String clmProfileId, + UUID clmProductId, + String eSignProfileId, + UUID eSignProductId, + UUID dsGroupId, + String userName, + String firstName, + String lastName, + String email, + UsersApi usersApi, + UUID organizationId, + UUID accountId) throws Exception { + //ds-snippet-start:Admin2Step5 + ProductPermissionProfileRequest clm = new ProductPermissionProfileRequest(); + ProductPermissionProfileRequest eSign = new ProductPermissionProfileRequest(); + clm.setPermissionProfileId(clmProfileId); + clm.setProductId(clmProductId); + + eSign.setPermissionProfileId(eSignProfileId); + eSign.setProductId(eSignProductId); + + DSGroupRequest dsGroup = new DSGroupRequest(); + dsGroup.setDsGroupId(dsGroupId); + // Fill the request with data from the form + + NewMultiProductUserAddRequest multiProductUserAddRequest = new NewMultiProductUserAddRequest() + .defaultAccountId(accountId) + .addProductPermissionProfilesItem(clm) + .addProductPermissionProfilesItem(eSign) + .addDsGroupsItem(dsGroup) + .userName(userName) + .firstName(firstName) + .lastName(lastName) + .autoActivateMemberships(true) + .email(email); + //ds-snippet-end:Admin2Step5 + + //ds-snippet-start:Admin2Step6 + ApiResponse response = usersApi.addOrUpdateUserWithHttpInfo(organizationId, accountId, + multiProductUserAddRequest); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + //ds-snippet-end:Admin2Step6 + } +} diff --git a/src/main/java/com/docusign/controller/admin/services/DeleteUserProductPermissionProfileById.java b/src/main/java/com/docusign/controller/admin/services/DeleteUserProductPermissionProfileById.java new file mode 100644 index 00000000..6b44b5d6 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/services/DeleteUserProductPermissionProfileById.java @@ -0,0 +1,46 @@ +package com.docusign.controller.admin.services; + +import com.docusign.admin.api.ProductPermissionProfilesApi; +import com.docusign.admin.client.ApiResponse; +import com.docusign.admin.model.RemoveUserProductsResponse; +import com.docusign.admin.model.UserProductProfileDeleteRequest; + +import java.time.Instant; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class DeleteUserProductPermissionProfileById { + public static RemoveUserProductsResponse deleteUserProductPermissionProfile( + ProductPermissionProfilesApi productPermissionProfilesApi, + UUID productId, + String emailAddress, + UUID organizationId, + UUID accountId) throws Exception { + + //ds-snippet-start:Admin9Step4 + var userProductProfileDeleteRequest = new UserProductProfileDeleteRequest(); + userProductProfileDeleteRequest.setProductIds(Collections.singletonList(productId)); + userProductProfileDeleteRequest.setUserEmail(emailAddress); + //ds-snippet-end:Admin9Step4 + + ApiResponse response = productPermissionProfilesApi + .removeUserProductPermissionWithHttpInfo( + organizationId, + accountId, + userProductProfileDeleteRequest); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } +} \ No newline at end of file diff --git a/src/main/java/com/docusign/controller/admin/services/RetrieveDocuSignProfileByEmailAddress.java b/src/main/java/com/docusign/controller/admin/services/RetrieveDocuSignProfileByEmailAddress.java new file mode 100644 index 00000000..78e9869d --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/services/RetrieveDocuSignProfileByEmailAddress.java @@ -0,0 +1,34 @@ +package com.docusign.controller.admin.services; + +import com.docusign.admin.api.UsersApi; +import com.docusign.admin.client.ApiResponse; +import com.docusign.admin.model.UsersDrilldownResponse; + +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class RetrieveDocuSignProfileByEmailAddress { + public static UsersDrilldownResponse getDocuSignProfileByEmailAddress( + UsersApi usersApi, + UUID organizationId, + String emailAddress) throws Exception { + var userOptions = usersApi.new GetUserDSProfilesByEmailOptions(); + userOptions.setEmail(emailAddress); + ApiResponse response = usersApi.getUserDSProfilesByEmailWithHttpInfo(organizationId, + userOptions); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/admin/services/RetrieveDocuSignProfileByUserId.java b/src/main/java/com/docusign/controller/admin/services/RetrieveDocuSignProfileByUserId.java new file mode 100644 index 00000000..41169806 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/services/RetrieveDocuSignProfileByUserId.java @@ -0,0 +1,33 @@ +package com.docusign.controller.admin.services; + +import com.docusign.admin.api.UsersApi; +import com.docusign.admin.api.UsersApi.GetUserDSProfileOptions; +import com.docusign.admin.client.ApiResponse; +import com.docusign.admin.model.UsersDrilldownResponse; + +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class RetrieveDocuSignProfileByUserId { + public static UsersDrilldownResponse getDocuSignProfileByUserId( + UsersApi usersApi, + UUID organizationId, + UUID userId) throws Exception { + ApiResponse response = usersApi.getUserDSProfileWithHttpInfo(organizationId, userId, + (GetUserDSProfileOptions) null); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/admin/services/UpdateUserProductPermissionProfileByEmail.java b/src/main/java/com/docusign/controller/admin/services/UpdateUserProductPermissionProfileByEmail.java new file mode 100644 index 00000000..23c538b5 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/services/UpdateUserProductPermissionProfileByEmail.java @@ -0,0 +1,52 @@ +package com.docusign.controller.admin.services; + +import com.docusign.admin.api.ProductPermissionProfilesApi; +import com.docusign.admin.client.ApiResponse; +import com.docusign.admin.model.ProductPermissionProfileRequest; +import com.docusign.admin.model.UserProductPermissionProfilesRequest; +import com.docusign.admin.model.UserProductPermissionProfilesResponse; + +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class UpdateUserProductPermissionProfileByEmail { + public static UserProductPermissionProfilesResponse updateUserProductPermissionProfile( + ProductPermissionProfilesApi productPermissionProfilesApi, + String permissionProfileId, + UUID productId, + String emailAddress, + UUID organizationId, + UUID accountId) throws Exception { + //ds-snippet-start:Admin8Step3 + var productPermissionProfileRequest = new ProductPermissionProfileRequest(); + productPermissionProfileRequest.setPermissionProfileId(permissionProfileId); + productPermissionProfileRequest.setProductId(productId); + + var userProductPermissionProfilesRequest = new UserProductPermissionProfilesRequest(); + userProductPermissionProfilesRequest.email(emailAddress); + userProductPermissionProfilesRequest.addProductPermissionProfilesItem(productPermissionProfileRequest); + //ds-snippet-end:Admin8Step3 + + //ds-snippet-start:Admin8Step4 + ApiResponse response = productPermissionProfilesApi + .addUserProductPermissionProfilesByEmailWithHttpInfo( + organizationId, + accountId, + userProductPermissionProfilesRequest); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + //ds-snippet-end:Admin8Step4 + } +} diff --git a/src/main/java/com/docusign/controller/admin/services/UserDataManagementService.java b/src/main/java/com/docusign/controller/admin/services/UserDataManagementService.java new file mode 100644 index 00000000..522d37a8 --- /dev/null +++ b/src/main/java/com/docusign/controller/admin/services/UserDataManagementService.java @@ -0,0 +1,103 @@ +package com.docusign.controller.admin.services; + +import com.docusign.admin.api.AccountsApi; +import com.docusign.admin.api.OrganizationsApi; +import com.docusign.admin.api.UsersApi; +import com.docusign.admin.client.ApiException; +import com.docusign.admin.client.ApiResponse; +import com.docusign.admin.model.IndividualMembershipDataRedactionRequest; +import com.docusign.admin.model.IndividualUserDataRedactionResponse; +import com.docusign.admin.model.UserDrilldownResponse; +import com.docusign.admin.model.UsersDrilldownResponse; +import com.docusign.admin.model.MembershipDataRedactionRequest; +import com.docusign.admin.model.IndividualUserDataRedactionRequest; + +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class UserDataManagementService { + public IndividualUserDataRedactionResponse deleteUserDataFromAccountByUserId( + AccountsApi accountsApi, + UUID userId, + UUID accountId) throws Exception { + //ds-snippet-start:Admin11Step3 + IndividualMembershipDataRedactionRequest membershipDataRedaction = new IndividualMembershipDataRedactionRequest(); + membershipDataRedaction.userId(userId); + //ds-snippet-end:Admin11Step3 + //ds-snippet-start:Admin11Step4 + ApiResponse response = accountsApi + .redactIndividualMembershipDataWithHttpInfo(accountId, membershipDataRedaction); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + //ds-snippet-end:Admin11Step4 + } + + public IndividualUserDataRedactionResponse deleteUserDataFromOrganizationByEmail( + UsersApi usersApi, + OrganizationsApi organizationsApi, + String emailAddress, + UUID organizationId) throws ApiException { + UsersApi.GetUserDSProfilesByEmailOptions getProfilesOptions = usersApi.new GetUserDSProfilesByEmailOptions(); + getProfilesOptions.setEmail(emailAddress); + + ApiResponse profiles = usersApi.getUserDSProfilesByEmailWithHttpInfo(organizationId, + getProfilesOptions); + + Map> headers = profiles.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + UserDrilldownResponse user = null; + if (profiles.getData().getUsers() != null && !profiles.getData().getUsers().isEmpty() + && profiles.getData().getUsers().get(0) != null) { + user = profiles.getData().getUsers().get(0); + } + + MembershipDataRedactionRequest memberships = new MembershipDataRedactionRequest(); + + if (user.getMemberships() != null && !user.getMemberships().isEmpty() && user.getMemberships().get(0) != null) { + memberships.accountId(user.getMemberships().get(0).getAccountId()); + } + + //ds-snippet-start:Admin10Step3 + IndividualUserDataRedactionRequest userRedactionRequest = new IndividualUserDataRedactionRequest(); + userRedactionRequest.setUserId(user.getId()); + userRedactionRequest.setMemberships(Arrays.asList(memberships)); + //ds-snippet-end:Admin10Step3 + //ds-snippet-start:Admin10Step4 + ApiResponse response = organizationsApi + .redactIndividualUserDataWithHttpInfo(organizationId, userRedactionRequest); + + headers = response.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + //ds-snippet-end:Admin10Step4 + } +} \ No newline at end of file diff --git a/src/main/java/com/docusign/controller/click/examples/AbstractClickController.java b/src/main/java/com/docusign/controller/click/examples/AbstractClickController.java new file mode 100644 index 00000000..7ed28f22 --- /dev/null +++ b/src/main/java/com/docusign/controller/click/examples/AbstractClickController.java @@ -0,0 +1,56 @@ +package com.docusign.controller.click.examples; + +import com.docusign.DSConfiguration; +import com.docusign.click.api.AccountsApi; +import com.docusign.click.client.ApiClient; +import com.docusign.click.client.auth.OAuth; +import com.docusign.core.controller.AbstractController; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Controller; + +/** + * Abstract base class for all Click controllers. + */ +@Controller +public abstract class AbstractClickController extends AbstractController { + + private static final String EXAMPLE_PAGES_PATH = "pages/click/examples/"; + + public AbstractClickController(DSConfiguration config, String exampleName) { + super(config, exampleName); + } + + /** + * Creates new instance of the Click API client. + * + * @param basePath URL to Click REST API + * @param userAccessToken user's access token + * @return an instance of the {@link ApiClient} + */ + protected static ApiClient createApiClient(String basePath, String userAccessToken) { + //ds-snippet-start:ClickJavaStep2 + ApiClient apiClient = new ApiClient(basePath); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + userAccessToken); + apiClient.addAuthorization("docusignAccessCode", new OAuth()); + return apiClient; + //ds-snippet-end:ClickJavaStep2 + } + + /** + * Creates a new instance of the ClickApi. This method + * creates an instance of the ApiClient class silently. + * + * @param basePath URL to Click REST API + * @param userAccessToken user's access token + * @return an instance of the {@link AccountsApi} + */ + protected static AccountsApi createAccountsApiClient(String basePath, String userAccessToken) { + ApiClient apiClient = createApiClient(basePath, userAccessToken); + return new AccountsApi(apiClient); + } + + protected String getExamplePagesPath() { + return AbstractClickController.EXAMPLE_PAGES_PATH; + } +} + diff --git a/src/main/java/com/docusign/controller/click/examples/C001ControllerCreateClickwrap.java b/src/main/java/com/docusign/controller/click/examples/C001ControllerCreateClickwrap.java new file mode 100644 index 00000000..8f73420d --- /dev/null +++ b/src/main/java/com/docusign/controller/click/examples/C001ControllerCreateClickwrap.java @@ -0,0 +1,75 @@ +package com.docusign.controller.click.examples; + +import com.docusign.DSConfiguration; +import com.docusign.click.api.AccountsApi; +import com.docusign.click.client.ApiException; +import com.docusign.click.model.ClickwrapRequest; +import com.docusign.click.model.ClickwrapVersionSummaryResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.click.services.CreateClickwrapService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Create a clickwrap. + */ +@Controller +@RequestMapping("/c001") +public class C001ControllerCreateClickwrap extends AbstractClickController { + + private static final String DOCUMENT_FILE_NAME = "TermsOfService.pdf"; + + private static final Integer DOCUMENT_ORDER = 0; + + private static final String DOCUMENT_NAME = "Terms of Service"; + + private final Session session; + + private final User user; + + public C001ControllerCreateClickwrap(DSConfiguration config, Session session, User user) { + super(config, "c001"); + this.session = session; + this.user = user; + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws IOException, ApiException { + // Step 2. Construct your API headers + AccountsApi accountsApi = createAccountsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + + // Step 3. Construct the request body for your clickwrap + //ds-snippet-start:Click1Step3 + ClickwrapRequest clickwrapRequest = CreateClickwrapService.createClickwrapRequest( + args.getClickwrapName(), + DOCUMENT_FILE_NAME, + DOCUMENT_NAME, + DOCUMENT_ORDER); + //ds-snippet-end:Click1Step3 + + // Step 4. Call the v1 Click API + //ds-snippet-start:Click1Step4 + ClickwrapVersionSummaryResponse createdClickwrap = CreateClickwrapService.createClickwrap( + accountsApi, + this.session.getAccountId(), + clickwrapRequest); + //ds-snippet-end:Click1Step4 + + this.session.setClickwrapId(createdClickwrap.getClickwrapId()); + this.session.setClickwrapVersionNumber(createdClickwrap.getVersionNumber()); + DoneExample.createDefault(this.title) + .withJsonObject(createdClickwrap) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText.replaceFirst("\\{0}", createdClickwrap.getClickwrapName())) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + // ***DS.snippet.0.end +} diff --git a/src/main/java/com/docusign/controller/click/examples/C002ControllerActivateClickwrap.java b/src/main/java/com/docusign/controller/click/examples/C002ControllerActivateClickwrap.java new file mode 100644 index 00000000..d7701706 --- /dev/null +++ b/src/main/java/com/docusign/controller/click/examples/C002ControllerActivateClickwrap.java @@ -0,0 +1,78 @@ +package com.docusign.controller.click.examples; + +import com.docusign.DSConfiguration; +import com.docusign.click.api.AccountsApi; +import com.docusign.click.client.ApiException; +import com.docusign.click.model.ClickwrapVersionSummaryResponse; +import com.docusign.click.model.ClickwrapVersionsResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.click.services.ActivateClickwrapService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +/** + * Activate a clickwrap. + */ +@Controller +@RequestMapping("/c002") +public class C002ControllerActivateClickwrap extends AbstractClickController { + + private static final String MODEL_CLICKWRAPS = "clickwraps"; + + private final Session session; + + private final User user; + + public C002ControllerActivateClickwrap(DSConfiguration config, Session session, User user) { + super(config, "c002"); + this.session = session; + this.user = user; + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + AccountsApi accountsApi = createAccountsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + ClickwrapVersionsResponse inactiveClickwraps = ActivateClickwrapService.getClickwrapsByStatus( + accountsApi, + this.session.getAccountId(), + "inactive"); + ClickwrapVersionsResponse draftClickwraps = ActivateClickwrapService.getClickwrapsByStatus( + accountsApi, + this.session.getAccountId(), + "draft"); + inactiveClickwraps.getClickwraps().addAll(draftClickwraps.getClickwraps()); + model.addAttribute(MODEL_CLICKWRAPS, inactiveClickwraps); + } + + @Override + // ***DS.snippet.0.start + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException { + AccountsApi accountsApi = createAccountsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + + String clickwrap = args.getClickwrap(); + String[] clickwrapData = clickwrap.split(":"); + String clickwrapId = clickwrapData[0]; + String versionNumber = clickwrapData[1]; + + ClickwrapVersionSummaryResponse updatedClickwrap = ActivateClickwrapService.activateClickwrap( + accountsApi, + this.session.getAccountId(), + clickwrapId, + versionNumber); + + DoneExample.createDefault(this.title) + .withJsonObject(updatedClickwrap) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + // ***DS.snippet.0.end +} diff --git a/src/main/java/com/docusign/controller/click/examples/C003ControllerCreateNewVersionClickwrap.java b/src/main/java/com/docusign/controller/click/examples/C003ControllerCreateNewVersionClickwrap.java new file mode 100644 index 00000000..86914734 --- /dev/null +++ b/src/main/java/com/docusign/controller/click/examples/C003ControllerCreateNewVersionClickwrap.java @@ -0,0 +1,79 @@ +package com.docusign.controller.click.examples; + +import com.docusign.DSConfiguration; +import com.docusign.click.api.AccountsApi; +import com.docusign.click.client.ApiException; +import com.docusign.click.model.ClickwrapVersionSummaryResponse; +import com.docusign.click.model.ClickwrapVersionsResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.click.services.CreateNewVersionClickwrapService; +import com.docusign.controller.click.services.GetListClickwrapsService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Create a clickwrap. + */ +@Controller +@RequestMapping("/c003") +public class C003ControllerCreateNewVersionClickwrap extends AbstractClickController { + + private static final String MODEL_CLICKWRAPS = "clickwraps"; + + private static final String DOCUMENT_FILE_NAME = "TermsOfService.pdf"; + + private static final Integer DOCUMENT_ORDER = 0; + + private static final String DOCUMENT_NAME = "Terms of Service"; + + private final Session session; + + private final User user; + + public C003ControllerCreateNewVersionClickwrap(DSConfiguration config, Session session, User user) { + super(config, "c003"); + this.session = session; + this.user = user; + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + AccountsApi accountsApi = createAccountsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + ClickwrapVersionsResponse clickwraps = GetListClickwrapsService.getListClickwrap(accountsApi, this.session.getAccountId()); + model.addAttribute(MODEL_CLICKWRAPS, clickwraps); + } + + @Override + // ***DS.snippet.0.start + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws IOException, ApiException { + // Step 2: Construct your API headers + AccountsApi accountsApi = createAccountsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + + ClickwrapVersionSummaryResponse createdClickwrap = CreateNewVersionClickwrapService.createNewVersionClickwrap( + accountsApi, + CreateNewVersionClickwrapService.createClickwrapRequest(DOCUMENT_FILE_NAME, DOCUMENT_NAME, DOCUMENT_ORDER, args.getClickwrapName()), + this.session.getAccountId(), + args.getClickwrapId() + ); + + this.session.setClickwrapId(createdClickwrap.getClickwrapId()); + this.session.setClickwrapVersionNumber(createdClickwrap.getVersionNumber()); + DoneExample.createDefault(this.title) + .withJsonObject(createdClickwrap) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", createdClickwrap.getVersionNumber()) + .replaceFirst("\\{1}", createdClickwrap.getClickwrapName())) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + // ***DS.snippet.0.end +} diff --git a/src/main/java/com/docusign/controller/click/examples/C004ControllerGetListClickwraps.java b/src/main/java/com/docusign/controller/click/examples/C004ControllerGetListClickwraps.java new file mode 100644 index 00000000..f4a94fd0 --- /dev/null +++ b/src/main/java/com/docusign/controller/click/examples/C004ControllerGetListClickwraps.java @@ -0,0 +1,51 @@ +package com.docusign.controller.click.examples; + +import com.docusign.DSConfiguration; +import com.docusign.click.api.AccountsApi; +import com.docusign.click.client.ApiException; +import com.docusign.click.model.ClickwrapVersionsResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.click.services.GetListClickwrapsService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +/** + * Get a list of clickwraps. + */ +@Controller +@RequestMapping("/c004") +public class C004ControllerGetListClickwraps extends AbstractClickController { + + private final Session session; + + private final User user; + + public C004ControllerGetListClickwraps(DSConfiguration config, Session session, User user) { + super(config, "c004"); + this.session = session; + this.user = user; + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException { + // Step 2: Construct your API headers + AccountsApi accountsApi = createAccountsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + + ClickwrapVersionsResponse clickwrapsResponse = GetListClickwrapsService.getListClickwrap( + accountsApi, + this.session.getAccountId()); + + DoneExample.createDefault(this.title) + .withJsonObject(clickwrapsResponse) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/click/examples/C005ControllerGetClickwrapResponses.java b/src/main/java/com/docusign/controller/click/examples/C005ControllerGetClickwrapResponses.java new file mode 100644 index 00000000..1fca20c7 --- /dev/null +++ b/src/main/java/com/docusign/controller/click/examples/C005ControllerGetClickwrapResponses.java @@ -0,0 +1,68 @@ +package com.docusign.controller.click.examples; + +import com.docusign.DSConfiguration; +import com.docusign.click.api.AccountsApi; +import com.docusign.click.client.ApiException; +import com.docusign.click.model.ClickwrapAgreementsResponse; +import com.docusign.click.model.ClickwrapVersionsResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.click.services.GetClickwrapResponsesService; +import com.docusign.controller.click.services.GetListClickwrapsService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +/** + * Get clickwrap responses. + */ +@Controller +@RequestMapping("/c005") +public class C005ControllerGetClickwrapResponses extends AbstractClickController { + + private static final String MODEL_CLICKWRAPS = "clickwraps"; + + private final Session session; + + private final User user; + + public C005ControllerGetClickwrapResponses(DSConfiguration config, Session session, User user) { + super(config, "c005"); + this.session = session; + this.user = user; + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + AccountsApi accountsApi = createAccountsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + ClickwrapVersionsResponse clickwraps = GetListClickwrapsService.getListClickwrap(accountsApi, this.session.getAccountId()); + model.addAttribute(MODEL_CLICKWRAPS, clickwraps); + } + + @Override + // ***DS.snippet.0.start + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException { + // Step 2: Construct your API headers + AccountsApi accountsApi = createAccountsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + + // Step 3: Call the v1 Click API + //ds-snippet-start:Click5Step3 + ClickwrapAgreementsResponse clickwrapAgreementsResponse = GetClickwrapResponsesService.getClickwrapResponses( + accountsApi, + this.session.getAccountId(), + args.getClickwrapId()); + //ds-snippet-end:Click5Step3 + + DoneExample.createDefault(this.title) + .withJsonObject(clickwrapAgreementsResponse) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/click/examples/C006ControllerEmbedClickwrap.java b/src/main/java/com/docusign/controller/click/examples/C006ControllerEmbedClickwrap.java new file mode 100644 index 00000000..7aeff1af --- /dev/null +++ b/src/main/java/com/docusign/controller/click/examples/C006ControllerEmbedClickwrap.java @@ -0,0 +1,85 @@ +package com.docusign.controller.click.examples; + +import com.docusign.DSConfiguration; +import com.docusign.click.api.AccountsApi; +import com.docusign.click.client.ApiException; +import com.docusign.click.model.ClickwrapVersionsResponse; +import com.docusign.common.WorkArguments; +import com.docusign.controller.click.services.ActivateClickwrapService; +import com.docusign.controller.click.services.EmbedClickwrapService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +/** + * Activate a clickwrap. + */ +@Controller +@RequestMapping("/c006") +public class C006ControllerEmbedClickwrap extends AbstractClickController { + + private static final String MODEL_CLICKWRAPS = "clickwraps"; + + private final Session session; + + private final User user; + + public C006ControllerEmbedClickwrap(DSConfiguration config, Session session, User user) { + super(config, "c006"); + this.session = session; + this.user = user; + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + AccountsApi accountsApi = createAccountsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + ClickwrapVersionsResponse clickwraps = EmbedClickwrapService.getActiveClickwraps(accountsApi, this.session.getAccountId()); + ClickwrapVersionsResponse inactiveClickwraps = ActivateClickwrapService.getClickwrapsByStatus(accountsApi, this.session.getAccountId(), "inactive"); + Boolean hasInactiveClickraps = inactiveClickwraps.getClickwraps().size() > 0; + model.addAttribute(MODEL_CLICKWRAPS, clickwraps); + model.addAttribute("hasInactiveClickraps", hasInactiveClickraps); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException { + // Step 2: Construct your API headers + AccountsApi accountsApi = createAccountsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + + String clickwrapId = args.getClickwrap(); + String fullName = args.getFullName(); + String email = args.getEmail(); + String company = args.getCompany(); + String title = args.getTitle(); + String date = args.getDate(); + + String url = EmbedClickwrapService.createAgreementUrl( + accountsApi, this.session.getAccountId(), + clickwrapId, fullName, email, company, title, date); + + if (url == "Already Agreed") { + new DoneExample() + .withTitle(exampleName) + .withName(title) + .withMessage("The email address was already used to agree to this elastic template. Provide a different email address if you want to view the agreement and agree to it.") + .addToModel(model, config); + return ERROR_PAGE; + } + else + { + String htmlSnippet = "

NOT AGREED

"; + + DoneExample.createDefault(this.title) + .withJsonObject(url) + .withMessage(getTextForCodeExample().ResultsPageText + htmlSnippet) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + } +} diff --git a/src/main/java/com/docusign/controller/click/examples/ClickwrapHelper.java b/src/main/java/com/docusign/controller/click/examples/ClickwrapHelper.java new file mode 100644 index 00000000..719806b4 --- /dev/null +++ b/src/main/java/com/docusign/controller/click/examples/ClickwrapHelper.java @@ -0,0 +1,48 @@ +package com.docusign.controller.click.examples; + +import com.docusign.click.model.Document; +import com.docusign.core.utils.FileUtils; +import org.apache.commons.io.FilenameUtils; + +import java.io.IOException; +import java.util.Base64; + +public class ClickwrapHelper { + + public static final String STATUS_ACTIVE = "active"; + + /** + * Loads document from a file and creates a document object that represents + * loaded document. + * + * @param fileName name of the file to load document; the extension of the + * loading file determines an extension of the created document + * @param docName the name of the document; it may be differ from the file + * @param order order of the created document + * @return the {@link Document} object + * @throws IOException if document cannot be loaded due to some reason + */ + public Document createDocumentFromFile(String fileName, String docName, Integer order) throws IOException { + byte[] buffer = new FileUtils().readFile(fileName); + String extension = FilenameUtils.getExtension(fileName); + return createDocument(buffer, docName, extension, order); + } + + /** + * Creates a document object from the raw data. + * + * @param data the raw data + * @param documentName the name of the document; it may be differ from the file + * @param fileExtension the extension of the creating file + * @param order order of the created document + * @return the {@link Document} object + */ + static Document createDocument(byte[] data, String documentName, String fileExtension, Integer order) { + Document document = new Document(); + document.setDocumentBase64(Base64.getEncoder().encodeToString(data)); + document.setDocumentName(documentName); + document.setFileExtension(fileExtension); + document.setOrder(order); + return document; + } +} diff --git a/src/main/java/com/docusign/controller/click/services/ActivateClickwrapService.java b/src/main/java/com/docusign/controller/click/services/ActivateClickwrapService.java new file mode 100644 index 00000000..33a64835 --- /dev/null +++ b/src/main/java/com/docusign/controller/click/services/ActivateClickwrapService.java @@ -0,0 +1,68 @@ +package com.docusign.controller.click.services; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +import com.docusign.click.api.AccountsApi; +import com.docusign.click.client.ApiException; +import com.docusign.click.client.ApiResponse; +import com.docusign.click.model.ClickwrapRequest; +import com.docusign.click.model.ClickwrapVersionResponse; +import com.docusign.click.model.ClickwrapVersionSummaryResponse; +import com.docusign.click.model.ClickwrapVersionsResponse; +import com.docusign.controller.click.examples.ClickwrapHelper; + +public final class ActivateClickwrapService { + public static ClickwrapVersionSummaryResponse activateClickwrap( + AccountsApi accountsApi, + String accountId, + String clickwrapId, + String clickwrapVersionNumber) throws ApiException { + //ds-snippet-start:Click2Step3 + ClickwrapRequest clickwrapRequest = new ClickwrapRequest().status(ClickwrapHelper.STATUS_ACTIVE); + //ds-snippet-end:Click2Step3 + + //ds-snippet-start:Click2Step4 + ApiResponse response = accountsApi.updateClickwrapVersionWithHttpInfo( + accountId, + clickwrapId, + clickwrapVersionNumber, + clickwrapRequest); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + //ds-snippet-end:Click2Step4 + } + + public static ClickwrapVersionsResponse getClickwrapsByStatus( + AccountsApi accountsApi, + String accountId, + String status) throws ApiException { + AccountsApi.GetClickwrapsOptions options = accountsApi.new GetClickwrapsOptions(); + options.setStatus(status); + + ApiResponse response = accountsApi.getClickwrapsWithHttpInfo(accountId, options); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/click/services/CreateClickwrapService.java b/src/main/java/com/docusign/controller/click/services/CreateClickwrapService.java new file mode 100644 index 00000000..23ee797d --- /dev/null +++ b/src/main/java/com/docusign/controller/click/services/CreateClickwrapService.java @@ -0,0 +1,62 @@ +package com.docusign.controller.click.services; + +import com.docusign.click.api.AccountsApi; +import com.docusign.click.client.ApiException; +import com.docusign.click.client.ApiResponse; +import com.docusign.click.model.ClickwrapRequest; +import com.docusign.click.model.ClickwrapVersionSummaryResponse; +import com.docusign.click.model.DisplaySettings; +import com.docusign.click.model.Document; +import com.docusign.controller.click.examples.ClickwrapHelper; + +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public final class CreateClickwrapService { + //ds-snippet-start:Click1Step3 + public static ClickwrapRequest createClickwrapRequest( + String clickwrapName, + String fileName, + String documentName, + Integer documentOrder) throws IOException { + Document document = new ClickwrapHelper().createDocumentFromFile(fileName, documentName, documentOrder); + DisplaySettings displaySettings = new DisplaySettings() + .displayName("Terms of Service") + .consentButtonText("I Agree") + .downloadable(true) + .format("modal") + .mustRead(true) + .requireAccept(true) + .documentDisplay("document"); + + return new ClickwrapRequest() + .addDocumentsItem(document) + .clickwrapName(clickwrapName) + .requireReacceptance(true) + .displaySettings(displaySettings); + } + //ds-snippet-end:Click1Step3 + + public static ClickwrapVersionSummaryResponse createClickwrap( + AccountsApi accountsApi, + String accountId, + ClickwrapRequest clickwrapRequest) throws IOException, ApiException { + ApiResponse response = accountsApi.createClickwrapWithHttpInfo( + accountId, + clickwrapRequest); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/click/services/CreateNewVersionClickwrapService.java b/src/main/java/com/docusign/controller/click/services/CreateNewVersionClickwrapService.java new file mode 100644 index 00000000..c3ad7ea9 --- /dev/null +++ b/src/main/java/com/docusign/controller/click/services/CreateNewVersionClickwrapService.java @@ -0,0 +1,68 @@ +package com.docusign.controller.click.services; + +import com.docusign.click.api.AccountsApi; +import com.docusign.click.client.ApiException; +import com.docusign.click.client.ApiResponse; +import com.docusign.click.model.ClickwrapRequest; +import com.docusign.click.model.ClickwrapVersionSummaryResponse; +import com.docusign.click.model.DisplaySettings; +import com.docusign.click.model.Document; +import com.docusign.controller.click.examples.ClickwrapHelper; + +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public final class CreateNewVersionClickwrapService { + public static ClickwrapVersionSummaryResponse createNewVersionClickwrap( + AccountsApi accountsApi, + ClickwrapRequest clickwrapRequest, + String accountId, + String clickwrapId) throws ApiException { + // Step 4: Call the v1 Click API + //ds-snippet-start:Click3Step4 + ApiResponse response = accountsApi.createClickwrapVersionWithHttpInfo( + accountId, + clickwrapId, + clickwrapRequest); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + //ds-snippet-end:Click3Step4 + } + + //ds-snippet-start:Click3Step3 + public static ClickwrapRequest createClickwrapRequest( + String fileName, + String documentName, + Integer documentOrder, + String clickwrapName) throws IOException { + Document document = new ClickwrapHelper().createDocumentFromFile(fileName, documentName, documentOrder); + DisplaySettings displaySettings = new DisplaySettings() + .displayName(clickwrapName) + .consentButtonText("I Agree") + .downloadable(true) + .format("modal") + .mustRead(true) + .requireAccept(true) + .documentDisplay("document"); + + return new ClickwrapRequest() + .addDocumentsItem(document) + .clickwrapName(clickwrapName) + .requireReacceptance(true) + .status(ClickwrapHelper.STATUS_ACTIVE) + .displaySettings(displaySettings); + } + //ds-snippet-end:Click3Step3 +} diff --git a/src/main/java/com/docusign/controller/click/services/EmbedClickwrapService.java b/src/main/java/com/docusign/controller/click/services/EmbedClickwrapService.java new file mode 100644 index 00000000..2ff26b60 --- /dev/null +++ b/src/main/java/com/docusign/controller/click/services/EmbedClickwrapService.java @@ -0,0 +1,78 @@ +package com.docusign.controller.click.services; + +import com.docusign.click.api.AccountsApi; +import com.docusign.click.client.ApiException; +import com.docusign.click.client.ApiResponse; +import com.docusign.click.model.ClickwrapVersionResponse; +import com.docusign.click.model.ClickwrapVersionsResponse; +import com.docusign.click.model.UserAgreementRequest; +import com.docusign.click.model.UserAgreementResponse; + +import java.time.Instant; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public final class EmbedClickwrapService { + public static String createAgreementUrl( + AccountsApi accountsApi, + String accountId, + String clickwrapId, + String fullName, + String email, + String company, + String title, + String date) throws ApiException { + + //ds-snippet-start:Click6Step3 + UserAgreementRequest userAgreementRequest = new UserAgreementRequest(); + userAgreementRequest.setClientUserId(email); + Map documentData = new HashMap(); + documentData.put("fullName", fullName); + documentData.put("email", email); + documentData.put("company", company); + documentData.put("title", title); + documentData.put("date", date); + userAgreementRequest.setDocumentData(documentData); + //ds-snippet-end:Click6Step3 + //ds-snippet-start:Click6Step4 + ApiResponse response = accountsApi.createHasAgreedWithHttpInfo(accountId, clickwrapId, + userAgreementRequest); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + if (response.getStatusCode() == 201) { + return response.getData().getAgreementUrl(); + } + return "Already Agreed"; + //ds-snippet-end:Click6Step4 + } + + public static ClickwrapVersionsResponse getActiveClickwraps( + AccountsApi accountsApi, + String accountId) throws ApiException { + AccountsApi.GetClickwrapsOptions options = accountsApi.new GetClickwrapsOptions(); + options.setStatus("active"); + ApiResponse response = accountsApi.getClickwrapsWithHttpInfo(accountId, options); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/click/services/GetClickwrapResponsesService.java b/src/main/java/com/docusign/controller/click/services/GetClickwrapResponsesService.java new file mode 100644 index 00000000..9d1624bf --- /dev/null +++ b/src/main/java/com/docusign/controller/click/services/GetClickwrapResponsesService.java @@ -0,0 +1,34 @@ +package com.docusign.controller.click.services; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +import com.docusign.click.api.AccountsApi; +import com.docusign.click.api.AccountsApi.GetClickwrapAgreementsOptions; +import com.docusign.click.client.ApiException; +import com.docusign.click.client.ApiResponse; +import com.docusign.click.model.ClickwrapAgreementsResponse; + +public final class GetClickwrapResponsesService { + public static ClickwrapAgreementsResponse getClickwrapResponses( + AccountsApi accountsApi, + String accountId, + String clickwrapId) throws ApiException { + // Step 3: Call the v1 Click API + ApiResponse response = accountsApi.getClickwrapAgreementsWithHttpInfo(accountId, + clickwrapId, (GetClickwrapAgreementsOptions) null); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/click/services/GetListClickwrapsService.java b/src/main/java/com/docusign/controller/click/services/GetListClickwrapsService.java new file mode 100644 index 00000000..96c561cb --- /dev/null +++ b/src/main/java/com/docusign/controller/click/services/GetListClickwrapsService.java @@ -0,0 +1,35 @@ +package com.docusign.controller.click.services; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +import com.docusign.click.api.AccountsApi; +import com.docusign.click.api.AccountsApi.GetClickwrapsOptions; +import com.docusign.click.client.ApiException; +import com.docusign.click.client.ApiResponse; +import com.docusign.click.model.ClickwrapVersionsResponse; + +public final class GetListClickwrapsService { + public static ClickwrapVersionsResponse getListClickwrap( + AccountsApi accountsApi, + String accountId) throws ApiException { + // Step 3: Call the v1 Click API + //ds-snippet-start:Click4Step3 + ApiResponse response = accountsApi.getClickwrapsWithHttpInfo(accountId, + (GetClickwrapsOptions) null); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + //ds-snippet-end:Click4Step3 + } +} diff --git a/src/main/java/com/docusign/controller/connect/examples/AbstractConnectController.java b/src/main/java/com/docusign/controller/connect/examples/AbstractConnectController.java new file mode 100644 index 00000000..177dec65 --- /dev/null +++ b/src/main/java/com/docusign/controller/connect/examples/AbstractConnectController.java @@ -0,0 +1,22 @@ +package com.docusign.controller.connect.examples; + +import com.docusign.DSConfiguration; +import com.docusign.core.controller.AbstractController; +import org.springframework.stereotype.Controller; + +/** + * Abstract base class for all Connect controllers. + */ +@Controller +public abstract class AbstractConnectController extends AbstractController { + + private static final String EXAMPLE_PAGES_PATH = "pages/connect/examples/"; + + public AbstractConnectController(DSConfiguration config, String exampleName) { + super(config, exampleName); + } + + protected String getExamplePagesPath() { + return AbstractConnectController.EXAMPLE_PAGES_PATH; + } +} diff --git a/src/main/java/com/docusign/controller/connect/examples/EG001ControllerValidateUsingHMAC.java b/src/main/java/com/docusign/controller/connect/examples/EG001ControllerValidateUsingHMAC.java new file mode 100644 index 00000000..5c6c0f01 --- /dev/null +++ b/src/main/java/com/docusign/controller/connect/examples/EG001ControllerValidateUsingHMAC.java @@ -0,0 +1,40 @@ +package com.docusign.controller.connect.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.connect.services.ValidateUsingHmacService; +import com.docusign.core.model.DoneExample; +import com.docusign.esign.client.ApiException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +@Controller +@RequestMapping("/con001") +public class EG001ControllerValidateUsingHMAC extends AbstractConnectController { + + public EG001ControllerValidateUsingHMAC(DSConfiguration config) { + super(config, "con001"); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException, IOException, NoSuchAlgorithmException, InvalidKeyException { + String hashedOutput = new ValidateUsingHmacService().computeHash( + args.getHmacSecret(), + args.getJsonPayload().getBytes() + ); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", hashedOutput) + ) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/connect/services/ValidateUsingHmacService.java b/src/main/java/com/docusign/controller/connect/services/ValidateUsingHmacService.java new file mode 100644 index 00000000..931b9988 --- /dev/null +++ b/src/main/java/com/docusign/controller/connect/services/ValidateUsingHmacService.java @@ -0,0 +1,26 @@ +package com.docusign.controller.connect.services; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.UnsupportedEncodingException; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +public final class ValidateUsingHmacService { + public static String computeHash(String secret, byte[] payload) + throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException { + String digest = "HmacSHA256"; + Mac mac = Mac.getInstance(digest); + mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), digest)); + return Base64.getEncoder().encodeToString(mac.doFinal(payload)); + } + + public static boolean isValid(String secret, byte[] payload, String verify) + throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException { + String computedHash = computeHash(secret, payload); + return MessageDigest.isEqual(computedHash.getBytes("UTF-8"), + verify.getBytes("UTF-8")); + } +} diff --git a/src/main/java/com/docusign/controller/connectedFields/examples/AbstractConnectedFieldsController.java b/src/main/java/com/docusign/controller/connectedFields/examples/AbstractConnectedFieldsController.java new file mode 100644 index 00000000..b56915f9 --- /dev/null +++ b/src/main/java/com/docusign/controller/connectedFields/examples/AbstractConnectedFieldsController.java @@ -0,0 +1,66 @@ +package com.docusign.controller.connectedFields.examples; + +import com.docusign.DSConfiguration; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.core.controller.AbstractController; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Controller; + +/** + * Abstract base class for all Connected fields controllers. + */ +@Controller +public abstract class AbstractConnectedFieldsController extends AbstractController { + + private static final String EXAMPLE_PAGES_PATH = "pages/connectedfields/examples/"; + + protected final User user; + + protected final Session session; + + public AbstractConnectedFieldsController(DSConfiguration config, String exampleName, User user, Session session) { + super(config, exampleName); + this.user = user; + this.session = session; + } + + /** + * Creates new instance of the eSignature API client. + * + * @param accessToken user's access token + * @param basePath basePath to the server + * @return an instance of the {@link ApiClient} + */ + protected static ApiClient createApiClient( + String accessToken, + String basePath) { + //ds-snippet-start:ConnectedFields1Step2 + ApiClient apiClient = new ApiClient(basePath); + apiClient.addDefaultHeader( + HttpHeaders.AUTHORIZATION, + BEARER_AUTHENTICATION + accessToken); + //ds-snippet-end:ConnectedFields1Step2 + + return apiClient; + } + + /** + * Creates a new instance of the EnvelopesApi. This method + * creates an instance of the EnvelopesApi class silently. + * + * @param accessToken user's access token + * @param basePath basePath to the server + * @return an instance of the {@link EnvelopesApi} + */ + protected EnvelopesApi createEnvelopesApi(String basePath, String userAccessToken) { + ApiClient apiClient = createApiClient(userAccessToken, basePath); + return new EnvelopesApi(apiClient); + } + + protected String getExamplePagesPath() { + return AbstractConnectedFieldsController.EXAMPLE_PAGES_PATH; + } +} diff --git a/src/main/java/com/docusign/controller/connectedFields/examples/CF001SetConnectedFields.java b/src/main/java/com/docusign/controller/connectedFields/examples/CF001SetConnectedFields.java new file mode 100644 index 00000000..1968c673 --- /dev/null +++ b/src/main/java/com/docusign/controller/connectedFields/examples/CF001SetConnectedFields.java @@ -0,0 +1,80 @@ +package com.docusign.controller.connectedFields.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.client.ApiException; +import com.docusign.common.WorkArguments; +import com.docusign.controller.connectedFields.services.SetConnectedFieldsService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletResponse; + +/** + * This example demonstrates how to set connected fields from extension. + */ +@Controller +@RequestMapping("/cf001") +public class CF001SetConnectedFields extends AbstractConnectedFieldsController { + + private static final Logger LOGGER = LoggerFactory.getLogger(CF001SetConnectedFields.class); + + private static final String MODEL_APPS_LIST = "appsList"; + + public CF001SetConnectedFields(DSConfiguration config, Session session, User user) { + super(config, "cf001", user, session); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + + try { + super.onInitModel(args, model); + + var extensionApps = SetConnectedFieldsService.getConnectedFieldsTabGroups( + session.getAccountId(), + user.getAccessToken()); + + var filteredExtensionApps = SetConnectedFieldsService.filterData(extensionApps); + + this.session.setExtensionApps(filteredExtensionApps); + model.addAttribute(MODEL_APPS_LIST, filteredExtensionApps); + } catch (ApiException e) { + LOGGER.info(String.valueOf(e)); + } + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + + var extensionApp = SetConnectedFieldsService.findAppById( + this.session.getExtensionApps(), + args.getAppId()); + //ds-snippet-start:ConnectedFields1Step6 + EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); + + EnvelopeDefinition envelope = SetConnectedFieldsService.makeEnvelope( + args.getSignerEmail(), + args.getSignerName(), + extensionApp); + EnvelopeSummary envelopeSummary = SetConnectedFieldsService.signingViaEmail( + envelopesApi, + session.getAccountId(), + envelope); + //ds-snippet-end:ConnectedFields1Step6 + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", envelopeSummary.getEnvelopeId())) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/connectedFields/services/SetConnectedFieldsService.java b/src/main/java/com/docusign/controller/connectedFields/services/SetConnectedFieldsService.java new file mode 100644 index 00000000..c0032ae3 --- /dev/null +++ b/src/main/java/com/docusign/controller/connectedFields/services/SetConnectedFieldsService.java @@ -0,0 +1,184 @@ +package com.docusign.controller.connectedFields.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.ConnectionInstance; +import com.docusign.esign.model.Document; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import com.docusign.esign.model.ExtensionData; +import com.docusign.esign.model.Recipients; +import com.docusign.esign.model.SignHere; +import com.docusign.esign.model.Signer; +import com.docusign.esign.model.Tabs; +import com.docusign.esign.model.Text; +import com.docusign.iam.sdk.IamClient; +import com.docusign.iam.sdk.models.components.TabInfo; +import com.docusign.iam.sdk.models.operations.ConnectedFieldsApiGetTabGroupsResponse; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class SetConnectedFieldsService { + + private static final String PDF_DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String PDF_DOCUMENT_NAME = "Lorem Ipsum"; + + public static EnvelopeSummary signingViaEmail( + EnvelopesApi envelopesApi, + String accountId, + EnvelopeDefinition envelope) throws ApiException { + return envelopesApi.createEnvelope(accountId, envelope); + } + + //ds-snippet-start:ConnectedFields1Step3 + public static ConnectedFieldsApiGetTabGroupsResponse getConnectedFieldsTabGroups(String accountId, + String accessToken) throws Exception { + return IamClient.builder() + .accessToken(accessToken) + .build() + .connectedFields() + .tabInfo() + .getConnectedFieldsTabGroups() + .accountId(accountId) + .call(); + } + //ds-snippet-end:ConnectedFields1Step3 + + //ds-snippet-start:ConnectedFields1Step5 + public static EnvelopeDefinition makeEnvelope(String signerEmail, String signerName, TabInfo selectedApp) + throws Exception { + String appId = selectedApp.appId(); + var tabLabels = selectedApp.tabs(); + + EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition(); + envelopeDefinition.setEmailSubject("Please sign this document set"); + envelopeDefinition.setStatus("sent"); + + Document document = EnvelopeHelpers.createDocumentFromFile( + PDF_DOCUMENT_FILE_NAME, + PDF_DOCUMENT_NAME, + "1"); + envelopeDefinition.setDocuments(Collections.singletonList(document)); + + Signer signer = new Signer(); + signer.setEmail(signerEmail); + signer.setName(signerName); + signer.setRecipientId("1"); + signer.setRoutingOrder("1"); + + SignHere signHere = new SignHere(); + signHere.setAnchorString("/sn1/"); + signHere.setAnchorUnits("pixels"); + signHere.setAnchorYOffset("10"); + signHere.setAnchorXOffset("20"); + + List textTabs = new ArrayList<>(); + + if (tabLabels != null) { + for (var tab : tabLabels) { + var extensionData = tab.extensionData(); + + String connectionKey = ""; + String connectionValue = ""; + + var connectionInstances = extensionData.connectionInstances(); + if (connectionInstances.isPresent() && !connectionInstances.get().isEmpty()) { + var firstInstance = connectionInstances.get().get(0); + connectionKey = firstInstance.connectionKey(); + connectionValue = firstInstance.connectionValue(); + } + + Text textTab = new Text(); + textTab.setRequireInitialOnSharedChange("false"); + textTab.setRequireAll("false"); + textTab.setName(extensionData.applicationName().orElse("App")); + textTab.setRequired("false"); + textTab.setLocked("false"); + textTab.setDisableAutoSize("false"); + textTab.setMaxLength("4000"); + textTab.setTabLabel(tab.tabLabel()); + textTab.setFont("lucidaconsole"); + textTab.setFontColor("black"); + textTab.setFontSize("size9"); + textTab.setDocumentId("1"); + textTab.setRecipientId("1"); + textTab.setPageNumber("1"); + textTab.setXPosition("273"); + textTab.setYPosition("191"); + textTab.setWidth("84"); + textTab.setHeight("22"); + textTab.setTemplateRequired("false"); + textTab.setTabType("text"); + + ExtensionData extension = new ExtensionData(); + extension.setExtensionGroupId(extensionData.extensionGroupId()); + extension.setPublisherName(extensionData.publisherName().orElse(null)); + extension.setApplicationId(appId); + extension.setApplicationName(extensionData.applicationName().orElse(null)); + extension.setActionName(extensionData.actionName().orElse(null)); + extension.setActionContract(extensionData.actionContract().orElse(null)); + extension.setExtensionName(extensionData.applicationName().orElse(null)); + extension.setExtensionContract(extensionData.extensionContract().orElse(null)); + extension.setRequiredForExtension(String.valueOf(extensionData.requiredForExtension())); + extension.setActionInputKey(extensionData.actionInputKey()); + extension.setExtensionPolicy("None"); + + ConnectionInstance connectionInstance = new ConnectionInstance(); + connectionInstance.setConnectionKey(connectionKey); + connectionInstance.setConnectionValue(connectionValue); + extension.setConnectionInstances(Collections.singletonList(connectionInstance)); + + textTab.setExtensionData(extension); + textTabs.add(textTab); + } + } + + Tabs tabs = new Tabs(); + tabs.setSignHereTabs(Collections.singletonList(signHere)); + tabs.setTextTabs(textTabs); + signer.setTabs(tabs); + + Recipients recipients = new Recipients(); + recipients.setSigners(Collections.singletonList(signer)); + envelopeDefinition.setRecipients(recipients); + + return envelopeDefinition; + } + //ds-snippet-end:ConnectedFields1Step5 + + //ds-snippet-start:ConnectedFields1Step4 + public static List filterData(ConnectedFieldsApiGetTabGroupsResponse connectedFields) { + List filteredList = new ArrayList<>(); + + for (var tabInfoGroup : connectedFields.tabInfos().orElse(List.of())) { + for (var tab : tabInfoGroup.tabs()) { + var extensionData = tab.extensionData(); + String tabLabel = tab.tabLabel(); + + boolean hasVerify = extensionData != null && + extensionData.actionContract().isPresent() && + extensionData.actionContract().get().contains("Verify"); + + boolean hasConnectedData = tabLabel != null && tabLabel.contains("connecteddata"); + + if (hasVerify || hasConnectedData) { + filteredList.add(tabInfoGroup); + break; + } + } + } + + return filteredList; + } + + public static TabInfo findAppById(List extensionApps, String appId) { + return extensionApps.stream() + .filter(app -> appId.equals(app.appId())) + .findFirst() + .orElse(null); + } + //ds-snippet-end:ConnectedFields1Step4 +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/AbstractEsignatureController.java b/src/main/java/com/docusign/controller/eSignature/examples/AbstractEsignatureController.java new file mode 100644 index 00000000..7a1b4079 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/AbstractEsignatureController.java @@ -0,0 +1,150 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.core.controller.AbstractController; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.api.TemplatesApi; +import com.docusign.esign.api.UsersApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.client.auth.OAuth; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Controller; + + +/** + * Abstract base class for all eSignature controllers. + */ +@Controller +public abstract class AbstractEsignatureController extends AbstractController { + + protected static final String MODEL_ENVELOPE_OK = "envelopeOk"; + + protected static final String MODEL_TEMPLATE_OK = "templateOk"; + + private static final String EXAMPLE_PAGES_PATH = "pages/esignature/examples/"; + + protected final Session session; + + protected final User user; + + public AbstractEsignatureController(DSConfiguration config, String exampleName, Session session, User user) { + super(config, exampleName); + this.session = session; + this.user = user; + } + + protected String getExamplePagesPath() { + return AbstractEsignatureController.EXAMPLE_PAGES_PATH; + } + + /** + * Creates new instance of the eSignature API client. + * + * @param basePath URL to eSignature REST API + * @param userAccessToken user's access token + * @return an instance of the {@link ApiClient} + */ + protected ApiClient createApiClient(String basePath, String userAccessToken) { + //ds-snippet-start:eSignJavaStep2 + ApiClient apiClient = new ApiClient(basePath); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + userAccessToken); + //ds-snippet-end:eSignJavaStep2 + return apiClient; + } + + /** + * Gets the information about the currently logged user. + * + * @param basePath URL to eSignature REST API + * @param userAccessToken user's access token + * @return an instance of the {@link OAuth.UserInfo} + */ + protected OAuth.UserInfo getCurrentUserInfo(String basePath, String userAccessToken) throws ApiException { + ApiClient apiClient = createApiClient(basePath, userAccessToken); + return apiClient.getUserInfo(userAccessToken); + } + + /** + * Creates a new instance of the eSignature EnvelopesApi. This method + * creates an instance of the ApiClient class silently. + * + * @param basePath URL to eSignature REST API + * @param userAccessToken user's access token + * @return an instance of the {@link EnvelopesApi} + */ + protected EnvelopesApi createEnvelopesApi(String basePath, String userAccessToken) { + ApiClient apiClient = createApiClient(basePath, userAccessToken); + return new EnvelopesApi(apiClient); + } + + /** + * Creates a new instance of the eSignature UsersApi. This method + * creates an instance of the ApiClient class silently. + * + * @param basePath URL to eSignature REST API + * @param userAccessToken user's access token + * @return an instance of the {@link UsersApi} + */ + protected UsersApi createUsersApi(String basePath, String userAccessToken) { + ApiClient apiClient = createApiClient(basePath, userAccessToken); + return new UsersApi(apiClient); + } + + /** + * Creates a new instance of the eSignature TemplatesApi. This method + * creates an instance of the ApiClient class silently. + * + * @param basePath URL to eSignature REST API + * @param userAccessToken user's access token + * @return an instance of the {@link TemplatesApi} + */ + protected TemplatesApi createTemplatesApi(String basePath, String userAccessToken) { + ApiClient apiClient = createApiClient(basePath, userAccessToken); + return new TemplatesApi(apiClient); + } + + /** + * Creates a new instance of the eSignature AccountsApi. This method + * creates an instance of the ApiClient class silently. + * + * @param basePath URL to eSignature REST API + * @param userAccessToken user's access token + * @return an instance of the {@link AccountsApi} + */ + protected AccountsApi createAccountsApi(String basePath, String userAccessToken) { + ApiClient apiClient = createApiClient(basePath, userAccessToken); + return new AccountsApi(apiClient); + } + + /** + * Get the email address of the authenticated user + * + * @param basePath URL to eSignature REST API + * @param userAccessToken user's access token + * @return users email address + */ + protected String getAuthenticatedUserEmail(String basePath, String userAccessToken) throws ApiException { + ApiClient apiClient = createApiClient(basePath, userAccessToken); + OAuth.UserInfo userInfo = apiClient.getUserInfo(userAccessToken); + + return userInfo.getEmail(); + } + + /** + * Get the name of the authenticated user + * + * @param basePath URL to eSignature REST API + * @param userAccessToken user's access token + * @return users email address + */ + protected String getAuthenticatedUserName(String basePath, String userAccessToken) throws ApiException { + ApiClient apiClient = createApiClient(basePath, userAccessToken); + OAuth.UserInfo userInfo = apiClient.getUserInfo(userAccessToken); + + return userInfo.getName(); + } +} diff --git a/src/main/java/com/docusign/controller/examples/DsModelUtils.java b/src/main/java/com/docusign/controller/eSignature/examples/DsModelUtils.java similarity index 96% rename from src/main/java/com/docusign/controller/examples/DsModelUtils.java rename to src/main/java/com/docusign/controller/eSignature/examples/DsModelUtils.java index e7a0921a..fb241007 100644 --- a/src/main/java/com/docusign/controller/examples/DsModelUtils.java +++ b/src/main/java/com/docusign/controller/eSignature/examples/DsModelUtils.java @@ -1,4 +1,4 @@ -package com.docusign.controller.examples; +package com.docusign.controller.eSignature.examples; import com.docusign.esign.model.AccountRoleSettings; import com.docusign.esign.model.SettingsMetadata; @@ -10,14 +10,17 @@ public final class DsModelUtils { public static final String FALSE = "false"; + public static final String TRUE = "true"; - private DsModelUtils() {} + private DsModelUtils() { + } /** * Creates {@link AccountRoleSettings} with default values. Now eSignature * API has an error. It requires a member 'signingUiVersion' but this class * doesn't contain such member. + * * @return a new AccountRoleSettings object */ public static AccountRoleSettings createDefaultRoleSettings() { diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG002ControllerSigningViaEmail.java b/src/main/java/com/docusign/controller/eSignature/examples/EG002ControllerSigningViaEmail.java new file mode 100644 index 00000000..2fd025dd --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG002ControllerSigningViaEmail.java @@ -0,0 +1,67 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.SigningViaEmailService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +/** + * Send an envelope with a remote (email) signer and cc recipient.
+ * The envelope includes a pdf, Word, and HTML document. Anchor text is used to + * position the signing fields in the documents. + */ +@Controller +@RequestMapping("/eg002") +public class EG002ControllerSigningViaEmail extends AbstractEsignatureController { + + public EG002ControllerSigningViaEmail(DSConfiguration config, Session session, User user) { + super(config, "eg002", session, user); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException, IOException { + // Set status for the makeEnvelope method + if (!EnvelopeHelpers.ENVELOPE_STATUS_CREATED.equalsIgnoreCase(args.getStatus())) { + args.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + } + + EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); + + EnvelopeDefinition envelope = SigningViaEmailService.makeEnvelope( + args.getSignerEmail(), + args.getSignerName(), + args.getCcEmail(), + args.getCcName(), + args.getStatus(), + args + ); + EnvelopeSummary envelopeSummary = SigningViaEmailService.signingViaEmail( + envelopesApi, + session.getAccountId(), + envelope); + + // process results + session.setEnvelopeId(envelopeSummary.getEnvelopeId()); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", envelopeSummary.getEnvelopeId()) + ) + .withJsonObject(envelopeSummary) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG003ControllerListEnvelopes.java b/src/main/java/com/docusign/controller/eSignature/examples/EG003ControllerListEnvelopes.java new file mode 100644 index 00000000..6a13d084 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG003ControllerListEnvelopes.java @@ -0,0 +1,47 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.ListEnvelopesServices; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopesInformation; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + + +/** + * List envelopes in the user's account.
+ * List the envelopes created in the last 30 days. This example demonstrates + * how to query DocuSign about envelopes sent by the current user. + */ +@Controller +@RequestMapping("/eg003") +public class EG003ControllerListEnvelopes extends AbstractEsignatureController { + + public EG003ControllerListEnvelopes(DSConfiguration config, Session session, User user) { + super(config, "eg003", session, user); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException { + //ds-snippet-start:eSign3Step2 + EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); + EnvelopesInformation envelopesInformation = ListEnvelopesServices.listEnvelopes( + envelopesApi, + session.getAccountId()); + //ds-snippet-end:eSign3Step2 + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(envelopesInformation) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/examples/EG004ControllerEnvelopeInfo.java b/src/main/java/com/docusign/controller/eSignature/examples/EG004ControllerEnvelopeInfo.java similarity index 64% rename from src/main/java/com/docusign/controller/examples/EG004ControllerEnvelopeInfo.java rename to src/main/java/com/docusign/controller/eSignature/examples/EG004ControllerEnvelopeInfo.java index 9d6e90b0..f4871d42 100644 --- a/src/main/java/com/docusign/controller/examples/EG004ControllerEnvelopeInfo.java +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG004ControllerEnvelopeInfo.java @@ -1,20 +1,21 @@ -package com.docusign.controller.examples; +package com.docusign.controller.eSignature.examples; import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.EnvelopeInfoService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; import com.docusign.esign.api.EnvelopesApi; import com.docusign.esign.client.ApiException; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; - -import javax.servlet.http.HttpServletResponse; - +import com.docusign.esign.model.Envelope; import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; +import javax.servlet.http.HttpServletResponse; + /** * Get an envelope's basic information and status.
@@ -27,21 +28,14 @@ */ @Controller @RequestMapping("/eg004") -public class EG004ControllerEnvelopeInfo extends AbstractController { - - private final Session session; - private final User user; - +public class EG004ControllerEnvelopeInfo extends AbstractEsignatureController { - @Autowired public EG004ControllerEnvelopeInfo(DSConfiguration config, Session session, User user) { - super(config, "eg004", "Get envelope information"); - this.session = session; - this.user = user; + super(config, "eg004", session, user); } @Override - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { super.onInitModel(args, model); model.addAttribute(MODEL_ENVELOPE_OK, StringUtils.isNotBlank(session.getEnvelopeId())); } @@ -51,10 +45,14 @@ protected void onInitModel(WorkArguments args, ModelMap model) throws ApiExcepti protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException { // Step 1. get envelope info EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); - DoneExample.createDefault(title) - .withJsonObject(envelopesApi.getEnvelope(session.getAccountId(), session.getEnvelopeId())) - .withMessage("Results from the Envelopes::get method:") - .addToModel(model); + Envelope envelope = EnvelopeInfoService.envelopeInfo( + envelopesApi, + session.getAccountId(), + session.getEnvelopeId()); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withJsonObject(envelope) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .addToModel(model, config); return DONE_EXAMPLE_PAGE; } // ***DS.snippet.0.end diff --git a/src/main/java/com/docusign/controller/examples/EG005ControllerEnvelopeRecipients.java b/src/main/java/com/docusign/controller/eSignature/examples/EG005ControllerEnvelopeRecipients.java similarity index 52% rename from src/main/java/com/docusign/controller/examples/EG005ControllerEnvelopeRecipients.java rename to src/main/java/com/docusign/controller/eSignature/examples/EG005ControllerEnvelopeRecipients.java index ba10749f..0e22ec6e 100644 --- a/src/main/java/com/docusign/controller/examples/EG005ControllerEnvelopeRecipients.java +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG005ControllerEnvelopeRecipients.java @@ -1,20 +1,21 @@ -package com.docusign.controller.examples; +package com.docusign.controller.eSignature.examples; import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.EnvelopeRecipientsService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; import com.docusign.esign.api.EnvelopesApi; import com.docusign.esign.client.ApiException; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; - -import javax.servlet.http.HttpServletResponse; - +import com.docusign.esign.model.Recipients; import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; +import javax.servlet.http.HttpServletResponse; + /** * List an envelope's recipients and their status.
@@ -22,35 +23,32 @@ */ @Controller @RequestMapping("/eg005") -public class EG005ControllerEnvelopeRecipients extends AbstractController { - - private final Session session; - private final User user; - +public class EG005ControllerEnvelopeRecipients extends AbstractEsignatureController { - @Autowired public EG005ControllerEnvelopeRecipients(DSConfiguration config, Session session, User user) { - super(config, "eg005", "List envelope recipients"); - this.session = session; - this.user = user; + super(config, "eg005", session, user); } @Override - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { super.onInitModel(args, model); model.addAttribute(MODEL_ENVELOPE_OK, StringUtils.isNotBlank(session.getEnvelopeId())); } @Override - // ***DS.snippet.0.start protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException { - // Step 1. get envelope recipients + // Get envelope recipients + //ds-snippet-start:eSign5Step2 EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); - DoneExample.createDefault(title) - .withJsonObject(envelopesApi.listRecipients(session.getAccountId(), session.getEnvelopeId())) - .withMessage("Results from the EnvelopeRecipients::list method:") - .addToModel(model); + Recipients recipients = EnvelopeRecipientsService.envelopeRecipients( + envelopesApi, + session.getAccountId(), + session.getEnvelopeId()); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withJsonObject(recipients) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .addToModel(model, config); return DONE_EXAMPLE_PAGE; + //ds-snippet-end:eSign5Step2 } - // ***DS.snippet.0.end } diff --git a/src/main/java/com/docusign/controller/examples/EG006ControllerEnvelopeDocs.java b/src/main/java/com/docusign/controller/eSignature/examples/EG006ControllerEnvelopeDocs.java similarity index 65% rename from src/main/java/com/docusign/controller/examples/EG006ControllerEnvelopeDocs.java rename to src/main/java/com/docusign/controller/eSignature/examples/EG006ControllerEnvelopeDocs.java index 3ffd3367..ea4479fa 100644 --- a/src/main/java/com/docusign/controller/examples/EG006ControllerEnvelopeDocs.java +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG006ControllerEnvelopeDocs.java @@ -1,26 +1,25 @@ -package com.docusign.controller.examples; +package com.docusign.controller.eSignature.examples; import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.EnvelopeDocsService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.EnvelopeDocumentInfo; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; import com.docusign.esign.api.EnvelopesApi; import com.docusign.esign.client.ApiException; import com.docusign.esign.model.EnvelopeDocument; import com.docusign.esign.model.EnvelopeDocumentsResult; -import com.docusign.model.DoneExample; -import com.docusign.model.EnvelopeDocumentInfo; -import com.docusign.model.Session; -import com.docusign.model.User; - -import java.util.ArrayList; -import java.util.List; - -import javax.servlet.http.HttpServletResponse; - import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; + /** * List an envelope's documents.
@@ -31,20 +30,14 @@ */ @Controller @RequestMapping("/eg006") -public class EG006ControllerEnvelopeDocs extends AbstractController { - - private final Session session; - private final User user; +public class EG006ControllerEnvelopeDocs extends AbstractEsignatureController { - @Autowired public EG006ControllerEnvelopeDocs(DSConfiguration config, Session session, User user) { - super(config, "eg006", "List envelope documents"); - this.session = session; - this.user = user; + super(config, "eg006", session, user); } @Override - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { super.onInitModel(args, model); model.addAttribute(MODEL_ENVELOPE_OK, StringUtils.isNotBlank(session.getEnvelopeId())); } @@ -54,10 +47,15 @@ protected void onInitModel(WorkArguments args, ModelMap model) throws ApiExcepti protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException { EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); - // Step 1. List the envelope's documents - EnvelopeDocumentsResult result = envelopesApi.listDocuments(session.getAccountId(), session.getEnvelopeId()); - - // Step 2. Process results + // List the envelope's documents + //ds-snippet-start:eSign6Step3 + EnvelopeDocumentsResult envelopeDocumentsResult = EnvelopeDocsService.envelopeDocs( + envelopesApi, + session.getAccountId(), + session.getEnvelopeId()); + //ds-snippet-end:eSign6Step3 + + // Process results // Save the envelopeId and its list of documents in the session so // they can be used in example 7 (download a document) List envelopeDocItems = new ArrayList<>(); @@ -65,7 +63,7 @@ protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse envelopeDocItems.add(new EnvelopeDocumentInfo("Combined", "content", "combined")); envelopeDocItems.add(new EnvelopeDocumentInfo("Zip archive", "zip", "archive")); - for (EnvelopeDocument doc : result.getEnvelopeDocuments()) { + for (EnvelopeDocument doc : envelopeDocumentsResult.getEnvelopeDocuments()) { String documentName = doc.getName(); if (StringUtils.equals(doc.getDocumentId(), "certificate")) { documentName = "Certificate of completion"; @@ -73,10 +71,10 @@ protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse envelopeDocItems.add(new EnvelopeDocumentInfo(documentName, doc.getType(), doc.getDocumentId())); } - DoneExample.createDefault(title) - .withJsonObject(result) - .withMessage("Results from the EnvelopeDocuments::list method:") - .addToModel(model); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withJsonObject(envelopeDocumentsResult) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .addToModel(model, config); return DONE_EXAMPLE_PAGE; } // ***DS.snippet.0.end diff --git a/src/main/java/com/docusign/controller/examples/EG007ControllerEnvelopeGetDoc.java b/src/main/java/com/docusign/controller/eSignature/examples/EG007ControllerEnvelopeGetDoc.java similarity index 60% rename from src/main/java/com/docusign/controller/examples/EG007ControllerEnvelopeGetDoc.java rename to src/main/java/com/docusign/controller/eSignature/examples/EG007ControllerEnvelopeGetDoc.java index f04d7ebf..6496a503 100644 --- a/src/main/java/com/docusign/controller/examples/EG007ControllerEnvelopeGetDoc.java +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG007ControllerEnvelopeGetDoc.java @@ -1,29 +1,27 @@ -package com.docusign.controller.examples; +package com.docusign.controller.eSignature.examples; import com.docusign.DSConfiguration; -import com.docusign.common.DocumentType; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.EnvelopeGetDocService; +import com.docusign.core.common.DocumentType; +import com.docusign.core.model.EnvelopeDocumentInfo; +import com.docusign.core.model.OptionItem; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; import com.docusign.esign.api.EnvelopesApi; import com.docusign.esign.client.ApiException; -import com.docusign.model.EnvelopeDocumentInfo; -import com.docusign.model.OptionItem; -import com.docusign.model.Session; -import com.docusign.model.User; - -import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; +import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URLConnection; import java.util.ArrayList; import java.util.List; -import javax.servlet.http.HttpServletResponse; - /** * Download a document from an envelope.
@@ -31,26 +29,31 @@ */ @Controller @RequestMapping("/eg007") -public class EG007ControllerEnvelopeGetDoc extends AbstractController { +public class EG007ControllerEnvelopeGetDoc extends AbstractEsignatureController { private static final String MODEL_DOCUMENTS_OK = "documentsOk"; + private static final String MODEL_DOCUMENT_OPTIONS = "documentOptions"; - private static final String HTTP_CONTENT_DISPOSITION_VALUE = "inline;filename="; - private static final String ZIP_EXTENSION = "zip"; - private final Session session; - private final User user; + private static final String HTTP_CONTENT_DISPOSITION_VALUE = "inline;filename="; + private static final String ZIP_EXTENSION = "zip"; - @Autowired public EG007ControllerEnvelopeGetDoc(DSConfiguration config, Session session, User user) { - super(config, "eg007", "Download a document"); - this.session = session; - this.user = user; + super(config, "eg007", session, user); + } + + private EnvelopeDocumentInfo find(List documents, String documentId) { + for (EnvelopeDocumentInfo docInfo : documents) { + if (StringUtils.equalsIgnoreCase(docInfo.getDocumentId(), documentId)) { + return docInfo; + } + } + throw new ExampleException("Requested document is not found.", null); } @Override - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { super.onInitModel(args, model); model.addAttribute(MODEL_ENVELOPE_OK, StringUtils.isNotBlank(session.getEnvelopeId())); List envelopeDocuments = session.getEnvelopeDocuments(); @@ -60,63 +63,72 @@ protected void onInitModel(WorkArguments args, ModelMap model) throws ApiExcepti return; } + boolean foundPdfp = false; ArrayList documentOptions = new ArrayList<>(); for (EnvelopeDocumentInfo docInfo : envelopeDocuments) { + if (docInfo.getName() == "PDF Portfolio") { + foundPdfp = true; + } OptionItem doc = new OptionItem(docInfo.getName(), docInfo.getDocumentId()); documentOptions.add(doc); } + if (!foundPdfp) { + OptionItem pdfp = new OptionItem("PDF Portfolio", "portfolio"); + documentOptions.add(pdfp); + } model.addAttribute(MODEL_DOCUMENT_OPTIONS, documentOptions); } @Override - // ***DS.snippet.0.start protected Object doWork(WorkArguments args, ModelMap model, - HttpServletResponse response) throws ApiException, IOException { + HttpServletResponse response) throws ApiException, IOException { + // Step 2 start EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); + // Step 2 end - // Step 1. EnvelopeDocuments::get. + // EnvelopeDocuments::get. // Exceptions will be caught by the calling function String documentId = args.getDocSelect(); - byte[] results = envelopesApi.getDocument(session.getAccountId(), session.getEnvelopeId(), documentId); - - // Step 2. process results + // Step 3 start + byte[] envelopeDocument = EnvelopeGetDocService.envelopeGetDoc( + envelopesApi, + session.getAccountId(), + session.getEnvelopeId(), + documentId); + // Step 3 end + + // Process results List envelopeDocuments = session.getEnvelopeDocuments(); + boolean foundPdfp = false; + for (EnvelopeDocumentInfo envDoc : envelopeDocuments) { + if (envDoc.getName() == "PDF Portfolio") { + foundPdfp = true; + break; + } + } + + if (!foundPdfp) { + EnvelopeDocumentInfo pdfp = new EnvelopeDocumentInfo("PDF Portfolio", "content", "portfolio"); + envelopeDocuments.add(pdfp); + } EnvelopeDocumentInfo docItem = find(envelopeDocuments, documentId); String docName = docItem.getName(); String docType = docItem.getType(); String pdfExtention = DocumentType.PDF.getDefaultFileExtention(); if (StringUtils.equalsAny(docType, "content", "summary", pdfExtention)) { - docName = addExtension(docName, pdfExtention); + docName = EnvelopeGetDocService.addExtension(docName, pdfExtention); } if (ZIP_EXTENSION.equals(docType)) { - docName = addExtension(docName, ZIP_EXTENSION); + docName = EnvelopeGetDocService.addExtension(docName, ZIP_EXTENSION); } response.setContentType(URLConnection.guessContentTypeFromName(docName)); - response.setContentLength(results.length); + response.setContentLength(envelopeDocument.length); response.setHeader(HttpHeaders.CONTENT_DISPOSITION, HTTP_CONTENT_DISPOSITION_VALUE + docName); - response.getOutputStream().write(results); + response.getOutputStream().write(envelopeDocument); response.flushBuffer(); return null; } - - private static String addExtension(String fileName, String extension) { - if (FilenameUtils.isExtension(fileName, extension)) { - return fileName; - } - return String.join(".", fileName, extension); - } - - private static EnvelopeDocumentInfo find(List documents, String documentId) { - for (EnvelopeDocumentInfo docInfo : documents) { - if (StringUtils.equalsIgnoreCase(docInfo.getDocumentId(), documentId)) { - return docInfo; - } - } - - throw new ExampleException("Requested document is not found.", null); - } - // ***DS.snippet.0.end } diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG008ControllerCreateTemplate.java b/src/main/java/com/docusign/controller/eSignature/examples/EG008ControllerCreateTemplate.java new file mode 100644 index 00000000..c347458c --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG008ControllerCreateTemplate.java @@ -0,0 +1,74 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.CreateTemplateService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeTemplate; +import com.docusign.esign.model.EnvelopeTemplateResults; +import com.docusign.esign.model.TemplateSummary; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +/** + * Create a template.
+ * Create a template with two roles, signer and cc. The template + * includes three documents. + */ +@Controller +@RequestMapping("/eg008") +public class EG008ControllerCreateTemplate extends AbstractEsignatureController { + + private static final String TEMPLATE_NAME = "Example Signer and CC template"; + + public EG008ControllerCreateTemplate(DSConfiguration config, Session session, User user) { + super(config, "eg008", session, user); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException, IOException { + // Step 1. list existing templates + ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); + String accountId = session.getAccountId(); + EnvelopeTemplateResults envelopeTemplateResults = CreateTemplateService.searchTemplatesByName( + apiClient, + accountId, + TEMPLATE_NAME); + + // Step 2. Process results. If template do not exist, create one + + if (Integer.parseInt(envelopeTemplateResults.getResultSetSize()) > 0) { + EnvelopeTemplate template = envelopeTemplateResults.getEnvelopeTemplates().get(0); + session.setTemplateId(template.getTemplateId()); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage( + "The template already exists in your account." + getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", template.getName()).replaceFirst("\\{1}", template.getTemplateId())) + .addToModel(model, config); + } else { + session.setTemplateName(TEMPLATE_NAME); + + //ds-snippet-start:eSign8Step3 + TemplateSummary template = CreateTemplateService.createTemplate(apiClient, accountId, CreateTemplateService.makeTemplate("Example Signer and CC template")); + //ds-snippet-end:eSign8Step3 + session.setTemplateId(template.getTemplateId()); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage( + "The template has been created!" + getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", template.getName()).replaceFirst("\\{1}", template.getTemplateId())) + .addToModel(model, config); + } + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG009ControllerUseTemplate.java b/src/main/java/com/docusign/controller/eSignature/examples/EG009ControllerUseTemplate.java new file mode 100644 index 00000000..a2d7b834 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG009ControllerUseTemplate.java @@ -0,0 +1,75 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.UseTemplateService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import com.docusign.esign.model.EnvelopeTemplateResults; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + + +/** + * Send an envelope using a template.
+ * The envelope is defined by the template. The signer and cc recipient name + * and email are used to fill in the template's roles. This example + * demonstrates a common pattern for DocuSign integrations: envelopes will be + * sent programmatically, based on a template. If the template definition needs + * to be updated, the DocuSign web tool can be used to easily update the + * template, thus avoiding the need to make software changes. + */ +@Controller +@RequestMapping("/eg009") +public class EG009ControllerUseTemplate extends AbstractEsignatureController { + + private static final String MODEL_LIST_TEMPLATE = "listTemplates"; + + public EG009ControllerUseTemplate(DSConfiguration config, Session session, User user) { + super(config, "eg009", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); + EnvelopeTemplateResults templates = UseTemplateService.listTemplates(apiClient, session.getAccountId()); + model.addAttribute(MODEL_LIST_TEMPLATE, templates.getEnvelopeTemplates()); + } + + @Override + // ***DS.snippet.0.start + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException { + EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); + EnvelopeDefinition envelope = UseTemplateService.makeEnvelope( + args.getSignerName(), + args.getSignerEmail(), + args.getCcEmail(), + args.getCcName(), + args.getTemplateId() + ); + EnvelopeSummary envelopeSummary = UseTemplateService.createEnvelopeTemplate( + envelopesApi, + session.getAccountId(), + envelope); + + session.setEnvelopeId(envelopeSummary.getEnvelopeId()); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withJsonObject(envelopeSummary) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", envelopeSummary.getEnvelopeId()) + ) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + // ***DS.snippet.0.end +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG010ControllerSendBinaryDocs.java b/src/main/java/com/docusign/controller/eSignature/examples/EG010ControllerSendBinaryDocs.java new file mode 100644 index 00000000..8cad64b1 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG010ControllerSendBinaryDocs.java @@ -0,0 +1,54 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.SendBinaryDocsService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.json.JSONObject; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +/** + * Send an envelope using binary document transfer.
+ * The envelope includes a pdf, doc, and HTML document. Multipart data transfer + * is used to send the documents in binary format to DocuSign. + */ +@Controller +@RequestMapping("/eg010") +public class EG010ControllerSendBinaryDocs extends AbstractEsignatureController { + + public EG010ControllerSendBinaryDocs(DSConfiguration config, Session session, User user) { + super(config, "eg010", session, user); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws IOException { + String responseString = SendBinaryDocsService.sendBinaryDocs( + args, + args.getSignerName(), + args.getSignerEmail(), + args.getCcName(), + args.getCcEmail(), + session.getBasePath(), + session.getAccountId(), + user.getAccessToken() + ); + JSONObject obj = new JSONObject(responseString); + String envelopeId = obj.getString("envelopeId"); + session.setEnvelopeId(envelopeId); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", envelopeId) + ) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/examples/EG011ControllerEmbeddedSending.java b/src/main/java/com/docusign/controller/eSignature/examples/EG011ControllerEmbeddedSending.java similarity index 53% rename from src/main/java/com/docusign/controller/examples/EG011ControllerEmbeddedSending.java rename to src/main/java/com/docusign/controller/eSignature/examples/EG011ControllerEmbeddedSending.java index 465248a8..fa4b4c1a 100644 --- a/src/main/java/com/docusign/controller/examples/EG011ControllerEmbeddedSending.java +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG011ControllerEmbeddedSending.java @@ -1,72 +1,68 @@ -package com.docusign.controller.examples; +package com.docusign.controller.eSignature.examples; import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.EmbeddedSendingService; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; import com.docusign.esign.api.EnvelopesApi; import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.EnvelopeDefinition; import com.docusign.esign.model.EnvelopeSummary; -import com.docusign.esign.model.ReturnUrlRequest; import com.docusign.esign.model.ViewUrl; -import com.docusign.model.Session; -import com.docusign.model.User; - -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.view.RedirectView; -import java.io.IOException; - import javax.servlet.http.HttpServletResponse; +import java.io.IOException; /** - * Embedded Sending
+ * Use embedded sending
* An envelope will be created in draft mode. A browser will then be redirected * to the DocuSign web tool where the envelope can be (optionally) updated and * then sent. The envelope includes a pdf, Word, and HTML document. */ @Controller @RequestMapping("/eg011") -public class EG011ControllerEmbeddedSending extends AbstractController { - - private final Session session; - private final User user; - +public class EG011ControllerEmbeddedSending extends AbstractEsignatureController { - @Autowired public EG011ControllerEmbeddedSending(DSConfiguration config, Session session, User user) { - super(config, "eg011", "Signing request by email"); - this.session = session; - this.user = user; + super(config, "eg011", session, user); } @Override // ***DS.snippet.0.start protected Object doWork(WorkArguments args, ModelMap model, - HttpServletResponse response) throws ApiException, IOException { - String accountId = session.getAccountId(); + HttpServletResponse response) throws ApiException, IOException { + String accountId = this.session.getAccountId(); EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); // Step 1. Make the envelope with "created" (draft) status - args.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_CREATED); - EnvelopeDefinition env = EG002ControllerSigningViaEmail.makeEnvelope(args); - EnvelopeSummary results = envelopesApi.createEnvelope(accountId, env); - String envelopeId = results.getEnvelopeId(); + EnvelopeSummary envelopeSummary = EmbeddedSendingService.createEnvelopeWithDraftStatus( + envelopesApi, + args.getSignerEmail(), + args.getSignerName(), + args.getCcEmail(), + args.getCcName(), + args.getStatus(), + args, + accountId); + String envelopeId = envelopeSummary.getEnvelopeId(); // Step 2. Create the sender view. // Set the url where you want the recipient to go once they are done // signing should typically be a callback route somewhere in your app. - ReturnUrlRequest viewRequest = new ReturnUrlRequest(); - viewRequest.setReturnUrl(config.getDsReturnUrl()); - ViewUrl viewUrl = envelopesApi.createSenderView(accountId, envelopeId, viewRequest); + ViewUrl viewUrl = EmbeddedSendingService.createSenderView( + envelopesApi, + accountId, + envelopeId, + config.getDsReturnUrl(), + args.getStartingView()); // Switch to Recipient and Documents view if requested by the user String url = viewUrl.getUrl(); - if ("recipient".equalsIgnoreCase(args.getStartingView())) { - url = url.replace("send=1", "send=0"); - } return new RedirectView(url); } diff --git a/src/main/java/com/docusign/controller/examples/EG012ControllerEmbeddedConsole.java b/src/main/java/com/docusign/controller/eSignature/examples/EG012ControllerEmbeddedConsole.java similarity index 55% rename from src/main/java/com/docusign/controller/examples/EG012ControllerEmbeddedConsole.java rename to src/main/java/com/docusign/controller/eSignature/examples/EG012ControllerEmbeddedConsole.java index 53a99994..05219539 100644 --- a/src/main/java/com/docusign/controller/examples/EG012ControllerEmbeddedConsole.java +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG012ControllerEmbeddedConsole.java @@ -1,22 +1,21 @@ -package com.docusign.controller.examples; +package com.docusign.controller.eSignature.examples; import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.EmbeddedConsoleService; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; import com.docusign.esign.api.EnvelopesApi; import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.ConsoleViewRequest; import com.docusign.esign.model.ViewUrl; -import com.docusign.model.Session; -import com.docusign.model.User; - -import javax.servlet.http.HttpServletResponse; - import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.view.RedirectView; +import javax.servlet.http.HttpServletResponse; + /** * Embedded the DocuSign Web UI.
@@ -27,46 +26,32 @@ */ @Controller @RequestMapping("/eg012") -public class EG012ControllerEmbeddedConsole extends AbstractController { +public class EG012ControllerEmbeddedConsole extends AbstractEsignatureController { - private final Session session; - private final User user; - - - @Autowired public EG012ControllerEmbeddedConsole(DSConfiguration config, Session session, User user) { - super(config, "eg012", "Embedded DocuSign web tool"); - this.session = session; - this.user = user; + super(config, "eg012", session, user); } @Override - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { super.onInitModel(args, model); model.addAttribute(MODEL_ENVELOPE_OK, StringUtils.isNotBlank(session.getEnvelopeId())); } @Override - // ***DS.snippet.0.start protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException { args.setDsReturnUrl(config.getDsReturnUrl()); EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); - // Step 1. Create the Console / Web UI view. - // Set the URL where you want the recipient to go once they are finished in - // the Web UI. There are cases where a user will never click "FINISH" within - // the Web UI, you cannot assume control will be passed back to your application. - ConsoleViewRequest viewRequest = new ConsoleViewRequest(); - viewRequest.setReturnUrl(config.getDsReturnUrl()); - String envelopeId = session.getEnvelopeId(); - if ("envelope".equalsIgnoreCase(args.getStartingView()) && envelopeId != null) { - viewRequest.setEnvelopeId(envelopeId); - } - // Step 2. Call the CreateSenderView API - ViewUrl viewUrl = envelopesApi.createConsoleView(session.getAccountId(), viewRequest); + ViewUrl viewUrl = EmbeddedConsoleService.createConsoleView( + envelopesApi, + config.getDsReturnUrl(), + session.getEnvelopeId(), + args.getStartingView(), + session.getAccountId()); + return new RedirectView(viewUrl.getUrl()); } - // ***DS.snippet.0.end } diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG013ControllerAddDocToTemplate.java b/src/main/java/com/docusign/controller/eSignature/examples/EG013ControllerAddDocToTemplate.java new file mode 100644 index 00000000..d259f6d9 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG013ControllerAddDocToTemplate.java @@ -0,0 +1,70 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.AddDocToTemplateService; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.ViewUrl; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.view.RedirectView; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +/** + * Use embedded signing from a template with an added document.
+ * This example sends an envelope based on a template. In addition to the + * template's document(s), the example adds an additional document to the + * envelope by using the Composite Templates. + */ +@Controller +@RequestMapping("/eg013") +public class EG013ControllerAddDocToTemplate extends AbstractEsignatureController { + + private final String SIGNER_CLIENT_ID = "1000"; + + public EG013ControllerAddDocToTemplate(DSConfiguration config, Session session, User user) { + super(config, "eg013", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + model.addAttribute(MODEL_TEMPLATE_OK, StringUtils.isNotBlank(session.getTemplateId())); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException, IOException { + + // Set status for the makeEnvelope method + if (!EnvelopeHelpers.ENVELOPE_STATUS_CREATED.equalsIgnoreCase(args.getStatus())) { + args.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + } + + String accountId = session.getAccountId(); + EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); + + ViewUrl embeddedEnvelope = AddDocToTemplateService.addDocumentToTemplate( + envelopesApi, + args.getSignerEmail(), + args.getSignerName(), + SIGNER_CLIENT_ID, + args.getCcEmail(), + args.getCcName(), + session.getTemplateId(), + accountId, + config.getDsReturnUrl(), + config.getDsPingUrl(), + args + ); + return new RedirectView(embeddedEnvelope.getUrl()); + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG014ControllerCollectPayment.java b/src/main/java/com/docusign/controller/eSignature/examples/EG014ControllerCollectPayment.java new file mode 100644 index 00000000..4e387268 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG014ControllerCollectPayment.java @@ -0,0 +1,85 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.CollectPaymentService; +import com.docusign.core.common.Utils; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +/** + * Send an envelope with an order form, including a payment field.
+ * This class programmatically constructs the order form. For many use cases, + * it would be better to create the order form as a template using the DocuSign + * web tool as a WYSIWYG form designer.
+ * Note: This example will only work if the sender's DocuSign account is + * set up with a DocuSign payment gateway. Next properties should are set: + *
    + *
  • Gateway_Account_Id
  • + *
  • Gateway_Name
  • + *
  • Gateway_Display_Name
  • + *
+ * Since the Payment Gateway ID is set in the configuration file, you will need + * to run your own instance of this project to set it. + */ +@Controller +@RequestMapping("/eg014") +public class EG014ControllerCollectPayment extends AbstractEsignatureController { + + private static final String MODEL_GATEWAY_OK = "gatewayOk"; + + public EG014ControllerCollectPayment(DSConfiguration config, Session session, User user) { + super(config, "eg014", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + if (Utils.isCfr(session.getBasePath(), user.getAccessToken(), session.getAccountId())) { + session.setStatusCFR("enabled"); + throw new Exception(config.getCodeExamplesText().getSupportingTexts().getCFRError()); + } + model.addAttribute(MODEL_GATEWAY_OK, null != config.getGatewayAccountId()); + } + + @Override + // ***DS.snippet.0.start + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException, IOException { + EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); + + // Step 1. Make the envelope request body + EnvelopeDefinition envelope = CollectPaymentService.makeEnvelope( + args.getSignerEmail(), + args.getSignerName(), + args.getCcName(), + args.getCcEmail(), + config.getGatewayAccountId(), + config.getGatewayName(), + config.getGatewayDisplayName(), + args); + + // Step 2. call Envelopes::create API method + EnvelopeSummary envelopeSummary = CollectPaymentService.collectPayment(envelopesApi, envelope, session.getAccountId()); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", envelopeSummary.getEnvelopeId()) + ) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + // ***DS.snippet.0.end +} diff --git a/src/main/java/com/docusign/controller/examples/EG015ControllerGetTabValues.java b/src/main/java/com/docusign/controller/eSignature/examples/EG015ControllerGetTabValues.java similarity index 51% rename from src/main/java/com/docusign/controller/examples/EG015ControllerGetTabValues.java rename to src/main/java/com/docusign/controller/eSignature/examples/EG015ControllerGetTabValues.java index aba862d8..2a8eff16 100644 --- a/src/main/java/com/docusign/controller/examples/EG015ControllerGetTabValues.java +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG015ControllerGetTabValues.java @@ -1,13 +1,15 @@ -package com.docusign.controller.examples; +package com.docusign.controller.eSignature.examples; import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.GetTabValuesService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; import com.docusign.esign.api.EnvelopesApi; import com.docusign.esign.client.ApiException; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; +import com.docusign.esign.model.EnvelopeFormData; import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; @@ -21,35 +23,33 @@ */ @Controller @RequestMapping("/eg015") -public class EG015ControllerGetTabValues extends AbstractController { +public class EG015ControllerGetTabValues extends AbstractEsignatureController { - private final Session session; - private final User user; - - - @Autowired public EG015ControllerGetTabValues(DSConfiguration config, Session session, User user) { - super(config, "eg015", "Get Envelope Tabs"); - this.session = session; - this.user = user; + super(config, "eg015", session, user); } @Override - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { super.onInitModel(args, model); model.addAttribute(MODEL_ENVELOPE_OK, StringUtils.isNotBlank(session.getEnvelopeId())); } @Override - // ***DS.snippet.0.start protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException { - // Step 1. get envelope recipients + //ds-snippet-start:eSign15Step2 EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); - DoneExample.createDefault(title) - .withJsonObject(envelopesApi.getFormData(session.getAccountId(), session.getEnvelopeId())) - .withMessage("Results from the Envelope::GetFormData method:") - .addToModel(model); + //ds-snippet-end:eSign15Step2 + //ds-snippet-start:eSign15Step3 + EnvelopeFormData envelopeFormData = GetTabValuesService.getTabValues( + envelopesApi, + session.getAccountId(), + session.getEnvelopeId()); + //ds-snippet-end:eSign15Step3 + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withJsonObject(envelopeFormData) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .addToModel(model, config); return DONE_EXAMPLE_PAGE; } - // ***DS.snippet.0.end } diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG016ControllerSetTabValues.java b/src/main/java/com/docusign/controller/eSignature/examples/EG016ControllerSetTabValues.java new file mode 100644 index 00000000..48eb2074 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG016ControllerSetTabValues.java @@ -0,0 +1,68 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.SetTabValuesService; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import com.docusign.esign.model.RecipientViewRequest; +import com.docusign.esign.model.ViewUrl; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.view.RedirectView; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +@Controller +@RequestMapping("/eg016") +public class EG016ControllerSetTabValues extends AbstractEsignatureController { + + public EG016ControllerSetTabValues(DSConfiguration config, Session session, User user) { + super(config, "eg016", session, user); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException, IOException { + String signerName = args.getSignerName(); + String signerEmail = args.getSignerEmail(); + String accountId = session.getAccountId(); + + EnvelopeDefinition envelope = SetTabValuesService.makeEnvelope(signerEmail, signerName); + + //ds-snippet-start:eSign16Step2 + ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); + EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); + //ds-snippet-end:eSign16Step2 + + // Call the eSignature REST API + //ds-snippet-start:eSign16Step4 + EnvelopeSummary envelopeSummary = SetTabValuesService.createEnvelope(envelopesApi, accountId, envelope); + //ds-snippet-end:eSign16Step4 + + String envelopeId = envelopeSummary.getEnvelopeId(); + session.setEnvelopeId(envelopeId); + + // Create the view request + //ds-snippet-start:eSign16Step5 + RecipientViewRequest viewRequest = SetTabValuesService.makeRecipientViewRequest( + signerEmail, + signerName, + config.getDsReturnUrl(), + config.getDsPingUrl()); + ViewUrl viewUrl = SetTabValuesService.createRecipientView(envelopesApi, accountId, envelopeId, viewRequest); + //ds-snippet-end:eSign16Step5 + + // State can be stored/recovered using the framework's session or a + // query parameter on the returnUrl (see the makeRecipientViewRequest method) + return new RedirectView(viewUrl.getUrl()); + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG017ControllerSetTemplateTabValues.java b/src/main/java/com/docusign/controller/eSignature/examples/EG017ControllerSetTemplateTabValues.java new file mode 100644 index 00000000..fef695b8 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG017ControllerSetTemplateTabValues.java @@ -0,0 +1,115 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.SetTemplateTabValuesService; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.api.TemplatesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.view.RedirectView; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Map; + +@Controller +@RequestMapping("/eg017") +public class EG017ControllerSetTemplateTabValues extends AbstractEsignatureController { + + private static final String MODEL_LIST_TEMPLATE = "listTemplates"; + + private static final String SIGNER_CLIENT_ID = "1000"; + + public EG017ControllerSetTemplateTabValues(DSConfiguration config, Session session, User user) { + super(config, "eg017", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); + TemplatesApi templatesApi = new TemplatesApi(apiClient); + var templates = templatesApi.listTemplatesWithHttpInfo(session.getAccountId(), templatesApi.new ListTemplatesOptions()); + Map> headers = templates.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + model.addAttribute(MODEL_LIST_TEMPLATE, templates.getData().getEnvelopeTemplates()); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException, IOException { + String signerName = args.getSignerName(); + String signerEmail = args.getSignerEmail(); + String accountId = session.getAccountId(); + String ccName = args.getCcName(); + String ccEmail = args.getCcEmail(); + String templateId = args.getTemplateId(); + + // Step 2. Construct your API headers + //ds-snippet-start:eSign17Step2 + ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); + //ds-snippet-end:eSign17Step2 + EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); + + // Step 3. is shown in the makeEnvelope method below + // Step 4. Construct your request body + EnvelopeDefinition envelope = SetTemplateTabValuesService.makeEnvelope( + signerEmail, + signerName, + ccEmail, + ccName, + templateId, + SIGNER_CLIENT_ID); + + // Step 5. Call the eSignature REST API + //ds-snippet-start:eSign17Step5 + var envelopeSummary = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, envelopesApi.new CreateEnvelopeOptions()); + Map> headers = envelopeSummary.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + String envelopeId = envelopeSummary.getData().getEnvelopeId(); + session.setEnvelopeId(envelopeId); + //ds-snippet-end:eSign17Step5 + + // Step 6. Create the view request + RecipientViewRequest viewRequest = SetTemplateTabValuesService.makeRecipientViewRequest( + signerEmail, + signerName, + config.getDsReturnUrl(), + SIGNER_CLIENT_ID, + config.getDsPingUrl()); + + ViewUrl viewUrl = SetTemplateTabValuesService.setTemplateTabValues( + envelopesApi, + accountId, + envelopeId, + viewRequest + ); + + // State can be stored/recovered using the framework's session or a + // query parameter on the returnUrl (see the makeRecipientViewRequest method) + return new RedirectView(viewUrl.getUrl()); + } +} diff --git a/src/main/java/com/docusign/controller/examples/EG018ControllerEnvelopeCustomFieldValues.java b/src/main/java/com/docusign/controller/eSignature/examples/EG018ControllerEnvelopeCustomFieldValues.java similarity index 52% rename from src/main/java/com/docusign/controller/examples/EG018ControllerEnvelopeCustomFieldValues.java rename to src/main/java/com/docusign/controller/eSignature/examples/EG018ControllerEnvelopeCustomFieldValues.java index cd2eb53e..65322946 100644 --- a/src/main/java/com/docusign/controller/examples/EG018ControllerEnvelopeCustomFieldValues.java +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG018ControllerEnvelopeCustomFieldValues.java @@ -1,13 +1,15 @@ -package com.docusign.controller.examples; +package com.docusign.controller.eSignature.examples; import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.EnvelopeCustomFieldValuesService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; import com.docusign.esign.api.EnvelopesApi; import com.docusign.esign.client.ApiException; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; +import com.docusign.esign.model.CustomFieldsEnvelope; import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; @@ -21,35 +23,35 @@ */ @Controller @RequestMapping("/eg018") -public class EG018ControllerEnvelopeCustomFieldValues extends AbstractController { +public class EG018ControllerEnvelopeCustomFieldValues extends AbstractEsignatureController { - private final Session session; - private final User user; - - - @Autowired public EG018ControllerEnvelopeCustomFieldValues(DSConfiguration config, Session session, User user) { - super(config, "eg018", "Get Envelope Custom Field Data"); - this.session = session; - this.user = user; + super(config, "eg018", session, user); } @Override - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { super.onInitModel(args, model); model.addAttribute(MODEL_ENVELOPE_OK, StringUtils.isNotBlank(session.getEnvelopeId())); } @Override - // ***DS.snippet.0.start protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException { - // Step 1. get envelope recipients + //ds-snippet-start:eSign18Step2 EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); - DoneExample.createDefault(title) - .withJsonObject(envelopesApi.listCustomFields(session.getAccountId(), session.getEnvelopeId())) - .withMessage("Results from the Envelope::GetFormData method:") - .addToModel(model); + //ds-snippet-end:eSign18Step2 + //ds-snippet-start:eSign18Step3 + CustomFieldsEnvelope customFieldsEnvelope = EnvelopeCustomFieldValuesService.envelopeCustomFieldValues( + envelopesApi, + session.getAccountId(), + session.getEnvelopeId() + ); + //ds-snippet-end:eSign18Step3 + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withJsonObject(customFieldsEnvelope) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .addToModel(model, config); return DONE_EXAMPLE_PAGE; } - // ***DS.snippet.0.end } diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG019ControllerAccessCodeAuthentication.java b/src/main/java/com/docusign/controller/eSignature/examples/EG019ControllerAccessCodeAuthentication.java new file mode 100644 index 00000000..fa36f84f --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG019ControllerAccessCodeAuthentication.java @@ -0,0 +1,63 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.AccessCodeAuthenticationService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +/** + * Send an envelope with a recipient using Access Code Authentication. Signer + * has to enter an access code for opening document to sign. + */ +@Controller +@RequestMapping("/eg019") +public class EG019ControllerAccessCodeAuthentication extends AbstractEsignatureController { + + public EG019ControllerAccessCodeAuthentication(DSConfiguration config, Session session, User user) { + super(config, "eg019", session, user); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException, IOException { + // Step 1: Construct your API headers + EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); + + // Step 2: Construct your envelope JSON body + EnvelopeDefinition envelope = AccessCodeAuthenticationService.createEnvelope( + args.getSignerName(), + args.getSignerEmail(), + args.getAccessCode() + ); + + // Step 3: Call the eSignature REST API + EnvelopeSummary envelopeSummary = AccessCodeAuthenticationService.accessCodeAuthentication( + envelopesApi, + session.getAccountId(), + envelope + ); + + session.setEnvelopeId(envelopeSummary.getEnvelopeId()); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withJsonObject(envelopeSummary) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", session.getEnvelopeId()) + ) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG020ControllerPhoneAuthentication.java b/src/main/java/com/docusign/controller/eSignature/examples/EG020ControllerPhoneAuthentication.java new file mode 100644 index 00000000..2e7e8b79 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG020ControllerPhoneAuthentication.java @@ -0,0 +1,106 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.PhoneAuthenticationService; +import com.docusign.core.common.Utils; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.AccountIdentityVerificationResponse; +import com.docusign.esign.model.AccountIdentityVerificationWorkflow; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Map; + +/** + * Example 020: Phone Authentication for recipient + */ +@Controller +@RequestMapping("/eg020") +public class EG020ControllerPhoneAuthentication extends AbstractEsignatureController { + + private static final Logger LOGGER = LoggerFactory.getLogger(EG023ControllerIdvAuthentication.class); + + public EG020ControllerPhoneAuthentication(DSConfiguration config, Session session, User user) { + super(config, "eg020", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + if (Utils.isCfr(session.getBasePath(), user.getAccessToken(), session.getAccountId())) { + session.setStatusCFR("enabled"); + throw new Exception(config.getCodeExamplesText().getSupportingTexts().getCFRError()); + } + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) + throws ApiException, IOException { + if (args.getSignerEmail().equals(config.getSignerEmail())) { + throw new ApiException(config.getCodeExamplesText().SupportingTexts.IdenticalEmailsNotAllowedErrorMessage); + } + + String accountId = session.getAccountId(); + + ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); + EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); + + //ds-snippet-start:eSign20Step3 + AccountsApi workflowDetails = new AccountsApi(apiClient); + var workflowRes = workflowDetails.getAccountIdentityVerificationWithHttpInfo(session.getAccountId(), workflowDetails.new GetAccountIdentityVerificationOptions()); + Map> headers = workflowRes.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + List identityVerification = workflowRes.getData().getIdentityVerification(); + String workflowId = ""; + for (int i = 0; i < identityVerification.size(); i++) { + if (identityVerification.get(i).getDefaultName().equals("Phone Authentication")) { + workflowId = identityVerification.get(i).getWorkflowId(); + } + } + //ds-snippet-end:eSign20Step3 + LOGGER.info("workflowId = " + workflowId); + if (workflowId.equals("")) { + throw new ApiException(0, getTextForCodeExampleByApiType().CustomErrorTexts.get(0).ErrorMessage); + } + //ds-snippet-start:eSign20Step5 + EnvelopeDefinition envelope = PhoneAuthenticationService.createEnvelope(args.getSignerName(), args.getSignerEmail(), args.getCountryCode(), + args.getPhoneNumber(), workflowId); + //ds-snippet-end:eSign20Step5 + //ds-snippet-start:eSign20Step4 + EnvelopeSummary results = PhoneAuthenticationService.phoneAuthentication(envelopesApi, accountId, envelope); + //ds-snippet-end:eSign20Step4 + + session.setEnvelopeId(results.getEnvelopeId()); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withJsonObject(results) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", results.getEnvelopeId()) + ) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG022ControllerKBAAuthentication.java b/src/main/java/com/docusign/controller/eSignature/examples/EG022ControllerKBAAuthentication.java new file mode 100644 index 00000000..6982ff12 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG022ControllerKBAAuthentication.java @@ -0,0 +1,66 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.KBAAuthenticationService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +/** + * Send an envelope with a recipient using Knowledge-Based Authentication. + */ +@Controller +@RequestMapping("/eg022") +public class EG022ControllerKBAAuthentication extends AbstractEsignatureController { + + public EG022ControllerKBAAuthentication(DSConfiguration config, Session session, User user) { + super(config, "eg022", session, user); + } + + @Override + // ***DS.snippet.0.start + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException, IOException { + if (args.getSignerEmail().equals(config.getSignerEmail())) { + throw new ApiException(config.getCodeExamplesText().SupportingTexts.IdenticalEmailsNotAllowedErrorMessage); + } + + // Step 1: Construct your API headers + EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); + + // Step 2: Construct your envelope JSON body + EnvelopeDefinition envelope = KBAAuthenticationService.createEnvelope( + args.getSignerName(), + args.getSignerEmail()); + + // Step 3: Call the eSignature REST API + EnvelopeSummary envelopeSummary = KBAAuthenticationService.kbaAuthentication( + envelopesApi, + session.getAccountId(), + envelope + ); + + session.setEnvelopeId(envelopeSummary.getEnvelopeId()); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withJsonObject(envelopeSummary) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", envelopeSummary.getEnvelopeId()) + ) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } + // ***DS.snippet.0.end +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG023ControllerIdvAuthentication.java b/src/main/java/com/docusign/controller/eSignature/examples/EG023ControllerIdvAuthentication.java new file mode 100644 index 00000000..f2cb6ca0 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG023ControllerIdvAuthentication.java @@ -0,0 +1,64 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.IdvAuthenticationService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * ID Verification authentication + */ +@Controller +@RequestMapping("/eg023") +public class EG023ControllerIdvAuthentication extends AbstractEsignatureController { + + private static final Logger LOGGER = LoggerFactory.getLogger(EG023ControllerIdvAuthentication.class); + + public EG023ControllerIdvAuthentication(DSConfiguration config, Session session, User user) { + super(config, "eg023", session, user); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException, IOException { + if (args.getSignerEmail().equals(config.getSignerEmail())) { + throw new ApiException(config.getCodeExamplesText().SupportingTexts.IdenticalEmailsNotAllowedErrorMessage); + } + + ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); + EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); + String workflowId = IdvAuthenticationService.retrieveWorkflowId(apiClient, session.getAccountId()); + LOGGER.info("workflowId = " + workflowId); + if (workflowId.equals("")) { + throw new ApiException(0, getTextForCodeExampleByApiType().CustomErrorTexts.get(0).ErrorMessage); + } + EnvelopeDefinition envelope = IdvAuthenticationService.createEnvelope(args.getSignerName(), args.getSignerEmail(), workflowId); + //ds-snippet-start:eSign23Step5 + EnvelopeSummary results = IdvAuthenticationService.idvAuthentication(envelopesApi, session.getAccountId(), envelope); + //ds-snippet-end:eSign23Step5 + + session.setEnvelopeId(results.getEnvelopeId()); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withJsonObject(results) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", results.getEnvelopeId()) + ) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/examples/EG024ControllerPermissionCreate.java b/src/main/java/com/docusign/controller/eSignature/examples/EG024ControllerPermissionCreate.java similarity index 53% rename from src/main/java/com/docusign/controller/examples/EG024ControllerPermissionCreate.java rename to src/main/java/com/docusign/controller/eSignature/examples/EG024ControllerPermissionCreate.java index 821b0eaf..f3b07d2e 100644 --- a/src/main/java/com/docusign/controller/examples/EG024ControllerPermissionCreate.java +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG024ControllerPermissionCreate.java @@ -1,21 +1,20 @@ -package com.docusign.controller.examples; - -import java.io.IOException; - -import javax.servlet.http.HttpServletResponse; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; +package com.docusign.controller.eSignature.examples; import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.PermissionCreateService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; import com.docusign.esign.api.AccountsApi; import com.docusign.esign.client.ApiException; import com.docusign.esign.model.PermissionProfile; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; /** * Permission profiles are collections of account settings that determine the @@ -25,37 +24,33 @@ */ @Controller @RequestMapping("/eg024") -public class EG024ControllerPermissionCreate extends AbstractController{ +public class EG024ControllerPermissionCreate extends AbstractEsignatureController { - private final Session session; - private final User user; - - @Autowired public EG024ControllerPermissionCreate(DSConfiguration config, Session session, User user) { - super(config, "eg024", "Creates a new permission profile"); - this.session = session; - this.user = user; + super(config, "eg024", session, user); } @Override protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException, IOException { + // Step 2. Construct your API headers AccountsApi accountsApi = createAccountsApi(session.getBasePath(), user.getAccessToken()); - // Step 3. Construct your request body - PermissionProfile profile = new PermissionProfile() - .permissionProfileName(args.getPermissionProfileName()) - .settings(DsModelUtils.createDefaultRoleSettings()); - // Step 4. Call the eSignature REST API - PermissionProfile newProfile = accountsApi.createPermissionProfile(session.getAccountId(), profile); + PermissionProfile newProfile = PermissionCreateService.createNewProfile( + accountsApi, + session.getAccountId(), + args.getPermissionProfileName() + ); - DoneExample.createDefault(title) + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) .withJsonObject(newProfile) - .withMessage("The permission profile is created!
Permission profile ID: " - + newProfile.getPermissionProfileId() + ".") - .addToModel(model); + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", newProfile.getPermissionProfileId()) + .replaceFirst("\\{1}", newProfile.getPermissionProfileName()) + ) + .addToModel(model, config); return DONE_EXAMPLE_PAGE; } -} \ No newline at end of file +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG025ControllerPermissionSetUserGroups.java b/src/main/java/com/docusign/controller/eSignature/examples/EG025ControllerPermissionSetUserGroups.java new file mode 100644 index 00000000..e8d8ad5b --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG025ControllerPermissionSetUserGroups.java @@ -0,0 +1,111 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.PermissionSetUserGroupsService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.api.GroupsApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.ErrorDetails; +import com.docusign.esign.model.GroupInformation; +import com.docusign.esign.model.PermissionProfileInformation; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.time.Instant; +import java.util.List; +import java.util.Map; + + +/** + * Permission profiles are collections of account settings that determine the + * behavior and actions available to the user groups to which they're applied. + * This code example demonstrates how to the permission profile for the group + * with the eSignature REST API. + */ +@Controller +@RequestMapping("/eg025") +public class EG025ControllerPermissionSetUserGroups extends AbstractEsignatureController { + + private static final String MODEL_LIST_PROFILES = "listProfiles"; + + private static final String MODEL_LIST_GROUPS = "listGroups"; + + public EG025ControllerPermissionSetUserGroups(DSConfiguration config, Session session, User user) { + super(config, "eg025", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + String accountId = session.getAccountId(); + + AccountsApi accountsApi = createAccountsApi(session.getBasePath(), user.getAccessToken()); + var permissionsInfo = accountsApi.listPermissionsWithHttpInfo(accountId, accountsApi.new ListPermissionsOptions()); + Map> headers = permissionsInfo.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + model.addAttribute(MODEL_LIST_PROFILES, permissionsInfo.getData().getPermissionProfiles()); + + //ds-snippet-start:eSign25Step4 + GroupsApi groupsApi = new GroupsApi(accountsApi.getApiClient()); + var groupInformation = groupsApi.listGroupsWithHttpInfo(accountId, groupsApi.new ListGroupsOptions()); + headers = groupInformation.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + model.addAttribute(MODEL_LIST_GROUPS, groupInformation.getData().getGroups()); + //ds-snippet-end:eSign25Step4 + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException { + // Construct your API headers + ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); + + //ds-snippet-start:eSign25Step3 + GroupInformation newGroupInfo = PermissionSetUserGroupsService.permissionSetUserGroups( + apiClient, + args.getGroupId(), + args.getProfileId(), + session.getAccountId() + ); + //ds-snippet-end:eSign25Step3 + + // Show result + ErrorDetails errorDetails = newGroupInfo.getGroups().get(0).getErrorDetails(); + if (errorDetails != null) { + new DoneExample() + .withTitle(exampleName) + .withName(title) + .withMessage( + getTextForCodeExampleByApiType().CustomErrorTexts.get(0).ErrorMessage + + "< br />Reason:" + + errorDetails.getMessage()) + .addToModel(model, config); + return ERROR_PAGE; + } + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withJsonObject(newGroupInfo) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG026ControllerPermissionChangeSingleSetting.java b/src/main/java/com/docusign/controller/eSignature/examples/EG026ControllerPermissionChangeSingleSetting.java new file mode 100644 index 00000000..e7a9d774 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG026ControllerPermissionChangeSingleSetting.java @@ -0,0 +1,99 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.PermissionChangeSingleSettingService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.PermissionProfile; +import com.docusign.esign.model.PermissionProfileInformation; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Map; + +/** + * This code example demonstrates how to edit individual permission settings on + * a permission profile with the eSignature REST API. + */ +@Controller +@RequestMapping("/eg026") +public class EG026ControllerPermissionChangeSingleSetting extends AbstractEsignatureController { + + private static final String MODEL_CUR_PROFILE_NAME = "permissionProfileName"; + + private static final String MODEL_CUR_PROFILE_ID = "profileId"; + + private static final String MODEL_LIST_PROFILES = "listProfiles"; + + public EG026ControllerPermissionChangeSingleSetting(DSConfiguration config, Session session, User user) { + super(config, "eg026", session, user); + } + + @GetMapping("/profile") + public void getProfile(@RequestParam String profileId, ModelMap model) { + session.setPermissionProfileId(profileId); + model.addAttribute(MODEL_CUR_PROFILE_NAME, profileId); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + AccountsApi accountsApi = createAccountsApi(session.getBasePath(), user.getAccessToken()); + + var permissionsInfo = accountsApi.listPermissionsWithHttpInfo(session.getAccountId(), accountsApi.new ListPermissionsOptions()); + Map> headers = permissionsInfo.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + List profiles = permissionsInfo.getData().getPermissionProfiles(); + model.addAttribute(MODEL_LIST_PROFILES, profiles); + + model.addAttribute(MODEL_CUR_PROFILE_NAME, profiles.get(0).getPermissionProfileName()); + model.addAttribute(MODEL_CUR_PROFILE_ID, profiles.get(0).getPermissionProfileId()); + PermissionChangeSingleSettingService.findProfile( + profiles, + session.getPermissionProfileId()).ifPresent((PermissionProfile curProfile) -> + { + model.addAttribute(MODEL_CUR_PROFILE_NAME, curProfile.getPermissionProfileName()); + model.addAttribute(MODEL_CUR_PROFILE_ID, curProfile.getPermissionProfileId()); + }); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) + throws ApiException, IOException { + // Step 2. Construct your API headers + AccountsApi accountsApi = createAccountsApi(session.getBasePath(), user.getAccessToken()); + String accountId = session.getAccountId(); + String curProfileId = args.getProfileId(); + + PermissionProfile newProfile = PermissionChangeSingleSettingService.permissionChangeSingleSetting( + accountsApi, + accountId, + curProfileId + ); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", newProfile.getPermissionProfileId()) + ) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE_COMPARE; + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG027ControllerPermissionDelete.java b/src/main/java/com/docusign/controller/eSignature/examples/EG027ControllerPermissionDelete.java new file mode 100644 index 00000000..bf89a00a --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG027ControllerPermissionDelete.java @@ -0,0 +1,84 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.PermissionDeleteService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.PermissionProfileInformation; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.time.Instant; +import java.util.List; +import java.util.Map; + + +/** + * Permission profiles are collections of account settings that determine the + * behavior and actions available to the user groups to which they're applied. + * This code example demonstrates how to delete a permission profile with the + * eSignature REST API. + */ +@Controller +@RequestMapping("/eg027") +public class EG027ControllerPermissionDelete extends AbstractEsignatureController { + + private static final String MODEL_LIST_PROFILES = "listProfiles"; + + public EG027ControllerPermissionDelete(DSConfiguration config, Session session, User user) { + super(config, "eg027", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + AccountsApi accountsApi = createAccountsApi(session.getBasePath(), user.getAccessToken()); + + var permissionsInfo = accountsApi.listPermissionsWithHttpInfo(session.getAccountId(), accountsApi.new ListPermissionsOptions()); + Map> headers = permissionsInfo.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + model.addAttribute(MODEL_LIST_PROFILES, permissionsInfo.getData().getPermissionProfiles()); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) { + // Construct your API headers + AccountsApi accountsApi = createAccountsApi(session.getBasePath(), user.getAccessToken()); + + // Call the eSignature Rest API to delete profile + //ds-snippet-start:eSign27Step3 + String curProfileId = args.getProfileId(); + try { + PermissionDeleteService.permissionDelete(accountsApi, session.getAccountId(), curProfileId); + //ds-snippet-end:eSign27Step3 + + // Show 'done' (successful) page + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText.replaceFirst("\\{0}", curProfileId)) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } catch (ApiException e) { + new DoneExample() + .withTitle(exampleName) + .withName(title) + .withMessage(getTextForCodeExampleByApiType().CustomErrorTexts.get(0).ErrorMessage) + .addToModel(model, config); + + return ERROR_PAGE; + } + } +} diff --git a/src/main/java/com/docusign/controller/examples/EG028ControllerCreateBrand.java b/src/main/java/com/docusign/controller/eSignature/examples/EG028ControllerCreateBrand.java similarity index 55% rename from src/main/java/com/docusign/controller/examples/EG028ControllerCreateBrand.java rename to src/main/java/com/docusign/controller/eSignature/examples/EG028ControllerCreateBrand.java index 9d87dd08..45950127 100644 --- a/src/main/java/com/docusign/controller/examples/EG028ControllerCreateBrand.java +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG028ControllerCreateBrand.java @@ -1,24 +1,21 @@ -package com.docusign.controller.examples; - -import java.io.IOException; -import java.util.List; - -import javax.servlet.http.HttpServletResponse; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; +package com.docusign.controller.eSignature.examples; import com.docusign.DSConfiguration; -import com.docusign.common.Languages; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.CreateBrandService; +import com.docusign.core.common.Languages; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; import com.docusign.esign.api.AccountsApi; import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.Brand; import com.docusign.esign.model.BrandsResponse; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; /** @@ -27,23 +24,16 @@ */ @Controller @RequestMapping("/eg028") -public class EG028ControllerCreateBrand extends AbstractController{ +public class EG028ControllerCreateBrand extends AbstractEsignatureController { private static final String MODEL_LIST_LANGUAGE = "listLanguage"; - private final Session session; - private final User user; - - - @Autowired public EG028ControllerCreateBrand(DSConfiguration config, Session session, User user) { - super(config, "eg028", "Creating a brand"); - this.session = session; - this.user = user; + super(config, "eg028", session, user); } @Override - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { super.onInitModel(args, model); model.addAttribute(MODEL_LIST_LANGUAGE, Languages.getSupportedLanguages()); } @@ -55,20 +45,23 @@ protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse AccountsApi accountsApi = createAccountsApi(session.getBasePath(), user.getAccessToken()); // Step 3: Construct your brand JSON body + //ds-snippet-start:eSign28Step3 String language = args.getLanguage(); - Brand brand = new Brand() - .brandName(args.getBrandName()) - .defaultBrandLanguage(language) - .brandLanguages(List.of(language)); - // Step 5: Call the eSignature REST API - BrandsResponse brandsResponse = accountsApi.createBrand(session.getAccountId(), brand); + BrandsResponse brandsResponse = CreateBrandService.createBrand( + accountsApi, + args.getBrandName(), + language, + session.getAccountId() + ); + //ds-snippet-end:eSign28Step3 - DoneExample.createDefault(title) + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) .withJsonObject(brandsResponse) - .withMessage("The brand has been created!
Brand ID " - + brandsResponse.getBrands().get(0).getBrandId() + ".") - .addToModel(model); + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", brandsResponse.getBrands().get(0).getBrandId()) + ) + .addToModel(model, config); return DONE_EXAMPLE_PAGE; } } diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG029ControllerApplyBrandToEnvelope.java b/src/main/java/com/docusign/controller/eSignature/examples/EG029ControllerApplyBrandToEnvelope.java new file mode 100644 index 00000000..d91b3511 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG029ControllerApplyBrandToEnvelope.java @@ -0,0 +1,80 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.ApplyBrandToEnvelopeService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.BrandsResponse; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +/** + * Applying a brand to an envelope
+ * The envelope includes a pdf document. Anchor text AutoPlace is used + * to position the signing fields in the documents. + */ +@Controller +@RequestMapping("/eg029") +public class EG029ControllerApplyBrandToEnvelope extends AbstractEsignatureController { + + private static final String MODEL_LIST_BRAND = "listBrands"; + + public EG029ControllerApplyBrandToEnvelope(DSConfiguration config, Session session, User user) { + super(config, "eg029", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + AccountsApi accountsApi = createAccountsApi(session.getBasePath(), user.getAccessToken()); + BrandsResponse brands = ApplyBrandToEnvelopeService.getBrands(accountsApi, session.getAccountId()); + model.addAttribute(MODEL_LIST_BRAND, brands.getBrands()); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) + throws ApiException, IOException { + // Construct your API headers + //ds-snippet-start:eSign29Step2 + EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); + //ds-snippet-end:eSign29Step2 + + // Construct your envelope JSON body + //ds-snippet-start:eSign29Step3 + EnvelopeDefinition envelope = ApplyBrandToEnvelopeService.makeEnvelope( + args.getSignerEmail(), + args.getSignerName(), + args.getBrandId() + ); + //ds-snippet-end:eSign29Step3 + + // Call the eSignature REST API + //ds-snippet-start:eSign29Step4 + EnvelopeSummary envelopeSummary = ApplyBrandToEnvelopeService.applyBrandToEnvelope( + envelopesApi, + session.getAccountId(), + envelope + ); + //ds-snippet-end:eSign29Step4 + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withJsonObject(envelopeSummary) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", envelopeSummary.getEnvelopeId()) + ) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/examples/EG030ControllerApplyBrandToTemplate.java b/src/main/java/com/docusign/controller/eSignature/examples/EG030ControllerApplyBrandToTemplate.java similarity index 59% rename from src/main/java/com/docusign/controller/examples/EG030ControllerApplyBrandToTemplate.java rename to src/main/java/com/docusign/controller/eSignature/examples/EG030ControllerApplyBrandToTemplate.java index c6d89bc4..2f69045d 100644 --- a/src/main/java/com/docusign/controller/examples/EG030ControllerApplyBrandToTemplate.java +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG030ControllerApplyBrandToTemplate.java @@ -1,29 +1,30 @@ -package com.docusign.controller.examples; - -import java.io.IOException; -import java.util.Arrays; - -import javax.servlet.http.HttpServletResponse; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; +package com.docusign.controller.eSignature.examples; import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.ApplyBrandToTemplateService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; import com.docusign.esign.api.AccountsApi; import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.api.TemplatesApi; import com.docusign.esign.client.ApiClient; import com.docusign.esign.client.ApiException; import com.docusign.esign.model.BrandsResponse; import com.docusign.esign.model.EnvelopeDefinition; import com.docusign.esign.model.EnvelopeSummary; -import com.docusign.esign.model.EnvelopeTemplateResults; import com.docusign.esign.model.TemplateRole; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.Map; /** @@ -38,35 +39,36 @@ */ @Controller @RequestMapping("/eg030") -public class EG030ControllerApplyBrandToTemplate extends AbstractController { +public class EG030ControllerApplyBrandToTemplate extends AbstractEsignatureController { private static final String MODEL_LIST_BRAND = "listBrands"; - private static final String MODEL_LIST_TEMPLATE = "listTemplates"; - - private final Session session; - private final User user; + private static final String MODEL_LIST_TEMPLATE = "listTemplates"; - @Autowired public EG030ControllerApplyBrandToTemplate(DSConfiguration config, Session session, User user) { - super(config, "eg030", "Apply brand to template"); - this.session = session; - this.user = user; + super(config, "eg030", session, user); } @Override - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { super.onInitModel(args, model); String accountId = session.getAccountId(); ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); AccountsApi accountsApi = new AccountsApi(apiClient); - BrandsResponse brands = accountsApi.listBrands(accountId); - model.addAttribute(MODEL_LIST_BRAND, brands.getBrands()); - - TemplatesApi templatesApi = new TemplatesApi(apiClient); - EnvelopeTemplateResults templates = templatesApi.listTemplates(accountId); - model.addAttribute(MODEL_LIST_TEMPLATE, templates.getEnvelopeTemplates()); + var brands = accountsApi.listBrandsWithHttpInfo(accountId, accountsApi.new ListBrandsOptions()); + Map> headers = brands.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + model.addAttribute(MODEL_LIST_BRAND, brands.getData().getBrands()); + + model.addAttribute(MODEL_TEMPLATE_OK, StringUtils.isNotBlank(session.getTemplateId())); } @Override @@ -76,20 +78,26 @@ protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); // Step 3: Construct your envelope JSON body - EnvelopeDefinition envelope = makeEnvelope(args); + EnvelopeDefinition envelope = makeEnvelope(args, session.getTemplateId()); - // Step 5: Call the eSignature REST API - EnvelopeSummary envelopeSummary = envelopesApi.createEnvelope(session.getAccountId(), envelope); + // Step 4: Call the eSignature REST API + EnvelopeSummary envelopeSummary = ApplyBrandToTemplateService.applyBrandToTemplate( + envelopesApi, + session.getAccountId(), + envelope + ); - DoneExample.createDefault(title) + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) .withJsonObject(envelopeSummary) - .withMessage("The envelope has been created and sent!
Envelope ID " - + envelopeSummary.getEnvelopeId() + ".") - .addToModel(model); + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", envelopeSummary.getEnvelopeId()) + ) + .addToModel(model, config); return DONE_EXAMPLE_PAGE; } - private static EnvelopeDefinition makeEnvelope(WorkArguments args) { + //ds-snippet-start:eSign30Step3 + private static EnvelopeDefinition makeEnvelope(WorkArguments args, String templateId) { TemplateRole signer = new TemplateRole() .email(args.getSignerEmail()) .name(args.getSignerName()) @@ -101,9 +109,10 @@ private static EnvelopeDefinition makeEnvelope(WorkArguments args) { .roleName(EnvelopeHelpers.CC_ROLE_NAME); return new EnvelopeDefinition() - .templateId(args.getTemplateId()) + .templateId(templateId) .templateRoles(Arrays.asList(signer, cc)) .brandId(args.getBrandId()) .status(EnvelopeHelpers.ENVELOPE_STATUS_SENT); } + //ds-snippet-end:eSign30Step3 } diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG031ControllerBulkSendEnvelopes.java b/src/main/java/com/docusign/controller/eSignature/examples/EG031ControllerBulkSendEnvelopes.java new file mode 100644 index 00000000..5534757f --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG031ControllerBulkSendEnvelopes.java @@ -0,0 +1,91 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.BulkSendEnvelopesService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.BulkEnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.BulkSendBatchStatus; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * This code example demonstrates how to send envelopes in bulk to multiple + * recipients with the eSignature API. To accomplish the task, you will first + * create a bulk send recipients list, and then create an envelope. From there, + * you will combine the envelope and bulk list to initiate bulk send + */ +@Controller +@RequestMapping("/eg031") +public class EG031ControllerBulkSendEnvelopes extends AbstractEsignatureController { + + private static final long BULK_REQUEST_DELAY = 15L; + + public EG031ControllerBulkSendEnvelopes(DSConfiguration config, Session session, User user) { + super(config, "eg031", session, user); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) + throws ApiException, IOException { + + // Construct your API headers + ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); + + // submit a bulk list + String accountId = session.getAccountId(); + BulkEnvelopesApi bulkEnvelopesApi = new BulkEnvelopesApi(apiClient); + String batchId = BulkSendEnvelopesService.bulkSendEnvelopes( + bulkEnvelopesApi, + apiClient, + args.getSignerName(), + args.getSignerEmail(), + args.getCcName(), + args.getCcEmail(), + args.getSignerName2(), + args.getSignerEmail2(), + args.getCcName2(), + args.getCcEmail2(), + session.getAccountId() + ); + + // Confirm successful bulk send + try { + + BulkSendBatchStatus status = BulkSendEnvelopesService.getBulkSendBatchStatus(bulkEnvelopesApi, accountId, batchId, BULK_REQUEST_DELAY); + + DoneExample.createDefault(getTextForCodeExample().ExampleName) + + .withJsonObject(status) + .withMessage(String.join( + "", + "Bulk request queued to ", status.getQueued(), " user lists.")) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } catch (InterruptedException exception) { + Thread.currentThread().interrupt(); + + new DoneExample() + .withTitle(exampleName) + .withName(title) + .withMessage( + getTextForCodeExampleByApiType().CustomErrorTexts.get(0).ErrorMessage + + "< br />Reason:" + + exception.getMessage() + ) + .addToModel(model, config); + + return ERROR_PAGE; + } + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG032ControllerPauseSignatureWorkflow.java b/src/main/java/com/docusign/controller/eSignature/examples/EG032ControllerPauseSignatureWorkflow.java new file mode 100644 index 00000000..eeed9b9f --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG032ControllerPauseSignatureWorkflow.java @@ -0,0 +1,76 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.PauseSignatureWorkflowService; +import com.docusign.core.common.Utils; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * This topic demonstrates how to create an envelope where the workflow + * is paused before the envelope is sent to a second recipient. + */ +@Controller +@RequestMapping("/eg032") +public class EG032ControllerPauseSignatureWorkflow extends AbstractEsignatureController { + + public EG032ControllerPauseSignatureWorkflow(DSConfiguration config, Session session, User user) { + super(config, "eg032", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + if (Utils.isCfr(session.getBasePath(), user.getAccessToken(), session.getAccountId())) { + session.setStatusCFR("enabled"); + throw new Exception(config.getCodeExamplesText().getSupportingTexts().getCFRError()); + } + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) + throws ApiException, IOException { + + //ds-snippet-start:eSign32Step2 + EnvelopesApi envelopesApi = createEnvelopesApi(this.session.getBasePath(), this.user.getAccessToken()); + //ds-snippet-end:eSign32Step2 + + // Construct your envelope JSON body + EnvelopeDefinition envelope = PauseSignatureWorkflowService.createEnvelope( + args.getSignerName(), + args.getSignerEmail(), + args.getSignerName2(), + args.getSignerEmail2() + ); + + //ds-snippet-start:eSign32Step4 + EnvelopeSummary envelopeSummary = PauseSignatureWorkflowService.pauseSignatureWorkflow( + envelopesApi, + this.session.getAccountId(), + envelope + ); + //ds-snippet-end:eSign32Step4 + + this.session.setEnvelopeId(envelopeSummary.getEnvelopeId()); + DoneExample.createDefault(this.title) + .withJsonObject(envelopeSummary) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", this.session.getEnvelopeId()) + ) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} \ No newline at end of file diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG033ControllerUnpauseSignatureWorkflow.java b/src/main/java/com/docusign/controller/eSignature/examples/EG033ControllerUnpauseSignatureWorkflow.java new file mode 100644 index 00000000..649de0c3 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG033ControllerUnpauseSignatureWorkflow.java @@ -0,0 +1,62 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.UnpauseSignatureWorkflowService; +import com.docusign.core.common.Utils; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeUpdateSummary; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + + +/** + * This topic demonstrates how to resume an envelope workflow that has been paused. + */ +@Controller +@RequestMapping("/eg033") +public class EG033ControllerUnpauseSignatureWorkflow extends AbstractEsignatureController { + + public EG033ControllerUnpauseSignatureWorkflow(DSConfiguration config, Session session, User user) { + super(config, "eg033", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + if (Utils.isCfr(session.getBasePath(), user.getAccessToken(), session.getAccountId())) { + session.setStatusCFR("enabled"); + throw new Exception(config.getCodeExamplesText().getSupportingTexts().getCFRError()); + } + super.onInitModel(args, model); + } + + @Override + // ***DS.snippet.0.start + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException { + + // Step 2: Construct your API headers + //ds-snippet-start:eSign33Step2 + EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); + //ds-snippet-end:eSign33Step2 + + EnvelopeUpdateSummary envelopeUpdateSummary = UnpauseSignatureWorkflowService.unpauseSignatureWorkflow( + envelopesApi, + this.session.getAccountId(), + this.session.getEnvelopeId() + ); + + DoneExample.createDefault(this.title) + .withJsonObject(envelopeUpdateSummary) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + // ***DS.snippet.0.end +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG034ControllerUseConditionalRecipients.java b/src/main/java/com/docusign/controller/eSignature/examples/EG034ControllerUseConditionalRecipients.java new file mode 100644 index 00000000..bc995390 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG034ControllerUseConditionalRecipients.java @@ -0,0 +1,85 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.UseConditionalRecipientsService; +import com.docusign.core.common.Utils; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * This topic demonstrates how to create an envelope where the workflow + * is paused before the envelope is sent to a second recipient. + */ +@Controller +@RequestMapping("/eg034") +public class EG034ControllerUseConditionalRecipients extends AbstractEsignatureController { + + public EG034ControllerUseConditionalRecipients(DSConfiguration config, Session session, User user) { + super(config, "eg034", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + if (Utils.isCfr(session.getBasePath(), user.getAccessToken(), session.getAccountId())) { + session.setStatusCFR("enabled"); + throw new Exception(config.getCodeExamplesText().getSupportingTexts().getCFRError()); + } + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) + throws ApiException, IOException { + // Step 2: Construct your API headers + EnvelopesApi envelopesApi = createEnvelopesApi(this.session.getBasePath(), this.user.getAccessToken()); + + // Step 3: Construct your envelope JSON body + //ds-snippet-start:eSign34Step3 + EnvelopeDefinition envelope = UseConditionalRecipientsService.createEnvelope( + args.getSignerNotCheckedName(), + args.getSignerNotCheckedEmail(), + args.getSignerCheckedName(), + args.getSignerCheckedEmail(), + args.getSignerName(), + args.getSignerEmail() + ); + //ds-snippet-end:eSign34Step3 + + // Step 4: Call the eSignature REST API + try { + EnvelopeSummary envelopeSummary = UseConditionalRecipientsService.useConditionalRecipients( + envelopesApi, + this.session.getAccountId(), + envelope + ); + + this.session.setEnvelopeId(envelopeSummary.getEnvelopeId()); + DoneExample.createDefault(this.title) + .withJsonObject(envelopeSummary) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", this.session.getEnvelopeId())) + .addToModel(model, config); + } catch (ApiException apiException) { + if (!apiException.getMessage().contains(getTextForCodeExampleByApiType().CustomErrorTexts.get(0).ErrorMessageCheck)) { + throw apiException; + } + DoneExample.createDefault(this.title) + .withMessage(getTextForCodeExampleByApiType().CustomErrorTexts.get(0).ErrorMessage) + .addToModel(model, config); + } + + return DONE_EXAMPLE_PAGE; + } +} \ No newline at end of file diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG035ControllerScheduledSending.java b/src/main/java/com/docusign/controller/eSignature/examples/EG035ControllerScheduledSending.java new file mode 100644 index 00000000..39771c68 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG035ControllerScheduledSending.java @@ -0,0 +1,80 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.ScheduledSendlingService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Map; + +/** + * Send an envelope with a remote (email) signer and cc recipient.
+ * The envelope includes a pdf, Word, and HTML document. Anchor text is used to + * position the signing fields in the documents. + */ +@Controller +@RequestMapping("/eg035") +public class EG035ControllerScheduledSending extends AbstractEsignatureController { + + public EG035ControllerScheduledSending(DSConfiguration config, Session session, User user) { + super(config, "eg035", session, user); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException, IOException { + // Set status for the makeEnvelope method + if (!EnvelopeHelpers.ENVELOPE_STATUS_CREATED.equalsIgnoreCase(args.getStatus())) { + args.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + } + + EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); + EnvelopeDefinition envelope = ScheduledSendlingService.makeEnvelope( + args.getSignerEmail(), + args.getSignerName(), + args.getResumeDate(), + args.getStatus()); + + // Step 3 start + //ds-snippet-start:eSign35Step3 + var results = envelopesApi.createEnvelopeWithHttpInfo( + session.getAccountId(), + envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = results.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + //ds-snippet-end:eSign35Step3 + // Step 3 end + + // process results + session.setEnvelopeId(results.getData().getEnvelopeId()); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", results.getData().getEnvelopeId())) + .withJsonObject(results) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG036ControllerDelayedRouting.java b/src/main/java/com/docusign/controller/eSignature/examples/EG036ControllerDelayedRouting.java new file mode 100644 index 00000000..c43845fb --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG036ControllerDelayedRouting.java @@ -0,0 +1,89 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.DelayedRoutingService; +import com.docusign.core.common.Utils; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Map; + +/** + * Send an envelope with a remote (email) signer and cc recipient.
+ * The envelope includes a pdf, Word, and HTML document. Anchor text is used to + * position the signing fields in the documents. + */ +@Controller +@RequestMapping("/eg036") +public class EG036ControllerDelayedRouting extends AbstractEsignatureController { + + public EG036ControllerDelayedRouting(DSConfiguration config, Session session, User user) { + super(config, "eg036", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + if (Utils.isCfr(session.getBasePath(), user.getAccessToken(), session.getAccountId())) { + session.setStatusCFR("enabled"); + throw new Exception(config.getCodeExamplesText().getSupportingTexts().getCFRError()); + } + super.onInitModel(args, model); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException, IOException { + // Set status for the makeEnvelope method + if (!EnvelopeHelpers.ENVELOPE_STATUS_CREATED.equalsIgnoreCase(args.getStatus())) { + args.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + } + + EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); + + EnvelopeDefinition envelope = DelayedRoutingService.makeEnvelope( + args.getSignerName(), + args.getSignerEmail(), + args.getSignerName2(), + args.getSignerEmail2(), + args.getDelay(), + args.getStatus()); + + //ds-snippet-start:eSign36Step3 + var results = envelopesApi.createEnvelopeWithHttpInfo( + session.getAccountId(), + envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = results.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + //ds-snippet-end:eSign36Step3 + + // process results + session.setEnvelopeId(results.getData().getEnvelopeId()); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", results.getData().getEnvelopeId())) + .withJsonObject(results) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG037ControllerSMSDelivery.java b/src/main/java/com/docusign/controller/eSignature/examples/EG037ControllerSMSDelivery.java new file mode 100644 index 00000000..b694cc62 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG037ControllerSMSDelivery.java @@ -0,0 +1,79 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.SMSDeliveryService; +import com.docusign.core.common.Utils; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Send an envelope with a remote (email) signer and cc recipient.
+ * The envelope includes a pdf, Word, and HTML document. Anchor text is used to + * position the signing fields in the documents. + */ +@Controller +@RequestMapping("/eg037") +public class EG037ControllerSMSDelivery extends AbstractEsignatureController { + + public EG037ControllerSMSDelivery(DSConfiguration config, Session session, User user) { + super(config, "eg037", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + if (Utils.isCfr(session.getBasePath(), user.getAccessToken(), session.getAccountId())) { + session.setStatusCFR("enabled"); + throw new Exception(config.getCodeExamplesText().getSupportingTexts().getCFRError()); + } + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException, IOException { + // Set status for the makeEnvelope method + if (!EnvelopeHelpers.ENVELOPE_STATUS_CREATED.equalsIgnoreCase(args.getStatus())) { + args.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + } + + EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); + + EnvelopeDefinition envelope = SMSDeliveryService.makeEnvelope( + args.getCountryCode(), + args.getPhoneNumber(), + args.getSignerName(), + args.getDeliveryMethod(), + args.getCcCountryCode(), + args.getCcPhoneNumber(), + args.getCcName(), + args.getStatus() + ); + EnvelopeSummary envelopeSummary = SMSDeliveryService.smsDelivery( + envelopesApi, + session.getAccountId(), + envelope + ); + + // process results + session.setEnvelopeId(envelopeSummary.getEnvelopeId()); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", envelopeSummary.getEnvelopeId()) + ) + .withJsonObject(envelopeSummary) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG038ControllerResponsiveSigning.java b/src/main/java/com/docusign/controller/eSignature/examples/EG038ControllerResponsiveSigning.java new file mode 100644 index 00000000..b6138b2d --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG038ControllerResponsiveSigning.java @@ -0,0 +1,106 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.ResponsiveSigningService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import com.docusign.esign.model.RecipientViewRequest; +import com.docusign.esign.model.ViewUrl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.view.RedirectView; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Map; + +@Controller +@RequestMapping("/eg038") +public class EG038ControllerResponsiveSigning extends AbstractEsignatureController { + + private static final Logger log = LoggerFactory.getLogger(EG038ControllerResponsiveSigning.class); + + private static final String SIGNER_CLIENT_ID = "1000"; + + private static final String FEATURE_WAS_DISABLED = "Please enable this feature in the developer account and try again."; + + public EG038ControllerResponsiveSigning(DSConfiguration config, Session session, User user) { + super(config, "eg038", session, user); + } + + @Override + //ds-snippet-start:eSign38Step3 + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException, IOException { + String signerName = args.getSignerName(); + String signerEmail = args.getSignerEmail(); + String ccName = args.getCcName(); + String ccEmail = args.getCcEmail(); + String accountId = session.getAccountId(); + ViewUrl viewUrl = null; + + EnvelopeDefinition envelope = ResponsiveSigningService.makeEnvelope( + signerEmail, + signerName, + SIGNER_CLIENT_ID, + ccEmail, + ccName, + args); + + ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); + EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); + + try { + var envelopeSummary = envelopesApi.createEnvelopeWithHttpInfo( + accountId, + envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = envelopeSummary.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + String envelopeId = envelopeSummary.getData().getEnvelopeId(); + + RecipientViewRequest viewRequest = ResponsiveSigningService.makeRecipientViewRequest( + signerEmail, + signerName, + config, + SIGNER_CLIENT_ID); + + viewUrl = ResponsiveSigningService.responsiveSigning( + envelopesApi, + accountId, + envelopeId, + viewRequest); + + } catch (ApiException apiException) { + log.error(apiException.getMessage()); + DoneExample.createDefault(this.title) + .withMessage("Feature Not Enabled") + .withFixingInstructions(FEATURE_WAS_DISABLED) + .addToModel(model, config); + return ERROR_PAGE; + } + + return new RedirectView(viewUrl.getUrl()); + } + //ds-snippet-end:eSign38Step3 +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG039ControllerInPersonSigning.java b/src/main/java/com/docusign/controller/eSignature/examples/EG039ControllerInPersonSigning.java new file mode 100644 index 00000000..9d6da6de --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG039ControllerInPersonSigning.java @@ -0,0 +1,95 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.InPersonSigningService; +import com.docusign.core.common.Utils; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import com.docusign.esign.model.RecipientViewRequest; +import com.docusign.esign.model.ViewUrl; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.view.RedirectView; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Map; + +@Controller +@RequestMapping("/eg039") +public class EG039ControllerInPersonSigning extends AbstractEsignatureController { + private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String DOCUMENT_NAME = "Lorem Ipsum"; + + private static final int ANCHOR_OFFSET_Y = 10; + + private static final int ANCHOR_OFFSET_X = 20; + + public EG039ControllerInPersonSigning(DSConfiguration config, Session session, User user) { + super(config, "eg039", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + if (Utils.isCfr(session.getBasePath(), user.getAccessToken(), session.getAccountId())) { + session.setStatusCFR("enabled"); + throw new Exception(config.getCodeExamplesText().getSupportingTexts().getCFRError()); + } + super.onInitModel(args, model); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException, IOException { + String basePath = session.getBasePath(); + String accessToken = user.getAccessToken(); + + String hostName = getAuthenticatedUserName(basePath, accessToken); + String hostEmail = getAuthenticatedUserEmail(basePath, accessToken); + String signerName = args.getSignerName(); + String accountId = session.getAccountId(); + + EnvelopeDefinition envelope = InPersonSigningService.makeEnvelope(hostEmail, hostName, signerName, + ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X, DOCUMENT_FILE_NAME, DOCUMENT_NAME); + + //ds-snippet-start:eSign39Step3 + ApiClient apiClient = createApiClient(basePath, accessToken); + EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); + + var envelopeSummary = envelopesApi.createEnvelopeWithHttpInfo( + accountId, + envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = envelopeSummary.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + //ds-snippet-end:eSign39Step3 + //ds-snippet-start:eSign39Step5 + RecipientViewRequest viewRequest = InPersonSigningService.makeRecipientViewRequest(hostEmail, hostName, config); + //ds-snippet-end:eSign39Step5 + + ViewUrl viewUrl = InPersonSigningService.inPersonSigning( + envelopesApi, + accountId, + envelopeSummary.getData().getEnvelopeId(), + viewRequest); + + return new RedirectView(viewUrl.getUrl()); + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG040ControllerSetDocumentVisibility.java b/src/main/java/com/docusign/controller/eSignature/examples/EG040ControllerSetDocumentVisibility.java new file mode 100644 index 00000000..eb9f1edc --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG040ControllerSetDocumentVisibility.java @@ -0,0 +1,101 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.SetDocumentVisibilityService; +import com.docusign.core.common.Utils; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Map; + +@Controller +@RequestMapping("/eg040") +public class EG040ControllerSetDocumentVisibility extends AbstractEsignatureController { + private static final String DOCUMENT_FILE_NAME_PDF = "World_Wide_Corp_lorem.pdf"; + + private static final String DOCUMENT_FILE_NAME_DOCX = "World_Wide_Corp_Battle_Plan_Trafalgar.docx"; + + private static final String DOCUMENT_FILE_NAME_HTML = "doc_1.html"; + + private static final String CASE_FOR_INSTRUCTIONS = "ACCOUNT_LACKS_PERMISSIONS"; + + private static final String FIXING_INSTRUCTIONS_FOR_PERMISSIONS = "See " + + "" + + "How to set document visibility for envelope recipients in the Docusign Developer Center " + + "for instructions on how to enable document visibility in your developer account."; + + public EG040ControllerSetDocumentVisibility(DSConfiguration config, Session session, User user) { + super(config, "eg040", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + if (Utils.isCfr(session.getBasePath(), user.getAccessToken(), session.getAccountId())) { + session.setStatusCFR("enabled"); + throw new Exception(config.getCodeExamplesText().getSupportingTexts().getCFRError()); + } + super.onInitModel(args, model); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException, IOException { + model.addAttribute("fixingInstructions", FIXING_INSTRUCTIONS_FOR_PERMISSIONS); + model.addAttribute("caseForInstructions", CASE_FOR_INSTRUCTIONS); + + String basePath = session.getBasePath(); + String accessToken = user.getAccessToken(); + + String signerName = args.getSignerName(); + String signerEmail = args.getSignerEmail(); + String signer2Name = args.getSignerName2(); + String signer2Email = args.getSignerEmail2(); + String ccName = args.getCcName(); + String ccEmail = args.getCcEmail(); + String accountId = session.getAccountId(); + + EnvelopeDefinition envelope = SetDocumentVisibilityService.makeEnvelope(signerEmail, signerName, signer2Email, + signer2Name, ccEmail, ccName, DOCUMENT_FILE_NAME_PDF, DOCUMENT_FILE_NAME_DOCX, DOCUMENT_FILE_NAME_HTML); + + //ds-snippet-start:eSign40Step2 + ApiClient apiClient = createApiClient(basePath, accessToken); + EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); + //ds-snippet-end:eSign40Step2 + + //ds-snippet-start:eSign40Step4 + var envelopeSummary = envelopesApi.createEnvelopeWithHttpInfo( + accountId, + envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = envelopeSummary.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + //ds-snippet-end:eSign40Step4 + + DoneExample.createDefault(title) + .withMessage("The envelope has been created and sent!
Envelope ID " + + envelopeSummary.getData().getEnvelopeId() + ".") + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG041ControllerCfrEmbeddedSigning.java b/src/main/java/com/docusign/controller/eSignature/examples/EG041ControllerCfrEmbeddedSigning.java new file mode 100644 index 00000000..f6d046f6 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG041ControllerCfrEmbeddedSigning.java @@ -0,0 +1,150 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.CfrEmbeddedSigningService; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.AccountIdentityVerificationResponse; +import com.docusign.esign.model.AccountIdentityVerificationWorkflow; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import com.docusign.esign.model.RecipientViewRequest; +import com.docusign.esign.model.ViewUrl; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.view.RedirectView; + +import javax.servlet.http.HttpServletResponse; + + +/** + * Use embedded signing.
+ * This example sends an envelope, and then uses embedded signing + * for the first signer. Embedded signing provides a smoother user experience + * for the signer: the DocuSign signing is initiated from your site. + */ +@Controller +@RequestMapping("/eg041") +public class EG041ControllerCfrEmbeddedSigning extends AbstractEsignatureController { + + private static final Logger LOGGER = LoggerFactory.getLogger(EG023ControllerIdvAuthentication.class); + + private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String DOCUMENT_NAME = "Lorem Ipsum"; + + private static final int ANCHOR_OFFSET_Y = -30; + + private static final int ANCHOR_OFFSET_X = 10; + + public EG041ControllerCfrEmbeddedSigning(DSConfiguration config, Session session, User user) { + super(config, "eg041", session, user); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws Exception { + String signerName = args.getSignerName(); + String signerEmail = args.getSignerEmail(); + String signerClientId = args.getSignerEmail(); + String countryCode = args.getCountryCode(); + String phoneNumber = args.getPhoneNumber(); + String accountId = session.getAccountId(); + + //ds-snippet-start:eSign41Step2 + ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); + + AccountsApi workflowDetails = new AccountsApi(apiClient); + var workflowRes = workflowDetails.getAccountIdentityVerificationWithHttpInfo(session.getAccountId(), workflowDetails.new GetAccountIdentityVerificationOptions()); + Map> headers = workflowRes.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + List identityVerification = workflowRes.getData().getIdentityVerification(); + String workflowId = ""; + for (int i = 0; i < identityVerification.size(); i++) { + if (identityVerification.get(i).getDefaultName().equals("SMS for access & signatures")) { + workflowId = identityVerification.get(i).getWorkflowId(); + } + } + //ds-snippet-end:eSign41Step2 + LOGGER.info("workflowId = " + workflowId); + if (workflowId.isEmpty()) { + throw new ApiException("Workflow ID is empty."); + } + + // Create the envelope definition + //ds-snippet-start:eSign41Step4 + EnvelopeDefinition envelope = CfrEmbeddedSigningService.makeEnvelope( + signerName, + signerEmail, + countryCode, + phoneNumber, + workflowId, + signerClientId, + ANCHOR_OFFSET_Y, + ANCHOR_OFFSET_X, + DOCUMENT_FILE_NAME, + DOCUMENT_NAME); + + // Call DocuSign to create the envelope + EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); + var envelopeSummary = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, envelopesApi.new CreateEnvelopeOptions()); + headers = envelopeSummary.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + String envelopeId = envelopeSummary.getData().getEnvelopeId(); + //ds-snippet-end:eSign41Step4 + + session.setEnvelopeId(envelopeId); + + // create the recipient view, the embedded signing + //ds-snippet-start:eSign41Step5 + RecipientViewRequest viewRequest = CfrEmbeddedSigningService.makeRecipientViewRequest( + signerEmail, + signerName, + config, + signerClientId); + + //ds-snippet-end:eSign41Step5 + + //ds-snippet-start:eSign41Step6 + ViewUrl viewUrl = CfrEmbeddedSigningService.embeddedSigning( + envelopesApi, + accountId, + envelopeId, + viewRequest + ); + //ds-snippet-end:eSign41Step6 + + // Step 4. Redirect the user to the embedded signing + // Don't use an iFrame! + // State can be stored/recovered using the framework's session or a + // query parameter on the returnUrl (see the makeRecipientViewRequest method) + return new RedirectView(viewUrl.getUrl()); + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG042ControllerDocumentGeneration.java b/src/main/java/com/docusign/controller/eSignature/examples/EG042ControllerDocumentGeneration.java new file mode 100644 index 00000000..3750cc03 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG042ControllerDocumentGeneration.java @@ -0,0 +1,59 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.DocumentGenerationService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.api.TemplatesApi; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +import static com.docusign.controller.eSignature.examples.EG042ControllerDocumentGeneration.EG_042; + +@Controller +@RequestMapping(EG_042) +public class EG042ControllerDocumentGeneration extends AbstractEsignatureController { + public static final String EG_042 = "/eg042"; + + private static final String DOCUMENT_FILE_NAME = "Offer_Letter_Dynamic_Table.docx"; + + public EG042ControllerDocumentGeneration(DSConfiguration config, Session session, User user) { + super(config, EG_042, session, user); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws Exception { + String basePath = session.getBasePath(); + String accessToken = user.getAccessToken(); + + EnvelopesApi envelopesApi = createEnvelopesApi(basePath, accessToken); + TemplatesApi templatesApi = createTemplatesApi(basePath, accessToken); + + String envelopeId = (new DocumentGenerationService()).generateDocument( + session.getAccountId(), + args.getCandidateEmail(), + args.getCandidateName(), + args.getManagerName(), + args.getJobTitle(), + args.getSalary(), + args.getRsus(), + args.getStartDate(), + DOCUMENT_FILE_NAME, + envelopesApi, + templatesApi); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", envelopeId) + ) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG043ControllerSharedAccess.java b/src/main/java/com/docusign/controller/eSignature/examples/EG043ControllerSharedAccess.java new file mode 100644 index 00000000..cadbb2ab --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG043ControllerSharedAccess.java @@ -0,0 +1,160 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.SharedAccessService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.api.UsersApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.client.auth.OAuth; +import com.docusign.esign.model.EnvelopesInformation; +import com.docusign.esign.model.NewUsersSummary; +import com.docusign.esign.model.UserInformation; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +import static com.docusign.controller.eSignature.examples.EG043ControllerSharedAccess.EG_043; + +@Controller +@RequestMapping(EG_043) +public class EG043ControllerSharedAccess extends AbstractEsignatureController { + public static final String EG_043 = "/eg043"; + + public static final String ACTIVATE_USER = "/activateUser"; + + public static final String LOGOUT = "/logout"; + + public static final String LIST_ENVELOPES = "/listEnvelopes"; + + public static final String ACT_ON_BEHALF = "X-DocuSign-Act-On-Behalf"; + + public static final String HOME_PAGE = "/"; + + public static final int AGENT_AUTHENTICATION_SUCCESSFULL = 0; + + public static final int AGENT_WAS_NOT_ACTIVATED = 3; + + public static final int NO_ENVELOPES_IN_USER_ACCOUNT = 2; + + public static final int ENVELOPES_MOVED_TO_ACCOUNT = 1; + + public EG043ControllerSharedAccess(DSConfiguration config, Session session, User user) { + super(config, EG_043, session, user); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws Exception { + String basePath = session.getBasePath(); + String accessToken = user.getAccessToken(); + + UsersApi usersApi = createUsersApi(basePath, accessToken); + + UserInformation userInformation = (new SharedAccessService()).getUserInfo( + usersApi, + session.getAccountId(), + args.getAgentEmail() + ); + + if (userInformation == null) { + NewUsersSummary usersSummary = (new SharedAccessService()).createAgent( + usersApi, + session.getAccountId(), + args.getAgentEmail(), + args.getAgentName(), + args.getActivationCode()); + + this.session.setCreatedUserId(usersSummary.getNewUsers().get(0).getUserId()); + + DoneExample.createDefault("Agent user created") + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(usersSummary) + .withRedirect(EG_043 + ACTIVATE_USER) + .addToModel(model, config); + } else { + this.session.setCreatedUserId(userInformation.getUserId()); + + DoneExample.createDefault("Agent user created") + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(userInformation) + .withRedirect(EG_043 + ACTIVATE_USER) + .addToModel(model, config); + } + + return DONE_EXAMPLE_PAGE; + } + + @GetMapping(value = ACTIVATE_USER, produces = MediaType.APPLICATION_JSON_VALUE) + public String activateUser(ModelMap model) { + String basePath = session.getBasePath(); + String accessToken = user.getAccessToken(); + + AccountsApi accountsApi = createAccountsApi(basePath, accessToken); + + try { + OAuth.UserInfo user = getCurrentUserInfo(basePath, accessToken); + String userId = user.getSub(); + + (new SharedAccessService()).activateAgent( + accountsApi, + session.getAccountId(), + userId, + session.getCreatedUserId()); + + this.config.setPrincipalUserId(userId); + this.config.setShareAccessExampleScenario(true); + this.config.setAdditionalRedirect(true); + + DoneExample.createDefault("Authenticate as the agent") + .withMessage(getTextForCodeExampleByApiType().getAdditionalPage().get(AGENT_AUTHENTICATION_SUCCESSFULL).ResultsPageText) + .withRedirect(LOGOUT) + .addToModel(model, config); + } catch (ApiException exception) { + DoneExample.createDefault("Authenticate as the agent") + .withMessage(getTextForCodeExampleByApiType().getAdditionalPage().get(AGENT_WAS_NOT_ACTIVATED).ResultsPageText) + .withRedirect(EG_043 + ACTIVATE_USER) + .addToModel(model, config); + } + + return DONE_EXAMPLE_PAGE; + } + + @GetMapping(value = LIST_ENVELOPES, produces = MediaType.APPLICATION_JSON_VALUE) + public String listEnvelopes(ModelMap model) throws ApiException { + String basePath = session.getBasePath(); + String accessToken = user.getAccessToken(); + + ApiClient apiClient = createApiClient(basePath, accessToken); + apiClient.addDefaultHeader(ACT_ON_BEHALF, this.config.getPrincipalUserId()); + EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); + + EnvelopesInformation envelopesInformation = (new SharedAccessService()).getEnvelopeInfo( + envelopesApi, + session.getAccountId()); + + if (envelopesInformation.getEnvelopes() == null || envelopesInformation.getEnvelopes().isEmpty()) { + DoneExample.createDefault("No envelopes in the principal user's account") + .withMessage(getTextForCodeExampleByApiType().getAdditionalPage().get(NO_ENVELOPES_IN_USER_ACCOUNT).ResultsPageText) + .withRedirect(HOME_PAGE) + .addToModel(model, config); + } else { + DoneExample.createDefault("Principal's envelopes visible in the agent's Shared Access UI") + .withMessage(getTextForCodeExampleByApiType().getAdditionalPage().get(ENVELOPES_MOVED_TO_ACCOUNT).ResultsPageText) + .withJson(envelopesInformation.toString()) + .withRedirect(HOME_PAGE) + .addToModel(model, config); + } + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG044ControllerFocusedView.java b/src/main/java/com/docusign/controller/eSignature/examples/EG044ControllerFocusedView.java new file mode 100644 index 00000000..e714bd43 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG044ControllerFocusedView.java @@ -0,0 +1,78 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.FocusedViewService; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.client.ApiClient; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + + +/** + * Used to generate an envelope and allow user to sign it directly from the app without having to open an email. + */ +@Controller +@RequestMapping("/eg044") +public class EG044ControllerFocusedView extends AbstractEsignatureController { + public static final String EMBED = "pages/esignature/examples/embed"; + + public static final String INTEGRATION_KEY = "integrationKey"; + + public static final String URL = "url"; + + public static final String ENVELOPE_ID = "envelopeId"; + + public static final String DOCUMENTATION = "documentation"; + + public EG044ControllerFocusedView(DSConfiguration config, Session session, User user){ + super(config, "eg044", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + } + + @Override + protected Object doWork( + WorkArguments args, + ModelMap model, + HttpServletResponse response + ) throws Exception { + String signerName = args.getSignerName(); + String signerEmail = args.getSignerEmail(); + String phoneNumber = args.getPhoneNumber(); + String countryCode = args.getCountryCode(); + String accountId = session.getAccountId(); + + // Call DocuSign to create the envelope + ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); + + // Call the method from Examples API to send envelope and generate url for focused view signing + String[] envelopeIdAndRedirectUrl = new FocusedViewService().sendEnvelopeWithFocusedView( + signerEmail, + signerName, + phoneNumber, + countryCode, + apiClient, + accountId, + config.getDsReturnUrl()); + + if(envelopeIdAndRedirectUrl.length == 2){ + model.addAttribute(ENVELOPE_ID, envelopeIdAndRedirectUrl[0]); + model.addAttribute(URL, envelopeIdAndRedirectUrl[1]); + } + + model.addAttribute(DOCUMENTATION, config.getDocumentationPath() + exampleName); + model.addAttribute(LAUNCHER_TEXTS, config.getCodeExamplesText().SupportingTexts); + model.addAttribute(INTEGRATION_KEY, config.getUserId()); + + return EMBED; + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG045ControllerDeleteRestoreEnvelope.java b/src/main/java/com/docusign/controller/eSignature/examples/EG045ControllerDeleteRestoreEnvelope.java new file mode 100644 index 00000000..926d3516 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG045ControllerDeleteRestoreEnvelope.java @@ -0,0 +1,131 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.DeleteRestoreEnvelopeService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.model.Folder; +import com.docusign.esign.model.FoldersResponse; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.text.MessageFormat; + +/** + * Used to delete the envelope and restore it back. + */ +@Controller +@RequestMapping("/eg045") +public class EG045ControllerDeleteRestoreEnvelope extends AbstractEsignatureController { + public static final String RECYCLE_BIN_FOLDER_ID = "recyclebin"; + + public static final String SENT_ITEMS_FOLDER_NAME = "Sent items"; + + public static final String EXAMPLE_NUMBER = "/eg045"; + + public static final String RESTORE_ENVELOPE = "/restoreEnvelope"; + + public static final String RESTORE_ENVELOPE_PAGE = "pages/esignature/examples/eg045RestoreEnvelope"; + + public EG045ControllerDeleteRestoreEnvelope(DSConfiguration config, Session session, User user) { + super(config, "eg045", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + model.addAttribute("envelopeId", session.getEnvelopeId()); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws Exception { + String envelopeId = args.getEnvelopeId(); + session.setEnvelopeId(envelopeId); + //ds-snippet-start:eSign45Step2 + ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); + //ds-snippet-end:eSign45Step2 + DeleteRestoreEnvelopeService.deleteEnvelope( + apiClient, + session.getAccountId(), + envelopeId); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage( + MessageFormat.format( + getTextForCodeExampleByApiType().AdditionalPage + .get(0).ResultsPageText, + envelopeId)) + .withRedirect(EXAMPLE_NUMBER + RESTORE_ENVELOPE) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } + + @GetMapping(value = RESTORE_ENVELOPE, produces = MediaType.APPLICATION_JSON_VALUE) + public String getRestoreEnvelope(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + + String envelopeId = session.getEnvelopeId(); + String restoreEnvelopeText = MessageFormat.format( + config.getCodeExamplesText().SupportingTexts.HelpingTexts.EnvelopeWillBeRestored, + envelopeId); + + model.addAttribute("restoreText", restoreEnvelopeText); + model.addAttribute("envelopeId", envelopeId); + + return RESTORE_ENVELOPE_PAGE; + } + + @PostMapping(value = RESTORE_ENVELOPE, produces = MediaType.APPLICATION_JSON_VALUE) + public String postRestoreEnvelope(WorkArguments args, ModelMap model) throws Exception { + String envelopeId = session.getEnvelopeId(); + String accountId = session.getAccountId(); + String folderName = args.getFolderName() != null ? args.getFolderName() : SENT_ITEMS_FOLDER_NAME; + + ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); + + FoldersResponse availableFolders = DeleteRestoreEnvelopeService.getFolders(apiClient, accountId); + Folder folder = DeleteRestoreEnvelopeService.getFolderIdByName(availableFolders.getFolders(), + folderName); + + if (folder == null) { + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage( + MessageFormat.format( + getTextForCodeExampleByApiType().AdditionalPage + .get(1).ResultsPageText, + folderName)) + .withRedirect(EXAMPLE_NUMBER + RESTORE_ENVELOPE) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } + + DeleteRestoreEnvelopeService.moveEnvelopeToFolder( + apiClient, + accountId, + envelopeId, + folder.getFolderId(), + RECYCLE_BIN_FOLDER_ID); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage( + MessageFormat.format( + getTextForCodeExampleByApiType().ResultsPageText, + envelopeId, + folder.getType(), + folderName)) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/examples/EG046ControllerMultipleDelivery.java b/src/main/java/com/docusign/controller/eSignature/examples/EG046ControllerMultipleDelivery.java new file mode 100644 index 00000000..8d4ddd8d --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/examples/EG046ControllerMultipleDelivery.java @@ -0,0 +1,87 @@ +package com.docusign.controller.eSignature.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.MultipleDeliveryService; +import com.docusign.controller.eSignature.services.SMSDeliveryService; +import com.docusign.core.common.Utils; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; + +/** + * Send an envelope with a remote signer and cc recipient o be notified via multiple + * delivery channels (Email and SMS or WhatsApp).
+ * The envelope includes a pdf, Word, and HTML document. Anchor text is used to + * position the signing fields in the documents. + */ +@Controller +@RequestMapping("/eg046") +public class EG046ControllerMultipleDelivery extends AbstractEsignatureController { + + public EG046ControllerMultipleDelivery(DSConfiguration config, Session session, User user) { + super(config, "eg046", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + if (Utils.isCfr(session.getBasePath(), user.getAccessToken(), session.getAccountId())) { + session.setStatusCFR("enabled"); + throw new Exception(config.getCodeExamplesText().getSupportingTexts().getCFRError()); + } + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws ApiException, IOException { + args.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); + + try{ + EnvelopeDefinition envelope = MultipleDeliveryService.makeEnvelope( + args.getSignerName(), + args.getSignerEmail(), + args.getCountryCode(), + args.getPhoneNumber(), + args.getCcName(), + args.getCcEmail(), + args.getCcCountryCode(), + args.getCcPhoneNumber(), + args.getDeliveryMethod(), + args.getStatus()); + + EnvelopeSummary envelopeSummary = SMSDeliveryService.smsDelivery( + envelopesApi, + session.getAccountId(), + envelope); + + session.setEnvelopeId(envelopeSummary.getEnvelopeId()); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", envelopeSummary.getEnvelopeId()) + ) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } catch (ApiException e) { + new DoneExample() + .withTitle(exampleName) + .withName(title) + .withFixingInstructions(getTextForCodeExampleByApiType().CustomErrorTexts.get(0).ErrorMessage) + .addToModel(model, config); + + return ERROR_PAGE; + } + } +} diff --git a/src/main/java/com/docusign/controller/examples/EnvelopeHelpers.java b/src/main/java/com/docusign/controller/eSignature/examples/EnvelopeHelpers.java similarity index 61% rename from src/main/java/com/docusign/controller/examples/EnvelopeHelpers.java rename to src/main/java/com/docusign/controller/eSignature/examples/EnvelopeHelpers.java index 4961b596..7bb9f871 100644 --- a/src/main/java/com/docusign/controller/examples/EnvelopeHelpers.java +++ b/src/main/java/com/docusign/controller/eSignature/examples/EnvelopeHelpers.java @@ -1,28 +1,17 @@ -package com.docusign.controller.examples; - -import java.io.IOException; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Base64; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; +package com.docusign.controller.eSignature.examples; +import com.docusign.esign.model.*; +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateException; import org.apache.commons.io.FilenameUtils; import org.springframework.core.io.ClassPathResource; import org.springframework.util.StreamUtils; -import com.docusign.esign.model.CarbonCopy; -import com.docusign.esign.model.Document; -import com.docusign.esign.model.Recipients; -import com.docusign.esign.model.SignHere; -import com.docusign.esign.model.Signer; -import com.docusign.esign.model.Tabs; - -import freemarker.template.Configuration; -import freemarker.template.Template; -import freemarker.template.TemplateException; +import java.io.IOException; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.util.*; /** @@ -31,22 +20,35 @@ public final class EnvelopeHelpers { public static final String ENVELOPE_STATUS_SENT = "sent"; + public static final String ENVELOPE_STATUS_CREATED = "created"; + public static final String SIGNER_STATUS_CREATED = "Created"; + public static final String DELIVERY_METHOD_EMAIL = "Email"; + public static final String SIGNER_ROLE_NAME = "signer"; + public static final String CC_ROLE_NAME = "cc"; + public static final String WORKFLOW_STEP_ACTION_PAUSE = "pause_before"; + + public static final String WORKFLOW_TRIGGER_ROUTING_ORDER = "routing_order"; + + public static final String WORKFLOW_STATUS_IN_PROGRESS = "in_progress"; + - private EnvelopeHelpers() {} + private EnvelopeHelpers() { + } /** * Loads a file content and copy it into a byte array. + * * @param path the absolute path within the class path * @return the new byte array that has been loaded from the file * @throws IOException in case of I/O errors */ - static byte[] readFile(String path) throws IOException { + public static byte[] readFile(String path) throws IOException { ClassPathResource resource = new ClassPathResource(path); return StreamUtils.copyToByteArray(resource.getInputStream()); } @@ -56,6 +58,7 @@ static byte[] readFile(String path) throws IOException { * wherever and it is used when it is needed to generate the html document. * Html document is generated by the method. * {@link #createHtmlFromTemplate(Template, String, Object)} + * * @param path the path to template file * @return a {@link Template} object * @throws IOException in case of I/O errors @@ -72,19 +75,20 @@ static Template loadHtmlTemplate(String path) throws IOException { /** * Generates a html document from the template. Placeholder looks like * ${objectName.fieldName} - * @param template the template object + * + * @param template the template object * @param objectName name of object to find placeholder related to a value - * @param value object which fields are used as a values in the template + * @param value object which fields are used as a values in the template * @return array of bytes representing created html document * @throws IOException in case of template parsing error */ - static byte[] createHtmlFromTemplate(Template template, String objectName, Object value) throws IOException { + static String createHtmlFromTemplate(Template template, String objectName, Object value) throws IOException { Map input = new HashMap<>(); input.put(objectName, value); StringWriter stringWriter = new StringWriter(); try { template.process(input, stringWriter); - return stringWriter.toString().getBytes(StandardCharsets.UTF_8); + return stringWriter.toString(); } catch (TemplateException exception) { throw new ExampleException("Can't process html template " + template.getName(), exception); } @@ -95,13 +99,31 @@ static byte[] createHtmlFromTemplate(Template template, String objectName, Objec * ${objectName.fieldName}. It is a convenient method which loads template * from a file using {@link #loadHtmlTemplate(String)} and creates a html * page from the loaded template using {@link #createHtmlFromTemplate(Template, String, Object)} - * @param path the path to template file + * + * @param path the path to template file + * @param objectName name of object to find placeholder related to a value + * @param value object which fields are used as a values in the template + * @return array of bytes representing created html document + * @throws IOException in case of I/O errors or template parsing error + */ + public static byte[] createHtmlFromTemplateFileInByte(String path, String objectName, Object value) throws IOException { + Template template = loadHtmlTemplate(path); + return createHtmlFromTemplate(template, objectName, value).getBytes(StandardCharsets.UTF_8); + } + + /** + * Generates a html document from the template file. Placeholder looks like + * ${objectName.fieldName}. It is a convenient method which loads template + * from a file using {@link #loadHtmlTemplate(String)} and creates a html + * page from the loaded template using {@link #createHtmlFromTemplate(Template, String, Object)} + * + * @param path the path to template file * @param objectName name of object to find placeholder related to a value - * @param value object which fields are used as a values in the template + * @param value object which fields are used as a values in the template * @return array of bytes representing created html document * @throws IOException in case of I/O errors or template parsing error */ - static byte[] createHtmlFromTemplateFile(String path, String objectName, Object value) throws IOException { + public static String createHtmlFromTemplateFile(String path, String objectName, Object value) throws IOException { Template template = loadHtmlTemplate(path); return createHtmlFromTemplate(template, objectName, value); } @@ -109,14 +131,15 @@ static byte[] createHtmlFromTemplateFile(String path, String objectName, Object /** * Loads document from a file and creates a document object that represents * loaded document. + * * @param fileName name of the file to load document; the extension of the - * loading file determines an extension of the created document - * @param docName the name of the document; it may be differ from the file - * @param docId identifier of the created document + * loading file determines an extension of the created document + * @param docName the name of the document; it may be differ from the file + * @param docId identifier of the created document * @return the {@link Document} object * @throws IOException if document cannot be loaded due to some reason */ - static Document createDocumentFromFile(String fileName, String docName, String docId) throws IOException { + public static Document createDocumentFromFile(String fileName, String docName, String docId) throws IOException { byte[] buffer = readFile(fileName); String extention = FilenameUtils.getExtension(fileName); return createDocument(buffer, docName, extention, docId); @@ -124,13 +147,14 @@ static Document createDocumentFromFile(String fileName, String docName, String d /** * Creates a document object from the raw data. - * @param data the raw data - * @param documentName the name of the document; it may be differ from the file + * + * @param data the raw data + * @param documentName the name of the document; it may be differ from the file * @param fileExtention the extension of the creating file - * @param documentId identifier of the created document + * @param documentId identifier of the created document * @return the {@link Document} object */ - static Document createDocument(byte[] data, String documentName, String fileExtention, String documentId) { + public static Document createDocument(byte[] data, String documentName, String fileExtention, String documentId) { Document document = new Document(); document.setDocumentBase64(Base64.getEncoder().encodeToString(data)); document.setName(documentName); @@ -142,13 +166,14 @@ static Document createDocument(byte[] data, String documentName, String fileExte /** * Create SignHere (see {@link SignHere}) field (also known as tabs) on the * documents using anchor (autoPlace) positioning. - * @param anchorString the anchor string; the DocuSign platform searches - * throughout your envelope's documents for matching anchor strings + * + * @param anchorString the anchor string; the DocuSign platform searches + * throughout your envelope's documents for matching anchor strings * @param yOffsetPixels the y offset of anchor in pixels * @param xOffsetPixels the x offset of anchor in pixels * @return the {@link SignHere} object */ - static SignHere createSignHere(String anchorString, int yOffsetPixels, int xOffsetPixels) { + public static SignHere createSignHere(String anchorString, int yOffsetPixels, int xOffsetPixels) { SignHere signHere = new SignHere(); signHere.setAnchorString(anchorString); signHere.setAnchorUnits("pixels"); @@ -160,23 +185,25 @@ static SignHere createSignHere(String anchorString, int yOffsetPixels, int xOffs /** * Create Tabs object containing a single SignHere (see {@link SignHere}) * field (also known as tabs) on the documents using anchor (autoPlace) positioning. - * @param anchorString the anchor string; the DocuSign platform searches - * throughout your envelope's documents for matching anchor strings + * + * @param anchorString the anchor string; the DocuSign platform searches + * throughout your envelope's documents for matching anchor strings * @param yOffsetPixels the y offset of anchor in pixels * @param xOffsetPixels the x offset of anchor in pixels * @return the {@link Tabs} object containing single SignHere object */ - static Tabs createSingleSignerTab(String anchorString, int yOffsetPixels, int xOffsetPixels) { + public static Tabs createSingleSignerTab(String anchorString, int yOffsetPixels, int xOffsetPixels) { SignHere signHere = createSignHere(anchorString, yOffsetPixels, xOffsetPixels); return createSignerTabs(signHere); } /** * Creates {@link SignHere} fields (also known as tabs) on the document. + * * @param signs the array of SignHere (see {@link SignHere}) * @return the {@link Tabs} object containing passed SignHere objects */ - static Tabs createSignerTabs(SignHere... signs) { + public static Tabs createSignerTabs(SignHere... signs) { Tabs signerTabs = new Tabs(); signerTabs.setSignHereTabs(Arrays.asList(signs)); return signerTabs; @@ -184,14 +211,27 @@ static Tabs createSignerTabs(SignHere... signs) { /** * Creates a {@link Recipients} object and add signer and cc to it. + * * @param signer the signer object - * @param cc the cc object + * @param cc the cc object * @return the {@link Recipients} object */ - static Recipients createRecipients(Signer signer, CarbonCopy cc) { + public static Recipients createRecipients(Signer signer, CarbonCopy cc) { + Recipients recipients = new Recipients(); + recipients.setSigners(Collections.singletonList(signer)); + recipients.setCarbonCopies(Collections.singletonList(cc)); + return recipients; + } + + public static Recipients createSingleRecipient(Signer signer) { + Recipients recipients = new Recipients(); + recipients.setSigners(Collections.singletonList(signer)); + return recipients; + } + + public static Recipients createTwoSigners(Signer signer, Signer signer2) { Recipients recipients = new Recipients(); - recipients.setSigners(Arrays.asList(signer)); - recipients.setCarbonCopies(Arrays.asList(cc)); + recipients.setSigners(Arrays.asList(signer, signer2)); return recipients; } } diff --git a/src/main/java/com/docusign/controller/examples/ExampleException.java b/src/main/java/com/docusign/controller/eSignature/examples/ExampleException.java similarity index 78% rename from src/main/java/com/docusign/controller/examples/ExampleException.java rename to src/main/java/com/docusign/controller/eSignature/examples/ExampleException.java index 09d7f8b3..c524da20 100644 --- a/src/main/java/com/docusign/controller/examples/ExampleException.java +++ b/src/main/java/com/docusign/controller/eSignature/examples/ExampleException.java @@ -1,4 +1,4 @@ -package com.docusign.controller.examples; +package com.docusign.controller.eSignature.examples; /** * Unchecked exception caused by examples. @@ -9,8 +9,9 @@ public class ExampleException extends RuntimeException { /** * Constructs a new exception with the specified detail message and cause. + * * @param message the detail message, which is kept as member - * @param cause the cause, which is saved as member + * @param cause the cause, which is saved as member */ public ExampleException(String message, Throwable cause) { super(message, cause); diff --git a/src/main/java/com/docusign/controller/eSignature/services/AccessCodeAuthenticationService.java b/src/main/java/com/docusign/controller/eSignature/services/AccessCodeAuthenticationService.java new file mode 100644 index 00000000..a53e2efc --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/AccessCodeAuthenticationService.java @@ -0,0 +1,65 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.time.Instant; +import java.util.Map; + +public final class AccessCodeAuthenticationService { + private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String DOCUMENT_NAME = "Lorem"; + + public static EnvelopeSummary accessCodeAuthentication( + EnvelopesApi envelopesApi, + String accountId, + EnvelopeDefinition envelope) throws ApiException { + //ds-snippet-start:eSign19Step4 + var createdEnvelope = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, + envelopesApi.new CreateEnvelopeOptions()); + + Map> headers = createdEnvelope.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return createdEnvelope.getData(); + //ds-snippet-end:eSign19Step4 + } + + //ds-snippet-start:eSign19Step3 + public static EnvelopeDefinition createEnvelope( + String signerName, + String signerEmail, + String accessCode) throws IOException { + Document doc = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, "1"); + + Signer signer = KBAAuthenticationService.setSignHereAndSignerForEnvelope(signerName, signerEmail); + signer.setAccessCode(accessCode); + + Recipients recipients = new Recipients(); + recipients.setSigners(Collections.singletonList(signer)); + + EnvelopeDefinition envelope = new EnvelopeDefinition(); + envelope.setEmailSubject("Please Sign"); + envelope.setDocuments(Collections.singletonList(doc)); + envelope.setEnvelopeIdStamping("true"); + envelope.setEmailBlurb("Sample text for email body"); + envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + envelope.setRecipients(recipients); + + return envelope; + } + //ds-snippet-end:eSign19Step3 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/AddDocToTemplateService.java b/src/main/java/com/docusign/controller/eSignature/services/AddDocToTemplateService.java new file mode 100644 index 00000000..bb40fb2e --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/AddDocToTemplateService.java @@ -0,0 +1,186 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.core.common.DocumentType; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public final class AddDocToTemplateService { + private static final String HTML_DOCUMENT_FILE_NAME = "templates/candy-bonbon2.ftl"; + + private static final String HTML_DOCUMENT_NAME = "Appendix 1--Sales order"; + + private static final int ANCHOR_OFFSET_Y = 10; + + private static final int ANCHOR_OFFSET_X = 20; + + public static ViewUrl addDocumentToTemplate( + EnvelopesApi envelopesApi, + String signerEmail, + String signerName, + String signerClientId, + String ccEmail, + String ccName, + String templateId, + String accountId, + String dsReturnUrl, + String dsPingUrl, + WorkArguments args) throws ApiException, IOException { + EnvelopeDefinition envelope = AddDocToTemplateService.makeEnvelope( + signerEmail, + signerName, + signerClientId, + ccEmail, + ccName, + templateId, + args); + + //ds-snippet-start:eSign13Step3 + var envelopeSummary = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = envelopeSummary.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null && reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + //ds-snippet-end:eSign13Step3 + + //ds-snippet-start:eSign13Step4 + RecipientViewRequest viewRequest = AddDocToTemplateService.makeRecipientViewRequest( + dsReturnUrl, + signerEmail, + signerName, + dsPingUrl); + var createRecipientView = envelopesApi.createRecipientViewWithHttpInfo(accountId, + envelopeSummary.getData().getEnvelopeId(), viewRequest); + headers = envelopeSummary.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null && reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return createRecipientView.getData(); + } + + public static RecipientViewRequest makeRecipientViewRequest( + String dsReturnUrl, + String signerEmail, + String signerName, + String dsPingUrl) { + RecipientViewRequest viewRequest = new RecipientViewRequest(); + // Set the url where you want the recipient to go once they are done signing + // should typically be a callback route somewhere in your app. + viewRequest.setReturnUrl(dsReturnUrl); + return SetTabValuesService.setEmailAndSignerNameForRecipientViewRequest( + viewRequest, + signerEmail, + signerName, + dsPingUrl); + } + //ds-snippet-end:eSign13Step4 + + // The envelope request object uses Composite Template to include in the + // envelope: + // 1. A template stored on the DocuSign service + // 2. An additional document which is a custom HTML source document + //ds-snippet-start:eSign13Step2 + public static EnvelopeDefinition makeEnvelope( + String signerEmail, + String signerName, + String signerClientId, + String ccEmail, + String ccName, + String templateId, + WorkArguments args) throws IOException { + // Create a signer and cc recipients for the signer role of the server template + CarbonCopy cc1 = new CarbonCopy(); + cc1.setEmail(ccEmail); + cc1.setName(ccName); + cc1.setRoleName(EnvelopeHelpers.CC_ROLE_NAME); + cc1.setRecipientId("2"); + + // create a composite template for the Server Template + CompositeTemplate compTemplate1 = new CompositeTemplate(); + compTemplate1.setCompositeTemplateId("1"); + ServerTemplate serverTemplates = new ServerTemplate(); + serverTemplates.setSequence("1"); + serverTemplates.setTemplateId(templateId); + compTemplate1.setServerTemplates(Collections.singletonList(serverTemplates)); + + // Add the roles via an inlineTemplate + InlineTemplate inlineTemplate = new InlineTemplate(); + inlineTemplate.setSequence("2"); + inlineTemplate.setRecipients(EnvelopeHelpers.createRecipients( + createSigner( + signerEmail, + signerName, + signerClientId), + cc1)); + compTemplate1.setInlineTemplates(Collections.singletonList(inlineTemplate)); + + // The signer recipient for the added document with a tab definition: + Tabs signer1Tabs = EnvelopeHelpers.createSingleSignerTab( + "**signature_1**", + ANCHOR_OFFSET_Y, + ANCHOR_OFFSET_X); + Signer signer1AddedDoc = createSigner( + signerEmail, + signerName, + signerClientId); + signer1AddedDoc.setTabs(signer1Tabs); + + // create the HTML document + byte[] htmlDoc = EnvelopeHelpers.createHtmlFromTemplateFile(HTML_DOCUMENT_FILE_NAME, "args", args) + .getBytes(StandardCharsets.UTF_8); + + // create a composite template for the added document and add the recipients via + // an inlineTemplate + CompositeTemplate compTemplate2 = new CompositeTemplate(); + compTemplate2.setCompositeTemplateId("2"); + InlineTemplate inlineTemplate2 = new InlineTemplate(); + inlineTemplate2.setSequence("1"); + inlineTemplate2.setRecipients(EnvelopeHelpers.createRecipients(signer1AddedDoc, cc1)); + compTemplate2.setInlineTemplates(Collections.singletonList(inlineTemplate2)); + compTemplate2.setDocument(EnvelopeHelpers.createDocument(htmlDoc, HTML_DOCUMENT_NAME, + DocumentType.HTML.getDefaultFileExtention(), "1")); + + EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition(); + envelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + envelopeDefinition.setCompositeTemplates(Arrays.asList(compTemplate1, compTemplate2)); + + return envelopeDefinition; + } + //ds-snippet-end:eSign13Step2 + + // Adding clientUserId transforms the template recipient into an embedded + // recipient + public static Signer createSigner( + String signerEmail, + String signerName, + String signerClientId) { + Signer signer = new Signer(); + signer.setEmail(signerEmail); + signer.setName(signerName); + signer.setRoleName(EnvelopeHelpers.SIGNER_ROLE_NAME); + signer.setRecipientId("1"); + signer.setClientUserId(signerClientId); + return signer; + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/ApplyBrandToEnvelopeService.java b/src/main/java/com/docusign/controller/eSignature/services/ApplyBrandToEnvelopeService.java new file mode 100644 index 00000000..ba4652f7 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/ApplyBrandToEnvelopeService.java @@ -0,0 +1,95 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.time.Instant; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public final class ApplyBrandToEnvelopeService { + private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String DOCUMENT_NAME = "EG025 Lorem Ipsum"; + + private static final int ANCHOR_OFFSET_Y = 10; + + private static final int ANCHOR_OFFSET_X = 20; + + //ds-snippet-start:eSign29Step4 + public static EnvelopeSummary applyBrandToEnvelope( + EnvelopesApi envelopesApi, + String accountId, + EnvelopeDefinition envelope) throws ApiException { + var createEnvelopeResponse = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = createEnvelopeResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return createEnvelopeResponse.getData(); + } + //ds-snippet-end:eSign29Step4 + + public static BrandsResponse getBrands( + AccountsApi accountsApi, + String accountId) throws ApiException { + var listBrandsResponse = accountsApi.listBrandsWithHttpInfo(accountId, accountsApi.new ListBrandsOptions()); + Map> headers = listBrandsResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return listBrandsResponse.getData(); + } + + // Creates an envelope. The envelope has one recipient who should sign an + // attached document. Attached document is read from a local directory. + // Also the envelope contains a brand Id which is created on EG028 example. + //ds-snippet-start:eSign29Step3 + public static EnvelopeDefinition makeEnvelope( + String signerEmail, + String signerName, + String brandId) throws IOException { + // Reads a file from a local directory and create Document object. + Document document = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, "1"); + + // Create a signer recipient to sign the document and associate sign tab + Tabs tabs = EnvelopeHelpers.createSingleSignerTab("/sn1/", ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X); + Signer signer = new Signer() + .email(signerEmail) + .name(signerName) + .recipientId("1") + .routingOrder("1") + .tabs(tabs); + + Recipients recipients = new Recipients(); + recipients.setSigners(Collections.singletonList(signer)); + + // Return envelope definition using created objects: the document, + // the recipients and obtained brand Id. + return new EnvelopeDefinition() + .emailSubject("EG029. Please Sign") + .documents(List.of(document)) + .recipients(recipients) + .brandId(brandId) + .status(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + } + //ds-snippet-end:eSign29Step3 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/ApplyBrandToTemplateService.java b/src/main/java/com/docusign/controller/eSignature/services/ApplyBrandToTemplateService.java new file mode 100644 index 00000000..aeae70d5 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/ApplyBrandToTemplateService.java @@ -0,0 +1,60 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import com.docusign.esign.model.TemplateRole; + +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public final class ApplyBrandToTemplateService { + public static EnvelopeSummary applyBrandToTemplate( + EnvelopesApi envelopesApi, + String accountId, + EnvelopeDefinition envelope) throws ApiException { + //ds-snippet-start:eSign30Step4 + var createEnvelopeResponse = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = createEnvelopeResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return createEnvelopeResponse.getData(); + //ds-snippet-end:eSign30Step4 + } + + public static EnvelopeDefinition makeEnvelope( + String signerEmail, + String signerName, + String ccEmail, + String ccName, + String templateId, + String brandId) { + TemplateRole signer = new TemplateRole() + .email(signerEmail) + .name(signerName) + .roleName(EnvelopeHelpers.SIGNER_ROLE_NAME); + + TemplateRole cc = new TemplateRole() + .email(ccEmail) + .name(ccName) + .roleName(EnvelopeHelpers.CC_ROLE_NAME); + + return new EnvelopeDefinition() + .templateId(templateId) + .templateRoles(Arrays.asList(signer, cc)) + .brandId(brandId) + .status(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/BulkSendEnvelopesService.java b/src/main/java/com/docusign/controller/eSignature/services/BulkSendEnvelopesService.java new file mode 100644 index 00000000..3717b85a --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/BulkSendEnvelopesService.java @@ -0,0 +1,233 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.DsModelUtils; +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.BulkEnvelopesApi; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.time.Instant; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public final class BulkSendEnvelopesService { + private static final String BULK_SIGNER_EMAIL_PLACEHOLDER = "MultiBulkRecipients-%s@docusign.com"; + + private static final String BULK_SIGNER_NAME_PLACEHOLDER = "Multi Bulk Recipients::%s"; + + private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String DOCUMENT_NAME = "Lorem Ipsum"; + + private static final int ANCHOR_OFFSET_Y = -5; + + private static final int ANCHOR_OFFSET_X = 15; + + //ds-snippet-start:eSign31Step7 + public static BulkSendBatchStatus getBulkSendBatchStatus( + BulkEnvelopesApi bulkEnvelopesApi, + String accountId, + String batchId, + long bulkRequestDelay) throws ApiException, InterruptedException { + TimeUnit.SECONDS.sleep(bulkRequestDelay); + // For 2000 recipients, it can take about an hour + var getBulkSendBatchStatus = bulkEnvelopesApi.getBulkSendBatchStatusWithHttpInfo(accountId, batchId); + Map> headers = getBulkSendBatchStatus.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return getBulkSendBatchStatus.getData(); + } + //ds-snippet-end:eSign31Step7 + + public static String bulkSendEnvelopes( + BulkEnvelopesApi bulkEnvelopesApi, + ApiClient apiClient, + String signerName, + String signerEmail, + String ccName, + String ccEmail, + String signerName2, + String signerEmail2, + String ccName2, + String ccEmail2, + String accountId) throws ApiException, IOException { + BulkSendingList sendingList = BulkSendEnvelopesService.getSendingList( + signerName, + signerEmail, + ccName, + ccEmail, + signerName2, + signerEmail2, + ccName2, + ccEmail2); + + var bulkListResponse = bulkEnvelopesApi.createBulkSendListWithHttpInfo(accountId, sendingList); + Map> headers = bulkListResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + String bulkListId = bulkListResponse.getData().getListId(); + + // Create an envelope + //ds-snippet-start:eSign31Step4 + EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); + var envelopeResponse = envelopesApi.createEnvelopeWithHttpInfo(accountId, makeEnvelope(), + envelopesApi.new CreateEnvelopeOptions()); + headers = envelopeResponse.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + String envelopeId = envelopeResponse.getData().getEnvelopeId(); + //ds-snippet-end:eSign31Step4 + + // Attach your bulk list ID to the envelope + //ds-snippet-start:eSign31Step5 + CustomFields customFields = createCustomFields(bulkListId); + var createCustomFields = envelopesApi.createCustomFieldsWithHttpInfo(accountId, envelopeId, customFields); + headers = createCustomFields.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + //ds-snippet-end:eSign31Step5 + + // Initiate bulk send + //ds-snippet-start:eSign31Step6 + BulkSendRequest request = new BulkSendRequest(); + request.setEnvelopeOrTemplateId(envelopeId); + + var bulkSendResponse = bulkEnvelopesApi.createBulkSendRequestWithHttpInfo(accountId, bulkListId, request); + headers = createCustomFields.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return bulkSendResponse.getData().getBatchId(); + //ds-snippet-end:eSign31Step6 + } + + //ds-snippet-start:eSign31Step3 + public static BulkSendingList getSendingList( + String signerName, + String signerEmail, + String ccName, + String ccEmail, + String signerName2, + String signerEmail2, + String ccName2, + String ccEmail2) { + List copies = List.of( + createBulkSending(signerName, signerEmail, ccName, ccEmail), + createBulkSending(signerName2, signerEmail2, ccName2, ccEmail2)); + return new BulkSendingList() + .name("sample.csv") + .bulkCopies(copies); + } + + public static BulkSendingCopy createBulkSending( + String signerName, + String signerEmail, + String ccName, + String ccEmail) { + BulkSendingCopyRecipient recipient1 = new BulkSendingCopyRecipient() + .name(signerName) + .email(signerEmail) + .tabs(Collections.emptyList()) + .roleName(EnvelopeHelpers.SIGNER_ROLE_NAME); + BulkSendingCopyRecipient recipient2 = new BulkSendingCopyRecipient() + .name(ccName) + .email(ccEmail) + .tabs(Collections.emptyList()) + .roleName(EnvelopeHelpers.CC_ROLE_NAME); + return new BulkSendingCopy() + .recipients(List.of(recipient1, recipient2)) + .customFields(Collections.emptyList()); + } + //ds-snippet-end:eSign31Step3 + + public static EnvelopeDefinition makeEnvelope() throws IOException { + Document document = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, "1"); + return new EnvelopeDefinition() + .documents(List.of(document)) + .envelopeIdStamping(DsModelUtils.TRUE) + .emailSubject("EG031 Please sign") + .status(EnvelopeHelpers.ENVELOPE_STATUS_CREATED) + .recipients(createRecipients()); + } + + public static CustomFields createCustomFields(String bulkListId) { + TextCustomField textCustomField = new TextCustomField() + .name("mailingListId") + .required(DsModelUtils.FALSE) + .show(DsModelUtils.FALSE) + .value(bulkListId); + + return new CustomFields() + .listCustomFields(Collections.emptyList()) + .textCustomFields(List.of(textCustomField)); + } + + public static Recipients createRecipients() { + Signer signer = createSignerPlaceholder(EnvelopeHelpers.SIGNER_ROLE_NAME, "1", "1"); + CarbonCopy cc = createCCPlaceholder(EnvelopeHelpers.CC_ROLE_NAME, "2", "2"); + return new Recipients() + .signers(List.of(signer)) + .carbonCopies(List.of(cc)); + } + + public static Signer createSignerPlaceholder(String roleName, String recipientId, String routingOrder) { + return new Signer() + .name(String.format(BULK_SIGNER_NAME_PLACEHOLDER, roleName)) + .email(String.format(BULK_SIGNER_EMAIL_PLACEHOLDER, roleName)) + .roleName(roleName) + .note("") + .routingOrder(routingOrder) + .status(EnvelopeHelpers.SIGNER_STATUS_CREATED) + .deliveryMethod(EnvelopeHelpers.DELIVERY_METHOD_EMAIL) + .recipientId(recipientId) + .recipientType(roleName) + .tabs(EnvelopeHelpers.createSingleSignerTab("/sn1/", ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X)); + } + + public static CarbonCopy createCCPlaceholder(String roleName, String recipientId, String routingOrder) { + return new CarbonCopy() + .name(String.format(BULK_SIGNER_NAME_PLACEHOLDER, roleName)) + .email(String.format(BULK_SIGNER_EMAIL_PLACEHOLDER, roleName)) + .roleName(roleName) + .note("") + .routingOrder(routingOrder) + .status(EnvelopeHelpers.SIGNER_STATUS_CREATED) + .deliveryMethod(EnvelopeHelpers.DELIVERY_METHOD_EMAIL) + .recipientId(recipientId) + .recipientType(roleName); + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/CfrEmbeddedSigningService.java b/src/main/java/com/docusign/controller/eSignature/services/CfrEmbeddedSigningService.java new file mode 100644 index 00000000..28de0742 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/CfrEmbeddedSigningService.java @@ -0,0 +1,131 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.DSConfiguration; +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.time.Instant; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public final class CfrEmbeddedSigningService { + //ds-snippet-start:eSign41Step6 + public static ViewUrl embeddedSigning( + EnvelopesApi envelopesApi, + String accountId, + String envelopeId, + RecipientViewRequest viewRequest) throws ApiException { + var recipientViewResponse = envelopesApi.createRecipientViewWithHttpInfo(accountId, envelopeId, viewRequest); + Map> headers = recipientViewResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return recipientViewResponse.getData(); + } + //ds-snippet-end:eSign41Step6 + + //ds-snippet-start:eSign41Step5 + public static RecipientViewRequest makeRecipientViewRequest( + String signerEmail, + String signerName, + DSConfiguration config, + String clientUserId) { + RecipientViewRequest viewRequest = new RecipientViewRequest(); + // Set the url where you want the recipient to go once they are done signing + // should typically be a callback route somewhere in your app. + // The query parameter is included as an example of how + // to save/recover state information during the redirect to + // the DocuSign signing. It's usually better to use + // the session mechanism of your web framework. Query parameters + // can be changed/spoofed very easily. + String stateValue = "?state=123"; + viewRequest.setReturnUrl(config.getDsReturnUrl() + stateValue); + + // How has your app authenticated the user? In addition to your app's + // authentication, you can include authenticate steps from DocuSign. + // Eg, SMS authentication + String authenticationMethod = "none"; + viewRequest.setAuthenticationMethod(authenticationMethod); + + // Recipient information must match embedded recipient info + // we used to create the envelope. + viewRequest.setEmail(signerEmail); + viewRequest.setUserName(signerName); + viewRequest.setClientUserId(clientUserId); + + // DocuSign recommends that you redirect to DocuSign for the + // embedded signing. There are multiple ways to save state. + // To maintain your application's session, use the pingUrl + // parameter. It causes the DocuSign signing web page + // (not the DocuSign server) to send pings via AJAX to your app. + // NOTE: The pings will only be sent if the pingUrl is an https address + String pingFrequency = "600"; + viewRequest.setPingFrequency(pingFrequency); // seconds + viewRequest.setPingUrl(config.getDsPingUrl()); + + return viewRequest; + } + //ds-snippet-end:eSign41Step5 + + //ds-snippet-start:eSign41Step3 + public static EnvelopeDefinition makeEnvelope( + String signerName, + String signerEmail, + String countryCode, + String number, + String workflowId, + String signerClientId, + Integer anchorOffsetY, + Integer anchorOffsetX, + String documentFileName, + String documentName) throws IOException { + // Create a signer recipient to sign the document, identified by name and email + // We set the clientUserId to enable embedded signing for the recipient + RecipientIdentityPhoneNumber phoneNumber = new RecipientIdentityPhoneNumber(); + phoneNumber.setCountryCode(countryCode); + phoneNumber.setNumber(number); + + RecipientIdentityInputOption inputOption = new RecipientIdentityInputOption(); + inputOption.setName("phone_number_list"); + inputOption.setValueType("PhoneNumberList"); + inputOption.setPhoneNumberList(List.of(phoneNumber)); + + RecipientIdentityVerification identityVerifcation = new RecipientIdentityVerification(); + + identityVerifcation.setWorkflowId(workflowId); + identityVerifcation.setInputOptions(List.of(inputOption)); + + Signer signer = new Signer(); + signer.setEmail(signerEmail); + signer.setName(signerName); + signer.clientUserId(signerClientId); + signer.recipientId("1"); + signer.setTabs(EnvelopeHelpers.createSingleSignerTab("/sn1/", anchorOffsetY, anchorOffsetX)); + signer.setIdentityVerification(identityVerifcation); + + // Add the recipient to the envelope object + Recipients recipients = new Recipients(); + recipients.setSigners(Collections.singletonList(signer)); + + EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition(); + envelopeDefinition.setEmailSubject("Please sign this document"); + envelopeDefinition.setRecipients(recipients); + Document doc = EnvelopeHelpers.createDocumentFromFile(documentFileName, documentName, "3"); + envelopeDefinition.setDocuments(Collections.singletonList(doc)); + // Request that the envelope be sent by setting |status| to "sent". + // To request that the envelope be created as a draft, set to "created" + envelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + + return envelopeDefinition; + } + //ds-snippet-end:eSign41Step3 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/CollectPaymentService.java b/src/main/java/com/docusign/controller/eSignature/services/CollectPaymentService.java new file mode 100644 index 00000000..1ad107e3 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/CollectPaymentService.java @@ -0,0 +1,215 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.core.common.DocumentType; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; + +public final class CollectPaymentService { + private static final String HTML_DOCUMENT_FILE_NAME = "templates/order-form.ftl"; + + private static final String HTML_DOCUMENT_NAME = "Order form"; + + // Order form constants + private static final String TRUE = "true"; + + private static final String FALSE = "false"; + + private static final int L1_PRICE = 5; + + private static final int L2_PRICE = 150; + + private static final int ANCHOR_OFFSET_Y = 10; + + private static final int ANCHOR_OFFSET_X = 20; + + private static final String DEFAULT_FONT = "helvetica"; + + private static final String DEFAULT_FONT_SIZE = "size11"; + + private static final String ANCHOR_UNITS = "pixels"; + + //ds-snippet-start:eSign14Step4 + public static EnvelopeSummary collectPayment( + EnvelopesApi envelopesApi, + EnvelopeDefinition envelope, + String accountId) throws ApiException { + // Call Envelopes::create API method + var createdEnvelope = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = createdEnvelope.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null && reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return createdEnvelope.getData(); + } + //ds-snippet-end:eSign14Step4 + // document 1 (html) has multiple tags: + // /l1q/ and /l2q/ -- quantities: drop down + // /l1e/ and /l2e/ -- extended: payment lines + // /l3t/ -- total -- formula + // + // The envelope has two recipients. + // recipient 1 - signer + // recipient 2 - cc + // The envelope will be sent first to the signer. + // After it is signed, a copy is sent to the cc person. + //ds-snippet-start:eSign14Step3 + + public static EnvelopeDefinition makeEnvelope( + String signerEmail, + String signerName, + String ccName, + String ccEmail, + String gatewayAccountId, + String gatewayName, + String gatewayDisplayName, + WorkArguments args) throws IOException { + byte[] htmlDoc = EnvelopeHelpers.createHtmlFromTemplateFile(HTML_DOCUMENT_FILE_NAME, "args", args) + .getBytes(StandardCharsets.UTF_8); + + // create a signer recipient to sign the document, identified by name and email + // routingOrder (lower means earlier) determines the order of deliveries + // to the recipients. Parallel routing order is supported by using the + // same integer as the order for two or more recipients. + Signer signer = new Signer() + .email(signerEmail) + .name(signerName) + .recipientId("1") + .routingOrder("1"); + signer.setTabs(createTabs(gatewayAccountId, gatewayName, gatewayDisplayName)); + + // create a cc recipient to receive a copy of the documents, identified by name + // and email + CarbonCopy cc = new CarbonCopy() + .email(ccEmail) + .name(ccName) + .routingOrder("2") + .recipientId("2"); + + // Create the envelope definition + // Request that the envelope be sent by setting |status| to "sent". + // To request that the envelope be created as a draft, set to "created" + EnvelopeDefinition envelope = new EnvelopeDefinition(); + envelope.setEmailSubject("Please complete your order"); + envelope.setDocuments(Collections.singletonList(EnvelopeHelpers.createDocument(htmlDoc, + HTML_DOCUMENT_NAME, DocumentType.HTML.getDefaultFileExtention(), "1"))); + envelope.setRecipients(EnvelopeHelpers.createRecipients(signer, cc)); + envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + + return envelope; + } + + // creates tabs per signer + private static Tabs createTabs(String gatewayAccountId, String gatewayName, String gatewayDisplayName) { + java.util.List listItems = java.util.List.of( + new ListItem().text("none").value("0"), + new ListItem().text("1").value("1"), + new ListItem().text("2").value("2"), + new ListItem().text("3").value("3"), + new ListItem().text("4").value("4"), + new ListItem().text("5").value("5"), + new ListItem().text("6").value("6"), + new ListItem().text("7").value("7"), + new ListItem().text("8").value("8"), + new ListItem().text("9").value("9"), + new ListItem().text("10").value("10")); + List listl1q = createList("/l1q/", "l1q", listItems); + List listl2q = createList("/l2q/", "l2q", listItems); + + // Create two formula tabs for the extended price on the line items and formula + // for the total + FormulaTab formulal1e = createFormulaTab("/l1e/", "l1e", L1_PRICE); + FormulaTab formulal2e = createFormulaTab("/l2e/", "l2e", L2_PRICE); + FormulaTab formulal3t = new FormulaTab() + .font(DEFAULT_FONT) + .bold(TRUE) + .fontSize("size12") + .anchorString("/l3t/") + .anchorYOffset("-8") + .anchorUnits(ANCHOR_UNITS) + .anchorXOffset("50") + .tabLabel("l3t") + .formula("[l1e] + [l2e]") + .roundDecimalPlaces("0") + .required(TRUE) + .locked(TRUE) + .disableAutoSize(FALSE); + PaymentLineItem paymentLineIteml1 = new PaymentLineItem() + .name("Harmonica") + .description(String.format("${%d} each", L1_PRICE)) + .amountReference("l1e"); + PaymentLineItem paymentLineIteml2 = new PaymentLineItem() + .name("Xylophone") + .description(String.format("${%d} each", L2_PRICE)) + .amountReference("l2e"); + PaymentDetails paymentDetails = new PaymentDetails() + .gatewayAccountId(gatewayAccountId) + .currencyCode("USD") + .gatewayName(gatewayName) + .gatewayDisplayName(gatewayDisplayName) + .lineItems(Arrays.asList(paymentLineIteml1, paymentLineIteml2)); + // Hidden formula for the payment itself + FormulaTab formulaPayment = new FormulaTab() + .tabLabel("payment") + .formula("([l1e] + [l2e]) * {100}") + .roundDecimalPlaces("0") + .paymentDetails(paymentDetails) + .hidden(TRUE) + .required(TRUE) + .locked(TRUE) + .documentId("1") + .pageNumber("1") + .xPosition("0") + .yPosition("0"); + + Tabs signerTabs = EnvelopeHelpers.createSingleSignerTab("/sn1/", ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X); + signerTabs.listTabs(Arrays.asList(listl1q, listl2q)); + signerTabs.formulaTabs(Arrays.asList(formulal1e, formulal2e, formulal3t, formulaPayment)); + return signerTabs; + } + + private static List createList(String anchor, String label, java.util.List items) { + return new List() + .font(DEFAULT_FONT) + .fontSize(DEFAULT_FONT_SIZE) + .anchorString(anchor) + .anchorYOffset("-10") + .anchorUnits(ANCHOR_UNITS) + .anchorXOffset("0") + .listItems(items) + .required(TRUE) + .tabLabel(label); + } + + private static FormulaTab createFormulaTab(String anchor, String label, int price) { + return new FormulaTab() + .font(DEFAULT_FONT) + .fontSize(DEFAULT_FONT_SIZE) + .anchorString(anchor) + .anchorYOffset("-8") + .anchorUnits(ANCHOR_UNITS) + .anchorXOffset("105") + .tabLabel(label) + .formula(String.format("[l1q] * {%d}", price)) + .roundDecimalPlaces("0") + .required(TRUE) + .locked(TRUE) + .disableAutoSize(FALSE); + } + //ds-snippet-end:eSign14Step3 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/CreateBrandService.java b/src/main/java/com/docusign/controller/eSignature/services/CreateBrandService.java new file mode 100644 index 00000000..f06fb152 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/CreateBrandService.java @@ -0,0 +1,38 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.Brand; +import com.docusign.esign.model.BrandsResponse; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public final class CreateBrandService { + public static BrandsResponse createBrand( + AccountsApi accountsApi, + String brandName, + String language, + String accountId) throws ApiException { + Brand brand = new Brand() + .brandName(brandName) + .defaultBrandLanguage(language) + .brandLanguages(List.of(language)); + + // Step 4. Call the eSignature REST API + //ds-snippet-start:eSign28Step4 + var brandResponse = accountsApi.createBrandWithHttpInfo(accountId, brand); + Map> headers = brandResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return brandResponse.getData(); + //ds-snippet-end:eSign28Step4 + } +} diff --git a/src/main/java/com/docusign/controller/examples/EG008ControllerCreateTemplate.java b/src/main/java/com/docusign/controller/eSignature/services/CreateTemplateService.java similarity index 53% rename from src/main/java/com/docusign/controller/examples/EG008ControllerCreateTemplate.java rename to src/main/java/com/docusign/controller/eSignature/services/CreateTemplateService.java index 0521ac6e..b43e8476 100644 --- a/src/main/java/com/docusign/controller/examples/EG008ControllerCreateTemplate.java +++ b/src/main/java/com/docusign/controller/eSignature/services/CreateTemplateService.java @@ -1,96 +1,66 @@ -package com.docusign.controller.examples; +package com.docusign.controller.eSignature.services; -import com.docusign.DSConfiguration; +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; import com.docusign.esign.api.TemplatesApi; import com.docusign.esign.client.ApiClient; import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.CarbonCopy; -import com.docusign.esign.model.Checkbox; -import com.docusign.esign.model.Document; -import com.docusign.esign.model.EnvelopeTemplate; -import com.docusign.esign.model.EnvelopeTemplateResults; -import com.docusign.esign.model.List; -import com.docusign.esign.model.ListItem; -import com.docusign.esign.model.Radio; -import com.docusign.esign.model.RadioGroup; -import com.docusign.esign.model.SignHere; -import com.docusign.esign.model.Signer; -import com.docusign.esign.model.Tabs; -import com.docusign.esign.model.TemplateSummary; -import com.docusign.esign.model.Text; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; +import com.docusign.esign.model.*; import java.io.IOException; +import java.time.Instant; import java.util.Arrays; +import java.util.Collections; import java.util.Locale; +import java.util.Map; -import javax.servlet.http.HttpServletResponse; - - -/** - * Create a template.
- * Create a template with two roles, signer and cc. The template - * includes three documents. - */ -@Controller -@RequestMapping("/eg008") -public class EG008ControllerCreateTemplate extends AbstractController { - - private static final String TEMPLATE_NAME = "Example Signer and CC template"; +public final class CreateTemplateService { private static final String PDF_DOCUMENT_FILE_NAME = "World_Wide_Corp_fields.pdf"; + private static final String PDF_DOCUMENT_NAME = "Lorem Ipsum"; + private static final String DOCUMENT_ID = "1"; - private static final String PAGE_NUMBER = "1"; - private static final String FALSE = "false"; - private final Session session; - private final User user; + private static final String PAGE_NUMBER = "1"; + private static final String FALSE = "false"; - @Autowired - public EG008ControllerCreateTemplate(DSConfiguration config, Session session, User user) { - super(config, "eg008", "Create a template"); - this.session = session; - this.user = user; + public static TemplateSummary createTemplate( + ApiClient apiClient, + String accountId, + EnvelopeTemplate envelopeTemplate) throws ApiException { + TemplatesApi templatesApi = new TemplatesApi(apiClient); + var templateResponse = templatesApi.createTemplateWithHttpInfo(accountId, envelopeTemplate); + Map> headers = templateResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return templateResponse.getData(); } - @Override - // ***DS.snippet.0.start - protected Object doWork(WorkArguments args, ModelMap model, - HttpServletResponse response) throws ApiException, IOException { - // Step 1. list existing templates - ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); + public static EnvelopeTemplateResults searchTemplatesByName( + ApiClient apiClient, + String accountId, + String templateName) throws ApiException { TemplatesApi templatesApi = new TemplatesApi(apiClient); TemplatesApi.ListTemplatesOptions options = templatesApi.new ListTemplatesOptions(); - options.setSearchText(TEMPLATE_NAME); - String accountId = session.getAccountId(); - EnvelopeTemplateResults results = templatesApi.listTemplates(accountId, options); - - // Step 2. Process results. If template do not exist, create one - if (Integer.parseInt(results.getResultSetSize()) > 0) { - EnvelopeTemplate template = results.getEnvelopeTemplates().get(0); - DoneExample.createDefault(title) - .withMessage(String.format( - "The template already exists in your account.
Template name: %s, ID %s.", - template.getName(), template.getTemplateId())) - .addToModel(model); - } else { - session.setTemplateName(TEMPLATE_NAME); - TemplateSummary template = templatesApi.createTemplate(accountId, makeTemplate()); - DoneExample.createDefault(title) - .withMessage(String.format( - "The template has been created!
Template name: %s, ID %s.", - template.getName(), template.getTemplateId())) - .addToModel(model); - } + options.setSearchText(templateName); - return DONE_EXAMPLE_PAGE; + var listTemplateResponse = templatesApi.listTemplatesWithHttpInfo(accountId, options); + Map> headers = listTemplateResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return listTemplateResponse.getData(); } // document 1 (pdf) has tag /sn1/ @@ -100,7 +70,8 @@ protected Object doWork(WorkArguments args, ModelMap model, // recipient 2 - cc // The template will be sent first to the signer. // After it is signed, a copy is sent to the cc person. - private EnvelopeTemplate makeTemplate() throws IOException { + //ds-snippet-start:eSign8Step2 + public static EnvelopeTemplate makeTemplate(String templateName) throws IOException { Document doc = EnvelopeHelpers.createDocumentFromFile(PDF_DOCUMENT_FILE_NAME, PDF_DOCUMENT_NAME, "1"); // Tabs are set per recipient / signer @@ -110,12 +81,13 @@ private EnvelopeTemplate makeTemplate() throws IOException { createCheckbox("ckAuthentication", "75", "447"), createCheckbox("ckAgreement", "75", "478"), createCheckbox("ckAcknowledgement", "75", "508"))); - signer1Tabs.setListTabs(Arrays.asList(createList())); - signer1Tabs.setRadioGroupTabs(Arrays.asList(createRadioGroup())); - signer1Tabs.setSignHereTabs(Arrays.asList(createSignHere())); - signer1Tabs.textTabs(Arrays.asList( - createText("text", "153", "230"), - createText("numbersOnly", "153", "260"))); + signer1Tabs.setListTabs(Collections.singletonList(createList())); + signer1Tabs.setRadioGroupTabs(Collections.singletonList(createRadioGroup())); + signer1Tabs.setSignHereTabs(Collections.singletonList(createSignHere())); + signer1Tabs.textTabs(java.util.List.of( + createText("text", "153", "230"))); + signer1Tabs.numericalTabs(java.util.List.of( + createNumerical("numericalCurrency", "153", "260"))); // create a signer recipient to sign the document, identified by name and email // routingOrder (lower means earlier) determines the order of deliveries @@ -127,7 +99,8 @@ private EnvelopeTemplate makeTemplate() throws IOException { signer.setRoutingOrder("1"); signer.setTabs(signer1Tabs); - // create a cc recipient to receive a copy of the documents, identified by name and email + // create a cc recipient to receive a copy of the documents, identified by name + // and email CarbonCopy cc1 = new CarbonCopy(); cc1.setRoleName(EnvelopeHelpers.CC_ROLE_NAME); cc1.setRoutingOrder("2"); @@ -136,9 +109,9 @@ private EnvelopeTemplate makeTemplate() throws IOException { // Create the overall template definition. The order in the docs array // determines the order in the envelope. EnvelopeTemplate template = new EnvelopeTemplate(); - template.setDocuments(Arrays.asList(doc)); + template.setDocuments(Collections.singletonList(doc)); template.setEmailSubject("Please sign this document"); - template.setName(session.getTemplateName()); + template.setName(templateName); template.setDescription("Example template created via the API"); template.setShared(FALSE); template.setRecipients(EnvelopeHelpers.createRecipients(signer, cc1)); @@ -147,7 +120,7 @@ private EnvelopeTemplate makeTemplate() throws IOException { return template; } - private static List createList() { + public static List createList() { List list = new List(); list.setDocumentId(DOCUMENT_ID); list.setPageNumber(PAGE_NUMBER); @@ -164,19 +137,18 @@ private static List createList() { createListItem("Green"), createListItem("Blue"), createListItem("Indigo"), - createListItem("Violet") - )); + createListItem("Violet"))); return list; } - private static ListItem createListItem(String color) { + public static ListItem createListItem(String color) { ListItem item = new ListItem(); item.setText(color); item.setValue(color.toLowerCase(Locale.ENGLISH)); return item; } - private static RadioGroup createRadioGroup() { + public static RadioGroup createRadioGroup() { RadioGroup radioGroup = new RadioGroup(); radioGroup.setDocumentId(DOCUMENT_ID); radioGroup.setGroupName("radio1"); @@ -184,12 +156,11 @@ private static RadioGroup createRadioGroup() { radioGroup.setRadios(Arrays.asList( createRadio("white", "142"), createRadio("red", "74"), - createRadio("blue", "220") - )); + createRadio("blue", "220"))); return radioGroup; } - private static Radio createRadio(String value, String xPosition) { + public static Radio createRadio(String value, String xPosition) { Radio radio = new Radio(); radio.setPageNumber(PAGE_NUMBER); radio.setValue(value); @@ -199,7 +170,7 @@ private static Radio createRadio(String value, String xPosition) { return radio; } - private static Checkbox createCheckbox(String label, String xPosition, String yPosition) { + public static Checkbox createCheckbox(String label, String xPosition, String yPosition) { Checkbox check = new Checkbox(); check.setDocumentId(DOCUMENT_ID); check.setPageNumber(PAGE_NUMBER); @@ -209,7 +180,7 @@ private static Checkbox createCheckbox(String label, String xPosition, String yP return check; } - private static Text createText(String label, String xPosition, String yPosition) { + public static Text createText(String label, String xPosition, String yPosition) { Text text = new Text(); text.setDocumentId(DOCUMENT_ID); text.setPageNumber(PAGE_NUMBER); @@ -224,7 +195,23 @@ private static Text createText(String label, String xPosition, String yPosition) return text; } - private static SignHere createSignHere() { + public static Numerical createNumerical(String label, String xPosition, String yPosition) { + Numerical numerical = new Numerical(); + numerical.setValidationType("Currency"); + numerical.setDocumentId(DOCUMENT_ID); + numerical.setPageNumber(PAGE_NUMBER); + numerical.setXPosition(xPosition); + numerical.setYPosition(yPosition); + numerical.setFont("helvetica"); + numerical.setFontSize("size14"); + numerical.setTabLabel(label); + numerical.setHeight("23"); + numerical.setWidth("84"); + numerical.setRequired(FALSE); + return numerical; + } + + public static SignHere createSignHere() { SignHere signHere = new SignHere(); signHere.setDocumentId(DOCUMENT_ID); signHere.setPageNumber(PAGE_NUMBER); @@ -232,5 +219,5 @@ private static SignHere createSignHere() { signHere.setYPosition("148"); return signHere; } - // ***DS.snippet.0.end + //ds-snippet-end:eSign8Step2 } diff --git a/src/main/java/com/docusign/controller/eSignature/services/DelayedRoutingService.java b/src/main/java/com/docusign/controller/eSignature/services/DelayedRoutingService.java new file mode 100644 index 00000000..c7b5af3a --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/DelayedRoutingService.java @@ -0,0 +1,109 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +public class DelayedRoutingService { + private static final String PDF_DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String PDF_DOCUMENT_NAME = "Lorem Ipsum"; + + private static final String DOCX_DOCUMENT_FILE_NAME = "World_Wide_Corp_Battle_Plan_Trafalgar.docx"; + + private static final String DOCX_DOCUMENT_NAME = "Battle Plan"; + + private static final int ANCHOR_OFFSET_Y = 10; + + private static final int ANCHOR_OFFSET_X = 20; + + private static final int ANCHOR_OFFSET_X_2 = 120; + + // document 1 (docx) has tag /sn1/ + // document 2 (pdf) has tag /sn1/ + // + // The envelope has two recipients. + // recipient 1 - signer + // recipient 2 - cc + // The envelope will be sent first to the signer. After it is signed, + // a copy is sent to the cc person. + public static EnvelopeDefinition makeEnvelope( + String signerName, + String signerEmail, + String signerName2, + String signerEmail2, + String delay, + String status) throws IOException { + // The DocuSign platform searches throughout your envelope's documents + // for matching anchor strings. So the signHere2 tab will be used in + // both document 2 and 3 since they use the same anchor string for + // their "signer 1" tabs. + + //ds-snippet-start:eSign36Step2 + Tabs signer1Tabs = EnvelopeHelpers.createSignerTabs( + EnvelopeHelpers.createSignHere("/sn1/", ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X)); + + Tabs signer2Tabs = EnvelopeHelpers.createSignerTabs( + EnvelopeHelpers.createSignHere("/sn1/", ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X_2)); + + // Create a signer recipient to sign the document, identified by name + // and email. We're setting the parameters via the object creation. + // RoutingOrder (lower means earlier) determines the order of deliveries + // to the recipients. Parallel routing order is supported by using the + // same integer as the order for two or more recipients. + Signer signer = new Signer(); + signer.setEmail(signerEmail); + signer.setName(signerName); + signer.setRecipientId("1"); + signer.setRoutingOrder("1"); + signer.setTabs(signer1Tabs); + + Signer signer2 = new Signer(); + signer2.setEmail(signerEmail2); + signer2.setName(signerName2); + signer2.setRecipientId("2"); + signer2.setRoutingOrder("2"); + signer2.setTabs(signer2Tabs); + + // The order in the docs array determines the order in the envelope + EnvelopeDefinition envelope = new EnvelopeDefinition(); + envelope.setEmailSubject("Please sign this document set"); + envelope.setDocuments(Arrays.asList( + EnvelopeHelpers.createDocumentFromFile(DOCX_DOCUMENT_FILE_NAME, DOCX_DOCUMENT_NAME, + "2"), + EnvelopeHelpers.createDocumentFromFile(PDF_DOCUMENT_FILE_NAME, PDF_DOCUMENT_NAME, + "3"))); + envelope.setRecipients(EnvelopeHelpers.createTwoSigners(signer, signer2)); + + // Add the workflow to delay the second recipient + + String delayFormatted = delay + ":00:00"; + EnvelopeDelayRule rule = new EnvelopeDelayRule(); + rule.setDelay(delayFormatted); + + DelayedRouting delayedRouting = new DelayedRouting(); + delayedRouting.setRules(List.of(rule)); + + WorkflowStep workflowStep = new WorkflowStep(); + workflowStep.setAction("pause_before"); + workflowStep.setTriggerOnItem("routing_order"); + workflowStep.setItemId("2"); + workflowStep.setStatus("pending"); + workflowStep.setDelayedRouting(delayedRouting); + + Workflow workflow = new Workflow(); + workflow.setWorkflowSteps(List.of(workflowStep)); + envelope.setWorkflow(workflow); + + // Request that the envelope be sent by setting |status| to "sent". + // To request that the envelope be created as a draft, set to "created" + envelope.setStatus(status); + + return envelope; + //ds-snippet-end:eSign36Step2 + + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/DeleteRestoreEnvelopeService.java b/src/main/java/com/docusign/controller/eSignature/services/DeleteRestoreEnvelopeService.java new file mode 100644 index 00000000..004172fa --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/DeleteRestoreEnvelopeService.java @@ -0,0 +1,105 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.esign.api.FoldersApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.model.Folder; +import com.docusign.esign.model.FoldersRequest; +import com.docusign.esign.model.FoldersResponse; + +import java.time.Instant; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public final class DeleteRestoreEnvelopeService { + public static final String RECYCLE_BIN_FOLDER_ID = "recyclebin"; + + public static FoldersResponse deleteEnvelope( + ApiClient apiClient, + String accountId, + String envelopeId) throws Exception { + FoldersApi foldersApi = new FoldersApi(apiClient); + //ds-snippet-start:eSign45Step3 + FoldersRequest foldersRequest = new FoldersRequest(); + foldersRequest.setEnvelopeIds(Collections.singletonList(envelopeId)); + //ds-snippet-end:eSign45Step3 + + //ds-snippet-start:eSign45Step4 + var moveEnvelopes = foldersApi.moveEnvelopesWithHttpInfo(accountId, RECYCLE_BIN_FOLDER_ID, foldersRequest); + Map> headers = moveEnvelopes.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return moveEnvelopes.getData(); + //ds-snippet-end:eSign45Step4 + } + //ds-snippet-start:eSign45Step6 + + public static FoldersResponse moveEnvelopeToFolder( + ApiClient apiClient, + String accountId, + String envelopeId, + String folderId, + String fromFolderId) throws Exception { + FoldersApi foldersApi = new FoldersApi(apiClient); + + FoldersRequest foldersRequest = new FoldersRequest(); + foldersRequest.setFromFolderId(fromFolderId); + foldersRequest.setEnvelopeIds(Collections.singletonList(envelopeId)); + + var moveEnvelopesResponse = foldersApi.moveEnvelopesWithHttpInfo(accountId, folderId, foldersRequest); + Map> headers = moveEnvelopesResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return moveEnvelopesResponse.getData(); + } + //ds-snippet-end:eSign45Step6 + + //ds-snippet-start:eSign45Step5 + + public static FoldersResponse getFolders( + ApiClient apiClient, + String accountId) throws Exception { + FoldersApi foldersApi = new FoldersApi(apiClient); + + var callListResponse = foldersApi.callListWithHttpInfo(accountId, foldersApi.new CallListOptions()); + Map> headers = callListResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return callListResponse.getData(); + } + + public static Folder getFolderIdByName(List folders, String targetName) { + for (Folder folder : folders) { + if (folder.getName().equals(targetName)) { + return folder; + } + + if (folder.getFolders() != null && !folder.getFolders().isEmpty()) { + Folder nestedFolder = DeleteRestoreEnvelopeService.getFolderIdByName(folder.getFolders(), targetName); + if (nestedFolder != null) { + return nestedFolder; + } + } + } + return null; + } + //ds-snippet-end:eSign45Step5 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/DocumentGenerationService.java b/src/main/java/com/docusign/controller/eSignature/services/DocumentGenerationService.java new file mode 100644 index 00000000..592bf401 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/DocumentGenerationService.java @@ -0,0 +1,339 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.api.TemplatesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * Document generation code example + */ +public final class DocumentGenerationService { + public static final String CANDIDATE_NAME = "Candidate_Name"; + + public static final String MANAGER_NAME = "Manager_Name"; + + public static final String JOB_TITLE = "Job_Title"; + + public static final String SALARY = "Salary"; + + public static final String BONUS = "Bonus"; + + public static final String RSUS = "RSUs"; + + public static final String START_DATE = "Start_Date"; + + public static final String COMPENSATION_PACKAGE = "Compensation_Package"; + + public static final String COMPENSATION_COMPONENT = "Compensation_Component"; + + public static final String DETAILS = "Details"; + + public static final String TEXT_BOX = "TextBox"; + + public static final String STRING_TRUE = "true"; + + public static final String ANCHOR_UNITS = "pixels"; + + public static final String DEFAULT_ID = "1"; + + //ds-snippet-start:eSign42Step3 + private static EnvelopeDefinition addDocumentTemplate(String offerDocDocx) throws IOException { + String documentName = "OfferLetterDemo.docx"; + Document document = EnvelopeHelpers.createDocumentFromFile(offerDocDocx, documentName, DEFAULT_ID); + document.setOrder("1"); + document.pages("1"); + + EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition(); + envelopeDefinition.setDocuments(Collections.singletonList(document)); + + return envelopeDefinition; + } + //ds-snippet-end:eSign42Step3 + + public String generateDocument( + String accountId, + String candidateEmail, + String candidateName, + String managerName, + String jobTitle, + String salary, + String rsus, + String startDate, + String offerDocDocx, + EnvelopesApi envelopesApi, + TemplatesApi templatesApi) throws ApiException, IOException { + //ds-snippet-start:eSign42Step2 + var template = templatesApi.createTemplateWithHttpInfo(accountId, makeTemplate()); + Map> headers = template.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + String templateId = template.getData().getTemplateId(); + //ds-snippet-end:eSign42Step2 + + //ds-snippet-start:eSign42Step3 + var updateResponse = templatesApi.updateDocumentWithHttpInfo(accountId, templateId, DEFAULT_ID, + addDocumentTemplate(offerDocDocx), templatesApi.new UpdateDocumentOptions()); + headers = updateResponse.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + //ds-snippet-end:eSign42Step3 + + //ds-snippet-start:eSign42Step4 + var tabsResponse = templatesApi.createTabsWithHttpInfo(accountId, templateId, DEFAULT_ID, prepareTabs()); + headers = tabsResponse.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + //ds-snippet-end:eSign42Step4 + + //ds-snippet-start:eSign42Step5 + var envelopeSummary = envelopesApi.createEnvelopeWithHttpInfo( + accountId, + makeEnvelope(candidateEmail, candidateName, template.getData().getTemplateId()), + envelopesApi.new CreateEnvelopeOptions()); + headers = envelopeSummary.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + ; + String envelopeId = envelopeSummary.getData().getEnvelopeId(); + //ds-snippet-end:eSign42Step5 + + //ds-snippet-start:eSign42Step6 + var formFieldResponse = envelopesApi.getEnvelopeDocGenFormFieldsWithHttpInfo(accountId, envelopeId); + headers = formFieldResponse.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + ; + + String documentId = ""; + if (!formFieldResponse.getData().getDocGenFormFields().isEmpty()) { + DocGenFormFields docGenFormFields = formFieldResponse.getData().getDocGenFormFields().get(0); + if (docGenFormFields != null) { + documentId = docGenFormFields.getDocumentId(); + } + } + //ds-snippet-end:eSign42Step6 + + //ds-snippet-start:eSign42Step7 + DocGenFormFieldRequest formFields = getFormFields( + documentId, + candidateName, + managerName, + jobTitle, + salary, + rsus, + startDate); + + var envelopeDocGenResponse = envelopesApi.updateEnvelopeDocGenFormFieldsWithHttpInfo(accountId, envelopeId, + formFields, envelopesApi.new UpdateEnvelopeDocGenFormFieldsOptions()); + headers = envelopeDocGenResponse.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + ; + //ds-snippet-end:eSign42Step7 + + //ds-snippet-start:eSign42Step8 + Envelope envelope = new Envelope(); + envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + + var envelopeUpdateSummary = envelopesApi.updateWithHttpInfo(accountId, envelopeId, envelope, + envelopesApi.new UpdateOptions()); + headers = envelopeUpdateSummary.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + ; + //ds-snippet-end:eSign42Step8 + return envelopeUpdateSummary.getData().getEnvelopeId(); + } + + //ds-snippet-start:eSign42Step4 + private TemplateTabs prepareTabs() { + SignHere signHere = createSignHere(); + DateSigned dateSigned = createDateSigned(); + + TemplateTabs templateTabs = new TemplateTabs(); + templateTabs.setSignHereTabs(Collections.singletonList(signHere)); + templateTabs.setDateSignedTabs(Collections.singletonList(dateSigned)); + + return templateTabs; + } + + private SignHere createSignHere() { + SignHere signHere = new SignHere(); + + signHere.setAnchorString("Employee Signature"); + signHere.setAnchorUnits(ANCHOR_UNITS); + signHere.setAnchorXOffset("5"); + signHere.setAnchorYOffset("-22"); + + return signHere; + } + + private DateSigned createDateSigned() { + DateSigned dateSigned = new DateSigned(); + + dateSigned.setAnchorString("Date Signed"); + dateSigned.setAnchorUnits(ANCHOR_UNITS); + dateSigned.setAnchorYOffset("-22"); + + return dateSigned; + } + //ds-snippet-end:eSign42Step4 + + //ds-snippet-start:eSign42Step7 + private DocGenFormFieldRequest getFormFields( + String documentId, + String candidateName, + String managerName, + String jobTitle, + String salary, + String rsus, + String startDate) { + DocGenFormField candidateNameField = new DocGenFormField(); + candidateNameField.setName(CANDIDATE_NAME); + candidateNameField.setValue(candidateName); + + DocGenFormField managerNameField = new DocGenFormField(); + managerNameField.setName(MANAGER_NAME); + managerNameField.setValue(managerName); + + DocGenFormField jobTitleField = new DocGenFormField(); + jobTitleField.setName(JOB_TITLE); + jobTitleField.setValue(jobTitle); + + DocGenFormField startDateField = new DocGenFormField(); + startDateField.setName(START_DATE); + startDateField.setValue(startDate); + + DocGenFormField compensationPackageField = new DocGenFormField(); + compensationPackageField.setName(COMPENSATION_PACKAGE); + compensationPackageField.setType("TableRow"); + compensationPackageField.setRowValues(Arrays.asList( + new DocGenFormFieldRowValue() + .docGenFormFieldList(Arrays.asList( + new DocGenFormField() + .name(COMPENSATION_COMPONENT) + .value(SALARY), + new DocGenFormField() + .name(DETAILS) + .value("$" + salary))), + new DocGenFormFieldRowValue() + .docGenFormFieldList(Arrays.asList( + new DocGenFormField() + .name(COMPENSATION_COMPONENT) + .value(BONUS), + new DocGenFormField() + .name(DETAILS) + .value("20%"))), + new DocGenFormFieldRowValue() + .docGenFormFieldList(Arrays.asList( + new DocGenFormField() + .name(COMPENSATION_COMPONENT) + .value(RSUS), + new DocGenFormField() + .name(DETAILS) + .value(rsus))))); + + DocGenFormFields formFields = new DocGenFormFields(); + formFields.setDocGenFormFieldList(Arrays.asList( + candidateNameField, + managerNameField, + jobTitleField, + startDateField, + compensationPackageField)); + formFields.setDocumentId(documentId); + + DocGenFormFieldRequest docGenFormFieldRequest = new DocGenFormFieldRequest(); + docGenFormFieldRequest.setDocGenFormFields(Collections.singletonList(formFields)); + + return docGenFormFieldRequest; + } + //ds-snippet-end:eSign42Step7 + + //ds-snippet-start:eSign42Step5 + private EnvelopeDefinition makeEnvelope(String candidateEmail, String candidateName, String templateId) { + TemplateRole signerRole = new TemplateRole(); + signerRole.setName(candidateName); + signerRole.setEmail(candidateEmail); + signerRole.setRoleName(EnvelopeHelpers.SIGNER_ROLE_NAME); + + EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition(); + envelopeDefinition.setTemplateRoles(Collections.singletonList(signerRole)); + envelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_CREATED); + envelopeDefinition.setTemplateId(templateId); + + return envelopeDefinition; + } + //ds-snippet-end:eSign42Step5 + + //ds-snippet-start:eSign42Step2 + private EnvelopeTemplate makeTemplate() { + Signer signer = new Signer(); + signer.setRoleName(EnvelopeHelpers.SIGNER_ROLE_NAME); + signer.setRecipientId(DEFAULT_ID); + signer.setRoutingOrder("1"); + + Recipients recipients = new Recipients(); + recipients.setSigners(Collections.singletonList(signer)); + + EnvelopeTemplate template = new EnvelopeTemplate(); + template.setEmailSubject("Please sign this document"); + template.setName("Example Template"); + template.setDescription("Example template created via the API"); + template.setRecipients(recipients); + template.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_CREATED); + + return template; + } + //ds-snippet-end:eSign42Step2 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/EmbeddedConsoleService.java b/src/main/java/com/docusign/controller/eSignature/services/EmbeddedConsoleService.java new file mode 100644 index 00000000..b1776d91 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/EmbeddedConsoleService.java @@ -0,0 +1,44 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.ConsoleViewRequest; +import com.docusign.esign.model.ViewUrl; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public final class EmbeddedConsoleService { + public static ViewUrl createConsoleView( + EnvelopesApi envelopesApi, + String dsReturnUrl, + String envelopeId, + String startingView, + String accountId) throws ApiException { + // Step 1. Create the Console / Web UI view. + // Set the URL where you want the recipient to go once they are finished in + // the Web UI. There are cases where a user will never click "FINISH" within + // the Web UI, you cannot assume control will be passed back to your application. + //ds-snippet-start:eSign12Step2 + ConsoleViewRequest viewRequest = new ConsoleViewRequest(); + viewRequest.setReturnUrl(dsReturnUrl); + if ("envelope".equalsIgnoreCase(startingView) && envelopeId != null) { + viewRequest.setEnvelopeId(envelopeId); + } + + // Step 2. Call the CreateSenderView API + var consoleView = envelopesApi.createConsoleViewWithHttpInfo(accountId, viewRequest); + Map> headers = consoleView.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return consoleView.getData(); + //ds-snippet-end:eSign12Step2 + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/EmbeddedSendingService.java b/src/main/java/com/docusign/controller/eSignature/services/EmbeddedSendingService.java new file mode 100644 index 00000000..ad85f62a --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/EmbeddedSendingService.java @@ -0,0 +1,113 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import com.docusign.esign.model.EnvelopeViewDocumentSettings; +import com.docusign.esign.model.EnvelopeViewRecipientSettings; +import com.docusign.esign.model.EnvelopeViewRequest; +import com.docusign.esign.model.EnvelopeViewSettings; +import com.docusign.esign.model.EnvelopeViewTaggerSettings; +import com.docusign.esign.model.EnvelopeViewTemplateSettings; +import com.docusign.esign.model.ViewUrl; + +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public final class EmbeddedSendingService { + //ds-snippet-start:eSign11Step3 + public static ViewUrl createSenderView( + EnvelopesApi envelopesApi, + String accountId, + String envelopeId, + String dsReturnUrl, + String startingScreen) throws ApiException { + // Create the sender view. + // Set the url where you want the recipient to go once they are done + // signing should typically be a callback route somewhere in your app. + EnvelopeViewRecipientSettings recipientSettings = new EnvelopeViewRecipientSettings(); + recipientSettings.setShowEditRecipients("false"); + recipientSettings.setShowContactsList("false"); + + EnvelopeViewDocumentSettings documentSettings = new EnvelopeViewDocumentSettings(); + documentSettings.setShowEditDocuments("false"); + documentSettings.setShowEditDocumentVisibility("false"); + documentSettings.setShowEditPages("false"); + + EnvelopeViewTaggerSettings taggerSettings = new EnvelopeViewTaggerSettings(); + taggerSettings.setPaletteSections("default"); + taggerSettings.setPaletteDefault("custom"); + + EnvelopeViewTemplateSettings templateSettings = new EnvelopeViewTemplateSettings(); + templateSettings.setShowMatchingTemplatesPrompt("true"); + + EnvelopeViewSettings viewSettings = new EnvelopeViewSettings(); + viewSettings.setStartingScreen(startingScreen); + viewSettings.setSendButtonAction("send"); + viewSettings.setShowBackButton("false"); + viewSettings.setBackButtonAction("previousPage"); + viewSettings.setShowHeaderActions("false"); + viewSettings.setShowDiscardAction("false"); + viewSettings.setLockToken(""); + viewSettings.setRecipientSettings(recipientSettings); + viewSettings.setDocumentSettings(documentSettings); + viewSettings.setTaggerSettings(taggerSettings); + viewSettings.setTemplateSettings(templateSettings); + + EnvelopeViewRequest viewRequest = new EnvelopeViewRequest(); + viewRequest.setReturnUrl(dsReturnUrl); + viewRequest.setViewAccess("envelope"); + viewRequest.setSettings(viewSettings); + + var senderViewResponse = envelopesApi.createSenderViewWithHttpInfo(accountId, envelopeId, viewRequest); + Map> headers = senderViewResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return senderViewResponse.getData(); + } + //ds-snippet-end:eSign11Step3 + + //ds-snippet-start:eSign11Step2 + public static EnvelopeSummary createEnvelopeWithDraftStatus( + EnvelopesApi envelopesApi, + String signerEmail, + String signerName, + String ccEmail, + String ccName, + String status, + WorkArguments args, + String accountId) throws IOException, ApiException { + args.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_CREATED); + EnvelopeDefinition env = SigningViaEmailService.makeEnvelope( + signerEmail, + signerName, + ccEmail, + ccName, + status, + args); + var createEnvelope = envelopesApi.createEnvelopeWithHttpInfo(accountId, env, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = createEnvelope.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return createEnvelope.getData(); + } + //ds-snippet-end:eSign11Step2 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/EmbeddedSigningService.java b/src/main/java/com/docusign/controller/eSignature/services/EmbeddedSigningService.java new file mode 100644 index 00000000..6c9170b2 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/EmbeddedSigningService.java @@ -0,0 +1,134 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.time.Instant; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public final class EmbeddedSigningService { + public static ViewUrl embeddedSigning( + ApiClient apiClient, + String accountId, + String envelopeId, + RecipientViewRequest viewRequest) throws ApiException { + EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); + + var recipientView = envelopesApi.createRecipientViewWithHttpInfo(accountId, envelopeId, viewRequest); + Map> headers = recipientView.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return recipientView.getData(); + } + + public static String createEnvelope( + ApiClient apiClient, + String accountId, + EnvelopeDefinition envelope) throws ApiException { + EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); + + var envelopeSummary = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = envelopeSummary.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return envelopeSummary.getData().getEnvelopeId(); + } + + //ds-snippet-start:eSign1Step4 + public static RecipientViewRequest makeRecipientViewRequest( + String signerEmail, + String signerName, + String clientUserId, + String dsReturnURL, + String pingURL) { + RecipientViewRequest viewRequest = new RecipientViewRequest(); + // Set the url where you want the recipient to go once they are done signing + // should typically be a callback route somewhere in your app. + // The query parameter is included as an example of how + // to save/recover state information during the redirect to + // the DocuSign signing. It's usually better to use + // the session mechanism of your web framework. Query parameters + // can be changed/spoofed very easily. + String stateValue = "?state=123"; + viewRequest.setReturnUrl(dsReturnURL + stateValue); + + // How has your app authenticated the user? In addition to your app's + // authentication, you can include authenticate steps from DocuSign. + // Eg, SMS authentication + String authenticationMethod = "none"; + viewRequest.setAuthenticationMethod(authenticationMethod); + + // Recipient information must match embedded recipient info + // we used to create the envelope. + viewRequest.setEmail(signerEmail); + viewRequest.setUserName(signerName); + viewRequest.setClientUserId(clientUserId); + + // DocuSign recommends that you redirect to DocuSign for the + // embedded signing. There are multiple ways to save state. + // To maintain your application's session, use the pingUrl + // parameter. It causes the DocuSign signing web page + // (not the DocuSign server) to send pings via AJAX to your app. + // NOTE: The pings will only be sent if the pingUrl is an https address + String pingFrequency = "600"; + viewRequest.setPingFrequency(pingFrequency); // seconds + viewRequest.setPingUrl(pingURL); + + return viewRequest; + } + //ds-snippet-end + + //ds-snippet-start:eSign1Step2 + public static EnvelopeDefinition makeEnvelope( + String signerEmail, + String signerName, + String signerClientId, + Integer anchorOffsetY, + Integer anchorOffsetX, + String documentFileName, + String documentName) throws IOException { + // Create a signer recipient to sign the document, identified by name and email + // We set the clientUserId to enable embedded signing for the recipient + Signer signer = new Signer(); + signer.setEmail(signerEmail); + signer.setName(signerName); + signer.clientUserId(signerClientId); + signer.recipientId("1"); + signer.setTabs(EnvelopeHelpers.createSingleSignerTab("/sn1/", anchorOffsetY, anchorOffsetX)); + + // Add the recipient to the envelope object + Recipients recipients = new Recipients(); + recipients.setSigners(Collections.singletonList(signer)); + + EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition(); + envelopeDefinition.setEmailSubject("Please sign this document"); + envelopeDefinition.setRecipients(recipients); + Document doc = EnvelopeHelpers.createDocumentFromFile(documentFileName, documentName, "3"); + envelopeDefinition.setDocuments(Collections.singletonList(doc)); + // Request that the envelope be sent by setting |status| to "sent". + // To request that the envelope be created as a draft, set to "created" + envelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + + return envelopeDefinition; + } + //ds-snippet-end +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/EnvelopeCustomFieldValuesService.java b/src/main/java/com/docusign/controller/eSignature/services/EnvelopeCustomFieldValuesService.java new file mode 100644 index 00000000..8f426f27 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/EnvelopeCustomFieldValuesService.java @@ -0,0 +1,28 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.CustomFieldsEnvelope; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public final class EnvelopeCustomFieldValuesService { + public static CustomFieldsEnvelope envelopeCustomFieldValues( + EnvelopesApi envelopesApi, + String accountId, + String envelopeId) throws ApiException { + var customFields = envelopesApi.listCustomFieldsWithHttpInfo(accountId, envelopeId); + Map> headers = customFields.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return customFields.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/EnvelopeDocsService.java b/src/main/java/com/docusign/controller/eSignature/services/EnvelopeDocsService.java new file mode 100644 index 00000000..7f410a98 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/EnvelopeDocsService.java @@ -0,0 +1,30 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDocumentsResult; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public final class EnvelopeDocsService { + public static EnvelopeDocumentsResult envelopeDocs( + EnvelopesApi envelopesApi, + String accountId, + String envelopeId) throws ApiException { + // Step 1. List the envelope's documents + var listDocuments = envelopesApi.listDocumentsWithHttpInfo(accountId, envelopeId, + envelopesApi.new ListDocumentsOptions()); + Map> headers = listDocuments.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return listDocuments.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/EnvelopeGetDocService.java b/src/main/java/com/docusign/controller/eSignature/services/EnvelopeGetDocService.java new file mode 100644 index 00000000..f7fae59e --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/EnvelopeGetDocService.java @@ -0,0 +1,40 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import org.apache.commons.io.FilenameUtils; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public final class EnvelopeGetDocService { + + public static byte[] envelopeGetDoc( + EnvelopesApi envelopesApi, + String accountId, + String envelopeId, + String documentId) throws ApiException { + //ds-snippet-start:eSign7Step3 + var documentResponse = envelopesApi.getDocumentWithHttpInfo(accountId, envelopeId, documentId, + envelopesApi.new GetDocumentOptions()); + Map> headers = documentResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return documentResponse.getData(); + //ds-snippet-end:eSign7Step3 + } + + public static String addExtension(String fileName, String extension) { + if (FilenameUtils.isExtension(fileName, extension)) { + return fileName; + } + return String.join(".", fileName, extension); + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/EnvelopeInfoService.java b/src/main/java/com/docusign/controller/eSignature/services/EnvelopeInfoService.java new file mode 100644 index 00000000..357acc96 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/EnvelopeInfoService.java @@ -0,0 +1,31 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.Envelope; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +//ds-snippet-start:eSign4Step2 +public final class EnvelopeInfoService { + public static Envelope envelopeInfo( + EnvelopesApi envelopesApi, + String accountId, + String envelopeId) throws ApiException { + var envelopeResponse = envelopesApi.getEnvelopeWithHttpInfo(accountId, envelopeId, + envelopesApi.new GetEnvelopeOptions()); + Map> headers = envelopeResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return envelopeResponse.getData(); + } +} +//ds-snippet-end:eSign4Step2 diff --git a/src/main/java/com/docusign/controller/eSignature/services/EnvelopeRecipientsService.java b/src/main/java/com/docusign/controller/eSignature/services/EnvelopeRecipientsService.java new file mode 100644 index 00000000..7bc9e36f --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/EnvelopeRecipientsService.java @@ -0,0 +1,29 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.Recipients; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public final class EnvelopeRecipientsService { + public static Recipients envelopeRecipients( + EnvelopesApi envelopesApi, + String accountId, + String envelopeId) throws ApiException { + var recipientsResponse = envelopesApi.listRecipientsWithHttpInfo(accountId, envelopeId, + envelopesApi.new ListRecipientsOptions()); + Map> headers = recipientsResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return recipientsResponse.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/FocusedViewService.java b/src/main/java/com/docusign/controller/eSignature/services/FocusedViewService.java new file mode 100644 index 00000000..bc86bfba --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/FocusedViewService.java @@ -0,0 +1,205 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.AccountIdentityVerificationWorkflow; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.RecipientIdentityInputOption; +import com.docusign.esign.model.RecipientIdentityPhoneNumber; +import com.docusign.esign.model.RecipientIdentityVerification; +import com.docusign.esign.model.RecipientViewRequest; +import com.docusign.esign.model.ViewUrl; +import com.docusign.esign.model.Signer; +import com.docusign.esign.model.Recipients; +import com.docusign.esign.model.Document; + +import java.io.IOException; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class FocusedViewService { + + private static String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static String DOCUMENT_NAME = "Lorem Ipsum"; + + private static String SIGNER_CLIENT_ID = "1000"; + + public static String STATE_123 = "?state=123"; + + public static String AUTHENTICATION_METHOD = "none"; + + public String[] sendEnvelopeWithFocusedView( + String signerEmail, + String signerName, + String phoneNumber, + String countryCode, + ApiClient apiClient, + String accountId, + String returnUrl) throws ApiException, IOException { + //ds-snippet-start:eSign44Step3 + String workflowId = null; + + // Resolve identity verification workflow only when phone auth is requested. + if (phoneNumber != null && !phoneNumber.isBlank()) { + AccountsApi accountsApi = new AccountsApi(apiClient); + var workflowRes = accountsApi.getAccountIdentityVerificationWithHttpInfo( + accountId, + accountsApi.new GetAccountIdentityVerificationOptions()); + + Map> headers = workflowRes.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + List identityVerification = + workflowRes.getData().getIdentityVerification(); + for (AccountIdentityVerificationWorkflow workflow : identityVerification) { + if ("Phone Authentication".equals(workflow.getDefaultName())) { + workflowId = workflow.getWorkflowId(); + break; + } + } + + if (workflowId == null) { + throw new ApiException("IDENTITY_WORKFLOW_INVALID_ID"); + } + } + + EnvelopeDefinition envelope = makeEnvelope( + signerEmail, + signerName, + SIGNER_CLIENT_ID, + workflowId, + phoneNumber, + countryCode, + DOCUMENT_FILE_NAME, + DOCUMENT_NAME); + + EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); + + var envelopeSummary = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = envelopeSummary.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + String envelopeId = envelopeSummary.getData().getEnvelopeId(); + //ds-snippet-end:eSign44Step3 + + //ds-snippet-start:eSign44Step5 + RecipientViewRequest viewRequest = makeRecipientViewRequest(signerEmail, signerName, returnUrl, + SIGNER_CLIENT_ID, returnUrl); + var viewUrl = envelopesApi.createRecipientViewWithHttpInfo(accountId, envelopeId, viewRequest); + headers = viewUrl.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + String redirectUrl = viewUrl.getData().getUrl(); + + return new String[] { envelopeId, redirectUrl }; + //ds-snippet-end:eSign44Step5 + } + + //ds-snippet-start:eSign44Step4 + public RecipientViewRequest makeRecipientViewRequest( + String signerEmail, String signerName, String returnUrl, String signerClientId, String pingUrl) + throws ApiException { + String pingFrequency = "600"; + String linkToLauncher = "http://localhost:8080"; + String linkToDocuSignServer = "https://apps-d.docusign.com"; + + RecipientViewRequest viewRequest = new RecipientViewRequest(); + + viewRequest.setReturnUrl(returnUrl + STATE_123); + viewRequest.setAuthenticationMethod(AUTHENTICATION_METHOD); + viewRequest.setEmail(signerEmail); + viewRequest.setUserName(signerName); + viewRequest.setClientUserId(signerClientId); + + if (pingUrl != null) { + viewRequest.setPingFrequency(pingFrequency); + viewRequest.setPingUrl(pingUrl); + } + + viewRequest.setFrameAncestors(Arrays.asList(new String[] { linkToLauncher, linkToDocuSignServer })); + viewRequest.setMessageOrigins(Arrays.asList(new String[] { linkToDocuSignServer })); + + return viewRequest; + } + //ds-snippet-end:eSign44Step4 + + //ds-snippet-start:eSign44Step2 + public EnvelopeDefinition makeEnvelope( + String signerEmail, + String signerName, + String signerClientId, + String workflowId, + String phoneNumber, + String countryCode, + String documentFileName, + String documentName) throws IOException { + String emailSubject = "Please sign this document"; + String recipientId = "1"; + String docId = "3"; + + Signer signer = new Signer(); + signer.setEmail(signerEmail); + signer.setName(signerName); + signer.clientUserId(signerClientId); + signer.recipientId(recipientId); + + if (phoneNumber != null && !phoneNumber.isBlank()) { + RecipientIdentityPhoneNumber recipientIdentityPhoneNumber = new RecipientIdentityPhoneNumber(); + recipientIdentityPhoneNumber.setCountryCode(countryCode); + recipientIdentityPhoneNumber.setNumber(phoneNumber); + + RecipientIdentityInputOption inputOption = new RecipientIdentityInputOption(); + inputOption.setName("phone_number_list"); + inputOption.setValueType("PhoneNumberList"); + inputOption.setPhoneNumberList(List.of(recipientIdentityPhoneNumber)); + + RecipientIdentityVerification identityVerification = new RecipientIdentityVerification(); + identityVerification.setWorkflowId(workflowId); + identityVerification.setInputOptions(List.of(inputOption)); + + signer.setIdentityVerification(identityVerification); + } + + Recipients recipients = new Recipients(); + recipients.setSigners(Collections.singletonList(signer)); + + EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition(); + envelopeDefinition.setEmailSubject(emailSubject); + envelopeDefinition.setRecipients(recipients); + + Document document = EnvelopeHelpers.createDocumentFromFile(documentFileName, documentName, docId); + envelopeDefinition.setDocuments(Collections.singletonList(document)); + envelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + + return envelopeDefinition; + } + //ds-snippet-end:eSign44Step2 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/GetTabValuesService.java b/src/main/java/com/docusign/controller/eSignature/services/GetTabValuesService.java new file mode 100644 index 00000000..db742065 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/GetTabValuesService.java @@ -0,0 +1,28 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeFormData; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public final class GetTabValuesService { + public static EnvelopeFormData getTabValues( + EnvelopesApi envelopesApi, + String accountId, + String envelopeId) throws ApiException { + var formData = envelopesApi.getFormDataWithHttpInfo(accountId, envelopeId); + Map> headers = formData.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return formData.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/IdvAuthenticationService.java b/src/main/java/com/docusign/controller/eSignature/services/IdvAuthenticationService.java new file mode 100644 index 00000000..fda3bd09 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/IdvAuthenticationService.java @@ -0,0 +1,126 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.time.Instant; +import java.util.Base64; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public final class IdvAuthenticationService { + private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + public static EnvelopeSummary idvAuthentication( + EnvelopesApi envelopesApi, + String accountId, + EnvelopeDefinition envelope) throws ApiException { + var createEnvelope = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = createEnvelope.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return createEnvelope.getData(); + } + + public static String retrieveWorkflowId(ApiClient apiClient, String accountId) throws ApiException { + //ds-snippet-start:eSign23Step3 + AccountsApi workflowDetails = new AccountsApi(apiClient); + var workflowRes = workflowDetails.getAccountIdentityVerificationWithHttpInfo(accountId, + workflowDetails.new GetAccountIdentityVerificationOptions()); + Map> headers = workflowRes.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + List identityVerification = workflowRes.getData() + .getIdentityVerification(); + String workflowId = ""; + for (int i = 0; i < identityVerification.size(); i++) { + if (identityVerification.get(i).getDefaultName().equals("DocuSign ID Verification")) { + workflowId = identityVerification.get(i).getWorkflowId(); + } + } + return workflowId; + //ds-snippet-end:eSign23Step3 + } + + //ds-snippet-start:eSign23Step4 + public static EnvelopeDefinition createEnvelope( + String signerName, + String signerEmail, + String workflowId) { + EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition(); + envelopeDefinition.setEmailSubject("Please sign"); + envelopeDefinition.setEmailBlurb("Sample text for email body"); + envelopeDefinition.setStatus("Sent"); + + byte[] fileBytes = new byte[0]; + try { + fileBytes = EnvelopeHelpers.readFile(DOCUMENT_FILE_NAME); + } catch (IOException e) { + e.printStackTrace(); + } + Document doc1 = new Document(); + doc1.setDocumentBase64(Base64.getEncoder().encodeToString(fileBytes)); + doc1.setDocumentId("1"); + doc1.setFileExtension("pdf"); + doc1.setName("Lorem"); + + SignHere signHere1 = new SignHere(); + signHere1.setName("SignHereTab"); + signHere1.setXPosition("75"); + signHere1.setYPosition("572"); + signHere1.setTabLabel("SignHereTab"); + signHere1.setPageNumber("1"); + signHere1.setDocumentId("1"); + // A 1- to 8-digit integer or 32-character GUID to match recipient IDs on your + // own systems. + // This value is referenced in the Tabs element below to assign tabs on a + // per-recipient basis. + signHere1.setRecipientId("1"); // represents your {RECIPIENT_ID} + + Tabs signer1Tabs = new Tabs(); + signer1Tabs.setSignHereTabs(Collections.singletonList(signHere1)); + RecipientIdentityVerification workflow = new RecipientIdentityVerification(); + workflow.setWorkflowId(workflowId); + + String status = "created"; + String deliveryMethod = "email"; + Signer signer1 = new Signer(); + signer1.setName(signerName); + signer1.setEmail(signerEmail); + signer1.setRoleName(""); + signer1.setNote(""); + signer1.setStatus(status); + signer1.setDeliveryMethod(deliveryMethod); + signer1.setRecipientId("1"); // represents your {RECIPIENT_ID} + signer1.setIdentityVerification(workflow); + signer1.setTabs(signer1Tabs); + + Recipients recipients = new Recipients(); + recipients.setSigners(Collections.singletonList(signer1)); + + envelopeDefinition.setRecipients(recipients); + envelopeDefinition.setDocuments(Collections.singletonList(doc1)); + return envelopeDefinition; + } + //ds-snippet-end:eSign23Step4 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/InPersonSigningService.java b/src/main/java/com/docusign/controller/eSignature/services/InPersonSigningService.java new file mode 100644 index 00000000..69b0f6ba --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/InPersonSigningService.java @@ -0,0 +1,88 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.DSConfiguration; +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.time.Instant; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public final class InPersonSigningService { + public static ViewUrl inPersonSigning( + EnvelopesApi envelopesApi, + String accountId, + String envelopeId, + RecipientViewRequest viewRequest) throws ApiException { + var recipientView = envelopesApi.createRecipientViewWithHttpInfo(accountId, envelopeId, viewRequest); + Map> headers = recipientView.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return recipientView.getData(); + } + + //ds-snippet-start:eSign39Step4 + public static RecipientViewRequest makeRecipientViewRequest( + String hostEmail, + String hostName, + DSConfiguration config) { + String stateValue = "?state=123"; + String authenticationMethod = "none"; + String pingFrequency = "600"; + + RecipientViewRequest viewRequest = new RecipientViewRequest(); + + viewRequest.setReturnUrl(config.getDsReturnUrl() + stateValue); + viewRequest.setAuthenticationMethod(authenticationMethod); + viewRequest.setEmail(hostEmail); + viewRequest.setUserName(hostName); + viewRequest.setPingFrequency(pingFrequency); + viewRequest.setPingUrl(config.getDsPingUrl()); + + return viewRequest; + } + //ds-snippet-end:eSign39Step4 + + //ds-snippet-start:eSign39Step2 + public static EnvelopeDefinition makeEnvelope( + String hostEmail, + String hostName, + String signerName, + Integer anchorOffsetY, + Integer anchorOffsetX, + String documentFileName, + String documentName) throws IOException { + InPersonSigner inPersonSigner = new InPersonSigner(); + + inPersonSigner.setHostEmail(hostEmail); + inPersonSigner.setHostName(hostName); + inPersonSigner.setSignerName(signerName); + inPersonSigner.setRecipientId("1"); + inPersonSigner.setRoutingOrder("1"); + inPersonSigner.setTabs(EnvelopeHelpers.createSingleSignerTab("/sn1/", anchorOffsetY, anchorOffsetX)); + + Recipients recipients = new Recipients(); + recipients.setInPersonSigners(Collections.singletonList(inPersonSigner)); + + EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition(); + envelopeDefinition.setEmailSubject("Please host this in-person signing session"); + envelopeDefinition.setRecipients(recipients); + + Document document = EnvelopeHelpers.createDocumentFromFile(documentFileName, documentName, "1"); + envelopeDefinition.setDocuments(Collections.singletonList(document)); + envelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + + return envelopeDefinition; + } + //ds-snippet-end:eSign39Step2 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/KBAAuthenticationService.java b/src/main/java/com/docusign/controller/eSignature/services/KBAAuthenticationService.java new file mode 100644 index 00000000..2f6efc34 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/KBAAuthenticationService.java @@ -0,0 +1,91 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.time.Instant; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public final class KBAAuthenticationService { + private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String DOCUMENT_NAME = "Lorem"; + + public static EnvelopeSummary kbaAuthentication( + EnvelopesApi envelopesApi, + String accountId, + EnvelopeDefinition envelope) throws ApiException { + //ds-snippet-start:eSign22Step4 + var envelopeResponse = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = envelopeResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return envelopeResponse.getData(); + //ds-snippet-end:eSign22Step4 + } + + //ds-snippet-start:eSign22Step3 + public static Signer setSignHereAndSignerForEnvelope( + String signerName, + String signerEmail) throws IOException { + Document doc = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, "1"); + SignHere signHere = new SignHere(); + signHere.setName("SignHereTab"); + signHere.setXPosition("75"); + signHere.setYPosition("572"); + signHere.setTabLabel("SignHereTab"); + signHere.setPageNumber("1"); + signHere.setDocumentId(doc.getDocumentId()); + // A 1- to 8-digit integer or 32-character GUID to match recipient IDs on your + // own systems. + // This value is referenced in the Tabs element below to assign tabs on a + // per-recipient basis. + signHere.setRecipientId("1"); + + Signer signer = new Signer(); + signer.setName(signerName); + signer.setEmail(signerEmail); + signer.setRoutingOrder("1"); + signer.setStatus(EnvelopeHelpers.SIGNER_STATUS_CREATED); + signer.setDeliveryMethod(EnvelopeHelpers.DELIVERY_METHOD_EMAIL); + signer.setRecipientId(signHere.getRecipientId()); + signer.setTabs(EnvelopeHelpers.createSignerTabs(signHere)); + + return signer; + } + + public static EnvelopeDefinition createEnvelope( + String signerName, + String signerEmail) throws IOException { + Document doc = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, "1"); + Signer signer = setSignHereAndSignerForEnvelope(signerName, signerEmail); + signer.setIdCheckConfigurationName("ID Check"); + signer.setRequireIdLookup("true"); + + Recipients recipients = new Recipients(); + recipients.setSigners(Collections.singletonList(signer)); + + EnvelopeDefinition envelope = new EnvelopeDefinition(); + envelope.setEmailSubject("Please Sign"); + envelope.setEnvelopeIdStamping("true"); + envelope.setEmailBlurb("Sample text for email body"); + envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + envelope.setDocuments(Collections.singletonList(doc)); + envelope.setRecipients(recipients); + + return envelope; + } + //ds-snippet-end:eSign22Step3 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/ListEnvelopesServices.java b/src/main/java/com/docusign/controller/eSignature/services/ListEnvelopesServices.java new file mode 100644 index 00000000..c6717a31 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/ListEnvelopesServices.java @@ -0,0 +1,33 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.core.utils.DateUtils; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopesInformation; + +import java.time.Instant; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +public final class ListEnvelopesServices { + private static final int FROM_DATE_OFFSET_DAYS = 30; + + public static EnvelopesInformation listEnvelopes(EnvelopesApi envelopesApi, String accountId) throws ApiException { + EnvelopesApi.ListStatusChangesOptions options = envelopesApi.new ListStatusChangesOptions(); + LocalDate date = LocalDate.now().minusDays(FROM_DATE_OFFSET_DAYS); + options.setFromDate(DateUtils.DATE_WITH_LINES.format(date)); + + var listStatus = envelopesApi.listStatusChangesWithHttpInfo(accountId, options); + Map> headers = listStatus.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return listStatus.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/MultipleDeliveryService.java b/src/main/java/com/docusign/controller/eSignature/services/MultipleDeliveryService.java new file mode 100644 index 00000000..e109d9fb --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/MultipleDeliveryService.java @@ -0,0 +1,137 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public final class MultipleDeliveryService { + private static final String EMAIL_DELIVERY = "Email"; + + private static final String PDF_DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String PDF_DOCUMENT_NAME = "Lorem Ipsum"; + + private static final String DOCX_DOCUMENT_FILE_NAME = "World_Wide_Corp_Battle_Plan_Trafalgar.docx"; + + private static final String DOCX_DOCUMENT_NAME = "Battle Plan"; + + private static final int ANCHOR_OFFSET_Y = 10; + + private static final int ANCHOR_OFFSET_X = 20; + + private static final String SIGNER_ID = "1"; + + private static final String CC_ID = "2"; + + //ds-snippet-start:eSign46Step3 + public static EnvelopeSummary smsDelivery( + EnvelopesApi envelopesApi, + String accountId, + EnvelopeDefinition envelope) throws ApiException { + var createEnvelopeResponse = envelopesApi.createEnvelopeWithHttpInfo( + accountId, + envelope, + envelopesApi.new CreateEnvelopeOptions() + ); + + Map> headers = createEnvelopeResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return createEnvelopeResponse.getData(); + } + //ds-snippet-end:eSign46Step3 + + //ds-snippet-start:eSign46Step2 + public static EnvelopeDefinition makeEnvelope( + String signerName, + String signerEmail, + String countryCode, + String signersPhoneNumber, + String ccName, + String ccEmail, + String ccCountryCode, + String carbonCopyPhoneNumber, + String deliveryMethod, + String status) throws IOException { + + Tabs signerTabs = EnvelopeHelpers.createSignerTabs( + EnvelopeHelpers.createSignHere( + "/sn1/", + ANCHOR_OFFSET_Y, + ANCHOR_OFFSET_X + )); + + Signer signer = new Signer(); + signer.setName(signerName); + signer.setEmail(signerEmail); + signer.setRecipientId(SIGNER_ID); + signer.setRoutingOrder("1"); + signer.setTabs(signerTabs); + signer.setDeliveryMethod(EMAIL_DELIVERY); + signer.setAdditionalNotifications(Arrays.asList( + createAdditionalNotification(countryCode, signersPhoneNumber, deliveryMethod) + )); + + CarbonCopy cc = new CarbonCopy(); + cc.setName(ccName); + cc.setEmail(ccEmail); + cc.setRecipientId(CC_ID); + cc.setRoutingOrder("2"); + cc.setDeliveryMethod(EMAIL_DELIVERY); + cc.setAdditionalNotifications(Arrays.asList( + createAdditionalNotification(ccCountryCode, carbonCopyPhoneNumber, deliveryMethod) + )); + + EnvelopeDefinition envelope = new EnvelopeDefinition(); + envelope.setEmailSubject("Please sign this document set"); + envelope.setDocuments( + Arrays.asList( + EnvelopeHelpers.createDocumentFromFile( + DOCX_DOCUMENT_FILE_NAME, + DOCX_DOCUMENT_NAME, + "2" + ), + EnvelopeHelpers.createDocumentFromFile( + PDF_DOCUMENT_FILE_NAME, + PDF_DOCUMENT_NAME, + "3" + ) + ) + ); + envelope.setRecipients(EnvelopeHelpers.createRecipients(signer, cc)); + envelope.setStatus(status); + + return envelope; + } + + private static RecipientAdditionalNotification createAdditionalNotification( + String countryCode, + String phoneNumber, + String deliveryMethod) { + + RecipientPhoneNumber phone = new RecipientPhoneNumber(); + phone.setCountryCode(countryCode); + phone.setNumber(phoneNumber); + + RecipientAdditionalNotification notification = new RecipientAdditionalNotification(); + notification.setSecondaryDeliveryMethod(deliveryMethod); + notification.setPhoneNumber(phone); + + return notification; + } + //ds-snippet-end:eSign46Step2 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/PauseSignatureWorkflowService.java b/src/main/java/com/docusign/controller/eSignature/services/PauseSignatureWorkflowService.java new file mode 100644 index 00000000..3406fee4 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/PauseSignatureWorkflowService.java @@ -0,0 +1,99 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public final class PauseSignatureWorkflowService { + private static final String DOCUMENT_FILE_NAME = "Welcome.txt"; + + private static final String DOCUMENT_ID = "1"; + + private static final String DOCUMENT_NAME = "Welcome"; + + public static EnvelopeSummary pauseSignatureWorkflow( + EnvelopesApi envelopesApi, + String accountId, + EnvelopeDefinition envelope) throws ApiException { + var envelopeResponse = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = envelopeResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return envelopeResponse.getData(); + } + + //ds-snippet-start:eSign32Step3 + public static EnvelopeDefinition createEnvelope( + String signerName, + String signerEmail, + String signerName2, + String signerEmail2) throws IOException { + Document document = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, DOCUMENT_ID); + + WorkflowStep workflowStep = new WorkflowStep(); + workflowStep.setAction(EnvelopeHelpers.WORKFLOW_STEP_ACTION_PAUSE); + workflowStep.setTriggerOnItem(EnvelopeHelpers.WORKFLOW_TRIGGER_ROUTING_ORDER); + workflowStep.setItemId("2"); + + Workflow workflow = new Workflow(); + workflow.setWorkflowSteps(Collections.singletonList(workflowStep)); + + SignHere signHere1 = new SignHere(); + signHere1.setName("SignHereTabs"); + signHere1.setXPosition("200"); + signHere1.setYPosition("200"); + signHere1.setTabLabel("Sign Here"); + signHere1.setPageNumber("1"); + signHere1.setDocumentId(document.getDocumentId()); + + Signer signer1 = new Signer(); + signer1.setName(signerName); + signer1.setEmail(signerEmail); + signer1.setRoutingOrder("1"); + signer1.setRecipientId("1"); + signer1.setTabs(EnvelopeHelpers.createSignerTabs(signHere1)); + + SignHere signHere2 = new SignHere(); + signHere2.setName("SignHereTabs"); + signHere2.setXPosition("300"); + signHere2.setYPosition("200"); + signHere2.setTabLabel("Sign Here"); + signHere2.setPageNumber("1"); + signHere2.setDocumentId(document.getDocumentId()); + + Signer signer2 = new Signer(); + signer2.setName(signerName2); + signer2.setEmail(signerEmail2); + signer2.setRoutingOrder("2"); + signer2.setRecipientId("2"); + signer2.setTabs(EnvelopeHelpers.createSignerTabs(signHere2)); + + Recipients recipients = new Recipients(); + recipients.setSigners(Arrays.asList(signer1, signer2)); + + EnvelopeDefinition envelope = new EnvelopeDefinition(); + envelope.setEmailSubject("EnvelopeWorkflowTest"); + envelope.setDocuments(Collections.singletonList(document)); + envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + envelope.setRecipients(recipients); + envelope.setWorkflow(workflow); + + return envelope; + } + //ds-snippet-end:eSign32Step3 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/PermissionChangeSingleSettingService.java b/src/main/java/com/docusign/controller/eSignature/services/PermissionChangeSingleSettingService.java new file mode 100644 index 00000000..244eddc0 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/PermissionChangeSingleSettingService.java @@ -0,0 +1,90 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.DsModelUtils; +import com.docusign.core.model.AccountRoleSettingsPatch; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.AccountRoleSettings; +import com.docusign.esign.model.PermissionProfile; +import com.docusign.esign.model.PermissionProfileInformation; +import com.google.gson.Gson; + +import java.time.Instant; +import java.util.*; + +public final class PermissionChangeSingleSettingService { + public static PermissionProfile permissionChangeSingleSetting( + AccountsApi accountsApi, + String accountId, + String curProfileId) throws ApiException { + // Step 3. Construct your request body + //ds-snippet-start:eSign26Step3 + var permissionsInfo = accountsApi.listPermissionsWithHttpInfo(accountId, + accountsApi.new ListPermissionsOptions()); + Map> headers = permissionsInfo.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + PermissionProfile profile = PermissionChangeSingleSettingService.findProfile( + permissionsInfo.getData().getPermissionProfiles(), curProfileId) + .orElseThrow(NoSuchElementException::new); + //ds-snippet-end:eSign26Step3 + + // Step 4. Call the eSignature REST API + //ds-snippet-start:eSign26Step4 + AccountRoleSettings newSettings = Objects.requireNonNullElse(profile.getSettings(), + DsModelUtils.createDefaultRoleSettings()); + profile.setSettings(PermissionChangeSingleSettingService.changeRandomSettings(newSettings)); + + var permissionProfile = accountsApi.updatePermissionProfileWithHttpInfo(accountId, curProfileId, profile, + accountsApi.new UpdatePermissionProfileOptions()); + headers = permissionProfile.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return permissionProfile.getData(); + //ds-snippet-end:eSign26Step4 + } + + public static Optional findProfile(List profiles, String profileId) { + return profiles.stream().filter(p -> p.getPermissionProfileId().equals(profileId)).findFirst(); + } + + // Changes random boolean properties; in a real application, changing properties + // will be read from the page or in a different way + private static AccountRoleSettings changeRandomSettings(AccountRoleSettings settings) { + Gson gson = new Gson(); + String signingUiVersion = "1"; + // Change this value back to: gson.fromJson(gson.toJson(settings), + // AccountRoleSettings.class); + // as soon as the signinguiversion is added back to the swagger spec. + // Also change the type back from AccountRoleSettingsPatch to + // AccountRoleSettings + AccountRoleSettingsPatch newSettings = gson.fromJson(gson.toJson(settings), AccountRoleSettingsPatch.class); + newSettings.signingUiVersion(signingUiVersion); + Random random = new Random(System.currentTimeMillis()); + + return newSettings.canCreateWorkspaces(randomBool(random)).allowEnvelopeSending(randomBool(random)) + .allowSignerAttachments(randomBool(random)).allowESealRecipients(randomBool(random)) + .allowTaggingInSendAndCorrect(randomBool(random)).allowWetSigningOverride(randomBool(random)) + .enableApiRequestLogging(randomBool(random)).enableRecipientViewingNotifications(randomBool(random)) + .allowSupplementalDocuments(randomBool(random)).disableDocumentUpload(randomBool(random)); + } + + private static String randomBool(Random random) { + if (random.nextBoolean()) { + return DsModelUtils.TRUE; + } + return DsModelUtils.FALSE; + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/PermissionCreateService.java b/src/main/java/com/docusign/controller/eSignature/services/PermissionCreateService.java new file mode 100644 index 00000000..c409d119 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/PermissionCreateService.java @@ -0,0 +1,51 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.DsModelUtils; +import com.docusign.core.model.AccountRoleSettingsPatch; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.AccountRoleSettings; +import com.docusign.esign.model.PermissionProfile; +import com.google.gson.Gson; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public class PermissionCreateService { + public static PermissionProfile createNewProfile( + AccountsApi accountsApi, + String accountId, + String permissionProfileName) throws ApiException { + // Step 3. Construct your request body + // We're extending the AccountSettings class with AccountSettingsPatch to + // include the signingUIVersion which is missing in the swagger spec at this + // time. + //ds-snippet-start:eSign24Step3 + Gson gson = new Gson(); + String signingUiVersion = "1"; + AccountRoleSettings settings = DsModelUtils.createDefaultRoleSettings(); + AccountRoleSettingsPatch newSettings = gson.fromJson(gson.toJson(settings), AccountRoleSettingsPatch.class); + newSettings.signingUiVersion(signingUiVersion); + PermissionProfile profile = new PermissionProfile() + .permissionProfileName(permissionProfileName) + .settings(newSettings); + //ds-snippet-end:eSign24Step3 + + // Step 4. Call the eSignature REST API + //ds-snippet-start:eSign24Step4 + var permissionProfile = accountsApi.createPermissionProfileWithHttpInfo(accountId, profile, + accountsApi.new CreatePermissionProfileOptions()); + Map> headers = permissionProfile.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return permissionProfile.getData(); + //ds-snippet-end:eSign24Step4 + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/PermissionDeleteService.java b/src/main/java/com/docusign/controller/eSignature/services/PermissionDeleteService.java new file mode 100644 index 00000000..9281bdaf --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/PermissionDeleteService.java @@ -0,0 +1,28 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.client.ApiException; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public final class PermissionDeleteService { + public static void permissionDelete( + AccountsApi accountsApi, + String accountId, + String curProfileId) throws ApiException { + var deletePermissionProfile = accountsApi.deletePermissionProfileWithHttpInfo(accountId, curProfileId, + accountsApi.new DeletePermissionProfileOptions()); + + Map> headers = deletePermissionProfile.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/PermissionSetUserGroupsService.java b/src/main/java/com/docusign/controller/eSignature/services/PermissionSetUserGroupsService.java new file mode 100644 index 00000000..544d86a8 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/PermissionSetUserGroupsService.java @@ -0,0 +1,40 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.esign.api.GroupsApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.Group; +import com.docusign.esign.model.GroupInformation; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public final class PermissionSetUserGroupsService { + public static GroupInformation permissionSetUserGroups( + ApiClient apiClient, + String groupId, + String profileId, + String accountId) throws ApiException { + GroupsApi groupsApi = new GroupsApi(apiClient); + + // Step 3: Perform request + Group newGroup = new Group() + .groupId(groupId) + .permissionProfileId(profileId); + GroupInformation groupInformation = new GroupInformation() + .groups(List.of(newGroup)); + + var groupResponse = groupsApi.updateGroupsWithHttpInfo(accountId, groupInformation); + Map> headers = groupResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return groupResponse.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/PhoneAuthenticationService.java b/src/main/java/com/docusign/controller/eSignature/services/PhoneAuthenticationService.java new file mode 100644 index 00000000..5f197436 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/PhoneAuthenticationService.java @@ -0,0 +1,93 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public final class PhoneAuthenticationService { + private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String DOCUMENT_NAME = "Lorem"; + + public static EnvelopeSummary phoneAuthentication( + EnvelopesApi envelopesApi, + String accountId, + EnvelopeDefinition envelope) throws ApiException { + var envelopeResponse = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, + envelopesApi.new CreateEnvelopeOptions()); + + Map> headers = envelopeResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return envelopeResponse.getData(); + } + + //ds-snippet-start:eSign20Step4 + public static EnvelopeDefinition createEnvelope(String signerName, String signerEmail, String countryCode, + String phone, String workFlowId) throws IOException { + Document doc = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, "1"); + + SignHere signHere = new SignHere(); + signHere.setName("SignHereTab"); + signHere.setXPosition("200"); + signHere.setYPosition("160"); + signHere.setTabLabel("SignHereTab"); + signHere.setPageNumber("1"); + signHere.setDocumentId(doc.getDocumentId()); + // A 1- to 8-digit integer or 32-character GUID to match recipient IDs on your + // own systems. + // This value is referenced in the Tabs element below to assign tabs on a + // per-recipient basis. + signHere.setRecipientId("1"); + + RecipientIdentityPhoneNumber phoneNumber = new RecipientIdentityPhoneNumber(); + phoneNumber.setCountryCode(countryCode); + phoneNumber.setNumber(phone); + + RecipientIdentityInputOption inputOption = new RecipientIdentityInputOption(); + inputOption.setName("phone_number_list"); + inputOption.setValueType("PhoneNumberList"); + inputOption.setPhoneNumberList(List.of(phoneNumber)); + + RecipientIdentityVerification identityVerification = new RecipientIdentityVerification(); + + identityVerification.setWorkflowId(workFlowId); + identityVerification.setInputOptions(List.of(inputOption)); + + Signer signer = new Signer(); + signer.setName(signerName); + signer.setEmail(signerEmail); + signer.setRoutingOrder("1"); + signer.setStatus(EnvelopeHelpers.SIGNER_STATUS_CREATED); + signer.setDeliveryMethod(EnvelopeHelpers.DELIVERY_METHOD_EMAIL); + signer.setRecipientId(signHere.getRecipientId()); + signer.setTabs(EnvelopeHelpers.createSignerTabs(signHere)); + signer.setIdentityVerification(identityVerification); + + Recipients recipients = new Recipients(); + recipients.setSigners(List.of(signer)); + + EnvelopeDefinition envelope = new EnvelopeDefinition(); + envelope.setEmailSubject("Please Sign"); + envelope.setDocuments(List.of(doc)); + envelope.setEnvelopeIdStamping("true"); + envelope.setEmailBlurb("Sample text for email body"); + envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + envelope.setRecipients(recipients); + + return envelope; + } + //ds-snippet-end:eSign20Step4 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/ResponsiveSigningService.java b/src/main/java/com/docusign/controller/eSignature/services/ResponsiveSigningService.java new file mode 100644 index 00000000..aee538a7 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/ResponsiveSigningService.java @@ -0,0 +1,163 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public final class ResponsiveSigningService { + //ds-snippet-start:eSign38Step2 + private static final String TRUE = "true"; + + private static final String FALSE = "false"; + + private static final int L1_PRICE = 5; + + private static final int L2_PRICE = 150; + + private static final int ANCHOR_OFFSET_Y = 10; + + private static final int ANCHOR_OFFSET_X = 20; + + private static final String DEFAULT_FONT = "helvetica"; + + private static final String DEFAULT_FONT_SIZE = "size11"; + + private static final String ANCHOR_UNITS = "pixels"; + + private static final String HTML_DOCUMENT_FILE_NAME = "templates/order-form.ftl"; + + public static EnvelopeDefinition makeEnvelope( + String signerEmail, + String signerName, + String signerClientId, + String ccEmail, + String ccName, + WorkArguments args) throws IOException { + String htmlDoc = EnvelopeHelpers.createHtmlFromTemplateFile(HTML_DOCUMENT_FILE_NAME, "args", args); + htmlDoc = htmlDoc + .replace("/l1q/", " ") + .replace("/l2q/", " "); + ; + + Signer signer = new Signer() + .email(signerEmail) + .name(signerName) + .clientUserId(signerClientId) + .recipientId("1") + .routingOrder("1") + .roleName("Signer"); + + CarbonCopy cc = new CarbonCopy() + .email(ccEmail) + .name(ccName) + .recipientId("2") + .routingOrder("1"); + + EnvelopeDefinition envelope = new EnvelopeDefinition(); + envelope.setEmailSubject("Example Signing Document"); + envelope.setDocuments(Collections.singletonList( + new Document() + .name("Lorem Ipsum") + .documentId("1") + .htmlDefinition(new DocumentHtmlDefinition().source(htmlDoc)))); + signer.setTabs(createTabs()); + envelope.setRecipients(EnvelopeHelpers.createRecipients(signer, cc)); + envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + + return envelope; + } + + private static Tabs createTabs() { + FormulaTab formulaForFirstNumber = createFormulaTab("/l1e/", "l1e", L1_PRICE, "l1q"); + FormulaTab formulaForSecondNumber = createFormulaTab("/l2e/", "l2e", L2_PRICE, "l2q"); + FormulaTab finalFormula = new FormulaTab() + .font(DEFAULT_FONT) + .bold(TRUE) + .fontSize(DEFAULT_FONT_SIZE) + .anchorString("/l3t/") + .anchorYOffset("-8") + .anchorUnits(ANCHOR_UNITS) + .anchorXOffset("105") + .tabLabel("l3t") + .formula("[l1e] + [l2e]") + .roundDecimalPlaces("0") + .required(TRUE) + .locked(TRUE) + .disableAutoSize(FALSE); + + Tabs signerTabs = EnvelopeHelpers.createSingleSignerTab("/sn1/", ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X); + signerTabs.formulaTabs(Arrays.asList(formulaForFirstNumber, formulaForSecondNumber, finalFormula)); + + return signerTabs; + } + + private static FormulaTab createFormulaTab(String anchor, String label, int price, String numerical) { + return new FormulaTab() + .font(DEFAULT_FONT) + .fontSize(DEFAULT_FONT_SIZE) + .anchorString(anchor) + .anchorYOffset("-8") + .anchorUnits(ANCHOR_UNITS) + .anchorXOffset("105") + .tabLabel(label) + .formula(String.format("[%s] * {%d}", numerical, price)) + .roundDecimalPlaces("0") + .required(TRUE) + .locked(TRUE) + .disableAutoSize(FALSE); + } + + public static ViewUrl responsiveSigning( + EnvelopesApi envelopesApi, + String accountId, + String envelopeId, + RecipientViewRequest viewRequest) throws ApiException { + var recipientViewResponse = envelopesApi.createRecipientViewWithHttpInfo(accountId, envelopeId, + viewRequest); + + Map> headers = recipientViewResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return recipientViewResponse.getData(); + } + + public static RecipientViewRequest makeRecipientViewRequest( + String signerEmail, + String signerName, + DSConfiguration config, + String clientUserId) { + RecipientViewRequest viewRequest = new RecipientViewRequest(); + String stateValue = "?state=123"; + viewRequest.setReturnUrl(config.getDsReturnUrl() + stateValue); + + String authenticationMethod = "none"; + viewRequest.setAuthenticationMethod(authenticationMethod); + + viewRequest.setEmail(signerEmail); + viewRequest.setUserName(signerName); + viewRequest.setClientUserId(clientUserId); + + String pingFrequency = "600"; + viewRequest.setPingFrequency(pingFrequency); + viewRequest.setPingUrl(config.getDsPingUrl()); + + return viewRequest; + } + //ds-snippet-end:eSign38Step2 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/SMSDeliveryService.java b/src/main/java/com/docusign/controller/eSignature/services/SMSDeliveryService.java new file mode 100644 index 00000000..935f1657 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/SMSDeliveryService.java @@ -0,0 +1,117 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public final class SMSDeliveryService { + private static final String PDF_DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String PDF_DOCUMENT_NAME = "Lorem Ipsum"; + + private static final String DOCX_DOCUMENT_FILE_NAME = "World_Wide_Corp_Battle_Plan_Trafalgar.docx"; + + private static final String DOCX_DOCUMENT_NAME = "Battle Plan"; + + private static final int ANCHOR_OFFSET_Y = 10; + + private static final int ANCHOR_OFFSET_X = 20; + + //ds-snippet-start:eSign37Step3 + public static EnvelopeSummary smsDelivery( + EnvelopesApi envelopesApi, + String accountId, + EnvelopeDefinition envelope) throws ApiException { + var createEnvelopeResponse = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = createEnvelopeResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return createEnvelopeResponse.getData(); + } + //ds-snippet-end:eSign37Step3 + + //ds-snippet-start:eSign37Step2 + // document 2 (docx) has tag /sn1/ + // document 3 (pdf) has tag /sn1/ + // + // The envelope has two recipients. + // recipient 1 - signer + // recipient 2 - cc + // The envelope will be sent first to the signer. After it is signed, + // a copy is sent to the cc person. + public static EnvelopeDefinition makeEnvelope( + String countryCode, + String signersPhoneNumber, + String signerName, + String deliveryMethod, + String ccCountryCode, + String carbonCopyPhoneNumber, + String ccName, + String status) throws IOException { + // The DocuSign platform searches throughout your envelope's documents + // for matching anchor strings. So the signHere2 tab will be used in + // both document 2 and 3 since they use the same anchor string for + // their "signer 1" tabs. + Tabs signerTabs = EnvelopeHelpers.createSignerTabs( + EnvelopeHelpers.createSignHere("/sn1/", ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X)); + + // Create a signer recipient to sign the document, identified by name + // and phone number. We're setting the parameters via the object creation. + // RoutingOrder (lower means earlier) determines the order of deliveries + // to the recipients. Parallel routing order is supported by using the + // same integer as the order for two or more recipients. + + RecipientPhoneNumber phoneNumber = new RecipientPhoneNumber(); + phoneNumber.setCountryCode(countryCode); + phoneNumber.setNumber(signersPhoneNumber); + + Signer signer = new Signer(); + signer.setName(signerName); + signer.setPhoneNumber(phoneNumber); + signer.setRecipientId("1"); + signer.setRoutingOrder("1"); + signer.setTabs(signerTabs); + signer.setDeliveryMethod(deliveryMethod); + + // create a cc recipient to receive a copy of the documents, identified by name + // and phone number + RecipientPhoneNumber ccPhoneNumber = new RecipientPhoneNumber(); + ccPhoneNumber.setCountryCode(ccCountryCode); + ccPhoneNumber.setNumber(carbonCopyPhoneNumber); + + CarbonCopy cc = new CarbonCopy(); + cc.setName(ccName); + cc.setPhoneNumber(ccPhoneNumber); + cc.setRecipientId("2"); + cc.setRoutingOrder("2"); + cc.setDeliveryMethod(deliveryMethod); + + // The order in the docs array determines the order in the envelope + EnvelopeDefinition envelope = new EnvelopeDefinition(); + envelope.setEmailSubject("Please sign this document set"); + envelope.setDocuments(Arrays.asList( + EnvelopeHelpers.createDocumentFromFile(DOCX_DOCUMENT_FILE_NAME, DOCX_DOCUMENT_NAME, "2"), + EnvelopeHelpers.createDocumentFromFile(PDF_DOCUMENT_FILE_NAME, PDF_DOCUMENT_NAME, "3"))); + envelope.setRecipients(EnvelopeHelpers.createRecipients(signer, cc)); + // Request that the envelope be sent by setting |status| to "sent". + // To request that the envelope be created as a draft, set to "created" + envelope.setStatus(status); + + return envelope; + //ds-snippet-end:eSign37Step2 + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/ScheduledSendlingService.java b/src/main/java/com/docusign/controller/eSignature/services/ScheduledSendlingService.java new file mode 100644 index 00000000..51cbe82f --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/ScheduledSendlingService.java @@ -0,0 +1,77 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.util.List; + +public class ScheduledSendlingService { + private static final String PDF_DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String PDF_DOCUMENT_NAME = "Lorem Ipsum"; + + private static final int ANCHOR_OFFSET_Y = 10; + + private static final int ANCHOR_OFFSET_X = 20; + // document 1 (PDF) has sign here anchor tag /sn1/ + // + // The envelope has one recipient. + // recipient 1 - signer + + // create the envelope definition + + public static EnvelopeDefinition makeEnvelope( + String signerEmail, + String signerName, + String resumeDate, + String status) throws IOException { + // The DocuSign platform searches throughout your envelope's documents + // for matching anchor strings. + + // Step 2 start + //ds-snippet-start:eSign35Step2 + Tabs signerTabs = EnvelopeHelpers.createSignerTabs( + EnvelopeHelpers.createSignHere("/sn1/", ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X)); + + // Create a signer recipient to sign the document, identified by name + // and email. We're setting the parameters via the object creation. + // RoutingOrder (lower means earlier) determines the order of deliveries + // to the recipients. Parallel routing order is supported by using the + // same integer as the order for two or more recipients. + Signer signer = new Signer(); + signer.setEmail(signerEmail); + signer.setName(signerName); + signer.setRecipientId("1"); + signer.setRoutingOrder("1"); + signer.setTabs(signerTabs); + + // The order in the docs array determines the order in the envelope + EnvelopeDefinition envelope = new EnvelopeDefinition(); + envelope.setEmailSubject("Please sign this document"); + envelope.setDocuments(List.of( + EnvelopeHelpers.createDocumentFromFile(PDF_DOCUMENT_FILE_NAME, PDF_DOCUMENT_NAME, "1"))); + envelope.setRecipients(EnvelopeHelpers.createSingleRecipient(signer)); + + // Add the workflow to schedule the envelope with a delay + EnvelopeDelayRule delayRule = new EnvelopeDelayRule(); + + delayRule.setResumeDate(resumeDate + "T00:00:00Z"); + + ScheduledSending scheduledSending = new ScheduledSending(); + scheduledSending.setRules(List.of(delayRule)); + + Workflow workflow = new Workflow(); + workflow.setScheduledSending(scheduledSending); + envelope.setWorkflow(workflow); + + // Request that the envelope be sent by setting |status| to "sent". + // To request that the envelope be created as a draft, set to "created" + envelope.setStatus(status); + + return envelope; + //ds-snippet-end:eSign35Step2 + + // Step 2 end + } +} diff --git a/src/main/java/com/docusign/controller/examples/EG010ControllerSendBinaryDocs.java b/src/main/java/com/docusign/controller/eSignature/services/SendBinaryDocsService.java similarity index 61% rename from src/main/java/com/docusign/controller/examples/EG010ControllerSendBinaryDocs.java rename to src/main/java/com/docusign/controller/eSignature/services/SendBinaryDocsService.java index c25df617..7562fbfe 100644 --- a/src/main/java/com/docusign/controller/examples/EG010ControllerSendBinaryDocs.java +++ b/src/main/java/com/docusign/controller/eSignature/services/SendBinaryDocsService.java @@ -1,129 +1,141 @@ -package com.docusign.controller.examples; +package com.docusign.controller.eSignature.services; -import com.docusign.DSConfiguration; -import com.docusign.common.DocumentType; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.controller.eSignature.examples.ExampleException; +import com.docusign.core.common.DocumentType; +import com.docusign.core.model.DoneExample; import com.docusign.esign.model.CarbonCopy; import com.docusign.esign.model.Signer; import com.docusign.esign.model.Tabs; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; - +import jakarta.ws.rs.HttpMethod; +import jakarta.ws.rs.core.MediaType; import lombok.Value; - import org.json.JSONArray; import org.json.JSONObject; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; import org.springframework.util.StreamUtils; -import org.springframework.web.bind.annotation.RequestMapping; -import javax.net.ssl.HttpsURLConnection; -import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.HttpMethod; -import javax.ws.rs.core.MediaType; +import javax.net.ssl.HttpsURLConnection; import java.io.DataOutputStream; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.time.Instant; import java.util.List; +import java.util.Map; +public final class SendBinaryDocsService { + private static final int ANCHOR_OFFSET_Y = 10; -/** - * Send an envelope using binary document transfer.
- * The envelope includes a pdf, doc, and HTML document. Multipart data transfer - * is used to send the documents in binary format to DocuSign. - */ -@Controller -@RequestMapping("/eg010") -public class EG010ControllerSendBinaryDocs extends AbstractController { + private static final int ANCHOR_OFFSET_X = 20; private static final String HYPHENS = "--"; + private static final String LINE_DELIMITER = "\r\n"; + private static final String BOUNDARY_DELIMITER = "multipartboundary_multipartboundary"; private static final String HTML_DOCUMENT_FILE_NAME = "templates/candy-bonbon.ftl"; + private static final String HTML_DOCUMENT_NAME = "Order acknowledgement"; + private static final String PDF_DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; - private static final String PDF_DOCUMENT_NAME = "Lorem Ipsum"; - private static final String DOCX_DOCUMENT_FILE_NAME = "World_Wide_Corp_Battle_Plan_Trafalgar.docx"; - private static final String DOCX_DOCUMENT_NAME = "Battle Plan"; - private static final int ANCHOR_OFFSET_Y = 10; - private static final int ANCHOR_OFFSET_X = 20; - private final Session session; - private final User user; + private static final String PDF_DOCUMENT_NAME = "Lorem Ipsum"; + private static final String DOCX_DOCUMENT_FILE_NAME = "World_Wide_Corp_Battle_Plan_Trafalgar.docx"; - @Autowired - public EG010ControllerSendBinaryDocs(DSConfiguration config, Session session, User user) { - super(config, "eg010", "Send envelope with multipart mime"); - this.session = session; - this.user = user; - } + private static final String DOCX_DOCUMENT_NAME = "Battle Plan"; - @Override - // ***DS.snippet.0.start - protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws IOException { - // Step 1. Gather documents and their headers + public static String sendBinaryDocs( + WorkArguments args, + String signerName, + String signerEmail, + String ccName, + String ccEmail, + String basePath, + String accountId, + String accessToken) throws IOException { List documents = List.of( - new DocumentInfo(HTML_DOCUMENT_NAME, "1", DocumentType.HTML, - EnvelopeHelpers.createHtmlFromTemplateFile(HTML_DOCUMENT_FILE_NAME, "args", args)), - new DocumentInfo(DOCX_DOCUMENT_NAME, "2", DocumentType.DOCX, + new DocumentInfo( + HTML_DOCUMENT_NAME, + "1", + DocumentType.HTML, + EnvelopeHelpers.createHtmlFromTemplateFile(HTML_DOCUMENT_FILE_NAME, "args", args) + .getBytes(StandardCharsets.UTF_8)), + new DocumentInfo( + DOCX_DOCUMENT_NAME, + "2", + DocumentType.DOCX, EnvelopeHelpers.readFile(DOCX_DOCUMENT_FILE_NAME)), - new DocumentInfo(PDF_DOCUMENT_NAME, "3", DocumentType.PDF, - EnvelopeHelpers.readFile(PDF_DOCUMENT_FILE_NAME)) - ); - - // Step 2. Make the envelope JSON request body - JSONObject envelopeJSON = makeEnvelopeJSON(args, documents); - - // Step 3. Create the multipart body - URL uri = new URL(String.format("%s/v2.1/accounts/%s/envelopes", session.getBasePath(), session.getAccountId())); - String contentType = String.join("",MediaType.MULTIPART_FORM_DATA, "; boundary=", BOUNDARY_DELIMITER); + new DocumentInfo( + PDF_DOCUMENT_NAME, + "3", + DocumentType.PDF, + EnvelopeHelpers.readFile(PDF_DOCUMENT_FILE_NAME))); + + // Make the envelope JSON request body + JSONObject envelopeJSON = SendBinaryDocsService.makeEnvelopeJSON( + signerName, + signerEmail, + ccName, + ccEmail, + documents); + + // Create the multipart body + URL uri = new URL(String.format("%s/v2.1/accounts/%s/envelopes", basePath, accountId)); + String contentType = String.join( + "", + MediaType.MULTIPART_FORM_DATA, + "; boundary=", BOUNDARY_DELIMITER); HttpsURLConnection connection = (HttpsURLConnection) uri.openConnection(); connection.setRequestMethod(HttpMethod.POST); connection.setRequestProperty(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON); connection.setRequestProperty(HttpHeaders.CONTENT_TYPE, contentType); - connection.setRequestProperty(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + user.getAccessToken()); + connection.setRequestProperty(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken); connection.setDoOutput(true); - // See https://developers.docusign.com/esign-rest-api/guides/requests-and-responses + // See + // https://developers.docusign.com/esign-rest-api/guides/requests-and-responses + //ds-snippet-start:eSign10Step4 DataOutputStream buffer = new DataOutputStream(connection.getOutputStream()); - writeBoundaryHeader(buffer, MediaType.APPLICATION_JSON, "form-data"); + SendBinaryDocsService.writeBoundaryHeader(buffer, MediaType.APPLICATION_JSON, "form-data"); buffer.writeBytes(envelopeJSON.toString(DoneExample.JSON_INDENT_FACTOR)); for (DocumentInfo docInfo : documents) { String content = String.format("file; filename=\"%s\";documentid=%s", docInfo.getName(), docInfo.getId()); buffer.writeBytes(LINE_DELIMITER); - writeBoundaryHeader(buffer, docInfo.getDocType().getMime(), content); + SendBinaryDocsService.writeBoundaryHeader(buffer, docInfo.getDocType().getMime(), content); buffer.write(docInfo.getData()); } - writeClosingBoundary(buffer); + SendBinaryDocsService.writeClosingBoundary(buffer); + + Map> headers = connection.getHeaderFields(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } int responseCode = connection.getResponseCode(); if (responseCode < HttpURLConnection.HTTP_OK || responseCode >= HttpURLConnection.HTTP_MULT_CHOICE) { String error = StreamUtils.copyToString(connection.getErrorStream(), StandardCharsets.UTF_8); throw new ExampleException(error, null); } - String responseString = StreamUtils.copyToString(connection.getInputStream(), StandardCharsets.UTF_8); - JSONObject obj = new JSONObject(responseString); - String envelopeId = obj.getString("envelopeId"); - session.setEnvelopeId(envelopeId); - - DoneExample.createDefault(title) - .withMessage("The envelope has been created and sent!
Envelope ID " + envelopeId + ".") - .addToModel(model); - return DONE_EXAMPLE_PAGE; + return StreamUtils.copyToString(connection.getInputStream(), StandardCharsets.UTF_8); } + //ds-snippet-end:eSign10Step4 - private static void writeBoundaryHeader(DataOutputStream buffer, - String contentType, String contentDisposition) throws IOException { + private static void writeBoundaryHeader( + DataOutputStream buffer, + String contentType, + String contentDisposition) throws IOException { buffer.writeBytes(HYPHENS); buffer.writeBytes(BOUNDARY_DELIMITER); buffer.writeBytes(LINE_DELIMITER); @@ -152,7 +164,13 @@ private static void writeClosingBoundary(DataOutputStream buffer) throws IOExcep // recipient 2 - cc // The envelope will be sent first to the signer. // After it is signed, a copy is sent to the cc person. - private static JSONObject makeEnvelopeJSON(WorkArguments args, List documents) { + //ds-snippet-start:eSign10Step3 + private static JSONObject makeEnvelopeJSON( + String signerName, + String signerEmail, + String ccName, + String ccEmail, + List documents) { // The DocuSign platform searches throughout your envelope's documents for // matching anchor strings. So the signHere2 tab will be used in both document // 2 and 3 since they use the same anchor string for their "signer 1" tabs. @@ -165,16 +183,17 @@ private static JSONObject makeEnvelopeJSON(WorkArguments args, List> headers = envelopeSummary.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return envelopeSummary.getData(); + } + + public static ViewUrl createRecipientView( + EnvelopesApi envelopesApi, + String accountId, + String envelopeId, + RecipientViewRequest viewRequest) throws ApiException { + var recipientView = envelopesApi.createRecipientViewWithHttpInfo(accountId, envelopeId, viewRequest); + Map> headers = recipientView.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return recipientView.getData(); + } + + public static RecipientViewRequest makeRecipientViewRequest( + String signerEmail, + String signerName, + String dsReturnUrl, + String dsPingUrl) { + RecipientViewRequest viewRequest = new RecipientViewRequest(); + // Set the url where you want the recipient to go once they are done signing + // should typically be a callback route somewhere in your app. + // The query parameter is included as an example of how + // to save/recover state information during the redirect to + // the DocuSign signing. It's usually better to use + // the session mechanism of your web framework. Query parameters + // can be changed/spoofed very easily. + String state = "?state=123"; + viewRequest.setReturnUrl(dsReturnUrl + state); + + return setEmailAndSignerNameForRecipientViewRequest( + viewRequest, + signerEmail, + signerName, + dsPingUrl); + } + + public static RecipientViewRequest setEmailAndSignerNameForRecipientViewRequest( + RecipientViewRequest viewRequest, + String signerEmail, + String signerName, + String dsPingUrl) { + // How has your app authenticated the user? In addition to your app's + // authentication, you can include authenticate steps from DocuSign. + // Eg, SMS authentication + String authenticationMethod = "none"; + viewRequest.setAuthenticationMethod(authenticationMethod); + + // Recipient information must match embedded recipient info + // we used to create the envelope. + viewRequest.setEmail(signerEmail); + viewRequest.setUserName(signerName); + viewRequest.setClientUserId(SIGNER_CLIENT_ID); + + // DocuSign recommends that you redirect to DocuSign for the + // Embedded signing . There are multiple ways to save state. + // To maintain your application's session, use the pingUrl + // parameter. It causes the DocuSign signing web page + // (not the DocuSign server) to send pings via AJAX to your app. + // NOTE: The pings will only be sent if the pingUrl is an https address + String pingFrequency = "600"; + viewRequest.setPingFrequency(pingFrequency); // seconds + viewRequest.setPingUrl(dsPingUrl); + + return viewRequest; + } + + // Construct your request body + //ds-snippet-start:eSign16Step3 + public static EnvelopeDefinition makeEnvelope(String signerEmail, String signerName) throws IOException { + // Create a signer recipient to sign the document, identified by name and email + // We set the clientUserId to enable embedded signing for the recipient + Signer signer = new Signer(); + signer.setEmail(signerEmail); + signer.setName(signerName); + signer.clientUserId(SIGNER_CLIENT_ID); + signer.recipientId("1"); + + // Create tabs and CustomFields + SignHere signHere = new SignHere(); + signHere.setAnchorString("/sn1"); + signHere.setAnchorUnits("pixels"); + signHere.setAnchorYOffset("10"); + signHere.setAnchorXOffset("20"); + + Text textLegal = new Text(); + textLegal.setAnchorString("/legal/"); + textLegal.setAnchorUnits("pixels"); + textLegal.setAnchorYOffset("-9"); + textLegal.setAnchorXOffset("5"); + textLegal.setFont("helvetica"); + textLegal.setFontSize("size11"); + textLegal.setBold("true"); + textLegal.setValue(signerName); + textLegal.setLocked("false"); + textLegal.setTabId("legal_name"); + textLegal.setTabLabel("Legal Name"); + + Text textFamiliar = new Text(); + textFamiliar.setAnchorString("/familiar/"); + textFamiliar.setAnchorUnits("pixels"); + textFamiliar.setAnchorYOffset("-9"); + textFamiliar.setAnchorXOffset("5"); + textFamiliar.setFont("helvetica"); + textFamiliar.setFontSize("size11"); + textFamiliar.setBold("true"); + textFamiliar.setValue(signerName); + textFamiliar.setLocked("false"); + textFamiliar.setTabId("familiar_name"); + textFamiliar.setTabLabel("Familiar Name"); + + Integer salary = 123000; + + Numerical numericalSalary = new Numerical(); + numericalSalary.setValidationType("Currency"); + numericalSalary.setPageNumber("1"); + numericalSalary.setDocumentId("1"); + numericalSalary.setXPosition("210"); + numericalSalary.setYPosition("235"); + numericalSalary.setHeight("20"); + numericalSalary.setWidth("70"); + numericalSalary.setFont("helvetica"); + numericalSalary.setFontSize("size11"); + numericalSalary.setBold("true"); + numericalSalary.setNumericalValue(String.format("%d", salary)); + numericalSalary.setTabId("salary"); + numericalSalary.setTabLabel("salary"); + + LocalePolicyTab localePolicyTab = new LocalePolicyTab(); + localePolicyTab.setCultureName("en-US"); + localePolicyTab.setCurrencyCode("usd"); + localePolicyTab.setCurrencyPositiveFormat("csym_1_comma_234_comma_567_period_89"); + localePolicyTab.setCurrencyNegativeFormat("minus_csym_1_comma_234_comma_567_period_89"); + localePolicyTab.setUseLongCurrencyFormat("true"); + numericalSalary.setLocalePolicy(localePolicyTab); + + TextCustomField salaryCustomField = new TextCustomField(); + salaryCustomField.setName("salary"); + salaryCustomField.setRequired("false"); + salaryCustomField.setShow("true"); // Yes, included in the CoC + salaryCustomField.setValue(String.valueOf(salary)); + + CustomFields cf = new CustomFields(); + cf.setTextCustomFields(Collections.singletonList(salaryCustomField)); + + Tabs tabs = new Tabs(); + tabs.setSignHereTabs(Collections.singletonList(signHere)); + tabs.setTextTabs(Arrays.asList(textLegal, textFamiliar)); + tabs.setNumericalTabs(List.of(numericalSalary)); + + signer.setTabs(tabs); + + // Add the recipient to the envelope object + Recipients recipients = new Recipients(); + recipients.setSigners(Collections.singletonList(signer)); + + EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition(); + envelopeDefinition.setEmailSubject("Please sign this document from the Java SDK"); + envelopeDefinition.setRecipients(recipients); + Document doc = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, "1"); + envelopeDefinition.setDocuments(Collections.singletonList(doc)); + envelopeDefinition.setCustomFields(cf); + // Request that the envelope be sent by setting |status| to "sent". + // To request that the envelope be created as a draft, set to "created" + envelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + + return envelopeDefinition; + } + //ds-snippet-end:eSign16Step3 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/SetTemplateTabValuesService.java b/src/main/java/com/docusign/controller/eSignature/services/SetTemplateTabValuesService.java new file mode 100644 index 00000000..d6be5331 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/SetTemplateTabValuesService.java @@ -0,0 +1,168 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; + +public final class SetTemplateTabValuesService { + public static ViewUrl setTemplateTabValues( + EnvelopesApi envelopesApi, + String accountId, + String envelopeId, + RecipientViewRequest viewRequest) throws ApiException { + var recipientView = envelopesApi.createRecipientViewWithHttpInfo(accountId, envelopeId, viewRequest); + Map> headers = recipientView.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null && reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return recipientView.getData(); + } + + public static RecipientViewRequest makeRecipientViewRequest( + String signerEmail, + String signerName, + String dsReturnUrl, + String clientUserId, + String dsPingUrl) { + //ds-snippet-start:eSign17Step6 + RecipientViewRequest viewRequest = new RecipientViewRequest(); + // Set the url where you want the recipient to go once they are done signing + // should typically be a callback route somewhere in your app. + // The query parameter is included as an example of how + // to save/recover state information during the redirect to + // the DocuSign signing. It's usually better to use + // the session mechanism of your web framework. Query parameters + // can be changed/spoofed very easily. + String state = "?state=123"; + viewRequest.setReturnUrl(dsReturnUrl + state); + + return SetTabValuesService.setEmailAndSignerNameForRecipientViewRequest( + viewRequest, + signerEmail, + signerName, + dsPingUrl); + //ds-snippet-end:eSign17Step6 + } + + public static EnvelopeDefinition makeEnvelope( + String signerEmail, + String signerName, + String ccEmail, + String ccName, + String templateId, + String clientUserId) { + // Create a signer recipient to sign the document, identified by name and email + // We set the clientUserId to enable embedded signing for the recipient + + // Create tabs and CustomFields + //ds-snippet-start:eSign17Step3 + List list1 = new List(); + list1.setValue("green"); + list1.setDocumentId("1"); + list1.setPageNumber("1"); + list1.setTabLabel("list"); + + // Checkboxes + Checkbox ck1 = new Checkbox(); + ck1.setTabLabel("ckAuthorization"); + ck1.setSelected("true"); + + Checkbox ck2 = new Checkbox(); + ck2.setTabLabel("ckAgreement"); + ck2.setSelected("true"); + + Radio radio = new Radio(); + radio.setValue("white"); + radio.setSelected("true"); + + RadioGroup rg = new RadioGroup(); + rg.setGroupName("radio1"); + rg.setRadios(Collections.singletonList(radio)); + + Text txt = new Text(); + txt.setTabLabel("text"); + txt.setValue("Jabberywocky!"); + + // We can also add a new tab (field) to the ones already in the template: + + Text txtExtra = new Text(); + txtExtra.setDocumentId("1"); + txtExtra.setPageNumber("1"); + txtExtra.setXPosition("280"); + txtExtra.setYPosition("172"); + txtExtra.setFont("helvetica"); + txtExtra.setFontSize("size14"); + txtExtra.setTabLabel("added text field"); + txtExtra.setHeight("23"); + txtExtra.setWidth("84"); + txtExtra.setRequired("false"); + txtExtra.setBold("true"); + txtExtra.setValue(signerName); + txtExtra.setLocked("false"); + txtExtra.setTabId("name"); + + // Add the tabs model (including the SignHere tab) to the signer. + // The Tabs object wants arrays of the different field/tab types + // Tabs are set per recipient / signer + + Tabs tabs = new Tabs(); + + tabs.setTextTabs(Arrays.asList(txt, txtExtra)); + tabs.setRadioGroupTabs(Collections.singletonList(rg)); + tabs.setCheckboxTabs(Arrays.asList(ck1, ck2)); + tabs.setListTabs(Collections.singletonList(list1)); + + // create a signer recipient to sign the document, identified by name and email + // We're setting the parameters via the object creation + TemplateRole signer = new TemplateRole(); + signer.setEmail(signerEmail); + signer.setName(signerName); + // Setting the client_user_id marks the signer as embedded + signer.setClientUserId(clientUserId); + signer.setRoleName("signer"); + signer.setTabs(tabs); + + TemplateRole cc = new TemplateRole(); + cc.setEmail(ccEmail); + cc.setName(ccName); + cc.setRoleName("cc"); + + // Create an envelope custom field to save our application's + // Data about the envelope + TextCustomField customField = new TextCustomField(); + customField.setName("app metadata item"); + customField.setValue("1234567"); + customField.setRequired("false"); + customField.show("true"); // Yes, include in the CoC + + CustomFields cf = new CustomFields(); + cf.setTextCustomFields(Collections.singletonList(customField)); + //ds-snippet-end:eSign17Step3 + + // Next, create the top level envelope definition and populate it. + //ds-snippet-start:eSign17Step4 + EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition(); + envelopeDefinition.setEmailSubject("Please sign this document from the Java SDK"); + // The Recipients object wants arrays for each recipient type + envelopeDefinition.setTemplateId(templateId); + envelopeDefinition.setTemplateRoles(Arrays.asList(signer, cc)); + envelopeDefinition.setCustomFields(cf); + // Request that the envelope be sent by setting |status| to "sent". + // To request that the envelope be created as a draft, set to "created" + envelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + + return envelopeDefinition; + //ds-snippet-end:eSign17Step4 + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/SharedAccessService.java b/src/main/java/com/docusign/controller/eSignature/services/SharedAccessService.java new file mode 100644 index 00000000..acdfd0c6 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/SharedAccessService.java @@ -0,0 +1,146 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.core.utils.DateUtils; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.api.UsersApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.Instant; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +public final class SharedAccessService { + private static final Logger LOGGER = LoggerFactory.getLogger(SharedAccessService.class); + + private static final int FROM_DATE_OFFSET_DAYS = 10; + + private static final String MANAGE = "manage"; + + public UserInformation getUserInfo(UsersApi usersApi, String accountId, String agentEmail) { + UserInformation userInformation = null; + UsersApi.CallListOptions callListOptions = usersApi.new CallListOptions(); + callListOptions.setEmail(agentEmail); + + try { + var informationList = usersApi.callListWithHttpInfo(accountId, callListOptions); + Map> headers = informationList.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null && reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + if (Integer.parseInt(informationList.getData().getResultSetSize()) > 0) { + userInformation = informationList.getData().getUsers().stream() + .filter(user -> "Active".equals(user.getUserStatus())).findFirst().get(); + } + } catch (ApiException e) { + LOGGER.error(e.getMessage()); + } + + return userInformation; + } + + public NewUsersSummary createAgent( + UsersApi usersApi, + String accountId, + String agentEmail, + String agentName, + String activation) throws ApiException { + //ds-snippet-start:eSign43Step3 + UserInformation user = new UserInformation(); + user.email(agentEmail); + user.userName(agentName); + user.activationAccessCode(activation); + + NewUsersDefinition usersDefinition = new NewUsersDefinition(); + usersDefinition.addNewUsersItem(user); + + var createUser = usersApi.createWithHttpInfo(accountId, usersDefinition); + Map> headers = createUser.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null && reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return createUser.getData(); + //ds-snippet-end:eSign43Step3 + } + + public void activateAgent( + AccountsApi accountsApi, + String accountId, + String userId, + String createdUserId) throws ApiException { + AccountsApi.GetAgentUserAuthorizationsOptions options = accountsApi.new GetAgentUserAuthorizationsOptions(); + options.setPermissions(MANAGE); + var userAuthorizations = accountsApi.getAgentUserAuthorizationsWithHttpInfo(accountId, createdUserId, options); + Map> headers = userAuthorizations.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null && reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + if (userAuthorizations.getData().getAuthorizations() == null + || userAuthorizations.getData().getAuthorizations().isEmpty()) { + //ds-snippet-start:eSign43Step4 + AuthorizationUser user = new AuthorizationUser(); + user.userId(createdUserId); + user.accountId(accountId); + + UserAuthorizationCreateRequest userAuthorizationCreateRequest = new UserAuthorizationCreateRequest(); + userAuthorizationCreateRequest.agentUser(user); + userAuthorizationCreateRequest.permission(MANAGE); + + var createAuthorization = accountsApi.createUserAuthorizationWithHttpInfo(accountId, userId, + userAuthorizationCreateRequest); + headers = createAuthorization.getHeaders(); + remaining = headers.get("X-RateLimit-Remaining"); + reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null && reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + //ds-snippet-end:eSign43Step4 + } + } + + public EnvelopesInformation getEnvelopeInfo( + EnvelopesApi envelopesApi, + String accountId) throws ApiException { + //ds-snippet-start:eSign43Step5 + EnvelopesApi.ListStatusChangesOptions options = envelopesApi.new ListStatusChangesOptions(); + LocalDate date = LocalDate.now().minusDays(FROM_DATE_OFFSET_DAYS); + options.setFromDate(DateUtils.DATE_WITH_SLASH.format(date)); + + var listStatusResponse = envelopesApi.listStatusChangesWithHttpInfo(accountId, options); + Map> headers = listStatusResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null && reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return listStatusResponse.getData(); + //ds-snippet-end:eSign43Step5 + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/SigningViaEmailService.java b/src/main/java/com/docusign/controller/eSignature/services/SigningViaEmailService.java new file mode 100644 index 00000000..4910113d --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/SigningViaEmailService.java @@ -0,0 +1,121 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.core.common.DocumentType; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public final class SigningViaEmailService { + + private static final String HTML_DOCUMENT_FILE_NAME = "templates/candy-bonbon.ftl"; + + private static final String HTML_DOCUMENT_NAME = "Order acknowledgement"; + + private static final String PDF_DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String PDF_DOCUMENT_NAME = "Lorem Ipsum"; + + private static final String DOCX_DOCUMENT_FILE_NAME = "World_Wide_Corp_Battle_Plan_Trafalgar.docx"; + + private static final String DOCX_DOCUMENT_NAME = "Battle Plan"; + + private static final int ANCHOR_OFFSET_Y = 10; + + private static final int ANCHOR_OFFSET_X = 20; + + //ds-snippet-start:eSign2Step3 + public static EnvelopeSummary signingViaEmail( + EnvelopesApi envelopesApi, + String accountId, + EnvelopeDefinition envelope) throws ApiException { + var createEnvelopeResponse = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = createEnvelopeResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return createEnvelopeResponse.getData(); + } + //ds-snippet-end:eSign2Step3 + + // document 1 (html) has tag **signature_1** + // document 2 (docx) has tag /sn1/ + // document 3 (pdf) has tag /sn1/ + // + // The envelope has two recipients. + // recipient 1 - signer + // recipient 2 - cc + // The envelope will be sent first to the signer. After it is signed, + // a copy is sent to the cc person. + + //ds-snippet-start:eSign2Step2 + public static EnvelopeDefinition makeEnvelope( + String signerEmail, + String signerName, + String ccEmail, + String ccName, + String status, + WorkArguments args) throws IOException { + // The DocuSign platform searches throughout your envelope's documents + // for matching anchor strings. So the signHere2 tab will be used in + // both document 2 and 3 since they use the same anchor string for + // their "signer 1" tabs. + Tabs signerTabs = EnvelopeHelpers.createSignerTabs( + EnvelopeHelpers.createSignHere("**signature_1**", ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X), + EnvelopeHelpers.createSignHere("/sn1/", ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X)); + + // Create a signer recipient to sign the document, identified by name + // and email. We're setting the parameters via the object creation. + // RoutingOrder (lower means earlier) determines the order of deliveries + // to the recipients. Parallel routing order is supported by using the + // same integer as the order for two or more recipients. + Signer signer = new Signer(); + signer.setEmail(signerEmail); + signer.setName(signerName); + signer.setRecipientId("1"); + signer.setRoutingOrder("1"); + signer.setTabs(signerTabs); + + // create a cc recipient to receive a copy of the documents, identified by name + // and email + CarbonCopy cc = new CarbonCopy(); + cc.setEmail(ccEmail); + cc.setName(ccName); + cc.setRecipientId("2"); + cc.setRoutingOrder("2"); + + // The order in the docs array determines the order in the envelope + byte[] htmlDocument = EnvelopeHelpers.createHtmlFromTemplateFile(HTML_DOCUMENT_FILE_NAME, "args", args) + .getBytes(StandardCharsets.UTF_8); + EnvelopeDefinition envelope = new EnvelopeDefinition(); + envelope.setEmailSubject("Please sign this document set"); + envelope.setDocuments(Arrays.asList( + EnvelopeHelpers.createDocument(htmlDocument, HTML_DOCUMENT_NAME, + DocumentType.HTML.getDefaultFileExtention(), "1"), + EnvelopeHelpers.createDocumentFromFile(DOCX_DOCUMENT_FILE_NAME, DOCX_DOCUMENT_NAME, + "2"), + EnvelopeHelpers.createDocumentFromFile(PDF_DOCUMENT_FILE_NAME, PDF_DOCUMENT_NAME, + "3"))); + envelope.setRecipients(EnvelopeHelpers.createRecipients(signer, cc)); + // Request that the envelope be sent by setting |status| to "sent". + // To request that the envelope be created as a draft, set to "created" + envelope.setStatus(status); + + return envelope; + } + //ds-snippet-end:eSign2Step2 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/UnpauseSignatureWorkflowService.java b/src/main/java/com/docusign/controller/eSignature/services/UnpauseSignatureWorkflowService.java new file mode 100644 index 00000000..1a50fde4 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/UnpauseSignatureWorkflowService.java @@ -0,0 +1,50 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.Envelope; +import com.docusign.esign.model.EnvelopeUpdateSummary; +import com.docusign.esign.model.Workflow; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public class UnpauseSignatureWorkflowService { + public static EnvelopeUpdateSummary unpauseSignatureWorkflow( + EnvelopesApi envelopesApi, + String accountId, + String envelopeId) throws ApiException { + // Step 3: Construct your envelope JSON body + //ds-snippet-start:eSign33Step3 + Workflow workflow = new Workflow(); + workflow.setWorkflowStatus(EnvelopeHelpers.WORKFLOW_STATUS_IN_PROGRESS); + + Envelope envelope = new Envelope(); + envelope.setWorkflow(workflow); + + EnvelopesApi.UpdateOptions updateOptions = envelopesApi.new UpdateOptions(); + updateOptions.setResendEnvelope("true"); + //ds-snippet-end:eSign33Step3 + + // Step 4: Call the eSignature REST API + //ds-snippet-start:eSign33Step4 + var updateEnvelopeResponse = envelopesApi.updateWithHttpInfo( + accountId, + envelopeId, + envelope, + updateOptions); + Map> headers = updateEnvelopeResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return updateEnvelopeResponse.getData(); + //ds-snippet-end:eSign33Step4 + } +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/UseConditionalRecipientsService.java b/src/main/java/com/docusign/controller/eSignature/services/UseConditionalRecipientsService.java new file mode 100644 index 00000000..dbbdeac0 --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/UseConditionalRecipientsService.java @@ -0,0 +1,226 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; + +import java.io.IOException; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class UseConditionalRecipientsService { + private static final String DOCUMENT_FILE_NAME = "Welcome1.txt"; + + private static final String DOCUMENT_ID = "1"; + + private static final String DOCUMENT_NAME = "Welcome"; + + //ds-snippet-start:eSign34Step4 + public static EnvelopeSummary useConditionalRecipients( + EnvelopesApi envelopesApi, + String accountId, + EnvelopeDefinition envelope) throws ApiException { + var createEnvelopeResponse = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = createEnvelopeResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return createEnvelopeResponse.getData(); + } + //ds-snippet-end:eSign34Step4 + + //ds-snippet-start:eSign34Step3 + public static EnvelopeDefinition createEnvelope( + String signerNotCheckedName, + String signerNotCheckedEmail, + String signerCheckedName, + String signerCheckedEmail, + String signerName, + String signerEmail) throws IOException { + Document document = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, DOCUMENT_ID); + + WorkflowStep workflowStep = new WorkflowStep(); + workflowStep.setAction(EnvelopeHelpers.WORKFLOW_STEP_ACTION_PAUSE); + workflowStep.setTriggerOnItem(EnvelopeHelpers.WORKFLOW_TRIGGER_ROUTING_ORDER); + workflowStep.setItemId("2"); + workflowStep.setStatus("pending"); + workflowStep.setRecipientRouting(createRecipientRouting( + signerNotCheckedName, + signerNotCheckedEmail, + signerCheckedName, + signerCheckedEmail)); + + Workflow workflow = new Workflow(); + workflow.setWorkflowSteps(Collections.singletonList(workflowStep)); + + Recipients recipients = new Recipients(); + recipients.setSigners(Arrays.asList( + createApprovalSigner(document.getDocumentId()), + createPurchaserSigner(signerName, signerEmail, document.getDocumentId()))); + + EnvelopeDefinition envelope = new EnvelopeDefinition(); + envelope.setEmailSubject("ApproveIfChecked"); + envelope.setDocuments(Collections.singletonList(document)); + envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + envelope.setRecipients(recipients); + envelope.setWorkflow(workflow); + + return envelope; + } + + private static Signer createPurchaserSigner( + String signerName, + String signerEmail, + String documentId) { + SignHere signHere = new SignHere(); + signHere.setName("SignHereTabs"); + signHere.setXPosition("200"); + signHere.setYPosition("200"); + signHere.setTabLabel("PurchaserSignature"); + signHere.setPageNumber("1"); + signHere.setDocumentId(documentId); + + Checkbox checkbox = new Checkbox(); + checkbox.setName("ClickToApprove"); + checkbox.setSelected("false"); + checkbox.setXPosition("50"); + checkbox.setYPosition("50"); + checkbox.setTabLabel("ApproveWhenChecked"); + checkbox.setPageNumber("1"); + checkbox.setDocumentId(documentId); + + Tabs tabs = EnvelopeHelpers.createSignerTabs(signHere); + tabs.setCheckboxTabs(Collections.singletonList(checkbox)); + + Signer signer = new Signer(); + signer.setName(signerName); + signer.setEmail(signerEmail); + signer.setRoutingOrder("1"); + signer.setRecipientId("1"); + signer.setRoleName("Purchaser"); + signer.setTabs(tabs); + + return signer; + } + + private static Signer createApprovalSigner(String documentId) { + SignHere signHere = new SignHere(); + signHere.setName("SignHere"); + signHere.setRecipientId("2"); + signHere.setXPosition("200"); + signHere.setYPosition("300"); + signHere.setTabLabel("ApproverSignature"); + signHere.setPageNumber("1"); + signHere.setDocumentId(documentId); + + Signer signer = new Signer(); + signer.setName("Approver"); + signer.setEmail("placeholder@example.com"); + signer.setRoutingOrder("2"); + signer.setRecipientId("2"); + signer.setRoleName("Approver"); + signer.setTabs(EnvelopeHelpers.createSignerTabs(signHere)); + return signer; + } + + private static List createConditionalRecipientRuleConditions() { + + ConditionalRecipientRuleFilter filter1 = new ConditionalRecipientRuleFilter(); + filter1.setRecipientId("1"); + filter1.setScope("tabs"); + filter1.setTabId("ApprovalTab"); + filter1.setOperator("equals"); + filter1.setValue("false"); + filter1.setTabType("checkbox"); + filter1.setTabLabel("ApproveWhenChecked"); + + ConditionalRecipientRuleFilter filter2 = new ConditionalRecipientRuleFilter(); + filter2.setRecipientId("1"); + filter2.setScope("tabs"); + filter2.setTabId("ApprovalTab"); + filter2.setOperator("equals"); + filter2.setValue("true"); + filter2.setTabType("checkbox"); + filter2.setTabLabel("ApproveWhenChecked"); + + ConditionalRecipientRuleCondition condition1 = new ConditionalRecipientRuleCondition(); + condition1.setRecipientLabel("signer2a"); + condition1.setOrder("1"); + condition1.setFilters(Collections.singletonList(filter1)); + + ConditionalRecipientRuleCondition condition2 = new ConditionalRecipientRuleCondition(); + condition2.setRecipientLabel("signer2b"); + condition2.setOrder("2"); + condition2.setFilters(Collections.singletonList(filter2)); + return Arrays.asList(condition1, condition2); + } + + private static RecipientGroup createRecipientGroup( + String signerNotCheckedName, + String signerNotCheckedEmail, + String signerCheckedName, + String signerCheckedEmail) { + RecipientOption recipientOption1 = new RecipientOption(); + recipientOption1.setRecipientLabel("signer2a"); + recipientOption1.setName(signerNotCheckedName); + recipientOption1.setRoleName("Signer when not checked"); + recipientOption1.setEmail(signerNotCheckedEmail); + + RecipientOption recipientOption2 = new RecipientOption(); + recipientOption2.setRecipientLabel("signer2b"); + recipientOption2.setName(signerCheckedName); + recipientOption2.setRoleName("Signer when checked"); + recipientOption2.setEmail(signerCheckedEmail); + + RecipientGroup recipientGroup = new RecipientGroup(); + recipientGroup.setGroupName("Approver"); + recipientGroup.setGroupMessage("Members of this group approve a workflow"); + recipientGroup.setRecipients(Arrays.asList(recipientOption1, recipientOption2)); + return recipientGroup; + } + + private static ConditionalRecipientRule createConditionalRecipientRule( + String signerNotCheckedName, + String signerNotCheckedEmail, + String signerCheckedName, + String signerCheckedEmail) { + ConditionalRecipientRule conditionalRecipientRule = new ConditionalRecipientRule(); + conditionalRecipientRule.setRecipientId("2"); + conditionalRecipientRule.setOrder("0"); + conditionalRecipientRule.setRecipientGroup(createRecipientGroup( + signerNotCheckedName, + signerNotCheckedEmail, + signerCheckedName, + signerCheckedEmail)); + conditionalRecipientRule.setConditions(createConditionalRecipientRuleConditions()); + return conditionalRecipientRule; + } + + private static RecipientRouting createRecipientRouting( + String signerNotCheckedName, + String signerNotCheckedEmail, + String signerCheckedName, + String signerCheckedEmail) { + RecipientRules recipientRules = new RecipientRules(); + recipientRules.setConditionalRecipients(Collections.singletonList(createConditionalRecipientRule( + signerNotCheckedName, + signerNotCheckedEmail, + signerCheckedName, + signerCheckedEmail))); + + RecipientRouting recipientRouting = new RecipientRouting(); + recipientRouting.setRules(recipientRules); + return recipientRouting; + } + //ds-snippet-end:eSign34Step3 +} diff --git a/src/main/java/com/docusign/controller/eSignature/services/UseTemplateService.java b/src/main/java/com/docusign/controller/eSignature/services/UseTemplateService.java new file mode 100644 index 00000000..acfb7d7a --- /dev/null +++ b/src/main/java/com/docusign/controller/eSignature/services/UseTemplateService.java @@ -0,0 +1,83 @@ +package com.docusign.controller.eSignature.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.api.TemplatesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import com.docusign.esign.model.EnvelopeTemplateResults; +import com.docusign.esign.model.TemplateRole; + +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public final class UseTemplateService { + //ds-snippet-start:eSign9Step3 + public static EnvelopeSummary createEnvelopeTemplate( + EnvelopesApi envelopesApi, + String accountId, + EnvelopeDefinition envelope) throws ApiException { + var createEnvelopeResponse = envelopesApi.createEnvelopeWithHttpInfo(accountId, envelope, + envelopesApi.new CreateEnvelopeOptions()); + Map> headers = createEnvelopeResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return createEnvelopeResponse.getData(); + } + //ds-snippet-end:eSign9Step3 + + public static EnvelopeTemplateResults listTemplates( + ApiClient apiClient, + String accountId) throws ApiException { + TemplatesApi templatesApi = new TemplatesApi(apiClient); + + var listTemplatesResponse = templatesApi.listTemplatesWithHttpInfo(accountId, + templatesApi.new ListTemplatesOptions()); + Map> headers = listTemplatesResponse.getHeaders(); + java.util.List remaining = headers.get("X-RateLimit-Remaining"); + java.util.List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + return listTemplatesResponse.getData(); + } + + //ds-snippet-start:eSign9Step2 + public static EnvelopeDefinition makeEnvelope( + String signerName, + String signerEmail, + String ccEmail, + String ccName, + String templateId) { + TemplateRole signer = new TemplateRole(); + signer.setEmail(signerEmail); + signer.setName(signerName); + signer.setRoleName(EnvelopeHelpers.SIGNER_ROLE_NAME); + + TemplateRole cc = new TemplateRole(); + cc.setEmail(ccEmail); + cc.setName(ccName); + cc.setRoleName(EnvelopeHelpers.CC_ROLE_NAME); + + EnvelopeDefinition envelope = new EnvelopeDefinition(); + envelope.setTemplateId(templateId); + envelope.setTemplateRoles(Arrays.asList(signer, cc)); + envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + + return envelope; + } + //ds-snippet-end:eSign9Step2 +} diff --git a/src/main/java/com/docusign/controller/examples/AbstractController.java b/src/main/java/com/docusign/controller/examples/AbstractController.java deleted file mode 100644 index 9f8f4494..00000000 --- a/src/main/java/com/docusign/controller/examples/AbstractController.java +++ /dev/null @@ -1,178 +0,0 @@ -package com.docusign.controller.examples; - -import com.docusign.DSConfiguration; -import com.docusign.esign.api.AccountsApi; -import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.client.ApiClient; -import com.docusign.esign.client.ApiException; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpHeaders; -import org.springframework.security.oauth2.client.OAuth2ClientContext; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; - -import java.io.IOException; -import java.util.Objects; -import javax.servlet.http.HttpServletResponse; - - -/** - * Abstract base class for all controllers. It handles all requests which are - * registered by the derived classes and delegates an example specific action - * back to the appropriate controllers. If a user had not been authorized, it - * redirects him onto an authentication page. Derived classes must override an - * abstract method {@link #doWork(WorkArguments, ModelMap, HttpServletResponse)} - * to do something. This method is called from the POST request. Optionally you - * can override method {@link #onInitModel(WorkArguments, ModelMap)} to add - * example specific attributes into a page. - */ -@Controller -public abstract class AbstractController { - - protected static final String MODEL_ENVELOPE_OK = "envelopeOk"; - private static final String REDIRECT_PREFIX = "redirect:"; - private static final String REDIRECT_AUTHENTICATION_PAGE = REDIRECT_PREFIX + "/ds/mustAuthenticate"; - private static final String EXAMPLE_PAGES_PATH = "pages/examples/"; - protected static final String BEARER_AUTHENTICATION = "Bearer "; - protected static final String DONE_EXAMPLE_PAGE = "pages/example_done"; - protected static final String DONE_EXAMPLE_PAGE_COMPARE = "pages/example_done_compare"; - protected static final String ERROR_PAGE = "error.jsp"; - - @Autowired - private OAuth2ClientContext oAuth2ClientContext; - - @Autowired - private Session session; - - protected final String exampleName; - protected final String title; - private final String pagePath; - protected final DSConfiguration config; - - public AbstractController(DSConfiguration config, String exampleName, String title) { - this.config = config; - this.exampleName = exampleName; - pagePath = EXAMPLE_PAGES_PATH + exampleName; - this.title = title; - } - - @GetMapping - public String get(WorkArguments args, ModelMap model) { - if (isTokenExpired()) { - return REDIRECT_AUTHENTICATION_PAGE; - } - - try { - onInitModel(args, model); - return pagePath; - } catch (ApiException exception) { - return handleException(exception, model); - } - } - - @PostMapping - public Object create(WorkArguments args, ModelMap model, HttpServletResponse response) { - if (isTokenExpired()) { - return REDIRECT_AUTHENTICATION_PAGE; - } - - try { - return doWork(args, model, response); - } catch (IOException|ApiException exception) { - return handleException(exception, model); - } - } - - /** - * This method is called from the GET request and it should initialize a - * model. Override this method if it is necessary to add example specific - * attributes into the model. - * @param args the session attributes - * @param model the model data - * @throws ApiException if calling eSign API has failed - */ - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { - Class clazz = Objects.requireNonNullElse(getClass().getEnclosingClass(), getClass()); - String srcPath = String.join("", config.getExampleUrl(), clazz.getName().replace('.', '/'), ".java"); - model.addAttribute("csrfToken", ""); - model.addAttribute("title", title); - model.addAttribute("sourceFile", clazz.getSimpleName() + ".java"); - model.addAttribute("sourceUrl", srcPath); - model.addAttribute("documentation", config.getDocumentationPath() + exampleName); - } - - /** - * This method is called from the POST request. Example pages must override - * it. Overridden method should return an Object means URL to redirect. - * @param args the work arguments got from the current page - * @param model page model holder - * @param response for HTTP-specific functionality in sending a response - * @return {@link Object}. Possible types and values: null, - * {@link String} representation of the URL or Spring RedirectView object, - * (see {@link org.springframework.web.servlet.view.RedirectView RedirectView}) - * @throws ApiException if calling eSignature API has failed - * @throws IOException if I/O operation has failed - */ - protected abstract Object doWork(WorkArguments args, ModelMap model, - HttpServletResponse response) throws ApiException, IOException; - - /** - * Creates new instance of the eSignature API client. - * @param basePath URL to eSignature REST API - * @param userAccessToken user's access token - * @return an instance of the {@link ApiClient} - */ - protected static ApiClient createApiClient(String basePath, String userAccessToken) { - ApiClient apiClient = new ApiClient(basePath); - apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + userAccessToken); - // it is a workaround to NPE, see DSPW-61 - apiClient.addAuthorization("docusignAccessCode", null); - return apiClient; - } - - /** - * Creates a new instance of the eSignature EnvelopesApi. This method - * creates an instance of the ApiClient class silently. - * @param basePath URL to eSignature REST API - * @param userAccessToken user's access token - * @return an instance of the {@link EnvelopesApi} - */ - protected static EnvelopesApi createEnvelopesApi(String basePath, String userAccessToken) { - ApiClient apiClient = createApiClient(basePath, userAccessToken); - return new EnvelopesApi(apiClient); - } - - /** - * Creates a new instance of the eSignature AccountsApi. This method - * creates an instance of the ApiClient class silently. - * @param basePath URL to eSignature REST API - * @param userAccessToken user's access token - * @return an instance of the {@link AccountsApi} - */ - protected static AccountsApi createAccountsApi(String basePath, String userAccessToken) { - ApiClient apiClient = createApiClient(basePath, userAccessToken); - return new AccountsApi(apiClient); - } - - private String handleException(Exception exception, ModelMap model) { - new DoneExample() - .withTitle(exampleName) - .withName(title) - .withMessage(exception.getMessage()) - .withStackTrace(exception.getStackTrace()) - .addToModel(model); - return ERROR_PAGE; - } - - private boolean isTokenExpired() { - OAuth2AccessToken accessToken = oAuth2ClientContext.getAccessToken(); - boolean tokenExpired = accessToken != null && accessToken.isExpired(); - session.setRefreshToken(tokenExpired); - return tokenExpired; - } -} diff --git a/src/main/java/com/docusign/controller/examples/EG001ControllerEmbeddedSigning.java b/src/main/java/com/docusign/controller/examples/EG001ControllerEmbeddedSigning.java deleted file mode 100644 index 9534f183..00000000 --- a/src/main/java/com/docusign/controller/examples/EG001ControllerEmbeddedSigning.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.docusign.controller.examples; - -import com.docusign.DSConfiguration; -import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.client.ApiClient; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.Document; -import com.docusign.esign.model.EnvelopeDefinition; -import com.docusign.esign.model.EnvelopeSummary; -import com.docusign.esign.model.RecipientViewRequest; -import com.docusign.esign.model.Recipients; -import com.docusign.esign.model.Signer; -import com.docusign.esign.model.ViewUrl; -import com.docusign.model.Session; -import com.docusign.model.User; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.servlet.view.RedirectView; - -import java.io.IOException; -import java.util.Arrays; - -import javax.servlet.http.HttpServletResponse; - - -/** - * Embedded Signing Ceremony.
- * This example sends an envelope, and then uses an embedded signing ceremony - * for the first signer. Embedded signing provides a smoother user experience - * for the signer: the DocuSign signing ceremony is initiated from your site. - */ -@Controller -@RequestMapping("/eg001") -public class EG001ControllerEmbeddedSigning extends AbstractController { - - private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; - private static final String DOCUMENT_NAME = "Lorem Ipsum"; - private static final int ANCHOR_OFFSET_Y = 20; - private static final int ANCHOR_OFFSET_X = 10; - private static final String SIGNER_CLIENT_ID = "1000"; - - private final Session session; - private final User user; - - - @Autowired - public EG001ControllerEmbeddedSigning(DSConfiguration config, Session session, User user) { - super(config, "eg001", "Embedded Signing Ceremony"); - this.session = session; - this.user = user; - } - - @Override - protected Object doWork(WorkArguments args, ModelMap model, - HttpServletResponse response) throws ApiException, IOException { - String signerName = args.getSignerName(); - String signerEmail = args.getSignerEmail(); - String accountId = session.getAccountId(); - - // Step 1. Create the envelope definition - EnvelopeDefinition envelope = makeEnvelope(signerEmail, signerName); - - // Step 2. Call DocuSign to create the envelope - ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); - EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); - EnvelopeSummary envelopeSummary = envelopesApi.createEnvelope(accountId, envelope); - - String envelopeId = envelopeSummary.getEnvelopeId(); - session.setEnvelopeId(envelopeId); - - // Step 3. create the recipient view, the Signing Ceremony - RecipientViewRequest viewRequest = makeRecipientViewRequest(signerEmail, signerName); - ViewUrl viewUrl = envelopesApi.createRecipientView(accountId, envelopeId, viewRequest); - - // Step 4. Redirect the user to the Signing Ceremony - // Don't use an iFrame! - // State can be stored/recovered using the framework's session or a - // query parameter on the returnUrl (see the makeRecipientViewRequest method) - return new RedirectView(viewUrl.getUrl()); - } - - private RecipientViewRequest makeRecipientViewRequest(String signerEmail, String signerName) { - RecipientViewRequest viewRequest = new RecipientViewRequest(); - // Set the url where you want the recipient to go once they are done signing - // should typically be a callback route somewhere in your app. - // The query parameter is included as an example of how - // to save/recover state information during the redirect to - // the DocuSign signing ceremony. It's usually better to use - // the session mechanism of your web framework. Query parameters - // can be changed/spoofed very easily. - viewRequest.setReturnUrl(config.getDsReturnUrl() + "?state=123"); - - // How has your app authenticated the user? In addition to your app's - // authentication, you can include authenticate steps from DocuSign. - // Eg, SMS authentication - viewRequest.setAuthenticationMethod("none"); - - // Recipient information must match embedded recipient info - // we used to create the envelope. - viewRequest.setEmail(signerEmail); - viewRequest.setUserName(signerName); - viewRequest.setClientUserId(SIGNER_CLIENT_ID); - - // DocuSign recommends that you redirect to DocuSign for the - // Signing Ceremony. There are multiple ways to save state. - // To maintain your application's session, use the pingUrl - // parameter. It causes the DocuSign Signing Ceremony web page - // (not the DocuSign server) to send pings via AJAX to your app. - // NOTE: The pings will only be sent if the pingUrl is an https address - viewRequest.setPingFrequency("600"); // seconds - viewRequest.setPingUrl(config.getDsPingUrl()); - - return viewRequest; - } - - private static EnvelopeDefinition makeEnvelope(String signerEmail, String signerName) throws IOException { - // Create a signer recipient to sign the document, identified by name and email - // We set the clientUserId to enable embedded signing for the recipient - Signer signer = new Signer(); - signer.setEmail(signerEmail); - signer.setName(signerName); - signer.clientUserId(SIGNER_CLIENT_ID); - signer.recipientId("1"); - signer.setTabs(EnvelopeHelpers.createSingleSignerTab("/sn1/", ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X)); - - // Add the recipient to the envelope object - Recipients recipients = new Recipients(); - recipients.setSigners(Arrays.asList(signer)); - - EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition(); - envelopeDefinition.setEmailSubject("Please sign this document"); - envelopeDefinition.setRecipients(recipients); - Document doc = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, "3"); - envelopeDefinition.setDocuments(Arrays.asList(doc)); - // Request that the envelope be sent by setting |status| to "sent". - // To request that the envelope be created as a draft, set to "created" - envelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); - - return envelopeDefinition; - } -} diff --git a/src/main/java/com/docusign/controller/examples/EG002ControllerSigningViaEmail.java b/src/main/java/com/docusign/controller/examples/EG002ControllerSigningViaEmail.java deleted file mode 100644 index 16baca91..00000000 --- a/src/main/java/com/docusign/controller/examples/EG002ControllerSigningViaEmail.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.docusign.controller.examples; - -import com.docusign.DSConfiguration; -import com.docusign.common.DocumentType; -import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.CarbonCopy; -import com.docusign.esign.model.EnvelopeDefinition; -import com.docusign.esign.model.EnvelopeSummary; -import com.docusign.esign.model.Signer; -import com.docusign.esign.model.Tabs; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import java.io.IOException; -import java.util.Arrays; - -import javax.servlet.http.HttpServletResponse; - - -/** - * Send an envelope with a remote (email) signer and cc recipient.
- * The envelope includes a pdf, Word, and HTML document. Anchor text is used to - * position the signing fields in the documents. - */ -@Controller -@RequestMapping("/eg002") -public class EG002ControllerSigningViaEmail extends AbstractController { - - private static final String HTML_DOCUMENT_FILE_NAME = "templates/candy-bonbon.ftl"; - private static final String HTML_DOCUMENT_NAME = "Order acknowledgement"; - private static final String PDF_DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; - private static final String PDF_DOCUMENT_NAME = "Lorem Ipsum"; - private static final String DOCX_DOCUMENT_FILE_NAME = "World_Wide_Corp_Battle_Plan_Trafalgar.docx"; - private static final String DOCX_DOCUMENT_NAME = "Battle Plan"; - private static final int ANCHOR_OFFSET_Y = 10; - private static final int ANCHOR_OFFSET_X = 20; - - private final Session session; - private final User user; - - @Autowired - public EG002ControllerSigningViaEmail(DSConfiguration config, Session session, User user) { - super(config, "eg002", "Signing request by email"); - this.session = session; - this.user = user; - } - - @Override - protected Object doWork(WorkArguments args, ModelMap model, - HttpServletResponse response) throws ApiException, IOException { - // Set status for the makeEnvelope method - if (!EnvelopeHelpers.ENVELOPE_STATUS_CREATED.equalsIgnoreCase(args.getStatus())) { - args.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); - } - - EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); - - EnvelopeDefinition envelope = makeEnvelope(args); - EnvelopeSummary results = envelopesApi.createEnvelope(session.getAccountId(), envelope); - - // process results - session.setEnvelopeId(results.getEnvelopeId()); - DoneExample.createDefault(title) - .withMessage("The envelope has been created and sent!
Envelope ID " - + results.getEnvelopeId() + ".") - .withJsonObject(results) - .addToModel(model); - return DONE_EXAMPLE_PAGE; - } - - // document 1 (html) has tag **signature_1** - // document 2 (docx) has tag /sn1/ - // document 3 (pdf) has tag /sn1/ - // - // The envelope has two recipients. - // recipient 1 - signer - // recipient 2 - cc - // The envelope will be sent first to the signer. After it is signed, - // a copy is sent to the cc person. - public static EnvelopeDefinition makeEnvelope(WorkArguments args) throws IOException { - // The DocuSign platform searches throughout your envelope's documents - // for matching anchor strings. So the signHere2 tab will be used in - // both document 2 and 3 since they use the same anchor string for - // their "signer 1" tabs. - Tabs signerTabs = EnvelopeHelpers.createSignerTabs( - EnvelopeHelpers.createSignHere("**signature_1**", ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X), - EnvelopeHelpers.createSignHere("/sn1/", ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X)); - - // Create a signer recipient to sign the document, identified by name - // and email. We're setting the parameters via the object creation. - // RoutingOrder (lower means earlier) determines the order of deliveries - // to the recipients. Parallel routing order is supported by using the - // same integer as the order for two or more recipients. - Signer signer = new Signer(); - signer.setEmail(args.getSignerEmail()); - signer.setName(args.getSignerName()); - signer.setRecipientId("1"); - signer.setRoutingOrder("1"); - signer.setTabs(signerTabs); - - // create a cc recipient to receive a copy of the documents, identified by name and email - CarbonCopy cc = new CarbonCopy(); - cc.setEmail(args.getCcEmail()); - cc.setName(args.getCcName()); - cc.setRecipientId("2"); - cc.setRoutingOrder("2"); - - // The order in the docs array determines the order in the envelope - byte[] htmlDocument = EnvelopeHelpers.createHtmlFromTemplateFile(HTML_DOCUMENT_FILE_NAME, "args", args); - EnvelopeDefinition envelope = new EnvelopeDefinition(); - envelope.setEmailSubject("Please sign this document set"); - envelope.setDocuments(Arrays.asList( - EnvelopeHelpers.createDocument(htmlDocument, HTML_DOCUMENT_NAME, - DocumentType.HTML.getDefaultFileExtention(), "1"), - EnvelopeHelpers.createDocumentFromFile(DOCX_DOCUMENT_FILE_NAME, DOCX_DOCUMENT_NAME, "2"), - EnvelopeHelpers.createDocumentFromFile(PDF_DOCUMENT_FILE_NAME, PDF_DOCUMENT_NAME, "3"))); - envelope.setRecipients(EnvelopeHelpers.createRecipients(signer, cc)); - // Request that the envelope be sent by setting |status| to "sent". - // To request that the envelope be created as a draft, set to "created" - envelope.setStatus(args.getStatus()); - - return envelope; - } -} diff --git a/src/main/java/com/docusign/controller/examples/EG003ControllerListEnvelopes.java b/src/main/java/com/docusign/controller/examples/EG003ControllerListEnvelopes.java deleted file mode 100644 index d363b2ee..00000000 --- a/src/main/java/com/docusign/controller/examples/EG003ControllerListEnvelopes.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.docusign.controller.examples; - -import com.docusign.DSConfiguration; -import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.api.EnvelopesApi.ListStatusChangesOptions; -import com.docusign.esign.client.ApiException; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; - -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; - -import javax.servlet.http.HttpServletResponse; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; - - -/** - * List envelopes in the user's account.
- * List the envelopes created in the last 30 days. This example demonstrates - * how to query DocuSign about envelopes sent by the current user. - */ -@Controller -@RequestMapping("/eg003") -public class EG003ControllerListEnvelopes extends AbstractController { - - private static final int FROM_DATE_OFFSET_DAYS = 30; - private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd"); - - private final Session session; - private final User user; - - - @Autowired - public EG003ControllerListEnvelopes(DSConfiguration config, Session session, User user) { - super(config, "eg003", "List envelopes"); - this.session = session; - this.user = user; - } - - @Override - // ***DS.snippet.0.start - protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException { - EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); - ListStatusChangesOptions options = envelopesApi.new ListStatusChangesOptions(); - LocalDate date = LocalDate.now().minusDays(FROM_DATE_OFFSET_DAYS); - options.setFromDate(DATE_FORMATTER.format(date)); - - DoneExample.createDefault(title) - .withMessage("Results from the Envelopes::listStatusChanges method:") - .withJsonObject(envelopesApi.listStatusChanges(session.getAccountId(), options)) - .addToModel(model); - return DONE_EXAMPLE_PAGE; - } - // ***DS.snippet.0.end -} diff --git a/src/main/java/com/docusign/controller/examples/EG009ControllerUseTemplate.java b/src/main/java/com/docusign/controller/examples/EG009ControllerUseTemplate.java deleted file mode 100644 index d8183f8c..00000000 --- a/src/main/java/com/docusign/controller/examples/EG009ControllerUseTemplate.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.docusign.controller.examples; - -import com.docusign.DSConfiguration; -import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.api.TemplatesApi; -import com.docusign.esign.client.ApiClient; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.EnvelopeDefinition; -import com.docusign.esign.model.EnvelopeSummary; -import com.docusign.esign.model.EnvelopeTemplateResults; -import com.docusign.esign.model.TemplateRole; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import java.util.Arrays; - -import javax.servlet.http.HttpServletResponse; - - -/** - * Send an envelope using a template.
- * The envelope is defined by the template. The signer and cc recipient name - * and email are used to fill in the template's roles. This example - * demonstrates a common pattern for DocuSign integrations: envelopes will be - * sent programmatically, based on a template. If the template definition needs - * to be updated, the DocuSign web tool can be used to easily update the - * template, thus avoiding the need to make software changes. - */ -@Controller -@RequestMapping("/eg009") -public class EG009ControllerUseTemplate extends AbstractController { - - private static final String MODEL_LIST_TEMPLATE = "listTemplates"; - - private final Session session; - private final User user; - - - @Autowired - public EG009ControllerUseTemplate(DSConfiguration config, Session session, User user) { - super(config, "eg009", "Envelope sent"); - this.session = session; - this.user = user; - } - - @Override - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { - super.onInitModel(args, model); - ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); - TemplatesApi templatesApi = new TemplatesApi(apiClient); - EnvelopeTemplateResults templates = templatesApi.listTemplates(session.getAccountId()); - model.addAttribute(MODEL_LIST_TEMPLATE, templates.getEnvelopeTemplates()); - } - - @Override - // ***DS.snippet.0.start - protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException { - EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); - EnvelopeDefinition envelope = makeEnvelope(args); - EnvelopeSummary result = envelopesApi.createEnvelope(session.getAccountId(), envelope); - - session.setEnvelopeId(result.getEnvelopeId()); - DoneExample.createDefault(title) - .withJsonObject(result) - .withMessage("The envelope has been created and sent!
Envelope ID " - + result.getEnvelopeId() + ".") - .addToModel(model); - return DONE_EXAMPLE_PAGE; - } - - private static EnvelopeDefinition makeEnvelope(WorkArguments args) { - TemplateRole signer = new TemplateRole(); - signer.setEmail(args.getSignerEmail()); - signer.setName(args.getSignerName()); - signer.setRoleName(EnvelopeHelpers.SIGNER_ROLE_NAME); - - TemplateRole cc = new TemplateRole(); - cc.setEmail(args.getCcEmail()); - cc.setName(args.getCcName()); - cc.setRoleName(EnvelopeHelpers.CC_ROLE_NAME); - - EnvelopeDefinition envelope = new EnvelopeDefinition(); - envelope.setTemplateId(args.getTemplateId()); - envelope.setTemplateRoles(Arrays.asList(signer, cc)); - envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); - - return envelope; - } - // ***DS.snippet.0.end -} diff --git a/src/main/java/com/docusign/controller/examples/EG013ControllerAddDocToTemplate.java b/src/main/java/com/docusign/controller/examples/EG013ControllerAddDocToTemplate.java deleted file mode 100644 index d431219e..00000000 --- a/src/main/java/com/docusign/controller/examples/EG013ControllerAddDocToTemplate.java +++ /dev/null @@ -1,182 +0,0 @@ -package com.docusign.controller.examples; - -import com.docusign.DSConfiguration; -import com.docusign.common.DocumentType; -import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.api.TemplatesApi; -import com.docusign.esign.client.ApiClient; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.CarbonCopy; -import com.docusign.esign.model.CompositeTemplate; -import com.docusign.esign.model.EnvelopeDefinition; -import com.docusign.esign.model.EnvelopeSummary; -import com.docusign.esign.model.EnvelopeTemplateResults; -import com.docusign.esign.model.InlineTemplate; -import com.docusign.esign.model.RecipientViewRequest; -import com.docusign.esign.model.ServerTemplate; -import com.docusign.esign.model.Signer; -import com.docusign.esign.model.Tabs; -import com.docusign.esign.model.ViewUrl; -import com.docusign.model.Session; -import com.docusign.model.User; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.servlet.view.RedirectView; - -import java.io.IOException; -import java.util.Arrays; - -import javax.servlet.http.HttpServletResponse; - - -/** - * Embedded Signing Ceremony from a template with an added document.
- * This example sends an envelope based on a template. In addition to the - * template's document(s), the example adds an additional document to the - * envelope by using the Composite Templates. - */ -@Controller -@RequestMapping("/eg013") -public class EG013ControllerAddDocToTemplate extends AbstractController { - - private static final String MODEL_LIST_TEMPLATE = "listTemplates"; - private static final String SIGNER_CLIENT_ID = "1000"; - private static final String HTML_DOCUMENT_FILE_NAME = "templates/candy-bonbon2.ftl"; - private static final String HTML_DOCUMENT_NAME = "Appendix 1--Sales order"; - private static final int ANCHOR_OFFSET_Y = 10; - private static final int ANCHOR_OFFSET_X = 20; - - private final Session session; - private final User user; - - - @Autowired - public EG013ControllerAddDocToTemplate(DSConfiguration config, Session session, User user) { - super(config, "eg013", "Embedded Signing Ceremony from template and extra doc"); - this.session = session; - this.user = user; - } - - @Override - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { - super.onInitModel(args, model); - ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); - TemplatesApi templatesApi = new TemplatesApi(apiClient); - EnvelopeTemplateResults templates = templatesApi.listTemplates(session.getAccountId()); - model.addAttribute(MODEL_LIST_TEMPLATE, templates.getEnvelopeTemplates()); - } - - @Override - // ***DS.snippet.0.start - protected Object doWork(WorkArguments args, ModelMap model, - HttpServletResponse response) throws ApiException, IOException { - String accountId = session.getAccountId(); - EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); - - // Step 1. Make the envelope request body - args.setDsReturnUrl(config.getDsReturnUrl()); - args.setDsPingUrl(config.getDsPingUrl()); - args.setSignerClientId(SIGNER_CLIENT_ID); - EnvelopeDefinition envelope = makeEnvelope(args); - - // Step 2. call Envelopes::create API method - EnvelopeSummary results = envelopesApi.createEnvelope(accountId, envelope); - - // Step 3. create the recipient view, the Signing Ceremony - RecipientViewRequest viewRequest = makeRecipientViewRequest(args); - ViewUrl viewUrl = envelopesApi.createRecipientView(accountId, results.getEnvelopeId(), viewRequest); - return new RedirectView(viewUrl.getUrl()); - } - - private static RecipientViewRequest makeRecipientViewRequest(WorkArguments args) { - RecipientViewRequest viewRequest = new RecipientViewRequest(); - // Set the url where you want the recipient to go once they are done signing - // should typically be a callback route somewhere in your app. - viewRequest.setReturnUrl(args.getDsReturnUrl()); - // How has your app authenticated the user? In addition to your app's - // authentication, you can include authenticate steps from DocuSign. - // Eg, SMS authentication - viewRequest.setAuthenticationMethod("none"); - // Recipient information must match embedded recipient info - // we used to create the envelope. - viewRequest.setEmail(args.getSignerEmail()); - viewRequest.setUserName(args.getSignerName()); - viewRequest.setClientUserId(args.getSignerClientId()); - - // DocuSign recommends that you redirect to DocuSign for the - // Signing Ceremony. There are multiple ways to save state. - // To maintain your application's session, use the pingUrl - // parameter. It causes the DocuSign Signing Ceremony web page - // (not the DocuSign server) to send pings via AJAX to your app. - // NOTE: The pings will only be sent if the pingUrl is an https address - viewRequest.setPingFrequency("600"); - viewRequest.setPingUrl(args.getDsPingUrl()); - - return viewRequest; - } - - // The envelope request object uses Composite Template to include in the envelope: - // 1. A template stored on the DocuSign service - // 2. An additional document which is a custom HTML source document - private EnvelopeDefinition makeEnvelope(WorkArguments args) throws IOException { - // Create a signer and cc recipients for the signer role of the server template - CarbonCopy cc1 = new CarbonCopy(); - cc1.setEmail(args.getCcEmail()); - cc1.setName(args.getCcName()); - cc1.setRoleName(EnvelopeHelpers.CC_ROLE_NAME); - cc1.setRecipientId("2"); - - // create a composite template for the Server Template - CompositeTemplate compTemplate1 = new CompositeTemplate(); - compTemplate1.setCompositeTemplateId("1"); - ServerTemplate serverTemplates = new ServerTemplate(); - serverTemplates.setSequence("1"); - serverTemplates.setTemplateId(args.getTemplateId()); - compTemplate1.setServerTemplates(Arrays.asList(serverTemplates)); - - // Add the roles via an inlineTemplate - InlineTemplate inlineTemplate = new InlineTemplate(); - inlineTemplate.setSequence("1"); - inlineTemplate.setRecipients(EnvelopeHelpers.createRecipients(createSigner(args), cc1)); - compTemplate1.setInlineTemplates(Arrays.asList(inlineTemplate)); - - // The signer recipient for the added document with a tab definition: - Tabs signer1Tabs = EnvelopeHelpers.createSingleSignerTab("**signature_1**", ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X); - Signer signer1AddedDoc = createSigner(args); - signer1AddedDoc.setTabs(signer1Tabs); - - // create the HTML document - byte[] htmlDoc = EnvelopeHelpers.createHtmlFromTemplateFile(HTML_DOCUMENT_FILE_NAME, "args", args); - - // create a composite template for the added document and add the recipients via an inlineTemplate - CompositeTemplate compTemplate2 = new CompositeTemplate(); - compTemplate2.setCompositeTemplateId("2"); - InlineTemplate inlineTemplate2 = new InlineTemplate(); - inlineTemplate2.setSequence("2"); - inlineTemplate2.setRecipients(EnvelopeHelpers.createRecipients(signer1AddedDoc, cc1)); - compTemplate2.setInlineTemplates(Arrays.asList(inlineTemplate2)); - compTemplate2.setDocument(EnvelopeHelpers.createDocument(htmlDoc, HTML_DOCUMENT_NAME, - DocumentType.HTML.getDefaultFileExtention(), "1")); - - EnvelopeDefinition env = new EnvelopeDefinition(); - env.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); - env.setCompositeTemplates(Arrays.asList(compTemplate1, compTemplate2)); - - return env; - } - - // Adding clientUserId transforms the template recipient into an embedded recipient - private static Signer createSigner(WorkArguments args) { - Signer signer = new Signer(); - signer.setEmail(args.getSignerEmail()); - signer.setName(args.getSignerName()); - signer.setRoleName(EnvelopeHelpers.SIGNER_ROLE_NAME); - signer.setRecipientId("1"); - signer.setClientUserId(args.getSignerClientId()); - return signer; - } - // ***DS.snippet.0.end -} diff --git a/src/main/java/com/docusign/controller/examples/EG014ControllerCollectPayment.java b/src/main/java/com/docusign/controller/examples/EG014ControllerCollectPayment.java deleted file mode 100644 index 6c2fe0ad..00000000 --- a/src/main/java/com/docusign/controller/examples/EG014ControllerCollectPayment.java +++ /dev/null @@ -1,241 +0,0 @@ -package com.docusign.controller.examples; - -import com.docusign.DSConfiguration; -import com.docusign.common.DocumentType; -import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.CarbonCopy; -import com.docusign.esign.model.EnvelopeDefinition; -import com.docusign.esign.model.EnvelopeSummary; -import com.docusign.esign.model.FormulaTab; -import com.docusign.esign.model.List; -import com.docusign.esign.model.ListItem; -import com.docusign.esign.model.PaymentDetails; -import com.docusign.esign.model.PaymentLineItem; -import com.docusign.esign.model.Signer; -import com.docusign.esign.model.Tabs; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import java.io.IOException; -import java.util.Arrays; - -import javax.servlet.http.HttpServletResponse; - - -/** - * Send an envelope with an order form, including a payment field.
- * This class programmatically constructs the order form. For many use cases, - * it would be better to create the order form as a template using the DocuSign - * web tool as a WYSIWYG form designer.
- * Note: This example will only work if the sender's DocuSign account is - * set up with a DocuSign payment gateway. Next properties should are set: - *
    - *
  • Gateway_Account_Id
  • - *
  • Gateway_Name
  • - *
  • Gateway_Display_Name
  • - *
- * Since the Payment Gateway ID is set in the configuration file, you will need - * to run your own instance of this project to set it. - */ -@Controller -@RequestMapping("/eg014") -public class EG014ControllerCollectPayment extends AbstractController { - - private static final String MODEL_GATEWAY_OK = "gatewayOk"; - private static final String HTML_DOCUMENT_FILE_NAME = "templates/order-form.ftl"; - private static final String HTML_DOCUMENT_NAME = "Order form"; - // Order form constants - private static final String TRUE = "true"; - private static final String FALSE = "false"; - private static final int L1_PRICE = 5; - private static final int L2_PRICE = 150; - private static final int ANCHOR_OFFSET_Y = 10; - private static final int ANCHOR_OFFSET_X = 20; - private static final String DEFAULT_FONT = "helvetica"; - private static final String DEFAULT_FONT_SIZE = "size11"; - private static final String ANCHOR_UNITS = "pixels"; - - private final Session session; - private final User user; - - - @Autowired - public EG014ControllerCollectPayment(DSConfiguration config, Session session, User user) { - super(config, "eg014", "Envelope sent"); - this.session = session; - this.user = user; - } - - @Override - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { - super.onInitModel(args, model); - model.addAttribute(MODEL_GATEWAY_OK, null != config.getGatewayAccountId()); - } - - @Override - // ***DS.snippet.0.start - protected Object doWork(WorkArguments args, ModelMap model, - HttpServletResponse response) throws ApiException, IOException { - EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); - - // Step 1. Make the envelope request body - EnvelopeDefinition envelope = makeEnvelope(args); - - // Step 2. call Envelopes::create API method - EnvelopeSummary results = envelopesApi.createEnvelope(session.getAccountId(), envelope); - - DoneExample.createDefault(title) - .withMessage(String.join("", "The envelope has been created and sent!
Envelope ID ", - results.getEnvelopeId(), ".")) - .addToModel(model); - return DONE_EXAMPLE_PAGE; - } - - // document 1 (html) has multiple tags: - // /l1q/ and /l2q/ -- quantities: drop down - // /l1e/ and /l2e/ -- extended: payment lines - // /l3t/ -- total -- formula - // - // The envelope has two recipients. - // recipient 1 - signer - // recipient 2 - cc - // The envelope will be sent first to the signer. - // After it is signed, a copy is sent to the cc person. - private EnvelopeDefinition makeEnvelope(WorkArguments args) throws IOException { - byte[] htmlDoc = EnvelopeHelpers.createHtmlFromTemplateFile(HTML_DOCUMENT_FILE_NAME, "args", args); - - // create a signer recipient to sign the document, identified by name and email - // routingOrder (lower means earlier) determines the order of deliveries - // to the recipients. Parallel routing order is supported by using the - // same integer as the order for two or more recipients. - Signer signer = new Signer() - .email(args.getSignerEmail()) - .name(args.getSignerName()) - .recipientId("1") - .routingOrder("1"); - signer.setTabs(createTabs()); - - // create a cc recipient to receive a copy of the documents, identified by name and email - CarbonCopy cc = new CarbonCopy() - .email(args.getCcEmail()) - .name(args.getCcName()) - .routingOrder("2") - .recipientId("2"); - - // Create the envelope definition - // Request that the envelope be sent by setting |status| to "sent". - // To request that the envelope be created as a draft, set to "created" - EnvelopeDefinition envelope = new EnvelopeDefinition(); - envelope.setEmailSubject("Please complete your order"); - envelope.setDocuments(Arrays.asList(EnvelopeHelpers.createDocument(htmlDoc, - HTML_DOCUMENT_NAME, DocumentType.HTML.getDefaultFileExtention(), "1"))); - envelope.setRecipients(EnvelopeHelpers.createRecipients(signer, cc)); - envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); - - return envelope; - } - - // creates tabs per signer - private Tabs createTabs() { - java.util.List listItems = java.util.List.of( - new ListItem().text("none").value("0"), - new ListItem().text("1").value("1"), - new ListItem().text("2").value("2"), - new ListItem().text("3").value("3"), - new ListItem().text("4").value("4"), - new ListItem().text("5").value("5"), - new ListItem().text("6").value("6"), - new ListItem().text("7").value("7"), - new ListItem().text("8").value("8"), - new ListItem().text("9").value("9"), - new ListItem().text("10").value("10")); - List listl1q = createList("/l1q/", "l1q", listItems); - List listl2q = createList("/l2q/", "l2q", listItems); - - // Create two formula tabs for the extended price on the line items and formula for the total - FormulaTab formulal1e = createFormulaTab("/l1e/", "l1e", L1_PRICE); - FormulaTab formulal2e = createFormulaTab("/l2e/", "l2e", L2_PRICE); - FormulaTab formulal3t = new FormulaTab() - .font(DEFAULT_FONT) - .bold(TRUE) - .fontSize("size12") - .anchorString("/l3t/") - .anchorYOffset("-8") - .anchorUnits(ANCHOR_UNITS) - .anchorXOffset("50") - .tabLabel("l3t") - .formula("[l1e] + [l2e]") - .roundDecimalPlaces("0") - .required(TRUE) - .locked(TRUE) - .disableAutoSize(FALSE); - PaymentLineItem paymentLineIteml1 = new PaymentLineItem() - .name("Harmonica") - .description(String.format("${%d} each", L1_PRICE)) - .amountReference("l1e"); - PaymentLineItem paymentLineIteml2 = new PaymentLineItem() - .name("Xylophone") - .description(String.format("${%d} each", L2_PRICE)) - .amountReference("l2e"); - PaymentDetails paymentDetails = new PaymentDetails() - .gatewayAccountId(config.getGatewayAccountId()) - .currencyCode("USD") - .gatewayName(config.getGatewayName()) - .gatewayDisplayName(config.getGatewayDisplayName()) - .lineItems(Arrays.asList(paymentLineIteml1, paymentLineIteml2)); - // Hidden formula for the payment itself - FormulaTab formulaPayment = new FormulaTab() - .tabLabel("payment") - .formula("([l1e] + [l2e]) * {100}") - .roundDecimalPlaces("0") - .paymentDetails(paymentDetails) - .hidden(TRUE) - .required(TRUE) - .locked(TRUE) - .documentId("1") - .pageNumber("1") - .xPosition("0") - .yPosition("0"); - - Tabs signerTabs = EnvelopeHelpers.createSingleSignerTab("/sn1/", ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X); - signerTabs.listTabs(Arrays.asList(listl1q, listl2q)); - signerTabs.formulaTabs(Arrays.asList(formulal1e, formulal2e, formulal3t, formulaPayment)); - return signerTabs; - } - - private static List createList(String anchor, String label, java.util.List items) { - return new List() - .font(DEFAULT_FONT) - .fontSize(DEFAULT_FONT_SIZE) - .anchorString(anchor) - .anchorYOffset("-10") - .anchorUnits(ANCHOR_UNITS) - .anchorXOffset("0") - .listItems(items) - .required(TRUE) - .tabLabel(label); - } - - private static FormulaTab createFormulaTab(String anchor, String label, int price) { - return new FormulaTab() - .font(DEFAULT_FONT) - .fontSize(DEFAULT_FONT_SIZE) - .anchorString(anchor) - .anchorYOffset("-8") - .anchorUnits(ANCHOR_UNITS) - .anchorXOffset("105") - .tabLabel(label) - .formula(String.format("[l1q] * {%d}", price)) - .roundDecimalPlaces("0") - .required(TRUE) - .locked(TRUE) - .disableAutoSize(FALSE); - } - // ***DS.snippet.0.end -} diff --git a/src/main/java/com/docusign/controller/examples/EG016ControllerSetTabValues.java b/src/main/java/com/docusign/controller/examples/EG016ControllerSetTabValues.java deleted file mode 100644 index 462a923c..00000000 --- a/src/main/java/com/docusign/controller/examples/EG016ControllerSetTabValues.java +++ /dev/null @@ -1,197 +0,0 @@ -package com.docusign.controller.examples; - -import com.docusign.DSConfiguration; -import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.client.ApiClient; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.*; -import com.docusign.model.Session; -import com.docusign.model.User; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.servlet.view.RedirectView; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import javax.servlet.http.HttpServletResponse; - - -@Controller -@RequestMapping("/eg016") -public class EG016ControllerSetTabValues extends AbstractController { - - private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_salary.pdf"; - private static final String DOCUMENT_NAME = "Lorem Ipsum"; - private static final int ANCHOR_OFFSET_Y = 20; - private static final int ANCHOR_OFFSET_X = 10; - private static final String SIGNER_CLIENT_ID = "1000"; - - private final Session session; - private final User user; - - - @Autowired - public EG016ControllerSetTabValues(DSConfiguration config, Session session, User user) { - super(config, "eg016", "Set envelope tab values"); - this.session = session; - this.user = user; - } - - @Override - protected Object doWork(WorkArguments args, ModelMap model, - HttpServletResponse response) throws ApiException, IOException { - String signerName = args.getSignerName(); - String signerEmail = args.getSignerEmail(); - String accountId = session.getAccountId(); - - // Step 1. Create the envelope definition - EnvelopeDefinition envelope = makeEnvelope(signerEmail, signerName); - - // Step 2. Call DocuSign to create the envelope - ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); - EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); - EnvelopeSummary envelopeSummary = envelopesApi.createEnvelope(accountId, envelope); - - String envelopeId = envelopeSummary.getEnvelopeId(); - session.setEnvelopeId(envelopeId); - - // Step 3. create the recipient view, the Signing Ceremony - RecipientViewRequest viewRequest = makeRecipientViewRequest(signerEmail, signerName); - ViewUrl viewUrl = envelopesApi.createRecipientView(accountId, envelopeId, viewRequest); - - // Step 4. Redirect the user to the Signing Ceremony - // Don't use an iFrame! - // State can be stored/recovered using the framework's session or a - // query parameter on the returnUrl (see the makeRecipientViewRequest method) - return new RedirectView(viewUrl.getUrl()); - } - - private RecipientViewRequest makeRecipientViewRequest(String signerEmail, String signerName) { - RecipientViewRequest viewRequest = new RecipientViewRequest(); - // Set the url where you want the recipient to go once they are done signing - // should typically be a callback route somewhere in your app. - // The query parameter is included as an example of how - // to save/recover state information during the redirect to - // the DocuSign signing ceremony. It's usually better to use - // the session mechanism of your web framework. Query parameters - // can be changed/spoofed very easily. - viewRequest.setReturnUrl(config.getDsReturnUrl() + "?state=123"); - - // How has your app authenticated the user? In addition to your app's - // authentication, you can include authenticate steps from DocuSign. - // Eg, SMS authentication - viewRequest.setAuthenticationMethod("none"); - - // Recipient information must match embedded recipient info - // we used to create the envelope. - viewRequest.setEmail(signerEmail); - viewRequest.setUserName(signerName); - viewRequest.setClientUserId(SIGNER_CLIENT_ID); - - // DocuSign recommends that you redirect to DocuSign for the - // Signing Ceremony. There are multiple ways to save state. - // To maintain your application's session, use the pingUrl - // parameter. It causes the DocuSign Signing Ceremony web page - // (not the DocuSign server) to send pings via AJAX to your app. - // NOTE: The pings will only be sent if the pingUrl is an https address - viewRequest.setPingFrequency("600"); // seconds - viewRequest.setPingUrl(config.getDsPingUrl()); - - return viewRequest; - } - - private static EnvelopeDefinition makeEnvelope(String signerEmail, String signerName) throws IOException { - // Create a signer recipient to sign the document, identified by name and email - // We set the clientUserId to enable embedded signing for the recipient - Signer signer = new Signer(); - signer.setEmail(signerEmail); - signer.setName(signerName); - signer.clientUserId(SIGNER_CLIENT_ID); - signer.recipientId("1"); - - SignHere signHere = new SignHere(); - signHere.setAnchorString("/sn1"); - signHere.setAnchorUnits("pixels"); - signHere.setAnchorYOffset("10"); - signHere.setAnchorXOffset("20"); - - Text textLegal = new Text(); - textLegal.setAnchorString("/legal/"); - textLegal.setAnchorUnits("pixels"); - textLegal.setAnchorYOffset("-9"); - textLegal.setAnchorXOffset("5"); - textLegal.setFont("helvetica"); - textLegal.setFontSize("size11"); - textLegal.setBold("true"); - textLegal.setValue(signerName); - textLegal.setLocked("false"); - textLegal.setTabId("legal_name"); - textLegal.setTabLabel("Legal Name"); - - Text textFamiliar = new Text(); - textFamiliar.setAnchorString("/familar/"); - textFamiliar.setAnchorUnits("pixels"); - textFamiliar.setAnchorYOffset("-9"); - textFamiliar.setAnchorXOffset("5"); - textFamiliar.setFont("helvetica"); - textFamiliar.setFontSize("size11"); - textFamiliar.setBold("true"); - textFamiliar.setValue(signerName); - textFamiliar.setLocked("false"); - textFamiliar.setTabId("familiar_name"); - textFamiliar.setTabLabel("Familiar Name"); - - Integer salary = 123000; - - Text textSalary = new Text(); - textSalary.setAnchorString("/salary/"); - textSalary.setAnchorUnits("pixels"); - textSalary.setAnchorYOffset("-9"); - textSalary.setAnchorXOffset("5"); - textSalary.setFont("helvetica"); - textSalary.setFontSize("size11"); - textSalary.setBold("true"); - textSalary.setValue(String.format("$ %,.2d", salary)); - textSalary.setLocked("true"); - textSalary.setTabId("salary"); - textSalary.setTabLabel("salary"); - - TextCustomField salaryCustomField = new TextCustomField(); - salaryCustomField.setName("salary"); - salaryCustomField.setRequired("false"); - salaryCustomField.setShow("true"); // Yes, included in the CoC - salaryCustomField.setValue(String.valueOf(salary)); - - CustomFields cf = new CustomFields(); - cf.setTextCustomFields(Arrays.asList(salaryCustomField)); - - Tabs tabs = new Tabs(); - tabs.setSignHereTabs(Arrays.asList(signHere)); - tabs.setTextTabs(Arrays.asList(textLegal, textFamiliar, textSalary)); - - signer.setTabs(tabs); - - - // Add the recipient to the envelope object - Recipients recipients = new Recipients(); - recipients.setSigners(Arrays.asList(signer)); - - EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition(); - envelopeDefinition.setEmailSubject("Please sign this document from the Java SDK"); - envelopeDefinition.setRecipients(recipients); - Document doc = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, "3"); - envelopeDefinition.setDocuments(Arrays.asList(doc)); - envelopeDefinition.setCustomFields(cf); - // Request that the envelope be sent by setting |status| to "sent". - // To request that the envelope be created as a draft, set to "created" - envelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); - - return envelopeDefinition; - } -} diff --git a/src/main/java/com/docusign/controller/examples/EG017ControllerSetTemplateTabValues.java b/src/main/java/com/docusign/controller/examples/EG017ControllerSetTemplateTabValues.java deleted file mode 100644 index 8a5ecd6f..00000000 --- a/src/main/java/com/docusign/controller/examples/EG017ControllerSetTemplateTabValues.java +++ /dev/null @@ -1,217 +0,0 @@ -package com.docusign.controller.examples; - -import com.docusign.DSConfiguration; -import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.client.ApiClient; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.*; -import com.docusign.esign.model.Checkbox; -import com.docusign.esign.model.List; -import com.docusign.model.Session; -import com.docusign.model.User; -import com.sun.xml.bind.v2.runtime.unmarshaller.XsiNilLoader; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.servlet.view.RedirectView; - -import javax.servlet.http.HttpServletResponse; -import java.awt.*; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; - - -@Controller -@RequestMapping("/eg017") -public class EG017ControllerSetTemplateTabValues extends AbstractController { - - private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_salary.pdf"; - private static final String DOCUMENT_NAME = "Lorem Ipsum"; - private static final int ANCHOR_OFFSET_Y = 20; - private static final int ANCHOR_OFFSET_X = 10; - private static final String SIGNER_CLIENT_ID = "1000"; - - private final Session session; - private final User user; - - - @Autowired - public EG017ControllerSetTemplateTabValues(DSConfiguration config, Session session, User user) { - super(config, "eg017", "Set template tab values"); - this.session = session; - this.user = user; - } - - @Override - protected Object doWork(WorkArguments args, ModelMap model, - HttpServletResponse response) throws ApiException, IOException { - String signerName = args.getSignerName(); - String signerEmail = args.getSignerEmail(); - String accountId = session.getAccountId(); - String ccName = args.getCcName(); - String ccEmail = args.getCcEmail(); - String templateId = args.getTemplateId(); - - // Step 1. Create the envelope definition - EnvelopeDefinition envelope = makeEnvelope(signerEmail, signerName, ccName, ccEmail, templateId); - - // Step 2. Call DocuSign to create the envelope - ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); - EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); - EnvelopeSummary envelopeSummary = envelopesApi.createEnvelope(accountId, envelope); - - String envelopeId = envelopeSummary.getEnvelopeId(); - session.setEnvelopeId(envelopeId); - - // Step 3. create the recipient view, the Signing Ceremony - RecipientViewRequest viewRequest = makeRecipientViewRequest(signerEmail, signerName); - ViewUrl viewUrl = envelopesApi.createRecipientView(accountId, envelopeId, viewRequest); - - // Step 4. Redirect the user to the Signing Ceremony - // Don't use an iFrame! - // State can be stored/recovered using the framework's session or a - // query parameter on the returnUrl (see the makeRecipientViewRequest method) - return new RedirectView(viewUrl.getUrl()); - } - - private RecipientViewRequest makeRecipientViewRequest(String signerEmail, String signerName) { - RecipientViewRequest viewRequest = new RecipientViewRequest(); - // Set the url where you want the recipient to go once they are done signing - // should typically be a callback route somewhere in your app. - // The query parameter is included as an example of how - // to save/recover state information during the redirect to - // the DocuSign signing ceremony. It's usually better to use - // the session mechanism of your web framework. Query parameters - // can be changed/spoofed very easily. - viewRequest.setReturnUrl(config.getDsReturnUrl() + "?state=123"); - - // How has your app authenticated the user? In addition to your app's - // authentication, you can include authenticate steps from DocuSign. - // Eg, SMS authentication - viewRequest.setAuthenticationMethod("none"); - - // Recipient information must match embedded recipient info - // we used to create the envelope. - viewRequest.setEmail(signerEmail); - viewRequest.setUserName(signerName); - viewRequest.setClientUserId(SIGNER_CLIENT_ID); - - // DocuSign recommends that you redirect to DocuSign for the - // Signing Ceremony. There are multiple ways to save state. - // To maintain your application's session, use the pingUrl - // parameter. It causes the DocuSign Signing Ceremony web page - // (not the DocuSign server) to send pings via AJAX to your app. - // NOTE: The pings will only be sent if the pingUrl is an https address - viewRequest.setPingFrequency("600"); // seconds - viewRequest.setPingUrl(config.getDsPingUrl()); - - return viewRequest; - } - - private static EnvelopeDefinition makeEnvelope(String signerEmail, String signerName, String ccEmail, String ccName, String templateId) throws IOException { - // Create a signer recipient to sign the document, identified by name and email - // We set the clientUserId to enable embedded signing for the recipient - - List list1 = new List(); - list1.setValue("green"); - list1.setDocumentId("1"); - list1.setPageNumber("1"); - list1.setTabLabel("list"); - - // Checkboxes - Checkbox ck1 = new Checkbox(); - ck1.setTabLabel("ckAuthorization"); - ck1.setSelected("true"); - - Checkbox ck2 = new Checkbox(); - ck2.setTabLabel("ckAgreement"); - ck2.setSelected("true"); - - Radio radio = new Radio(); - radio.setValue("white"); - radio.setSelected("true"); - - RadioGroup rg = new RadioGroup(); - rg.setGroupName("radio1"); - rg.setRadios(Arrays.asList(radio)); - - - Text txt = new Text(); - txt.setTabLabel("text"); - txt.setValue("Jabberywocky!"); - - // We can also add a new tab (field) to the ones already in the template: - - Text txtExtra = new Text(); - txtExtra.setDocumentId("1"); - txtExtra.setPageNumber("1"); - txtExtra.setXPosition("280"); - txtExtra.setYPosition("172"); - txtExtra.setFont("helvetica"); - txtExtra.setFontSize("size14"); - txtExtra.setTabLabel("added text field"); - txtExtra.setHeight("23"); - txtExtra.setWidth("84"); - txtExtra.setRequired("false"); - txtExtra.setBold("true"); - txtExtra.setValue(signerName); - txtExtra.setLocked("false"); - txtExtra.setTabId("name"); - - - // Add the tabs model (including the SignHere tab) to the signer. - // The Tabs object wants arrays of the different field/tab types - // Tabs are set per recipient / signer - - Tabs tabs = new Tabs(); - - tabs.setTextTabs(Arrays.asList(txt, txtExtra)); - tabs.setRadioGroupTabs(Arrays.asList(rg)); - tabs.setCheckboxTabs(Arrays.asList(ck1, ck2)); - tabs.setListTabs(Arrays.asList(list1)); - - - // create a signer recipient to sign the document, identified by name and email - // We're setting the parameters via the object creation - TemplateRole signer = new TemplateRole(); - signer.setEmail(signerEmail); - signer.setName(signerName); - // Setting the client_user_id marks the signer as embedded - signer.setClientUserId(SIGNER_CLIENT_ID); - signer.setRoleName("signer"); - signer.setTabs(tabs); - - TemplateRole cc = new TemplateRole(); - cc.setEmail(ccEmail); - cc.setName(ccName); - cc.setRoleName("cc"); - - // Create an envelope custom field to save our application"s - // Data about the envelope - TextCustomField customField = new TextCustomField(); - customField.setName("app metadata item"); - customField.setValue("1234567"); - customField.setRequired("false"); - customField.show("true"); //Yes, include in the CoC - - - CustomFields cf = new CustomFields(); - cf.setTextCustomFields(Arrays.asList(customField)); - - - // Next, create the top level envelope definition and populate it. - EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition(); - envelopeDefinition.setEmailSubject("Please sign this document from the Java SDK"); - // The Recipients object wants arrays for each recipient type - envelopeDefinition.setTemplateId(templateId); - envelopeDefinition.setTemplateRoles(Arrays.asList(signer, cc)); - envelopeDefinition.setCustomFields(cf); - // Request that the envelope be sent by setting |status| to "sent". - // To request that the envelope be created as a draft, set to "created" - envelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); - - return envelopeDefinition; - } -} diff --git a/src/main/java/com/docusign/controller/examples/EG019ControllerAccessCodeAuthentication.java b/src/main/java/com/docusign/controller/examples/EG019ControllerAccessCodeAuthentication.java deleted file mode 100644 index fbede6e0..00000000 --- a/src/main/java/com/docusign/controller/examples/EG019ControllerAccessCodeAuthentication.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.docusign.controller.examples; - -import com.docusign.DSConfiguration; -import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.Document; -import com.docusign.esign.model.EnvelopeDefinition; -import com.docusign.esign.model.EnvelopeSummary; -import com.docusign.esign.model.Recipients; -import com.docusign.esign.model.SignHere; -import com.docusign.esign.model.Signer; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import java.io.IOException; -import java.util.Arrays; - -import javax.servlet.http.HttpServletResponse; - - -/** - * Send an envelope with a recipient using Access Code Authentication. Signer - * has to enter an access code for opening document to sign. - */ -@Controller -@RequestMapping("/eg019") -public class EG019ControllerAccessCodeAuthentication extends AbstractController { - - private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; - private static final String DOCUMENT_NAME = "Lorem"; - - private final Session session; - private final User user; - - - @Autowired - public EG019ControllerAccessCodeAuthentication(DSConfiguration config, Session session, User user) { - super(config, "eg019", "Signing request by email"); - this.session = session; - this.user = user; - } - - @Override - // ***DS.snippet.0.start - protected Object doWork(WorkArguments args, ModelMap model, - HttpServletResponse response) throws ApiException, IOException { - // Step 1: Construct your API headers - EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); - - // Step 2: Construct your envelope JSON body - EnvelopeDefinition envelope = createEnvelope(args); - - // Step 3: Call the eSignature REST API - EnvelopeSummary results = envelopesApi.createEnvelope(session.getAccountId(), envelope); - - session.setEnvelopeId(results.getEnvelopeId()); - DoneExample.createDefault(title) - .withJsonObject(results) - .withMessage("The envelope has been created and sent!
Envelope ID " - + session.getEnvelopeId() + ".") - .addToModel(model); - - return DONE_EXAMPLE_PAGE; - } - - private static EnvelopeDefinition createEnvelope(WorkArguments args) throws IOException { - Document doc = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, "1"); - - SignHere signHere = new SignHere(); - signHere.setName("SignHereTab"); - signHere.setXPosition("75"); - signHere.setYPosition("572"); - signHere.setTabLabel("SignHereTab"); - signHere.setPageNumber("1"); - signHere.setDocumentId(doc.getDocumentId()); - // A 1- to 8-digit integer or 32-character GUID to match recipient IDs on your own systems. - // This value is referenced in the Tabs element below to assign tabs on a per-recipient basis. - signHere.setRecipientId("1"); - - Signer signer = new Signer(); - signer.setName(args.getSignerName()); - signer.setEmail(args.getSignerEmail()); - signer.setRoutingOrder("1"); - signer.setStatus(EnvelopeHelpers.SIGNER_STATUS_CREATED); - signer.setDeliveryMethod(EnvelopeHelpers.DELIVERY_METHOD_EMAIL); - signer.setRecipientId(signHere.getRecipientId()); - signer.setTabs(EnvelopeHelpers.createSignerTabs(signHere)); - signer.setAccessCode(args.getAccessCode()); - - Recipients recipients = new Recipients(); - recipients.setSigners(Arrays.asList(signer)); - - EnvelopeDefinition envelope = new EnvelopeDefinition(); - envelope.setEmailSubject("Please Sign"); - envelope.setDocuments(Arrays.asList(doc)); - envelope.setEnvelopeIdStamping("true"); - envelope.setEmailBlurb("Sample text for email body"); - envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); - envelope.setRecipients(recipients); - - return envelope; - } - // ***DS.snippet.0.end -} diff --git a/src/main/java/com/docusign/controller/examples/EG020ControllerSmsAuthentication.java b/src/main/java/com/docusign/controller/examples/EG020ControllerSmsAuthentication.java deleted file mode 100644 index ae548bf7..00000000 --- a/src/main/java/com/docusign/controller/examples/EG020ControllerSmsAuthentication.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.docusign.controller.examples; - -import com.docusign.DSConfiguration; -import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.Document; -import com.docusign.esign.model.EnvelopeDefinition; -import com.docusign.esign.model.EnvelopeSummary; -import com.docusign.esign.model.RecipientSMSAuthentication; -import com.docusign.esign.model.Recipients; -import com.docusign.esign.model.SignHere; -import com.docusign.esign.model.Signer; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; - -import javax.servlet.http.HttpServletResponse; - - -/** - * Send an envelope with a recipient using SMS Authentication. - */ -@Controller -@RequestMapping("/eg020") -public class EG020ControllerSmsAuthentication extends AbstractController { - - private static final List RECIPIENT_PHONE_NUMBERS = List.of("415-555-1212", "415-555-3434"); - private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; - private static final String DOCUMENT_NAME = "Lorem"; - - private final Session session; - private final User user; - - - @Autowired - public EG020ControllerSmsAuthentication(DSConfiguration config, Session session, User user) { - super(config, "eg020", "Signing request by email"); - this.session = session; - this.user = user; - } - - @Override - // ***DS.snippet.0.start - protected Object doWork(WorkArguments args, ModelMap model, - HttpServletResponse response) throws ApiException, IOException { - String accountId = session.getAccountId(); - - // Step 2: Construct your API headers - EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); - - // Step 3: Construct your envelope JSON body - EnvelopeDefinition envelope = createEnvelope(args.getSignerName(), args.getSignerEmail()); - - // Step 4: Call the eSignature REST API - EnvelopeSummary results = envelopesApi.createEnvelope(accountId, envelope); - - session.setEnvelopeId(results.getEnvelopeId()); - DoneExample.createDefault(title) - .withJsonObject(results) - .withMessage("The envelope has been created and sent!
Envelope ID " - + results.getEnvelopeId() + ".") - .addToModel(model); - - return DONE_EXAMPLE_PAGE; - } - - private static EnvelopeDefinition createEnvelope(String signerName, String signerEmail) throws IOException { - Document doc = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, "1"); - - SignHere signHere = new SignHere(); - signHere.setName("SignHereTab"); - signHere.setXPosition("75"); - signHere.setYPosition("572"); - signHere.setTabLabel("SignHereTab"); - signHere.setPageNumber("1"); - signHere.setDocumentId(doc.getDocumentId()); - // A 1- to 8-digit integer or 32-character GUID to match recipient IDs on your own systems. - // This value is referenced in the Tabs element below to assign tabs on a per-recipient basis. - signHere.setRecipientId("1"); - - RecipientSMSAuthentication smsAuth = new RecipientSMSAuthentication(); - smsAuth.setSenderProvidedNumbers(RECIPIENT_PHONE_NUMBERS); - - Signer signer = new Signer(); - signer.setName(signerName); - signer.setEmail(signerEmail); - signer.setRoutingOrder("1"); - signer.setStatus(EnvelopeHelpers.SIGNER_STATUS_CREATED); - signer.setDeliveryMethod(EnvelopeHelpers.DELIVERY_METHOD_EMAIL); - signer.setRecipientId(signHere.getRecipientId()); - signer.setTabs(EnvelopeHelpers.createSignerTabs(signHere)); - signer.setRequireIdLookup("true"); - signer.setSmsAuthentication(smsAuth); - signer.setIdCheckConfigurationName("SMS Auth $"); - - Recipients recipients = new Recipients(); - recipients.setSigners(Arrays.asList(signer)); - - EnvelopeDefinition envelope = new EnvelopeDefinition(); - envelope.setEmailSubject("Please Sign"); - envelope.setDocuments(Arrays.asList(doc)); - envelope.setEnvelopeIdStamping("true"); - envelope.setEmailBlurb("Sample text for email body"); - envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); - envelope.setRecipients(recipients); - - return envelope; - } - // ***DS.snippet.0.end -} diff --git a/src/main/java/com/docusign/controller/examples/EG021ControllerPhoneAuthentication.java b/src/main/java/com/docusign/controller/examples/EG021ControllerPhoneAuthentication.java deleted file mode 100644 index f1341eb1..00000000 --- a/src/main/java/com/docusign/controller/examples/EG021ControllerPhoneAuthentication.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.docusign.controller.examples; - -import com.docusign.DSConfiguration; -import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.Document; -import com.docusign.esign.model.EnvelopeDefinition; -import com.docusign.esign.model.EnvelopeSummary; -import com.docusign.esign.model.RecipientPhoneAuthentication; -import com.docusign.esign.model.Recipients; -import com.docusign.esign.model.SignHere; -import com.docusign.esign.model.Signer; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; - -import javax.servlet.http.HttpServletResponse; - -/** - * Send an envelope with a recipient using Phone Authentication. - */ -@Controller -@RequestMapping("/eg021") -public class EG021ControllerPhoneAuthentication extends AbstractController { - - private static final List RECIPIENT_PHONE_NUMBERS = List.of("415-555-1212", "415-555-3434"); - private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; - private static final String DOCUMENT_NAME = "Lorem"; - - private final Session session; - private final User user; - - - @Autowired - public EG021ControllerPhoneAuthentication(DSConfiguration config, Session session, User user) { - super(config, "eg021", "Signing request by email"); - this.session = session; - this.user = user; - } - - @Override - // ***DS.snippet.0.start - protected Object doWork(WorkArguments args, ModelMap model, - HttpServletResponse response) throws ApiException, IOException { - // Step 1: Construct your API headers - EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); - - // Step 2: Construct your envelope JSON body - EnvelopeDefinition envelope = createEnvelope(args.getSignerName(), args.getSignerEmail()); - - // Step 3: Call the eSignature REST API - EnvelopeSummary results = envelopesApi.createEnvelope(session.getAccountId(), envelope); - - session.setEnvelopeId(results.getEnvelopeId()); - DoneExample.createDefault(title) - .withJsonObject(results) - .withMessage("The envelope has been created and sent!
Envelope ID " - + results.getEnvelopeId() + ".") - .addToModel(model); - - return DONE_EXAMPLE_PAGE; - } - - private static EnvelopeDefinition createEnvelope(String signerName, String signerEmail) throws IOException { - Document doc = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, "1"); - - SignHere signHere = new SignHere(); - signHere.setName("SignHereTab"); - signHere.setXPosition("75"); - signHere.setYPosition("572"); - signHere.setTabLabel("SignHereTab"); - signHere.setPageNumber("1"); - signHere.setDocumentId(doc.getDocumentId()); - // A 1- to 8-digit integer or 32-character GUID to match recipient IDs on your own systems. - // This value is referenced in the Tabs element below to assign tabs on a per-recipient basis. - signHere.setRecipientId("1"); - - RecipientPhoneAuthentication phoneAuth = new RecipientPhoneAuthentication(); - phoneAuth.setRecipMayProvideNumber("true"); - phoneAuth.setSenderProvidedNumbers(RECIPIENT_PHONE_NUMBERS); - - Signer signer = new Signer(); - signer.setName(signerName); - signer.setEmail(signerEmail); - signer.setRoutingOrder("1"); - signer.setStatus(EnvelopeHelpers.SIGNER_STATUS_CREATED); - signer.setDeliveryMethod(EnvelopeHelpers.DELIVERY_METHOD_EMAIL); - signer.setRecipientId(signHere.getRecipientId()); - signer.setTabs(EnvelopeHelpers.createSignerTabs(signHere)); - signer.setRequireIdLookup("true"); - signer.setPhoneAuthentication(phoneAuth); - signer.setIdCheckConfigurationName("Phone Auth $"); - - Recipients recipients = new Recipients(); - recipients.setSigners(Arrays.asList(signer)); - - EnvelopeDefinition envelope = new EnvelopeDefinition(); - envelope.setEmailSubject("Please Sign"); - envelope.setEnvelopeIdStamping("true"); - envelope.setEmailBlurb("Sample text for email body"); - envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); - envelope.setRecipients(recipients); - envelope.setDocuments(Arrays.asList(doc)); - - return envelope; - } - // ***DS.snippet.0.end -} diff --git a/src/main/java/com/docusign/controller/examples/EG022ControllerKBAAuthentication.java b/src/main/java/com/docusign/controller/examples/EG022ControllerKBAAuthentication.java deleted file mode 100644 index dad45c63..00000000 --- a/src/main/java/com/docusign/controller/examples/EG022ControllerKBAAuthentication.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.docusign.controller.examples; - -import com.docusign.DSConfiguration; -import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.Document; -import com.docusign.esign.model.EnvelopeDefinition; -import com.docusign.esign.model.EnvelopeSummary; -import com.docusign.esign.model.Recipients; -import com.docusign.esign.model.SignHere; -import com.docusign.esign.model.Signer; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import java.io.IOException; -import java.util.Arrays; - -import javax.servlet.http.HttpServletResponse; - - -/** - * Send an envelope with a recipient using Knowledge-Based Authentication. - */ -@Controller -@RequestMapping("/eg022") -public class EG022ControllerKBAAuthentication extends AbstractController { - - private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; - private static final String DOCUMENT_NAME = "Lorem"; - - private final Session session; - private final User user; - - - @Autowired - public EG022ControllerKBAAuthentication(DSConfiguration config, Session session, User user) { - super(config, "eg022", "Signing request by email"); - this.session = session; - this.user = user; - } - - @Override - // ***DS.snippet.0.start - protected Object doWork(WorkArguments args, ModelMap model, - HttpServletResponse response) throws ApiException, IOException { - // Step 1: Construct your API headers - EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); - - // Step 2: Construct your envelope JSON body - EnvelopeDefinition envelope = createEnvelope(args.getSignerName(), args.getSignerEmail()); - - // Step 3: Call the eSignature REST API - EnvelopeSummary results = envelopesApi.createEnvelope(session.getAccountId(), envelope); - - session.setEnvelopeId(results.getEnvelopeId()); - DoneExample.createDefault(title) - .withJsonObject(results) - .withMessage("The envelope has been created and sent!
Envelope ID " - + results.getEnvelopeId() + ".") - .addToModel(model); - - return DONE_EXAMPLE_PAGE; - } - - private static EnvelopeDefinition createEnvelope(String signerName, String signerEmail) throws IOException { - Document doc = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, "1"); - - SignHere signHere = new SignHere(); - signHere.setName("SignHereTab"); - signHere.setXPosition("75"); - signHere.setYPosition("572"); - signHere.setTabLabel("SignHereTab"); - signHere.setPageNumber("1"); - signHere.setDocumentId(doc.getDocumentId()); - // A 1- to 8-digit integer or 32-character GUID to match recipient IDs on your own systems. - // This value is referenced in the Tabs element below to assign tabs on a per-recipient basis. - signHere.setRecipientId("1"); - - Signer signer = new Signer(); - signer.setName(signerName); - signer.setEmail(signerEmail); - signer.setRoutingOrder("1"); - signer.setStatus(EnvelopeHelpers.SIGNER_STATUS_CREATED); - signer.setDeliveryMethod(EnvelopeHelpers.DELIVERY_METHOD_EMAIL); - signer.setRecipientId(signHere.getRecipientId()); - signer.setTabs(EnvelopeHelpers.createSignerTabs(signHere)); - signer.setIdCheckConfigurationName("ID Check"); - signer.setRequireIdLookup("true"); - - Recipients recipients = new Recipients(); - recipients.setSigners(Arrays.asList(signer)); - - EnvelopeDefinition envelope = new EnvelopeDefinition(); - envelope.setEmailSubject("Please Sign"); - envelope.setEnvelopeIdStamping("true"); - envelope.setEmailBlurb("Sample text for email body"); - envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); - envelope.setDocuments(Arrays.asList(doc)); - envelope.setRecipients(recipients); - - return envelope; - } - // ***DS.snippet.0.end -} diff --git a/src/main/java/com/docusign/controller/examples/EG023ControllerIdvAuthentication.java b/src/main/java/com/docusign/controller/examples/EG023ControllerIdvAuthentication.java deleted file mode 100644 index 2efc8d62..00000000 --- a/src/main/java/com/docusign/controller/examples/EG023ControllerIdvAuthentication.java +++ /dev/null @@ -1,138 +0,0 @@ -package com.docusign.controller.examples; - -import com.docusign.DSConfiguration; -import com.docusign.esign.api.AccountsApi; -import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.client.ApiClient; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.AccountIdentityVerificationResponse; -import com.docusign.esign.model.AccountIdentityVerificationWorkflow; -import com.docusign.esign.model.Document; -import com.docusign.esign.model.EnvelopeDefinition; -import com.docusign.esign.model.EnvelopeSummary; -import com.docusign.esign.model.RecipientIdentityVerification; -import com.docusign.esign.model.Recipients; -import com.docusign.esign.model.SignHere; -import com.docusign.esign.model.Signer; -import com.docusign.esign.model.Tabs; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; - -import java.io.IOException; -import java.util.Base64; -import java.util.Collections; -import java.util.List; -import javax.servlet.http.HttpServletResponse; - -/** - * ID Verification authentication - */ -@Controller -@RequestMapping("/eg023") -public class EG023ControllerIdvAuthentication extends AbstractController { - - private static final Logger logger = LoggerFactory.getLogger(EG023ControllerIdvAuthentication.class); - private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; - private static final String DOCUMENT_NAME = "Lorem"; - private final Session session; - private final User user; - - @Autowired - public EG023ControllerIdvAuthentication(DSConfiguration config, Session session, User user) { - super(config, "eg023", "ID Verification Authentication"); - this.session = session; - this.user = user; - } - - @Override - protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException, IOException { - // Step 1: Construct your API headers - ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); - EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); - //Step 2: Retrieve the workflow ID - AccountsApi workflowDetails = new AccountsApi(apiClient); - AccountIdentityVerificationResponse workflowRes = workflowDetails.getAccountIdentityVerification(session.getAccountId()); - List identityVerification = workflowRes.getIdentityVerification(); - if (identityVerification == null || identityVerification.isEmpty()) { - throw new ApiException("Error. Cant get AccountIdentityVerificationWorkflow"); - } - String workflowId = identityVerification.get(0).getWorkflowId(); - logger.info("workflowId = " + workflowId); - // Step 3: Construct your envelope JSON body - EnvelopeDefinition envelope = createEnvelope(args.getSignerName(), args.getSignerEmail(), workflowId); - // Step 4: Create envelope - EnvelopeSummary results = envelopesApi.createEnvelope(session.getAccountId(), envelope); - - session.setEnvelopeId(results.getEnvelopeId()); - DoneExample.createDefault(title) - .withJsonObject(results) - .withMessage("The envelope has been created and sent!
Envelope ID " - + results.getEnvelopeId() + ".") - .addToModel(model); - - return DONE_EXAMPLE_PAGE; - } - - private static EnvelopeDefinition createEnvelope(String signerName, String signerEmail, - String workflowId) { - EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition(); - envelopeDefinition.setEmailSubject("Please sign"); - envelopeDefinition.setEmailBlurb("Sample text for email body"); - envelopeDefinition.setStatus("Sent"); - - - byte[] fileBytes = new byte[0]; - try { - fileBytes = EnvelopeHelpers.readFile(DOCUMENT_FILE_NAME); - } catch (IOException e) { - e.printStackTrace(); - } - Document doc1 = new Document(); - doc1.setDocumentBase64(Base64.getEncoder().encodeToString(fileBytes)); - doc1.setDocumentId("1"); - doc1.setFileExtension("pdf"); - doc1.setName("Lorem"); - - SignHere signHere1 = new SignHere(); - signHere1.setName("SignHereTab"); - signHere1.setXPosition("75"); - signHere1.setYPosition("572"); - signHere1.setTabLabel("SignHereTab"); - signHere1.setPageNumber("1"); - signHere1.setDocumentId("1"); - // A 1- to 8-digit integer or 32-character GUID to match recipient IDs on your own systems. - // This value is referenced in the Tabs element below to assign tabs on a per-recipient basis. - signHere1.setRecipientId("1"); //represents your {RECIPIENT_ID} - - Tabs signer1Tabs = new Tabs(); - signer1Tabs.setSignHereTabs(Collections.singletonList(signHere1)); - RecipientIdentityVerification workflow = new RecipientIdentityVerification(); - workflow.setWorkflowId(workflowId); - - Signer signer1 = new Signer(); - signer1.setName(signerName); - signer1.setEmail(signerEmail); - signer1.setRoleName(""); - signer1.setNote(""); - signer1.setStatus("created"); - signer1.setDeliveryMethod("email"); - signer1.setRecipientId("1"); //represents your {RECIPIENT_ID} - signer1.setIdentityVerification(workflow); - signer1.setTabs(signer1Tabs); - - Recipients recipients = new Recipients(); - recipients.setSigners(Collections.singletonList(signer1)); - - envelopeDefinition.setRecipients(recipients); - //TODO: Uncomment - //envelopeDefinition.setDocuments(Collections.singletonList(doc1)); - return envelopeDefinition; - } -} diff --git a/src/main/java/com/docusign/controller/examples/EG025ControllerPermissionSetUserGroups.java b/src/main/java/com/docusign/controller/examples/EG025ControllerPermissionSetUserGroups.java deleted file mode 100644 index 90b30899..00000000 --- a/src/main/java/com/docusign/controller/examples/EG025ControllerPermissionSetUserGroups.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.docusign.controller.examples; - -import java.util.List; - -import javax.servlet.http.HttpServletResponse; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; - -import com.docusign.DSConfiguration; -import com.docusign.esign.api.AccountsApi; -import com.docusign.esign.api.GroupsApi; -import com.docusign.esign.client.ApiClient; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.ErrorDetails; -import com.docusign.esign.model.Group; -import com.docusign.esign.model.GroupInformation; -import com.docusign.esign.model.PermissionProfileInformation; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; - - -/** - * Permission profiles are collections of account settings that determine the - * behavior and actions available to the user groups to which they're applied. - * This code example demonstrates how to the permission profile for the group - * with the eSignature REST API. - */ -@Controller -@RequestMapping("/eg025") -public class EG025ControllerPermissionSetUserGroups extends AbstractController { - - private static final String MODEL_LIST_PROFILES = "listProfiles"; - private static final String MODEL_LIST_GROUPS = "listGroups"; - - private final Session session; - private final User user; - - - @Autowired - public EG025ControllerPermissionSetUserGroups(DSConfiguration config, Session session, User user) { - super(config, "eg025", "Setting a permission profile"); - this.session = session; - this.user = user; - } - - @Override - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { - super.onInitModel(args, model); - String accountId = session.getAccountId(); - - AccountsApi accountsApi = createAccountsApi(session.getBasePath(), user.getAccessToken()); - PermissionProfileInformation permissionsInfo = accountsApi.listPermissions(accountId); - model.addAttribute(MODEL_LIST_PROFILES, permissionsInfo.getPermissionProfiles()); - - GroupsApi groupsApi = new GroupsApi(accountsApi.getApiClient()); - GroupInformation groupInformation = groupsApi.listGroups(accountId); - model.addAttribute(MODEL_LIST_GROUPS, groupInformation.getGroups()); - } - - @Override - protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException { - // Step 2: Construct your API headers - ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); - GroupsApi groupsApi = new GroupsApi(apiClient); - - // Step 3: Perform request - Group newGroup = new Group() - .groupId(args.getGroupId()) - .permissionProfileId(args.getProfileId()); - GroupInformation groupInformation = new GroupInformation() - .groups(List.of(newGroup)); - GroupInformation newGroupInfo = groupsApi.updateGroups(session.getAccountId(), groupInformation); - - // Step 4: Show result - ErrorDetails errorDetails = newGroupInfo.getGroups().get(0).getErrorDetails(); - if (errorDetails != null) { - new DoneExample() - .withTitle(exampleName) - .withName(title) - .withMessage(errorDetails.getMessage()) - .addToModel(model); - return ERROR_PAGE; - } - DoneExample.createDefault(title) - .withJsonObject(newGroupInfo) - .withMessage("The permission profile was successfully set to the user group!") - .addToModel(model); - return DONE_EXAMPLE_PAGE; - } -} diff --git a/src/main/java/com/docusign/controller/examples/EG026ControllerPermissionChangeSingleSetting.java b/src/main/java/com/docusign/controller/examples/EG026ControllerPermissionChangeSingleSetting.java deleted file mode 100644 index 8844ec59..00000000 --- a/src/main/java/com/docusign/controller/examples/EG026ControllerPermissionChangeSingleSetting.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.docusign.controller.examples; - -import java.io.IOException; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.Optional; -import java.util.Random; - -import javax.servlet.http.HttpServletResponse; - -import com.docusign.model.AccountRoleSettingsPatch; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -import com.docusign.DSConfiguration; -import com.docusign.common.Utils; -import com.docusign.esign.api.AccountsApi; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.AccountRoleSettings; -import com.docusign.esign.model.PermissionProfile; -import com.docusign.esign.model.PermissionProfileInformation; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; -import com.google.gson.Gson; - -/** - * This code example demonstrates how to edit individual permission settings on - * a permission profile with the eSignature REST API. - */ -@Controller -@RequestMapping("/eg026") -public class EG026ControllerPermissionChangeSingleSetting extends AbstractController { - - private static final String MODEL_PERMISSIONS = "permissions"; - private static final String MODEL_CUR_PROFILE_NAME = "permissionProfileName"; - private static final String MODEL_CUR_PROFILE_ID = "profileId"; - private static final String MODEL_LIST_PROFILES = "listProfiles"; - - private final Session session; - private final User user; - - @Autowired - public EG026ControllerPermissionChangeSingleSetting(DSConfiguration config, Session session, User user) { - super(config, "eg026", "Change single permission setting"); - this.session = session; - this.user = user; - } - - @GetMapping("/profile") - public void getProfile(@RequestParam String profileId, ModelMap model) { - session.setPermissionProfileId(profileId); - model.addAttribute(MODEL_CUR_PROFILE_NAME, profileId); - } - - @Override - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { - super.onInitModel(args, model); - AccountsApi accountsApi = createAccountsApi(session.getBasePath(), user.getAccessToken()); - - PermissionProfileInformation permissionsInfo = accountsApi.listPermissions(session.getAccountId()); - List profiles = permissionsInfo.getPermissionProfiles(); - model.addAttribute(MODEL_LIST_PROFILES, profiles); - - model.addAttribute(MODEL_CUR_PROFILE_NAME, profiles.get(0).getPermissionProfileName()); - model.addAttribute(MODEL_CUR_PROFILE_ID, profiles.get(0).getPermissionProfileId()); - findProfile(profiles, session.getPermissionProfileId()).ifPresent((PermissionProfile curProfile) -> { - model.addAttribute(MODEL_CUR_PROFILE_NAME, curProfile.getPermissionProfileName()); - model.addAttribute(MODEL_CUR_PROFILE_ID, curProfile.getPermissionProfileId()); - // model.addAttribute(MODEL_PERMISSIONS, - // Utils.compareFields(curProfile.getSettings(), null, true)); - }); - } - - @Override - protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) - throws ApiException, IOException { - // Step 2. Construct your API headers - AccountsApi accountsApi = createAccountsApi(session.getBasePath(), user.getAccessToken()); - String accountId = session.getAccountId(); - String curProfileId = args.getProfileId(); - - // Step 3. Construct your request body - PermissionProfileInformation permissionsInfo = accountsApi.listPermissions(accountId); - PermissionProfile profile = findProfile(permissionsInfo.getPermissionProfiles(), curProfileId) - .orElseThrow(NoSuchElementException::new); - - // Step 4. Call the eSignature REST API - AccountRoleSettings newSettings = Objects.requireNonNullElse(profile.getSettings(), - DsModelUtils.createDefaultRoleSettings()); - profile.setSettings(changeRandomSettings(newSettings)); - PermissionProfile newProfile = accountsApi.updatePermissionProfile(accountId, curProfileId, profile); - - DoneExample.createDefault(title).withMessage("The permission profile is updated!
Permission profile ID: " - + newProfile.getPermissionProfileId() + ".").addToModel(model); - return DONE_EXAMPLE_PAGE_COMPARE; - } - - private static Optional findProfile(List profiles, String profileId) { - - return profiles.stream().filter(p -> p.getPermissionProfileId().equals(profileId)).findFirst(); - } - - // Changes random boolean properties; in a real application, changing properties - // will be read from the page or in a different way - private static AccountRoleSettings changeRandomSettings(AccountRoleSettings settings) { - Gson gson = new Gson(); - // Change this value back to: gson.fromJson(gson.toJson(settings), - // AccountRoleSettings.class); - // as soon as the signinguiversion is added back to the swagger spec. - AccountRoleSettings newSettings = gson.fromJson(gson.toJson(settings), AccountRoleSettingsPatch.class); - Random random = new Random(System.currentTimeMillis()); - - return newSettings.canCreateWorkspaces(randomBool(random)).allowEnvelopeSending(randomBool(random)) - .allowSignerAttachments(randomBool(random)).allowESealRecipients(randomBool(random)) - .allowTaggingInSendAndCorrect(randomBool(random)).allowWetSigningOverride(randomBool(random)) - .enableApiRequestLogging(randomBool(random)).enableRecipientViewingNotifications(randomBool(random)) - .allowSupplementalDocuments(randomBool(random)).disableDocumentUpload(randomBool(random)); - } - - private static String randomBool(Random random) { - if (random.nextBoolean()) { - return DsModelUtils.TRUE; - } - return DsModelUtils.FALSE; - } -} diff --git a/src/main/java/com/docusign/controller/examples/EG027ControllerPermissionDelete.java b/src/main/java/com/docusign/controller/examples/EG027ControllerPermissionDelete.java deleted file mode 100644 index 204beb0f..00000000 --- a/src/main/java/com/docusign/controller/examples/EG027ControllerPermissionDelete.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.docusign.controller.examples; - -import javax.servlet.http.HttpServletResponse; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; - -import com.docusign.DSConfiguration; -import com.docusign.esign.api.AccountsApi; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.PermissionProfileInformation; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; - - -/** - * Permission profiles are collections of account settings that determine the - * behavior and actions available to the user groups to which they're applied. - * This code example demonstrates how to delete a permission profile with the - * eSignature REST API. - */ -@Controller -@RequestMapping("/eg027") -public class EG027ControllerPermissionDelete extends AbstractController { - - private static final String MODEL_LIST_PROFILES = "listProfiles"; - - private final Session session; - private final User user; - - - @Autowired - public EG027ControllerPermissionDelete(DSConfiguration config, Session session, User user) { - super(config, "eg027", "Deleting a permission profile"); - this.session = session; - this.user = user; - } - - @Override - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { - super.onInitModel(args, model); - AccountsApi accountsApi = createAccountsApi(session.getBasePath(), user.getAccessToken()); - - PermissionProfileInformation permissionsInfo = accountsApi.listPermissions(session.getAccountId()); - model.addAttribute(MODEL_LIST_PROFILES, permissionsInfo.getPermissionProfiles()); - } - - @Override - protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws ApiException { - // Step 2: Construct your API headers - AccountsApi accountsApi = createAccountsApi(session.getBasePath(), user.getAccessToken()); - - // Step 3: Call the eSignature Rest API to delete profile - String curProfileId = args.getProfileId(); - accountsApi.deletePermissionProfile(session.getAccountId(), curProfileId); - - // Step 4: Show 'done' (successful) page - DoneExample.createDefault(title) - .withMessage(String.join("", "The permission profile '", curProfileId, "' is deleted.")) - .addToModel(model); - return DONE_EXAMPLE_PAGE; - } -} diff --git a/src/main/java/com/docusign/controller/examples/EG029ControllerApplyBrandToEnvelope.java b/src/main/java/com/docusign/controller/examples/EG029ControllerApplyBrandToEnvelope.java deleted file mode 100644 index c06732e2..00000000 --- a/src/main/java/com/docusign/controller/examples/EG029ControllerApplyBrandToEnvelope.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.docusign.controller.examples; - -import java.io.IOException; -import java.util.Arrays; -import java.util.List; - -import javax.servlet.http.HttpServletResponse; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; - -import com.docusign.DSConfiguration; -import com.docusign.esign.api.AccountsApi; -import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.BrandsResponse; -import com.docusign.esign.model.Document; -import com.docusign.esign.model.EnvelopeDefinition; -import com.docusign.esign.model.EnvelopeSummary; -import com.docusign.esign.model.Recipients; -import com.docusign.esign.model.Signer; -import com.docusign.esign.model.Tabs; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; - - -/** - * Applying a brand to an envelope
- * The envelope includes a pdf document. Anchor text AutoPlace is used - * to position the signing fields in the documents. - */ -@Controller -@RequestMapping("/eg029") -public class EG029ControllerApplyBrandToEnvelope extends AbstractController { - - private static final String MODEL_LIST_BRAND = "listBrands"; - private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; - private static final String DOCUMENT_NAME = "EG025 Lorem Ipsum"; - private static final int ANCHOR_OFFSET_Y = 10; - private static final int ANCHOR_OFFSET_X = 20; - - private final Session session; - private final User user; - - - @Autowired - public EG029ControllerApplyBrandToEnvelope(DSConfiguration config, Session session, User user) { - super(config, "eg029", "Apply brand to envelope"); - this.session = session; - this.user = user; - } - - @Override - protected void onInitModel(WorkArguments args, ModelMap model) throws ApiException { - super.onInitModel(args, model); - AccountsApi accountsApi = createAccountsApi(session.getBasePath(), user.getAccessToken()); - BrandsResponse brands = accountsApi.listBrands(session.getAccountId()); - model.addAttribute(MODEL_LIST_BRAND, brands.getBrands()); - } - - @Override - protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) - throws ApiException, IOException { - // Step 2: Construct your API headers - EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); - - // Step 3: Construct your envelope JSON body - EnvelopeDefinition envelope = makeEnvelope(args); - - // Step 5: Call the eSignature REST API - EnvelopeSummary envelopeSummary = envelopesApi.createEnvelope(session.getAccountId(), envelope); - - DoneExample.createDefault(title) - .withJsonObject(envelopeSummary) - .withMessage("The envelope has been created and sent!
Envelope ID " - + envelopeSummary.getEnvelopeId() + ".") - .addToModel(model); - return DONE_EXAMPLE_PAGE; - } - - // Creates an envelope. The envelope has one recipient who should sign an - // attached document. Attached document is read from a local directory. - // Also the envelope contains a brand Id which is created on EG024 example. - private static EnvelopeDefinition makeEnvelope(WorkArguments args) throws IOException { - // Reads a file from a local directory and create Document object. - Document document = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, "1"); - - // Create a signer recipient to sign the document and associate sign tab - Tabs tabs = EnvelopeHelpers.createSingleSignerTab("/sn1/", ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X); - Signer signer = new Signer() - .email(args.getSignerEmail()) - .name(args.getSignerName()) - .recipientId("1") - .routingOrder("1") - .tabs(tabs); - - Recipients recipients = new Recipients(); - recipients.setSigners(Arrays.asList(signer)); - - // Return envelope definition using created objects: the document, - // the recipients and obtained brand Id. - return new EnvelopeDefinition() - .emailSubject("EG025. Please complete your order") - .documents(List.of(document)) - .recipients(recipients) - .brandId(args.getBrandId()) - .status(EnvelopeHelpers.ENVELOPE_STATUS_SENT); - } -} diff --git a/src/main/java/com/docusign/controller/examples/EG031ControllerBulkSendEnvelopes.java b/src/main/java/com/docusign/controller/examples/EG031ControllerBulkSendEnvelopes.java deleted file mode 100644 index a43a1de1..00000000 --- a/src/main/java/com/docusign/controller/examples/EG031ControllerBulkSendEnvelopes.java +++ /dev/null @@ -1,176 +0,0 @@ -package com.docusign.controller.examples; - -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import javax.servlet.http.HttpServletResponse; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; - -import com.docusign.DSConfiguration; -import com.docusign.esign.api.BulkEnvelopesApi; -import com.docusign.esign.api.EnvelopesApi; -import com.docusign.esign.client.ApiClient; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.model.BulkEnvelopeStatus; -import com.docusign.esign.model.BulkSendRequest; -import com.docusign.esign.model.BulkSendingCopy; -import com.docusign.esign.model.BulkSendingCopyRecipient; -import com.docusign.esign.model.BulkSendingList; -import com.docusign.esign.model.CustomFields; -import com.docusign.esign.model.Document; -import com.docusign.esign.model.EnvelopeDefinition; -import com.docusign.esign.model.Recipients; -import com.docusign.esign.model.Signer; -import com.docusign.esign.model.TextCustomField; -import com.docusign.model.DoneExample; -import com.docusign.model.Session; -import com.docusign.model.User; - -/** - * This code example demonstrates how to send envelopes in bulk to multiple - * recipients with the eSignature API. To accomplish the task, you will first - * create a bulk send recipients list, and then create an envelope. From there, - * you will combine the envelope and bulk list to initiate bulk send - */ -@Controller -@RequestMapping("/eg031") -public class EG031ControllerBulkSendEnvelopes extends AbstractController { - - private static final long BULK_REQUEST_DELAY = 15L; - private static final String BULK_SIGNER_EMAIL_PLACEHOLDER = "MultiBulkRecipients-%s@docusign.com"; - private static final String BULK_SIGNER_NAME_PLACEHOLDER = "Multi Bulk Recipients::%s"; - private static final String DOCX_DOCUMENT_FILE_NAME = "World_Wide_Corp_Battle_Plan_Trafalgar.docx"; - private static final String DOCX_DOCUMENT_NAME = "Battle Plan"; - - private final Session session; - private final User user; - - - @Autowired - public EG031ControllerBulkSendEnvelopes(DSConfiguration config, Session session, User user) { - super(config, "eg031", "Bulk sending envelopes to multiple recipients"); - this.session = session; - this.user = user; - } - - @Override - protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) - throws ApiException, IOException { - - // Step 2. Construct your API headers - ApiClient apiClient = createApiClient(session.getBasePath(), user.getAccessToken()); - String accountId = session.getAccountId(); - - // Step 3. Submit a bulk list - BulkEnvelopesApi bulkEnvelopesApi = new BulkEnvelopesApi(apiClient); - BulkSendingList sendingList = getSendingList(args); - String bulkListId = bulkEnvelopesApi.createBulkSendList(accountId, sendingList).getListId(); - - // Step 4. Create an envelope - EnvelopesApi envelopesApi = new EnvelopesApi(apiClient); - String envelopeId = envelopesApi.createEnvelope(accountId, makeEnvelope()).getEnvelopeId(); - - // Step 5. Attach your bulk list ID to the envelope - CustomFields customFields = createCustomFields(bulkListId); - envelopesApi.createCustomFields(accountId, envelopeId, customFields); - - // Step 6. Add placeholder recipients - envelopesApi.createRecipient(accountId, envelopeId, createRecipients()); - - // Step 7. Initiate bulk send - BulkSendRequest request = new BulkSendRequest(); - request.setEnvelopeOrTemplateId(envelopeId); - String batchId = bulkEnvelopesApi.createBulkSendRequest(accountId, bulkListId, request).getBatchId(); - - // Step 8. Confirm successful bulk send - try { - TimeUnit.SECONDS.sleep(BULK_REQUEST_DELAY); - // For 2000 recipients, it can take about an hour - BulkEnvelopeStatus status = bulkEnvelopesApi.get(accountId, batchId); - DoneExample.createDefault(title) - .withJsonObject(status) - .withMessage(String.join("", "Bulk request was sent to ", status.getSent(), " user lists.")) - .addToModel(model); - } catch (InterruptedException exception) { - Thread.currentThread().interrupt(); - return null; - } - - return DONE_EXAMPLE_PAGE; - } - - private static BulkSendingList getSendingList(WorkArguments args) { - List copies = List.of( - createBulkSending(args.getSignerName(), args.getSignerEmail(), args.getCcName(), args.getCcEmail()), - createBulkSending(args.getSignerName2(), args.getSignerEmail2(), args.getCcName2(), args.getCcEmail2()) - ); - return new BulkSendingList() - .name("sample.csv") - .bulkCopies(copies); - } - - private static BulkSendingCopy createBulkSending(String signerName, - String signerEmail, String ccName, String ccEmail) { - BulkSendingCopyRecipient recipient1 = new BulkSendingCopyRecipient() - .name(signerName) - .email(signerEmail) - .tabs(Collections.emptyList()) - .roleName(EnvelopeHelpers.SIGNER_ROLE_NAME); - BulkSendingCopyRecipient recipient2 = new BulkSendingCopyRecipient() - .name(ccName) - .email(ccEmail) - .tabs(Collections.emptyList()) - .roleName(EnvelopeHelpers.CC_ROLE_NAME); - return new BulkSendingCopy() - .recipients(List.of(recipient1, recipient2)) - .customFields(Collections.emptyList()); - } - - private static EnvelopeDefinition makeEnvelope() throws IOException { - Document document = EnvelopeHelpers.createDocumentFromFile(DOCX_DOCUMENT_FILE_NAME, DOCX_DOCUMENT_NAME, "1"); - return new EnvelopeDefinition() - .documents(List.of(document)) - .envelopeIdStamping(DsModelUtils.TRUE) - .emailSubject("EG031 Please sign") - .status(EnvelopeHelpers.ENVELOPE_STATUS_CREATED); - } - - private static CustomFields createCustomFields(String bulkListId) { - TextCustomField textCustomField = new TextCustomField() - .name("mailingListId") - .required(DsModelUtils.FALSE) - .show(DsModelUtils.FALSE) - .value(bulkListId); - - return new CustomFields() - .listCustomFields(Collections.emptyList()) - .textCustomFields(List.of(textCustomField)); - } - - private static Recipients createRecipients() { - List signers = List.of( - createSignerPlaceholder(EnvelopeHelpers.SIGNER_ROLE_NAME, "1"), - createSignerPlaceholder(EnvelopeHelpers.CC_ROLE_NAME, "2")); - return new Recipients() - .signers(signers); - } - - private static Signer createSignerPlaceholder(String roleName, String recipientId) { - return new Signer() - .name(String.format(BULK_SIGNER_NAME_PLACEHOLDER, roleName)) - .email(String.format(BULK_SIGNER_EMAIL_PLACEHOLDER, roleName)) - .roleName(roleName) - .note("") - .routingOrder("1") - .status(EnvelopeHelpers.SIGNER_STATUS_CREATED) - .deliveryMethod(EnvelopeHelpers.DELIVERY_METHOD_EMAIL) - .recipientId(recipientId) - .recipientType(EnvelopeHelpers.SIGNER_ROLE_NAME); - } -} \ No newline at end of file diff --git a/src/main/java/com/docusign/controller/examples/WorkArguments.java b/src/main/java/com/docusign/controller/examples/WorkArguments.java deleted file mode 100644 index 8d3d3200..00000000 --- a/src/main/java/com/docusign/controller/examples/WorkArguments.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.docusign.controller.examples; - -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; -import org.springframework.web.context.WebApplicationContext; - -import lombok.Data; - - -@Component -@Scope(value = WebApplicationContext.SCOPE_REQUEST) -@Data -public class WorkArguments { - private String item; - private String quantity; - private String signerEmail; - private String signerName; - private String ccEmail; - private String ccName; - private String signerEmail2; - private String signerName2; - private String ccEmail2; - private String ccName2; - private String status; - private String startingView; - private String dsReturnUrl; - private String dsPingUrl; - private String signerClientId; - private String docSelect; - private String accessCode; - private String brandName; - private String language; - private String brandId; - private String templateId; - private String profileId; - private String groupId; - private String permissionProfileName; -} diff --git a/src/main/java/com/docusign/controller/maestro/examples/AbstractMaestroController.java b/src/main/java/com/docusign/controller/maestro/examples/AbstractMaestroController.java new file mode 100644 index 00000000..6e4ce884 --- /dev/null +++ b/src/main/java/com/docusign/controller/maestro/examples/AbstractMaestroController.java @@ -0,0 +1,48 @@ +package com.docusign.controller.maestro.examples; + +import com.docusign.DSConfiguration; +import com.docusign.core.controller.AbstractController; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.iam.sdk.IamClient; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import org.springframework.stereotype.Controller; + +/** + * Abstract base class for all Maestro fields controllers. + */ +@Controller +public abstract class AbstractMaestroController extends AbstractController { + + private static final String EXAMPLE_PAGES_PATH = "pages/maestro/examples/"; + + protected final User user; + + protected final Session session; + + public AbstractMaestroController(DSConfiguration config, String exampleName, User user, Session session) { + super(config, exampleName); + this.user = user; + this.session = session; + } + + //ds-snippet-start:MaestroJavaStep2 + protected IamClient createAuthenticatedClient(String accessToken) { + return IamClient.builder() + .accessToken(accessToken) + .build(); + } + //ds-snippet-end:MaestroJavaStep2 + + protected String serializeObjectToJson(Object data) throws Exception { + ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(new Jdk8Module()); + + return mapper.writeValueAsString(data); + } + + protected String getExamplePagesPath() { + return AbstractMaestroController.EXAMPLE_PAGES_PATH; + } +} diff --git a/src/main/java/com/docusign/controller/maestro/examples/Mae001TriggerWorkflowController.java b/src/main/java/com/docusign/controller/maestro/examples/Mae001TriggerWorkflowController.java new file mode 100644 index 00000000..a6433027 --- /dev/null +++ b/src/main/java/com/docusign/controller/maestro/examples/Mae001TriggerWorkflowController.java @@ -0,0 +1,137 @@ +package com.docusign.controller.maestro.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.maestro.services.TriggerWorkflowService; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.util.Optional; + +/** + * This example demonstrates how to trigger maestro workflow. + */ +@Controller +@RequestMapping("/mae001") +public class Mae001TriggerWorkflowController extends AbstractMaestroController { + public static final String EMBED = "pages/maestro/examples/embed"; + + private static final String MAESTRO_WORKFLOW_CONFIG = "maestro-workflow-definition.json"; + + public static final String URL = "url"; + + private static final String TEMPLATE_ID = "templateId"; + + private static final String WORKFLOW_ID = "workflowId"; + + private static final String PUBLISH_LINK = "publishLink"; + + public static final String WORKFLOW_NAME = "Example workflow - send invite to signer"; + + public static final String STATUS = "active"; + + public Mae001TriggerWorkflowController(DSConfiguration config, Session session, User user) { + super(config, "mae001", user, session); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + + try { + ensureWorkflowExists(model); + } catch(Exception exception) { + throw new Exception(getTextForCodeExampleByApiType().CustomErrorTexts.get(0).ErrorMessage); + } + + model.addAttribute(TEMPLATE_ID, session.getTemplateId()); + model.addAttribute(WORKFLOW_ID, session.getWorkflowId()); + } + + @Override + protected Object doWork( + WorkArguments args, + ModelMap model, + HttpServletResponse response + ) throws Exception{ + var accountId = session.getAccountId(); + var accessToken = user.getAccessToken(); + var client = createAuthenticatedClient(accessToken); + + var triggerResponse = TriggerWorkflowService.triggerWorkflowInstance( + client, + accountId, + session.getWorkflowId(), + args.getSignerEmail(), + args.getSignerName(), + args.getCcEmail(), + args.getCcName(), + args.getInstanceName()); + + triggerResponse.triggerWorkflowSuccess().ifPresent(success -> { + session.setInstanceId(success.instanceId().orElse(null)); + model.addAttribute(URL, success.instanceUrl().orElse("")); + }); + + model.addAttribute(LAUNCHER_TEXTS, config.getCodeExamplesText().SupportingTexts); + model.addAttribute("example", this.getTextForCodeExample()); + + return EMBED; + } + + private void ensureWorkflowExists(ModelMap model) throws Exception { + var accountId = session.getAccountId(); + var accessToken = user.getAccessToken(); + var templateId = session.getTemplateId(); + + if (session.getWorkflowId() == null) { + findActiveWorkflow(accessToken, accountId) + .ifPresent(workflowId -> session.setWorkflowId(workflowId)); + } + + if (session.getIsWorkflowPublished()) { + publishAndSetLink(model, accessToken, accountId, session.getWorkflowId()); + } + + if (session.getWorkflowId() == null && templateId != null) { + var workflowId = TriggerWorkflowService.createWorkflow(accessToken, accountId, templateId, MAESTRO_WORKFLOW_CONFIG); + + session.setWorkflowId(workflowId); + session.setIsWorkflowPublished(true); + + publishAndSetLink(model, accessToken, accountId, workflowId); + } + } + + private Optional findActiveWorkflow(String accessToken, String accountId) throws Exception { + var client = createAuthenticatedClient(accessToken); + var workflowsResponse = TriggerWorkflowService.getMaestroWorkflow(client, accountId); + + return workflowsResponse.workflowsListSuccess().stream() + .filter(w -> w.data().isPresent()) + .flatMap(w -> w.data().orElseThrow().stream()) + .filter(workflow -> workflow.name().orElseThrow().equals(WORKFLOW_NAME)) + .map(workflow -> workflow.id().orElse(null)) + .findFirst(); + } + + private void publishAndSetLink(ModelMap model, String accessToken, String accountId, String workflowId) throws Exception { + String publishLink = TriggerWorkflowService.publishWorkflow(accessToken, accountId, workflowId); + + if (!publishLink.isEmpty()) { + String linkText = getTextForCodeExampleByApiType() + .getAdditionalPage() + .get(0) + .getResultsPageText() + .replaceFirst("\\{0}", publishLink); + + model.addAttribute(PUBLISH_LINK, linkText); + } else { + session.setIsWorkflowPublished(false); + } + } +} diff --git a/src/main/java/com/docusign/controller/maestro/examples/Mae002PauseWorkflowController.java b/src/main/java/com/docusign/controller/maestro/examples/Mae002PauseWorkflowController.java new file mode 100644 index 00000000..c5c1d9e6 --- /dev/null +++ b/src/main/java/com/docusign/controller/maestro/examples/Mae002PauseWorkflowController.java @@ -0,0 +1,64 @@ +package com.docusign.controller.maestro.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.maestro.services.PauseWorkflowService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +/** + * This example demonstrates how to pause workflow. + */ +@Controller +@RequestMapping("/mae002") +public class Mae002PauseWorkflowController extends AbstractMaestroController { + + private static final String MODEL_IS_WORKFLOW_ID_PRESENT = "isWorkflowIdPresent"; + + public static final String NO_WORKFLOW_AVAILABLE_TO_PAUSE = "No workflow available to pause."; + + public Mae002PauseWorkflowController(DSConfiguration config, Session session, User user) { + super(config, "mae002", user, session); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + model.addAttribute(MODEL_IS_WORKFLOW_ID_PRESENT, session.getWorkflowId() != null ); + } + + @Override + protected Object doWork( + WorkArguments args, + ModelMap model, + HttpServletResponse response + ) throws Exception{ + var accountId = session.getAccountId(); + var accessToken = user.getAccessToken(); + var workflowId = session.getWorkflowId(); + var client = createAuthenticatedClient(accessToken); + + if (workflowId == null) { + throw new IllegalStateException(NO_WORKFLOW_AVAILABLE_TO_PAUSE); + } + + var paused = PauseWorkflowService.PauseMaestroWorkflow( + client, + accountId, + workflowId); + var jsonResponse = serializeObjectToJson(paused.pauseNewWorkflowInstancesSuccess().orElseThrow()); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(jsonResponse) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/maestro/examples/Mae003ResumeWorkflowController.java b/src/main/java/com/docusign/controller/maestro/examples/Mae003ResumeWorkflowController.java new file mode 100644 index 00000000..575780c3 --- /dev/null +++ b/src/main/java/com/docusign/controller/maestro/examples/Mae003ResumeWorkflowController.java @@ -0,0 +1,63 @@ +package com.docusign.controller.maestro.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.maestro.services.ResumeWorkflowService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +/** + * This example demonstrates how to resume workflow. + */ +@Controller +@RequestMapping("/mae003") +public class Mae003ResumeWorkflowController extends AbstractMaestroController { + private static final String MODEL_IS_WORKFLOW_ID_PRESENT = "isWorkflowIdPresent"; + + public static final String NO_WORKFLOW_AVAILABLE_TO_RESUME = "No workflow available to resume."; + + public Mae003ResumeWorkflowController(DSConfiguration config, Session session, User user) { + super(config, "mae003", user, session); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + model.addAttribute(MODEL_IS_WORKFLOW_ID_PRESENT, session.getWorkflowId() != null ); + } + + @Override + protected Object doWork( + WorkArguments args, + ModelMap model, + HttpServletResponse response + ) throws Exception{ + var accountId = session.getAccountId(); + var accessToken = user.getAccessToken(); + var workflowId = session.getWorkflowId(); + var client = createAuthenticatedClient(accessToken); + + if (workflowId == null) { + throw new IllegalStateException(NO_WORKFLOW_AVAILABLE_TO_RESUME); + } + + var paused = ResumeWorkflowService.ResumeMaestroWorkflow( + client, + accountId, + workflowId); + var jsonResponse = serializeObjectToJson(paused.resumeNewWorkflowInstancesSuccess().orElseThrow()); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(jsonResponse) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/maestro/examples/Mae004CancelWorkflowInstanceController.java b/src/main/java/com/docusign/controller/maestro/examples/Mae004CancelWorkflowInstanceController.java new file mode 100644 index 00000000..e19c8fc3 --- /dev/null +++ b/src/main/java/com/docusign/controller/maestro/examples/Mae004CancelWorkflowInstanceController.java @@ -0,0 +1,77 @@ +package com.docusign.controller.maestro.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.maestro.services.CancelWorkflowInstanceService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +/** + * This example demonstrates how to cancel workflow instance. + */ +@Controller +@RequestMapping("/mae004") +public class Mae004CancelWorkflowInstanceController extends AbstractMaestroController { + public static final String IN_PROGRESS = "In Progress"; + + private static final String MODEL_IS_WORKFLOW_ID_PRESENT = "isWorkflowIdPresent"; + + public static final String NO_WORKFLOW_INSTANCE_AVAILABLE_TO_CANCEL = "No workflow instance available to cancel."; + + public Mae004CancelWorkflowInstanceController(DSConfiguration config, Session session, User user) { + super(config, "mae004", user, session); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + model.addAttribute(MODEL_IS_WORKFLOW_ID_PRESENT, session.getWorkflowId() != null && session.getInstanceId() != null ); + } + + @Override + protected Object doWork( + WorkArguments args, + ModelMap model, + HttpServletResponse response + ) throws Exception{ + var accountId = session.getAccountId(); + var accessToken = user.getAccessToken(); + var workflowId = session.getWorkflowId(); + var instanceId = session.getInstanceId(); + var client = createAuthenticatedClient(accessToken); + + if (workflowId == null || instanceId == null) { + throw new IllegalStateException(NO_WORKFLOW_INSTANCE_AVAILABLE_TO_CANCEL); + } + + var workflowInstance = CancelWorkflowInstanceService.GetWorkflowInstanceStatus(client, + accountId, + workflowId, + instanceId); + + if(!workflowInstance.workflowInstance().get().workflowStatus().get().equals(IN_PROGRESS)) { + throw new IllegalStateException(getTextForCodeExampleByApiType().CustomErrorTexts.get(2).ErrorMessage); + } + + var paused = CancelWorkflowInstanceService.CancelMaestroWorkflowInstance( + client, + accountId, + workflowId, + instanceId); + + var jsonResponse = serializeObjectToJson(paused.cancelWorkflowInstanceResponse().orElseThrow()); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(jsonResponse) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/maestro/services/CancelWorkflowInstanceService.java b/src/main/java/com/docusign/controller/maestro/services/CancelWorkflowInstanceService.java new file mode 100644 index 00000000..f37c5953 --- /dev/null +++ b/src/main/java/com/docusign/controller/maestro/services/CancelWorkflowInstanceService.java @@ -0,0 +1,26 @@ +package com.docusign.controller.maestro.services; + +import com.docusign.iam.sdk.IamClient; +import com.docusign.iam.sdk.models.operations.*; + +public class CancelWorkflowInstanceService { + //ds-snippet-start:Maestro4Step3 + public static CancelWorkflowInstanceResponse CancelMaestroWorkflowInstance( + IamClient client, + String accountId, + String workflowId, + String instanceId) throws Exception { + return client.workflowBuilder().workflowInstanceManagement() + .cancelWorkflowInstance(accountId, workflowId, instanceId); + } + //ds-snippet-end:Maestro4Step3 + + public static GetWorkflowInstanceResponse GetWorkflowInstanceStatus( + IamClient client, + String accountId, + String workflowId, + String instanceId) throws Exception { + return client.workflowBuilder().workflowInstanceManagement() + .getWorkflowInstance(accountId, workflowId, instanceId); + } +} diff --git a/src/main/java/com/docusign/controller/maestro/services/PauseWorkflowService.java b/src/main/java/com/docusign/controller/maestro/services/PauseWorkflowService.java new file mode 100644 index 00000000..16e9691b --- /dev/null +++ b/src/main/java/com/docusign/controller/maestro/services/PauseWorkflowService.java @@ -0,0 +1,16 @@ +package com.docusign.controller.maestro.services; + +import com.docusign.iam.sdk.IamClient; +import com.docusign.iam.sdk.models.operations.*; + +public class PauseWorkflowService { + //ds-snippet-start:Maestro2Step3 + public static PauseNewWorkflowInstancesResponse PauseMaestroWorkflow( + IamClient client, + String accountId, + String workflowId) throws Exception { + return client.workflowBuilder() + .workflows().pauseNewWorkflowInstances(accountId, workflowId); + } + //ds-snippet-end:Maestro2Step3 +} diff --git a/src/main/java/com/docusign/controller/maestro/services/ResumeWorkflowService.java b/src/main/java/com/docusign/controller/maestro/services/ResumeWorkflowService.java new file mode 100644 index 00000000..6f5182f0 --- /dev/null +++ b/src/main/java/com/docusign/controller/maestro/services/ResumeWorkflowService.java @@ -0,0 +1,16 @@ +package com.docusign.controller.maestro.services; + +import com.docusign.iam.sdk.IamClient; +import com.docusign.iam.sdk.models.operations.*; + +public class ResumeWorkflowService { + //ds-snippet-start:Maestro3Step3 + public static ResumePausedWorkflowResponse ResumeMaestroWorkflow( + IamClient client, + String accountId, + String workflowId) throws Exception { + return client.workflowBuilder() + .workflows().resumePausedWorkflow(accountId, workflowId); + } + //ds-snippet-end:Maestro3Step3 +} diff --git a/src/main/java/com/docusign/controller/maestro/services/TriggerWorkflowService.java b/src/main/java/com/docusign/controller/maestro/services/TriggerWorkflowService.java new file mode 100644 index 00000000..03bb122f --- /dev/null +++ b/src/main/java/com/docusign/controller/maestro/services/TriggerWorkflowService.java @@ -0,0 +1,161 @@ +package com.docusign.controller.maestro.services; + +import com.docusign.iam.sdk.IamClient; +import com.docusign.iam.sdk.models.components.TriggerInputs; +import com.docusign.iam.sdk.models.components.TriggerWorkflow; +import com.docusign.iam.sdk.models.operations.*; +import org.json.JSONObject; +import org.springframework.core.io.ClassPathResource; +import org.springframework.util.StreamUtils; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +public class TriggerWorkflowService { + private static final String MaestroBasePath = "https://demo.services.docusign.net/aow-manage/v1.0"; + + public static final String CONTENT_TYPE = "application/json"; + + public static final String BEARER = "Bearer "; + + public static final String AUTHORIZATION_HEADER = "Authorization"; + + public static final String ACCEPT_HEADER = "Accept"; + + public static String createWorkflow( + String accessToken, + String accountId, + String templateId, + String fileLocation + ) throws Exception { + String signerId = UUID.randomUUID().toString(); + String ccId = UUID.randomUUID().toString(); + String triggerId = "wfTrigger"; + + String requestJson = prepareWorkflowDefinition(fileLocation, templateId, signerId, ccId, triggerId, accountId); + + HttpClient httpClient = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(MaestroBasePath + "/management/accounts/" + accountId + "/workflowDefinitions")) + .header(AUTHORIZATION_HEADER, BEARER + accessToken) + .header(ACCEPT_HEADER, CONTENT_TYPE) + .header("Content-Type", CONTENT_TYPE) + .POST(HttpRequest.BodyPublishers.ofString(requestJson)) + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + String responseBody = response.body(); + + if (response.statusCode() >= 300) { + throw new Exception("Unable to create a new workflow: " + responseBody); + } + + JSONObject jsonResponse = new JSONObject(responseBody); + return jsonResponse.optString("workflowDefinitionId", null); + } + + public static String publishWorkflow( + String accessToken, + String accountId, + String workflowId + ) throws Exception { + HttpClient httpClient = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(MaestroBasePath + "/management/accounts/" + accountId + "/workflowDefinitions/" + + workflowId + "/publish?isPreRunCheck=true")) + .header(AUTHORIZATION_HEADER, BEARER + accessToken) + .header(ACCEPT_HEADER, CONTENT_TYPE) + .POST(HttpRequest.BodyPublishers.noBody()) + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + String responseBody = response.body(); + + if (response.statusCode() > 201) { + JSONObject jsonResponse = new JSONObject(responseBody); + String message = jsonResponse.optString("message", null); + String consentUrl = jsonResponse.optString("consentUrl", null); + + if ("Consent required".equals(message) && consentUrl != null && !consentUrl.isEmpty()) { + return consentUrl; + } + + throw new Exception("Error publishing workflow. " + message); + } + + return ""; + } + + private static String prepareWorkflowDefinition( + String fileLocation, + String templateId, + String signerId, + String ccId, + String triggerId, + String accountId) throws Exception { + try { + ClassPathResource resource = new ClassPathResource(fileLocation); + byte[] buffer = StreamUtils.copyToByteArray(resource.getInputStream()); + + String workflowDefinition = new String(buffer); + return workflowDefinition + .replace("TEMPLATE_ID", templateId) + .replace("ACCOUNT_ID", accountId) + .replace("SIGNER_ID", signerId) + .replace("CC_ID", ccId) + .replace("TRIGGER_ID", triggerId); + } catch (IOException ex) { + throw new Exception("An error occurred: " + ex.getMessage(), ex); + } + } + + private static TriggerInputs createTriggerInput(String value) { + return TriggerInputs.of(value); + } + + public static TriggerWorkflowResponse triggerWorkflowInstance( + IamClient client, + String accountId, + String workflowId, + String signerEmail, + String signerName, + String ccEmail, + String ccName, + String instanceName) throws Exception { + //ds-snippet-start:Maestro1Step4 + Map triggerInputs = new HashMap<>(); + triggerInputs.put("signerName", createTriggerInput(signerName)); + triggerInputs.put("signerEmail", createTriggerInput(signerEmail)); + triggerInputs.put("ccName", createTriggerInput(ccName)); + triggerInputs.put("ccEmail", createTriggerInput(ccEmail)); + //ds-snippet-end:Maestro1Step4 + + //ds-snippet-start:Maestro1Step5 + var triggerWorkflow = new TriggerWorkflow(instanceName, triggerInputs); + + return client.workflowBuilder() + .workflows() + .triggerWorkflow(accountId, workflowId, triggerWorkflow); + } + //ds-snippet-end:Maestro1Step5 + + //ds-snippet-start:Maestro1Step3 + public static GetWorkflowsListResponse getMaestroWorkflow( + IamClient client, + String accountId) throws Exception { + return client.workflowBuilder() + .workflows() + .getWorkflowsList(accountId, Optional.of(Status.ACTIVE), Optional.empty()); + } + //ds-snippet-end:Maestro1Step3 +} diff --git a/src/main/java/com/docusign/controller/monitor/examples/AbstractMonitorController.java b/src/main/java/com/docusign/controller/monitor/examples/AbstractMonitorController.java new file mode 100644 index 00000000..c7a5dffb --- /dev/null +++ b/src/main/java/com/docusign/controller/monitor/examples/AbstractMonitorController.java @@ -0,0 +1,67 @@ +package com.docusign.controller.monitor.examples; + +import com.docusign.DSConfiguration; +import com.docusign.core.controller.AbstractController; +import com.docusign.core.model.AuthType; +import com.docusign.core.model.Session; +import com.docusign.monitor.api.DataSetApi; +import com.docusign.monitor.client.ApiClient; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Controller; +import org.springframework.web.servlet.ModelAndView; + +/** + * Abstract base class for all Monitor controllers. + */ +@Controller +public abstract class AbstractMonitorController extends AbstractController { + + private static final String EXAMPLE_PAGES_PATH = "pages/monitor/examples/"; + + public AbstractMonitorController(DSConfiguration config, String exampleName) { + super(config, exampleName); + } + + protected String getExamplePagesPath() { + return AbstractMonitorController.EXAMPLE_PAGES_PATH; + } + + protected ModelAndView ensureUsageOfJWTToken(String accessToken, Session session) { + if (session.getAuthTypeSelected() != AuthType.JWT || accessToken.isEmpty()) { + return new ModelAndView("pages/ds_must_authenticate"); + } + + return null; + } + + /** + * Creates new instance of the Monitor API client. + * + * @param accessToken user's access token + * @param session active session + * @return an instance of the {@link com.docusign.monitor.client.ApiClient} + */ + protected ApiClient createApiClient(String accessToken, Session session) { + + //ds-snippet-start:Monitor1Step2 + ApiClient apiClient = new ApiClient(config.getMonitorBasePath()); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + accessToken); + apiClient.setBasePath(config.getMonitorBasePath()); + //ds-snippet-end:Monitor1Step2 + return apiClient; + } + + /** + * Creates a new instance of the DataSetApi. This method + * creates an instance of the ApiClient class silently. + * + * @param accessToken user's access token + * @param session active session + * @return an instance of the {@link DataSetApi} + */ + protected DataSetApi createDataSetApi(String accessToken, Session session) { + ApiClient apiClient = createApiClient(accessToken, session); + return new DataSetApi(apiClient); + } +} + diff --git a/src/main/java/com/docusign/controller/monitor/examples/M001GetMonitoringData.java b/src/main/java/com/docusign/controller/monitor/examples/M001GetMonitoringData.java new file mode 100644 index 00000000..9caef851 --- /dev/null +++ b/src/main/java/com/docusign/controller/monitor/examples/M001GetMonitoringData.java @@ -0,0 +1,62 @@ +package com.docusign.controller.monitor.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.monitor.services.GetMonitoringDataService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.json.JSONArray; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +/** + * Get monitoring data
+ * This example demonstrates how to get monitoring data from the Monitor API. + */ +@Controller +@RequestMapping("/m001") +public class M001GetMonitoringData extends AbstractMonitorController { + + private final Session session; + + private final User user; + + public M001GetMonitoringData(DSConfiguration config, Session session, User user) { + super(config, "m001"); + this.session = session; + this.user = user; + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + String accessToken = this.user.getAccessToken(); + + // Check, if you are using the JWT authentication + ensureUsageOfJWTToken(accessToken, this.session); + JSONArray monitoringData = GetMonitoringDataService.getMonitoringData(createDataSetApi(accessToken, this.session)); + + if (monitoringData.getJSONObject(0).has("Error")) { + new DoneExample() + .withTitle(getTextForCodeExample().ExampleName) + .withName("") + .withMessage(monitoringData.getJSONObject(0).getString("Error")) + .addToModel(model, config); + return ERROR_PAGE; + } + + // Cleaning the data from wrong symbols + String monitoringDataCleaned = monitoringData.toString().replaceAll("'", ""); + + // Process results + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(monitoringDataCleaned) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/monitor/services/GetMonitoringDataService.java b/src/main/java/com/docusign/controller/monitor/services/GetMonitoringDataService.java new file mode 100644 index 00000000..5272f567 --- /dev/null +++ b/src/main/java/com/docusign/controller/monitor/services/GetMonitoringDataService.java @@ -0,0 +1,80 @@ +package com.docusign.controller.monitor.services; + +import com.docusign.monitor.api.DataSetApi; +import com.docusign.monitor.client.ApiResponse; +import com.docusign.monitor.model.CursoredResult; +import org.json.JSONArray; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; + +public final class GetMonitoringDataService { + private static final Logger LOGGER = LoggerFactory.getLogger(GetMonitoringDataService.class); + + public static JSONArray getMonitoringData(DataSetApi datasetApi) throws Exception { + // Declare variables + boolean complete = false; + LocalDate cursorDate = LocalDate.now().minusDays(1); + String cursorValue = cursorDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + "T00:00:00Z"; + JSONArray monitoringData = new JSONArray(); + + LOGGER.info("before optinos"); + DataSetApi.GetStreamOptions options = datasetApi.new GetStreamOptions(); + options.setLimit(2000); + + // First call the endpoint with no cursor to get the first records. + // After each call, save the cursor and use it to make the next + // call from the point where the previous one left off when iterating through + // the monitoring records + try { + //ds-snippet-start:Monitor1Step3 + do { + if (!cursorValue.isEmpty()) { + options.setCursor(cursorValue); + } + + LOGGER.info("options set: " + options); + ApiResponse cursoredResult = datasetApi.getStreamWithHttpInfo("2.0", "monitor", + options); + + Map> headers = cursoredResult.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + LOGGER.info("cursor results " + cursoredResult.getData()); + String endCursor = cursoredResult.getData().getEndCursor(); + + // If the endCursor from the response is the same as the one that you already + // have, + // it means that you have reached the end of the records + if (endCursor.equals(cursorValue)) { + complete = true; + } else { + cursorValue = endCursor; + monitoringData.put(new JSONObject(cursoredResult)); + } + } while (!complete); + //ds-snippet-end:Monitor1Step3 + } catch (Exception e) { + LOGGER.error(String.valueOf(e)); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("Error", + "You do not have Monitor enabled for your account, follow How to enable Monitor for your account to get it enabled."); + monitoringData.put(jsonObject); + } + + return monitoringData; + } +} diff --git a/src/main/java/com/docusign/controller/navigator/examples/AbstractNavigatorController.java b/src/main/java/com/docusign/controller/navigator/examples/AbstractNavigatorController.java new file mode 100644 index 00000000..beadb7fc --- /dev/null +++ b/src/main/java/com/docusign/controller/navigator/examples/AbstractNavigatorController.java @@ -0,0 +1,30 @@ +package com.docusign.controller.navigator.examples; + +import com.docusign.DSConfiguration; +import com.docusign.core.controller.AbstractController; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; + +/** + * Abstract base class for all Navigator fields controllers. + */ +@Controller +public abstract class AbstractNavigatorController extends AbstractController { + + private static final String EXAMPLE_PAGES_PATH = "pages/navigator/examples/"; + + protected final User user; + + protected final Session session; + + public AbstractNavigatorController(DSConfiguration config, String exampleName, User user, Session session) { + super(config, exampleName); + this.user = user; + this.session = session; + } + + protected String getExamplePagesPath() { + return AbstractNavigatorController.EXAMPLE_PAGES_PATH; + } +} diff --git a/src/main/java/com/docusign/controller/navigator/examples/Nav001ListAgreementsController.java b/src/main/java/com/docusign/controller/navigator/examples/Nav001ListAgreementsController.java new file mode 100644 index 00000000..614f7a2b --- /dev/null +++ b/src/main/java/com/docusign/controller/navigator/examples/Nav001ListAgreementsController.java @@ -0,0 +1,44 @@ +package com.docusign.controller.navigator.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.navigator.services.NavigatorMethodsService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +/** + * This example demonstrates how to get all agreements. + */ +@Controller +@RequestMapping("/nav001") +public class Nav001ListAgreementsController extends AbstractNavigatorController { + + public Nav001ListAgreementsController(DSConfiguration config, Session session, User user) { + super(config, "nav001", user, session); + } + + @Override + //ds-snippet-start:Navigator1Step3 + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + var accountId = session.getAccountId(); + var accessToken = user.getAccessToken(); + + var agreements = NavigatorMethodsService.getAgreements(accountId, accessToken); + var agreementsData = agreements.agreementsResponse().orElseThrow().data().orElseThrow(); + var jsonAgreements = NavigatorMethodsService.serializeObjectToJson(agreementsData); + //ds-snippet-end:Navigator1Step3 + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(jsonAgreements) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/navigator/examples/Nav002GetSingleAgreementController.java b/src/main/java/com/docusign/controller/navigator/examples/Nav002GetSingleAgreementController.java new file mode 100644 index 00000000..14912efa --- /dev/null +++ b/src/main/java/com/docusign/controller/navigator/examples/Nav002GetSingleAgreementController.java @@ -0,0 +1,68 @@ +package com.docusign.controller.navigator.examples; + +import com.docusign.DSConfiguration; +import com.docusign.admin.client.ApiException; +import com.docusign.common.WorkArguments; +import com.docusign.controller.navigator.services.NavigatorMethodsService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +/** + * This example demonstrates how to get agreement by id. + */ +@Controller +@RequestMapping("/nav002") +public class Nav002GetSingleAgreementController extends AbstractNavigatorController { + + private static final Logger LOGGER = LoggerFactory.getLogger(Nav002GetSingleAgreementController.class); + + private static final String MODEL_AGREEMENTS_LIST = "agreements"; + + public Nav002GetSingleAgreementController(DSConfiguration config, Session session, User user) { + super(config, "nav002", user, session); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + try { + super.onInitModel(args, model); + + var accountId = session.getAccountId(); + var accessToken = user.getAccessToken(); + + var agreements = NavigatorMethodsService.getAgreements(accountId, accessToken); + var agreementsData = agreements.agreementsResponse().orElseThrow().data().orElseThrow(); + + model.addAttribute(MODEL_AGREEMENTS_LIST, agreementsData); + } catch (ApiException e) { + LOGGER.info(String.valueOf(e)); + } + } + + @Override + //ds-snippet-start:Navigator2Step3 + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + var accountId = session.getAccountId(); + var accessToken = user.getAccessToken(); + var agreementId = args.getAgreementId(); + + var agreement = NavigatorMethodsService.getAgreement(accountId, accessToken, agreementId); + var jsonAgreement = NavigatorMethodsService.serializeObjectToJson(agreement.agreement().orElseThrow()); + //ds-snippet-end:Navigator2Step3 + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(jsonAgreement) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/navigator/examples/Nav003BulkUploadDocumentsController.java b/src/main/java/com/docusign/controller/navigator/examples/Nav003BulkUploadDocumentsController.java new file mode 100644 index 00000000..84f68230 --- /dev/null +++ b/src/main/java/com/docusign/controller/navigator/examples/Nav003BulkUploadDocumentsController.java @@ -0,0 +1,96 @@ +package com.docusign.controller.navigator.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.navigator.services.NavigatorMethodsService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +/** + * This example demonstrates how to bulk upload documents to Navigator. + * Step 1: Create a bulk upload job. + * Step 2: Upload demo documents to the job's blob storage URLs. + * Step 3: Mark the job as complete. + */ +@Controller +@RequestMapping("/nav003") +public class Nav003BulkUploadDocumentsController extends AbstractNavigatorController { + + private static final String UPLOAD_DOCUMENTS_PAGE = + "pages/navigator/examples/nav003UploadDocuments"; + + private static final String COMPLETE_UPLOAD_PAGE = + "pages/navigator/examples/nav003CompleteUpload"; + + public Nav003BulkUploadDocumentsController(DSConfiguration config, Session session, User user) { + super(config, "nav003", user, session); + } + + //ds-snippet-start:Navigator3Step2 + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) + throws Exception { + var accountId = session.getAccountId(); + var accessToken = user.getAccessToken(); + + var jobInfo = NavigatorMethodsService.createBulkUploadJob(accountId, accessToken); + session.setBulkJobId(jobInfo.getJobId()); + session.setBulkUploadUrls(jobInfo.getUploadUrls()); + + return "redirect:/nav003/uploadDocuments"; + } + //ds-snippet-end:Navigator3Step2 + + //ds-snippet-start:Navigator3Step3 + @GetMapping("/uploadDocuments") + public String getUploadDocuments(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + return UPLOAD_DOCUMENTS_PAGE; + } + + @PostMapping("/uploadDocuments") + public String postUploadDocuments(WorkArguments args, ModelMap model) throws Exception { + if (session.getBulkUploadUrls() == null) { + return "redirect:/nav003"; + } + NavigatorMethodsService.uploadDocumentsToJob(session.getBulkUploadUrls()); + return "redirect:/nav003/completeUpload"; + } + //ds-snippet-end:Navigator3Step3 + + //ds-snippet-start:Navigator3Step4 + @GetMapping("/completeUpload") + public String getCompleteUpload(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + return COMPLETE_UPLOAD_PAGE; + } + + @PostMapping("/completeUpload") + public String postCompleteUpload(WorkArguments args, ModelMap model) throws Exception { + var jobId = session.getBulkJobId(); + if (jobId == null) { + return "redirect:/nav003"; + } + var accountId = session.getAccountId(); + var accessToken = user.getAccessToken(); + + var completeUploadResult = NavigatorMethodsService.completeBulkUploadJob(accountId, accessToken, jobId); + + var jsonAgreement = NavigatorMethodsService.serializeObjectToJson(completeUploadResult.bulkJob().orElseThrow()); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().AdditionalPage.get(1).ResultsPageText) + .withJsonObject(jsonAgreement) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + //ds-snippet-end:Navigator3Step4 + } +} diff --git a/src/main/java/com/docusign/controller/navigator/services/NavigatorMethodsService.java b/src/main/java/com/docusign/controller/navigator/services/NavigatorMethodsService.java new file mode 100644 index 00000000..65826460 --- /dev/null +++ b/src/main/java/com/docusign/controller/navigator/services/NavigatorMethodsService.java @@ -0,0 +1,215 @@ +package com.docusign.controller.navigator.services; + +import com.docusign.core.model.BulkUploadJobInfo; +import com.docusign.iam.sdk.IamClient; +import com.docusign.iam.sdk.models.components.CreateBulkJob; +import com.docusign.iam.sdk.models.operations.GetAgreementResponse; +import com.docusign.iam.sdk.models.operations.GetAgreementsListRequest; +import com.docusign.iam.sdk.models.operations.GetAgreementsListResponse; +import com.docusign.iam.sdk.models.operations.UploadCompleteBulkJobResponse; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.openapitools.jackson.nullable.JsonNullableModule; + +import java.util.List; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.ArrayList; +import java.util.logging.Logger; + +public class NavigatorMethodsService { + private static final HttpClient HTTP_CLIENT = HttpClient.newHttpClient(); + + //ds-snippet-start:NavigatorJavaStep2 + private static IamClient createIamClient(String accessToken) { + return IamClient.builder() + .accessToken(accessToken) + .build(); + } + //ds-snippet-end:NavigatorJavaStep2 + + public static GetAgreementsListResponse getAgreements(String accountId, String accessToken) throws Exception { + return createIamClient(accessToken) + .agreementManager() + .agreements() + .getAgreementsList() + .request(new GetAgreementsListRequest(accountId)) + .call(); + } + + public static GetAgreementResponse getAgreement(String accountId, String accessToken, String agreementId) + throws Exception { + return createIamClient(accessToken) + .agreementManager() + .agreements() + .getAgreement() + .accountId(accountId) + .agreementId(agreementId) + .call(); + } + + public static String serializeObjectToJson(Object data) throws Exception { + var mapper = new ObjectMapper() + .setSerializationInclusion(JsonInclude.Include.NON_NULL) + .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + .registerModule(new JavaTimeModule()) + .registerModule(new Jdk8Module()) + .registerModule(new JsonNullableModule()); + + return mapper.writeValueAsString(data); + } + + public static BulkUploadJobInfo createBulkUploadJob( + String accountId, + String accessToken + ) throws Exception { + var client = createIamClient(accessToken); + + var demoDocs = getAvailableDemoDocuments(); + if (demoDocs.isEmpty()) { + throw new IllegalStateException("No demo documents found on classpath"); + } + + var createJob = CreateBulkJob.builder() + .jobName("Example bulk upload job") + .expectedNumberOfDocs(demoDocs.size()) + .language("en-US") + .build(); + + var createResponse = client.agreementManager().bulkJob() + .createBulkUploadJob(accountId, createJob); + + var bulkJob = createResponse.bulkJob().orElseThrow(); + var jobId = bulkJob.id(); + if (jobId == null || jobId.isBlank()) { + throw new IllegalStateException("API returned a bulk job with no ID"); + } + + var documents = bulkJob.embedded().orElseThrow().documents().orElseThrow(); + + var uploadUrls = new ArrayList(); + for (var doc : documents) { + var actions = doc.actions().orElse(null); + var url = actions != null ? actions.uploadDocument().orElse(null) : null; + uploadUrls.add(url != null ? url : ""); + } + + return new BulkUploadJobInfo(jobId, uploadUrls); + } + + public static void uploadDocumentsToJob(List uploadUrls) throws Exception { + var demoDocs = getAvailableDemoDocuments(); + + for (int i = 0; i < demoDocs.size(); i++) { + if (i >= uploadUrls.size()) + break; + + var uploadUrl = uploadUrls.get(i); + if (uploadUrl == null || uploadUrl.isEmpty()) + continue; + + var docInfo = demoDocs.get(i); + var bytes = loadClasspathResource(docInfo); + if (bytes == null) + continue; + + uploadToBlobStorage(bytes, getContentType(docInfo), docInfo, uploadUrl); + } + } + + public static UploadCompleteBulkJobResponse completeBulkUploadJob( + String accountId, + String accessToken, + String jobId + ) throws Exception { + return createIamClient(accessToken).agreementManager().bulkJob() + .uploadCompleteBulkJob(accountId, jobId); + } + + private static List getAvailableDemoDocuments() { + String[] candidates = { + "World_Wide_Corp_Battle_Plan_Trafalgar.docx", + "World_Wide_Corp_lorem.pdf", + "doc_1.html", + "Welcome.txt", + "Id.jpg", + }; + + var available = new ArrayList(); + for (var doc : candidates) { + if (NavigatorMethodsService.class.getClassLoader().getResource(doc) != null) { + available.add(doc); + } + } + return available; + } + + private static String getContentType(String filename) { + String extension = ""; + int lastDot = filename.lastIndexOf('.'); + + if (lastDot >= 0) { + extension = filename.substring(lastDot).toLowerCase(); + } + + switch (extension) { + case ".docx": { + return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; + } + case ".pdf": { + return "application/pdf"; + } + case ".html": { + return "text/html"; + } + case ".txt": { + return "text/plain"; + } + case ".jpg": + case ".jpeg": { + return "image/jpeg"; + } + default: { + return "application/octet-stream"; + } + } + } + + private static byte[] loadClasspathResource(String resourcePath) { + try (var stream = NavigatorMethodsService.class.getClassLoader().getResourceAsStream(resourcePath)) { + if (stream == null) + return null; + + return stream.readAllBytes(); + } catch (Exception e) { + Logger.getLogger(NavigatorMethodsService.class.getName()) + .warning("Could not load resource: " + resourcePath); + return null; + } + } + + private static void uploadToBlobStorage( + byte[] bytes, + String contentType, + String fileName, + String url + ) throws Exception { + var request = HttpRequest.newBuilder() + .uri(URI.create(url)) + .header("Content-Type", contentType) + .header("x-ms-blob-type", "BlockBlob") + .header("x-ms-meta-filename", fileName) + .PUT(HttpRequest.BodyPublishers.ofByteArray(bytes)) + .build(); + var httpResponse = HTTP_CLIENT.send(request, HttpResponse.BodyHandlers.discarding()); + + if (httpResponse.statusCode() < 200 || httpResponse.statusCode() >= 300) { + throw new java.io.IOException("Blob upload failed for " + fileName + ": HTTP " + httpResponse.statusCode()); + } + } +} diff --git a/src/main/java/com/docusign/controller/notary/examples/AbstractNotaryController.java b/src/main/java/com/docusign/controller/notary/examples/AbstractNotaryController.java new file mode 100644 index 00000000..36ad3c99 --- /dev/null +++ b/src/main/java/com/docusign/controller/notary/examples/AbstractNotaryController.java @@ -0,0 +1,64 @@ +package com.docusign.controller.notary.examples; + +import com.docusign.DSConfiguration; +import com.docusign.core.controller.AbstractController; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.auth.OAuth; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Controller; + +/** + * Abstract base class for all controllers. + */ +@Controller +public abstract class AbstractNotaryController extends AbstractController { + + private static final String EXAMPLE_PAGES_PATH = "pages/notary/examples/"; + + protected Session session; + + protected User user; + + public AbstractNotaryController(DSConfiguration config, String exampleName, Session session, User user) { + super(config, exampleName); + this.session = session; + this.user = user; + } + + /** + * Creates new instance of the Rooms API client. + * + * @param basePath URL to eSignature REST API + * @param userAccessToken user's access token + * @return an instance of the {@link ApiClient} + */ + + //ds-snippet-start:Notary4Step2 + protected static ApiClient createApiClient(String basePath, String userAccessToken) { + ApiClient apiClient = new ApiClient(basePath); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + userAccessToken); + apiClient.addAuthorization("docusignAccessCode", new OAuth()); + return apiClient; + } + //ds-snippet-end:Notary4Step2 + + /** + * Creates a new instance of the eSignature EnvelopesApi. This method + * creates an instance of the ApiClient class silently. + * + * @param basePath URL to eSignature REST API + * @param userAccessToken user's access token + * @return an instance of the {@link EnvelopesApi} + */ + protected EnvelopesApi createEnvelopesApi(String basePath, String userAccessToken) { + ApiClient apiClient = createApiClient(basePath, userAccessToken); + return new EnvelopesApi(apiClient); + } + + protected String getExamplePagesPath() { + return AbstractNotaryController.EXAMPLE_PAGES_PATH; + } +} diff --git a/src/main/java/com/docusign/controller/notary/examples/Neg004SendWithThirdPartyNotaryController.java b/src/main/java/com/docusign/controller/notary/examples/Neg004SendWithThirdPartyNotaryController.java new file mode 100644 index 00000000..6c777432 --- /dev/null +++ b/src/main/java/com/docusign/controller/notary/examples/Neg004SendWithThirdPartyNotaryController.java @@ -0,0 +1,49 @@ +package com.docusign.controller.notary.examples; + +import java.io.IOException; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiException; +import com.docusign.controller.notary.services.SendWithThirdPartyNotaryService; + +@Controller +@RequestMapping("/n004") +public class Neg004SendWithThirdPartyNotaryController extends AbstractNotaryController { + + public Neg004SendWithThirdPartyNotaryController(DSConfiguration config, Session session, User user) { + super(config, "n004", session, user); + } + + @Override + protected Object doWork( + WorkArguments args, + ModelMap model, + HttpServletResponse response) + throws ApiException, IOException, com.docusign.webforms.client.ApiException { + EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken()); + + // Call the Examples API method to create and send an notary envelope via email + var envelopeId = SendWithThirdPartyNotaryService.sendWithNotary( + args.getSignerEmail(), + args.getSignerName(), + this.session.getAccountId(), + envelopesApi, + args); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", envelopeId)) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/notary/services/SendWithThirdPartyNotaryService.java b/src/main/java/com/docusign/controller/notary/services/SendWithThirdPartyNotaryService.java new file mode 100644 index 00000000..18564f6f --- /dev/null +++ b/src/main/java/com/docusign/controller/notary/services/SendWithThirdPartyNotaryService.java @@ -0,0 +1,140 @@ +package com.docusign.controller.notary.services; + +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.core.common.DocumentType; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.api.EnvelopesApi.CreateEnvelopeOptions; +import com.docusign.esign.client.ApiResponse; +import com.docusign.esign.model.*; +import com.docusign.webforms.client.ApiException; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public final class SendWithThirdPartyNotaryService { + private static final String HTML_DOCUMENT_FILE_NAME = "order_form.html"; + + private static final String HTML_DOCUMENT_NAME = "Order form"; + + //ds-snippet-start:Notary4Step4 + public static String sendWithNotary(String signerEmail, String signerName, String accountId, + EnvelopesApi envelopesApi, WorkArguments args) + throws ApiException, com.docusign.esign.client.ApiException, IOException { + EnvelopeDefinition envelopeDefinition = makeEnvelope(signerEmail, signerName, args); + + ApiResponse envelopeSummary = envelopesApi.createEnvelopeWithHttpInfo(accountId, + envelopeDefinition, (CreateEnvelopeOptions) null); + + Map> headers = envelopeSummary.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return envelopeSummary.getData().getEnvelopeId(); + } + //ds-snippet-end:Notary4Step4 + + //ds-snippet-start:Notary4Step3 + private static EnvelopeDefinition makeEnvelope(String signerEmail, String signerName, WorkArguments args) + throws IOException { + EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition(); + envelopeDefinition.setEmailSubject("Please sign this document set"); + + envelopeDefinition.setDocuments(getDocuments(signerEmail, signerName, args)); + + Recipients recipients = new Recipients(); + recipients.setSigners(getSigners(signerEmail, signerName)); + recipients.setNotaries(getNotaryRecipients()); + + envelopeDefinition.setRecipients(recipients); + envelopeDefinition.setStatus("sent"); + + return envelopeDefinition; + } + + private static java.util.List getDocuments(String signerEmail, String signerName, WorkArguments args) + throws IOException { + byte[] htmlDoc = EnvelopeHelpers.createHtmlFromTemplateFile(HTML_DOCUMENT_FILE_NAME, "args", args) + .getBytes(StandardCharsets.UTF_8); + Document document = EnvelopeHelpers.createDocument(htmlDoc, HTML_DOCUMENT_NAME, + DocumentType.HTML.getDefaultFileExtention(), "1"); + + return Collections.singletonList(document); + } + + private static java.util.List getSigners(String signerEmail, String signerName) { + Signer signer = new Signer(); + signer.setClientUserId("1000"); + signer.setEmail(signerEmail); + signer.setName(signerName); + signer.setRecipientId("2"); + signer.setRoutingOrder("1"); + signer.setNotaryId("1"); + + SignHere signHere1 = new SignHere(); + signHere1.setDocumentId("1"); + signHere1.setXPosition("200"); + signHere1.setYPosition("235"); + signHere1.setPageNumber("1"); + + SignHere signHere2 = new SignHere(); + signHere2.setStampType("stamp"); + signHere2.setDocumentId("1"); + signHere2.setXPosition("200"); + signHere2.setYPosition("150"); + signHere2.setPageNumber("1"); + + Tabs signerTabs = new Tabs(); + signerTabs.setSignHereTabs(java.util.Arrays.asList(signHere1, signHere2)); + signer.setTabs(signerTabs); + + return Collections.singletonList(signer); + } + + private static java.util.List getNotaryRecipients() { + NotarySeal notarySealTabs = new NotarySeal(); + notarySealTabs.setXPosition("300"); + notarySealTabs.setYPosition("235"); + notarySealTabs.setDocumentId("1"); + notarySealTabs.setPageNumber("1"); + + SignHere notarySignHere = new SignHere(); + notarySignHere.setXPosition("300"); + notarySignHere.setYPosition("150"); + notarySignHere.setDocumentId("1"); + notarySignHere.setPageNumber("1"); + + Tabs notaryTabs = new Tabs(); + notaryTabs.setSignHereTabs(Collections.singletonList(notarySignHere)); + notaryTabs.setNotarySealTabs(Collections.singletonList(notarySealTabs)); + + NotaryRecipient notaryRecipient = new NotaryRecipient(); + notaryRecipient.setName("Notary"); + notaryRecipient.setRecipientId("1"); + notaryRecipient.setRoutingOrder("1"); + notaryRecipient.setTabs(notaryTabs); + notaryRecipient.setNotaryType("remote"); + notaryRecipient.setNotarySourceType("thirdparty"); + notaryRecipient.setNotaryThirdPartyPartner("onenotary"); + + RecipientSignatureProvider signatureProvider = new RecipientSignatureProvider(); + signatureProvider.setSealDocumentsWithTabsOnly("false"); + signatureProvider.setSignatureProviderName("ds_authority_idv"); + signatureProvider.setSignatureProviderOptions(new RecipientSignatureProviderOptions()); + + notaryRecipient.setRecipientSignatureProviders(Collections.singletonList(signatureProvider)); + + return Collections.singletonList(notaryRecipient); + } + //ds-snippet-end:Notary4Step3 +} diff --git a/src/main/java/com/docusign/controller/rooms/examples/AbstractRoomsController.java b/src/main/java/com/docusign/controller/rooms/examples/AbstractRoomsController.java new file mode 100644 index 00000000..f1ffa046 --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/examples/AbstractRoomsController.java @@ -0,0 +1,143 @@ +package com.docusign.controller.rooms.examples; + +import com.docusign.DSConfiguration; +import com.docusign.core.controller.AbstractController; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.rooms.api.*; +import com.docusign.rooms.client.ApiClient; +import com.docusign.rooms.client.auth.OAuth; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Controller; + + +/** + * Abstract base class for all Rooms controllers. + */ +@Controller +public abstract class AbstractRoomsController extends AbstractController { + + private static final String EXAMPLE_PAGES_PATH = "pages/rooms/examples/"; + + protected Session session; + + protected User user; + + public AbstractRoomsController(DSConfiguration config, String exampleName) { + super(config, exampleName); + } + + /** + * Creates new instance of the Rooms API client. + * + * @param basePath URL to eSignature REST API + * @param userAccessToken user's access token + * @return an instance of the {@link ApiClient} + */ + + //ds-snippet-start:RoomsJavaStep2 + protected static ApiClient createApiClient(String basePath, String userAccessToken) { + ApiClient apiClient = new ApiClient(basePath); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + userAccessToken); + apiClient.addAuthorization("docusignAccessCode", new OAuth()); + return apiClient; + } + + /** + * Creates a new instance of the RoomsApi. This method + * creates an instance of the ApiClient class silently. + * + * @param basePath URL to Rooms REST API + * @param userAccessToken user's access token + * @return an instance of the {@link RoomsApi} + */ + protected static RoomsApi createRoomsApiClient(String basePath, String userAccessToken) { + ApiClient apiClient = createApiClient(basePath, userAccessToken); + return new RoomsApi(apiClient); + } + + /** + * Creates a new instance of the rooms RolesApi. This method + * creates an instance of the ApiClient class silently. + * + * @param basePath URL to Rooms REST API + * @param userAccessToken user's access token + * @return an instance of the {@link RolesApi} + */ + protected static RolesApi createRolesApiClient(String basePath, String userAccessToken) { + ApiClient apiClient = createApiClient(basePath, userAccessToken); + return new RolesApi(apiClient); + } + //ds-snippet-end:RoomsJavaStep2 + + /** + * Creates a new instance of the rooms OfficesApi. This method + * creates an instance of the ApiClient class silently. + * + * @param basePath URL to Rooms REST API + * @param userAccessToken user's access token + * @return an instance of the {@link OfficesApi} + */ + protected static OfficesApi createOfficesApiClient(String basePath, String userAccessToken) { + ApiClient apiClient = createApiClient(basePath, userAccessToken); + return new OfficesApi(apiClient); + } + + /** + * Creates a new instance of the rooms ExternalFormFillSessionsApi. This method + * creates an instance of the ApiClient class silently. + * + * @param basePath URL to Rooms REST API + * @param userAccessToken user's access token + * @return an instance of the {@link ExternalFormFillSessionsApi} + */ + protected static ExternalFormFillSessionsApi createExternalFormFillSessionsApiClient( + String basePath, + String userAccessToken) { + ApiClient apiClient = createApiClient(basePath, userAccessToken); + return new ExternalFormFillSessionsApi(apiClient); + } + + /** + * Creates a new instance of the rooms RoomTemplatesApi. This method + * creates an instance of the ApiClient class silently. + * + * @param basePath URL to Rooms REST API + * @param userAccessToken user's access token + * @return an instance of the {@link RoomTemplatesApi} + */ + protected static RoomTemplatesApi createRoomTemplatesApiClient(String basePath, String userAccessToken) { + ApiClient apiClient = createApiClient(basePath, userAccessToken); + return new RoomTemplatesApi(apiClient); + } + + /** + * Creates a new instance of the FormLibrariesApi. This method + * creates an instance of the ApiClient class silently. + * + * @param basePath URL to Rooms REST API + * @param userAccessToken user's access token + * @return an instance of the {@link RoomsApi} + */ + protected static FormLibrariesApi createFormLibrariesApi(String basePath, String userAccessToken) { + ApiClient apiClient = createApiClient(basePath, userAccessToken); + return new FormLibrariesApi(apiClient); + } + + /** + * Creates a new instance of the FormGroupsApi. This method + * creates an instance of the ApiClient class silently. + * + * @param basePath URL to Rooms REST API + * @param userAccessToken user's access token + * @return an instance of the {@link RoomsApi} + */ + protected static FormGroupsApi createFormGroupsApi(String basePath, String userAccessToken) { + ApiClient apiClient = createApiClient(basePath, userAccessToken); + return new FormGroupsApi(apiClient); + } + + protected String getExamplePagesPath() { + return AbstractRoomsController.EXAMPLE_PAGES_PATH; + } +} diff --git a/src/main/java/com/docusign/controller/rooms/examples/R001ControllerCreateRoom.java b/src/main/java/com/docusign/controller/rooms/examples/R001ControllerCreateRoom.java new file mode 100644 index 00000000..e3c1bcdf --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/examples/R001ControllerCreateRoom.java @@ -0,0 +1,66 @@ +package com.docusign.controller.rooms.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.rooms.services.CreateRoomService; +import com.docusign.controller.rooms.services.GetAdminRolesService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.rooms.api.RoomsApi; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.model.RoleSummary; +import com.docusign.rooms.model.Room; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Create a room. + */ +@Controller +@RequestMapping("/r001") +public class R001ControllerCreateRoom extends AbstractRoomsController { + + public R001ControllerCreateRoom(DSConfiguration config, Session session, User user) { + super(config, "r001"); + this.session = session; + this.user = user; + } + + @Override + // ***DS.snippet.0.start + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws IOException, ApiException { + + RoleSummary adminRole = GetAdminRolesService.getAdminRole( + createRolesApiClient(this.session.getBasePath(), this.user.getAccessToken()), + this.session.getAccountId()); + + // Step 2: Construct your API headers + //ds-snippet-start:Rooms1Step2 + RoomsApi roomsApi = createRoomsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + //ds-snippet-end:Rooms1Step2 + + // Step 3: Call the v2 Rooms API + //ds-snippet-start:Rooms1Step3 + Room createdRoom = CreateRoomService.createRoomFromModel( + roomsApi, + this.session.getAccountId(), + CreateRoomService.createRoomModel(adminRole.getRoleId(), args.getRoomName())); + //ds-snippet-end:Rooms1Step3 + + DoneExample.createDefault(this.title) + .withJsonObject(createdRoom) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", createdRoom.getName()) + .replaceFirst("\\{1}", createdRoom.getRoomId().toString()) + ) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + // ***DS.snippet.0.end +} diff --git a/src/main/java/com/docusign/controller/rooms/examples/R002ControllerCreateRoomWithTemplate.java b/src/main/java/com/docusign/controller/rooms/examples/R002ControllerCreateRoomWithTemplate.java new file mode 100644 index 00000000..47344539 --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/examples/R002ControllerCreateRoomWithTemplate.java @@ -0,0 +1,85 @@ +package com.docusign.controller.rooms.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.rooms.services.CreateRoomWithTemplateService; +import com.docusign.controller.rooms.services.GetAdminRolesService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.rooms.api.RoomTemplatesApi; +import com.docusign.rooms.api.RoomsApi; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.model.RoleSummary; +import com.docusign.rooms.model.Room; +import com.docusign.rooms.model.RoomTemplatesSummaryList; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Create a room with template. + */ +@Controller +@RequestMapping("/r002") +public class R002ControllerCreateRoomWithTemplate extends AbstractRoomsController { + + private static final String MODEL_TEMPLATES_LIST = "templateList"; + + public R002ControllerCreateRoomWithTemplate(DSConfiguration config, Session session, User user) { + super(config, "r002"); + this.session = session; + this.user = user; + } + + @Override + // ***DS.snippet.0.start + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + + // Step 3: Retrieve a Rooms Template ID + //ds-snippet-start:Rooms2Step3 + RoomTemplatesApi templatesApi = createRoomTemplatesApiClient( + this.session.getBasePath(), + this.user.getAccessToken()); + RoomTemplatesSummaryList templatesSummaryList = templatesApi.getRoomTemplates(this.session.getAccountId()); + //ds-snippet-end:Rooms2Step3 + model.addAttribute(MODEL_TEMPLATES_LIST, templatesSummaryList.getRoomTemplates()); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws IOException, ApiException { + RoleSummary adminRole = GetAdminRolesService.getAdminRole( + createRolesApiClient(this.session.getBasePath(), this.user.getAccessToken()), + this.session.getAccountId()); + + // Step 2: Construct your API headers + //ds-snippet-start:Rooms2Step2 + RoomsApi roomsApi = createRoomsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + //ds-snippet-end:Rooms2Step2 + + // Step 4: Call the v2 Rooms API + //ds-snippet-start:Rooms2Step4 + Room createdRoom = CreateRoomWithTemplateService.createRoomFromModel( + roomsApi, + this.session.getAccountId(), + CreateRoomWithTemplateService.createRoom( + adminRole.getRoleId(), + args.getRoomName(), + args.getRoomTemplateId())); + //ds-snippet-end:Rooms2Step4 + DoneExample.createDefault(this.title) + .withJsonObject(createdRoom) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", createdRoom.getName()) + .replaceFirst("\\{1}", createdRoom.getRoomId().toString()) + ) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + // ***DS.snippet.0.end +} diff --git a/src/main/java/com/docusign/controller/rooms/examples/R003ControllerExportingDataFromRoom.java b/src/main/java/com/docusign/controller/rooms/examples/R003ControllerExportingDataFromRoom.java new file mode 100644 index 00000000..150f8d4a --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/examples/R003ControllerExportingDataFromRoom.java @@ -0,0 +1,69 @@ +package com.docusign.controller.rooms.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.rooms.services.ExportingDataFromRoomService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.rooms.api.RoomsApi; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.model.FieldData; +import com.docusign.rooms.model.RoomSummaryList; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +/** + * Exporting data from a room. + */ +@Controller +@RequestMapping("/r003") +public class R003ControllerExportingDataFromRoom extends AbstractRoomsController { + + private static final String MODEL_ROOM_LIST = "roomList"; + + public R003ControllerExportingDataFromRoom(DSConfiguration config, Session session, User user) { + super(config, "r003"); + this.session = session; + this.user = user; + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + RoomsApi roomsApi = createRoomsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + RoomSummaryList roomSummaryList = roomsApi.getRooms(this.session.getAccountId()); + + model.addAttribute(MODEL_ROOM_LIST, roomSummaryList.getRooms()); + } + + @Override + // ***DS.snippet.0.start + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws IOException, ApiException { + // Step 2: Construct your API headers + //ds-snippet-start:Rooms3Step2 + RoomsApi roomsApi = createRoomsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + //ds-snippet-end:Rooms3Step2 + + // Step 3: Call the v2 Rooms API + //ds-snippet-start:Rooms3Step3 + FieldData fieldData = ExportingDataFromRoomService.exportDataFromRoom( + roomsApi, + this.session.getAccountId(), + args.getRoomId()); + //ds-snippet-end:Rooms3Step3 + + DoneExample.createDefault(this.title) + .withJsonObject(fieldData) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + // ***DS.snippet.0.end +} diff --git a/src/main/java/com/docusign/controller/rooms/examples/R004ControllerAddingFormsToRoom.java b/src/main/java/com/docusign/controller/rooms/examples/R004ControllerAddingFormsToRoom.java new file mode 100644 index 00000000..91fa2e48 --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/examples/R004ControllerAddingFormsToRoom.java @@ -0,0 +1,87 @@ +package com.docusign.controller.rooms.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.rooms.services.AddingFormsToRoomService; +import com.docusign.controller.rooms.services.GetFormSummaryListService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.rooms.api.RoomsApi; +import com.docusign.rooms.api.RoomsApi.GetRoomsOptions; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.model.FormSummary; +import com.docusign.rooms.model.RoomDocument; +import com.docusign.rooms.model.RoomSummaryList; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; + + +/** + * Adding forms to a room. + */ +@Controller +@RequestMapping("/r004") +public class R004ControllerAddingFormsToRoom extends AbstractRoomsController { + + private static final String MODEL_FORM_LIST = "formList"; + + private static final String MODEL_ROOM_LIST = "roomList"; + + public R004ControllerAddingFormsToRoom(DSConfiguration config, Session session, User user) { + super(config, "r004"); + this.session = session; + this.user = user; + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + RoomsApi roomsApi = createRoomsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + + // Step 3. Obtain the desired form ID + //ds-snippet-start:Rooms4Step3 + GetRoomsOptions gro = roomsApi.new GetRoomsOptions(); + gro.setCount(5); + RoomSummaryList roomSummaryList = roomsApi.getRooms(this.session.getAccountId(), gro); + + List forms = GetFormSummaryListService.getFormSummaryList( + createFormLibrariesApi(session.getBasePath(), this.user.getAccessToken()), + this.session.getAccountId()); + + //ds-snippet-end:Rooms4Step3 + model.addAttribute(MODEL_ROOM_LIST, roomSummaryList.getRooms()); + model.addAttribute(MODEL_FORM_LIST, forms); + } + + @Override + // ***DS.snippet.0.start + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws IOException, ApiException { + // Step 2. Construct your API headers + //ds-snippet-start:Rooms4Step2 + RoomsApi roomsApi = createRoomsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + //ds-snippet-end:Rooms4Step2 + + // Step 4. Call the v2 Rooms API + //ds-snippet-start:Rooms4Step4 + RoomDocument roomDocument = AddingFormsToRoomService.addFormsToRoom( + roomsApi, + this.session.getAccountId(), + args.getFormId(), + args.getRoomId()); + //ds-snippet-end:Rooms4Step4 + + DoneExample.createDefault(this.title) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .withJsonObject(roomDocument) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + // ***DS.snippet.0.end +} diff --git a/src/main/java/com/docusign/controller/rooms/examples/R005ControllerGetRoomsWithFilters.java b/src/main/java/com/docusign/controller/rooms/examples/R005ControllerGetRoomsWithFilters.java new file mode 100644 index 00000000..12a46699 --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/examples/R005ControllerGetRoomsWithFilters.java @@ -0,0 +1,79 @@ +package com.docusign.controller.rooms.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.rooms.services.GetRoomsWithFiltersService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.core.utils.DateUtils; +import com.docusign.rooms.api.RoomsApi; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.model.RoomSummaryList; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.time.LocalDateTime; + +/** + * Get Rooms with filters. + */ +@Controller +@RequestMapping("/r005") +public class R005ControllerGetRoomsWithFilters extends AbstractRoomsController { + + private static final String MODEL_START_DATE = "startDate"; + + private static final String MODEL_END_DATE = "endDate"; + + private static final int FROM_DATE_OFFSET_DAYS = 10; + + private static final int FROM_DATE_FORWARD_DAYS = 1; + + public R005ControllerGetRoomsWithFilters(DSConfiguration config, Session session, User user) { + super(config, "r005"); + this.session = session; + this.user = user; + } + + @Override + // ***DS.snippet.0.start + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + + LocalDateTime current = LocalDateTime.now().plusDays(FROM_DATE_FORWARD_DAYS); + LocalDateTime past = LocalDateTime.now().minusDays(FROM_DATE_OFFSET_DAYS); + + model.addAttribute(MODEL_START_DATE, DateUtils.DATE_WITH_LINES.format(past)); + model.addAttribute(MODEL_END_DATE, DateUtils.DATE_WITH_LINES.format(current)); + } + + @Override + // ***DS.snippet.0.start + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws IOException, ApiException { + // Step 2: Construct your API headers + //ds-snippet-start:Rooms5Step2 + RoomsApi roomsApi = createRoomsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + //ds-snippet-end:Rooms5Step2 + + // Step 4. Call the v2 Rooms API + //ds-snippet-start:Rooms5Step4 + RoomSummaryList rooms = GetRoomsWithFiltersService.getRoomsWithFilters( + roomsApi, + this.session.getAccountId(), + args.getStartDate(), + args.getEndDate()); + //ds-snippet-end:Rooms5Step4 + + DoneExample.createDefault(this.title) + .withJsonObject(rooms) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + // ***DS.snippet.0.end +} diff --git a/src/main/java/com/docusign/controller/rooms/examples/R006ControllerCreateExternalFormFillSession.java b/src/main/java/com/docusign/controller/rooms/examples/R006ControllerCreateExternalFormFillSession.java new file mode 100644 index 00000000..5d685427 --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/examples/R006ControllerCreateExternalFormFillSession.java @@ -0,0 +1,86 @@ +package com.docusign.controller.rooms.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.rooms.services.ExternalFormSessionService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.rooms.api.ExternalFormFillSessionsApi; +import com.docusign.rooms.api.RoomsApi; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.model.ExternalFormFillSession; +import com.docusign.rooms.model.ExternalFormFillSessionForCreate; +import com.docusign.rooms.model.RoomDocumentList; +import com.docusign.rooms.model.RoomSummaryList; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Creating an external form fill session. + */ +@Controller +@RequestMapping("/r006") +public class R006ControllerCreateExternalFormFillSession extends AbstractRoomsController { + + private static final String MODEL_ROOMS_LIST = "roomsList"; + + private static final String MODEL_DOCUMENTS_LIST = "documentsList"; + + public R006ControllerCreateExternalFormFillSession(DSConfiguration config, Session session, User user) { + super(config, "r006"); + this.session = session; + this.user = user; + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + + RoomsApi roomsApi = createRoomsApiClient(this.session.getBasePath(), this.user.getAccessToken()); + RoomSummaryList rooms = (new ExternalFormSessionService()).getRooms(roomsApi, this.session.getAccountId()); + + Integer roomsId = args.getRoomId(); + + if (roomsId != null) { + RoomDocumentList documents = (new ExternalFormSessionService()).getDocuments(roomsApi, this.session.getAccountId(), roomsId); + model.addAttribute(MODEL_DOCUMENTS_LIST, documents.getDocuments()); + } + + model.addAttribute(MODEL_ROOMS_LIST, rooms.getRooms()); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws IOException, ApiException { + ExternalFormFillSessionsApi externalFormFillSessionsApi = createExternalFormFillSessionsApiClient( + this.session.getBasePath(), this.user.getAccessToken()); + + //ds-snippet-start:Rooms6Step3 + ExternalFormFillSessionForCreate sessionToCreate = new ExternalFormFillSessionForCreate(); + sessionToCreate.setRoomId(args.getRoomId()); + sessionToCreate.setFormId(args.getDocumentId()); + sessionToCreate.setXFrameAllowedUrl("http://localhost:8080"); + //ds-snippet-end:Rooms6Step3 + + //ds-snippet-start:Rooms6Step4 + ExternalFormFillSession formFillSession = (new ExternalFormSessionService()).createSession( + externalFormFillSessionsApi, + this.session.getAccountId(), + sessionToCreate); + //ds-snippet-end:Rooms6Step4 + //ds-snippet-start:Rooms6Step5 + DoneExample.createDefault(this.title) + .withMessage(getTextForCodeExample().ResultsPageText) + .withJsonObject(formFillSession) + .withFormFill(formFillSession.getUrl()) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + //ds-snippet-end:Rooms6Step5 + } + // ***DS.snippet.0.end +} diff --git a/src/main/java/com/docusign/controller/rooms/examples/R007ControllerCreateFormGroup.java b/src/main/java/com/docusign/controller/rooms/examples/R007ControllerCreateFormGroup.java new file mode 100644 index 00000000..01e2dfe1 --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/examples/R007ControllerCreateFormGroup.java @@ -0,0 +1,55 @@ +package com.docusign.controller.rooms.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.rooms.services.CreateFormGroupService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.rooms.api.FormGroupsApi; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.model.FormGroup; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Creating create a form group. + */ +@Controller +@RequestMapping("/r007") +public class R007ControllerCreateFormGroup extends AbstractRoomsController { + + public R007ControllerCreateFormGroup(DSConfiguration config, Session session, User user) { + super(config, "r007"); + this.session = session; + this.user = user; + } + + @Override + // ***DS.snippet.0.start + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws IOException, ApiException { + + //ds-snippet-start:Rooms7Step2 + FormGroupsApi formGroupsApi = createFormGroupsApi( + this.session.getBasePath(), this.user.getAccessToken() + ); + //ds-snippet-end:Rooms7Step2 + + FormGroup formGroup = CreateFormGroupService.createFormGroup( + formGroupsApi, + this.session.getAccountId(), + args.getFormGroupName()); + + DoneExample.createDefault(this.title) + .withJsonObject(formGroup) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", formGroup.getName())) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/rooms/examples/R008ControllerGrantOfficeAccessToFormGroup.java b/src/main/java/com/docusign/controller/rooms/examples/R008ControllerGrantOfficeAccessToFormGroup.java new file mode 100644 index 00000000..9b83cd4d --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/examples/R008ControllerGrantOfficeAccessToFormGroup.java @@ -0,0 +1,94 @@ +package com.docusign.controller.rooms.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.rooms.services.GrantOfficeAccessToFormGroupService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.rooms.api.FormGroupsApi; +import com.docusign.rooms.api.OfficesApi; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.model.FormGroupSummaryList; +import com.docusign.rooms.model.OfficeSummaryList; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Granting office access to a form group. + */ +@Controller +@RequestMapping("/r008") +public class R008ControllerGrantOfficeAccessToFormGroup extends AbstractRoomsController { + + private static final String MODEL_OFFICE_LIST = "officeList"; + + private static final String MODEL_FORM_GROUP_LIST = "formGroupList"; + + private static final String OFFICE_ALREADY_HAS_ACCESS_TO_FORM_GROUP_ERROR_MESSAGE = "OFFICE_ALREADY_HAS_ACCESS_TO_FORM_GROUP"; + + private FormGroupsApi formGroupsApi; + + public R008ControllerGrantOfficeAccessToFormGroup(DSConfiguration config, Session session, User user) { + super(config, "r008"); + this.session = session; + this.user = user; + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + + //ds-snippet-start:Rooms8Step2 + this.formGroupsApi = createFormGroupsApi( + this.session.getBasePath(), this.user.getAccessToken() + ); + //ds-snippet-end:Rooms8Step2 + + //ds-snippet-start:Rooms8Step3 + OfficesApi officesApi = createOfficesApiClient(this.session.getBasePath(), this.user.getAccessToken()); + OfficeSummaryList officeSummaryList = officesApi.getOffices(this.session.getAccountId()); + //ds-snippet-end:Rooms8Step3 + + //ds-snippet-start:Rooms8Step4 + FormGroupSummaryList formGroupSummaryList = formGroupsApi.getFormGroups(this.session.getAccountId()); + //ds-snippet-end:Rooms8Step4 + + model.addAttribute(MODEL_FORM_GROUP_LIST, formGroupSummaryList.getFormGroups()); + model.addAttribute(MODEL_OFFICE_LIST, officeSummaryList.getOfficeSummaries()); + } + + @Override + // ***DS.snippet.0.start + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws IOException, ApiException { + + try { + //ds-snippet-start:Rooms8Step5 + GrantOfficeAccessToFormGroupService.grantOfficeAccessToFormGroup( + this.formGroupsApi, + this.session.getAccountId(), + args.getFormGroupId(), + args.getOfficeId()); + //ds-snippet-end:Rooms8Step5 + + DoneExample.createDefault(this.title) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", String.valueOf(args.getOfficeId())) + .replaceFirst("\\{1}", String.valueOf(args.getFormGroupId()))) + .addToModel(model, config); + } catch (ApiException apiException) { + if (!apiException.getMessage().contains(OFFICE_ALREADY_HAS_ACCESS_TO_FORM_GROUP_ERROR_MESSAGE)) { + throw apiException; + } + DoneExample.createDefault(this.title) + .withMessage("The selected office already has access to a form group!") + .addToModel(model, config); + } + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/rooms/examples/R009ControllerAssignFormToFormGroup.java b/src/main/java/com/docusign/controller/rooms/examples/R009ControllerAssignFormToFormGroup.java new file mode 100644 index 00000000..fd542161 --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/examples/R009ControllerAssignFormToFormGroup.java @@ -0,0 +1,98 @@ +package com.docusign.controller.rooms.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.rooms.services.AssignFormToFormGroupService; +import com.docusign.controller.rooms.services.GetFormSummaryListService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.rooms.api.FormGroupsApi; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.model.FormGroupFormToAssign; +import com.docusign.rooms.model.FormGroupSummaryList; +import com.docusign.rooms.model.FormSummary; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; + +/** + * Assigning a form to a form group. + */ +@Controller +@RequestMapping("/r009") +public class R009ControllerAssignFormToFormGroup extends AbstractRoomsController { + + private static final String MODEL_FORM_LIST = "formList"; + + private static final String MODEL_FORM_GROUP_LIST = "formGroupList"; + + private static final String FORM_ALREADY_EXISTS_ERROR_MESSAGE = "Form in the form group already exists"; + + private FormGroupsApi formGroupsApi; + + public R009ControllerAssignFormToFormGroup(DSConfiguration config, Session session, User user) { + super(config, "r009"); + this.session = session; + this.user = user; + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + + //ds-snippet-start:Rooms9Step4 + this.formGroupsApi = createFormGroupsApi( + this.session.getBasePath(), this.user.getAccessToken() + ); + FormGroupSummaryList formGroupSummaryList = formGroupsApi.getFormGroups(this.session.getAccountId()); + //ds-snippet-end:Rooms9Step4 + + //ds-snippet-start:Rooms9Step3 + List forms = GetFormSummaryListService.getFormSummaryList( + createFormLibrariesApi(session.getBasePath(), this.user.getAccessToken()), + this.session.getAccountId()); + //ds-snippet-end:Rooms9Step3 + + model.addAttribute(MODEL_FORM_GROUP_LIST, formGroupSummaryList.getFormGroups()); + model.addAttribute(MODEL_FORM_LIST, forms); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws IOException, ApiException { + try { + //ds-snippet-start:Rooms9Step6 + FormGroupFormToAssign formGroupFormToAssign = AssignFormToFormGroupService.assignFormToFormGroup( + this.formGroupsApi, + this.session.getAccountId(), + args.getFormId(), + args.getFormGroupId()); + //ds-snippet-end:Rooms9Step6 + + DoneExample.createDefault(this.title) + .withJsonObject(formGroupFormToAssign) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", String.valueOf(args.getFormId())) + .replaceFirst("\\{1}", String.valueOf(args.getFormGroupId()))) + .addToModel(model, config); + } catch (ApiException apiException) { + if (apiException.getMessage().contains(FORM_ALREADY_EXISTS_ERROR_MESSAGE)) { + DoneExample.createDefault(this.title) + .withMessage(FORM_ALREADY_EXISTS_ERROR_MESSAGE) + .addToModel(model, config); + } else if (apiException.getMessage().contains(getTextForCodeExampleByApiType().CustomErrorTexts.get(0).ErrorMessageCheck)) { + DoneExample.createDefault(this.title) + .withMessage(getTextForCodeExampleByApiType().CustomErrorTexts.get(0).ErrorMessage) + .addToModel(model, config); + } + + throw apiException; + } + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/rooms/services/AddingFormsToRoomService.java b/src/main/java/com/docusign/controller/rooms/services/AddingFormsToRoomService.java new file mode 100644 index 00000000..4a073b12 --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/services/AddingFormsToRoomService.java @@ -0,0 +1,35 @@ +package com.docusign.controller.rooms.services; + +import com.docusign.rooms.api.RoomsApi; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.client.ApiResponse; +import com.docusign.rooms.model.FormForAdd; +import com.docusign.rooms.model.RoomDocument; + +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public final class AddingFormsToRoomService { + public static RoomDocument addFormsToRoom( + RoomsApi roomsApi, + String accountId, + UUID formId, + Integer roomId) throws ApiException { + FormForAdd formForAdd = new FormForAdd().formId(formId); + ApiResponse response = roomsApi.addFormToRoomWithHttpInfo(accountId, roomId, formForAdd); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/rooms/services/AssignFormToFormGroupService.java b/src/main/java/com/docusign/controller/rooms/services/AssignFormToFormGroupService.java new file mode 100644 index 00000000..84b5051d --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/services/AssignFormToFormGroupService.java @@ -0,0 +1,39 @@ +package com.docusign.controller.rooms.services; + +import com.docusign.rooms.api.FormGroupsApi; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.client.ApiResponse; +import com.docusign.rooms.model.FormGroupFormToAssign; + +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public final class AssignFormToFormGroupService { + public static FormGroupFormToAssign assignFormToFormGroup( + FormGroupsApi formGroupsApi, + String accountId, + UUID formId, + UUID formGroupId) throws ApiException { + //ds-snippet-start:Rooms9Step5 + FormGroupFormToAssign formGroupFormToAssignRequest = new FormGroupFormToAssign() + .formId(formId); + //ds-snippet-end:Rooms9Step5 + + ApiResponse response = formGroupsApi.assignFormGroupFormWithHttpInfo( + accountId, formGroupId, formGroupFormToAssignRequest); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/rooms/services/CreateFormGroupService.java b/src/main/java/com/docusign/controller/rooms/services/CreateFormGroupService.java new file mode 100644 index 00000000..e74d5e4d --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/services/CreateFormGroupService.java @@ -0,0 +1,39 @@ +package com.docusign.controller.rooms.services; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +import com.docusign.rooms.api.FormGroupsApi; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.client.ApiResponse; +import com.docusign.rooms.model.FormGroup; +import com.docusign.rooms.model.FormGroupForCreate; + +public final class CreateFormGroupService { + public static FormGroup createFormGroup( + FormGroupsApi formGroupsApi, + String accountId, + String formGroupName) throws ApiException { + //ds-snippet-start:Rooms7Step3 + FormGroupForCreate formGroupForCreate = new FormGroupForCreate() + .name(formGroupName); + //ds-snippet-end:Rooms7Step3 + + //ds-snippet-start:Rooms7Step4 + ApiResponse response = formGroupsApi.createFormGroupWithHttpInfo(accountId, formGroupForCreate); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + //ds-snippet-end:Rooms7Step4 + } +} diff --git a/src/main/java/com/docusign/controller/rooms/services/CreateRoomService.java b/src/main/java/com/docusign/controller/rooms/services/CreateRoomService.java new file mode 100644 index 00000000..7c409b65 --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/services/CreateRoomService.java @@ -0,0 +1,53 @@ +package com.docusign.controller.rooms.services; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +import com.docusign.rooms.api.RoomsApi; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.client.ApiResponse; +import com.docusign.rooms.model.FieldDataForCreate; +import com.docusign.rooms.model.Room; +import com.docusign.rooms.model.RoomForCreate; + +//ds-snippet-start:Rooms1Step4 +public final class CreateRoomService { + public static Room createRoomFromModel( + RoomsApi roomsApi, + String accountId, + RoomForCreate roomForCreate) throws ApiException { + ApiResponse response = roomsApi.createRoomWithHttpInfo(accountId, roomForCreate); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } + //ds-snippet-end:Rooms1Step4 + + public static RoomForCreate createRoomModel(Integer roleId, String roomName) { + return new RoomForCreate() + .name(roomName) + .roleId(roleId) + .transactionSideId("listbuy") + .fieldData( + new FieldDataForCreate() + .putDataItem("address1", "123 EZ Street") + .putDataItem("address2", "unit 10") + .putDataItem("city", "Galaxian") + .putDataItem("state", "US-HI") + .putDataItem("postalCode", "11112") + .putDataItem("companyRoomStatus", "5") + .putDataItem( + "comments", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")); + } +} diff --git a/src/main/java/com/docusign/controller/rooms/services/CreateRoomWithTemplateService.java b/src/main/java/com/docusign/controller/rooms/services/CreateRoomWithTemplateService.java new file mode 100644 index 00000000..9db2f697 --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/services/CreateRoomWithTemplateService.java @@ -0,0 +1,52 @@ +package com.docusign.controller.rooms.services; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +import com.docusign.rooms.api.RoomsApi; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.client.ApiResponse; +import com.docusign.rooms.model.FieldDataForCreate; +import com.docusign.rooms.model.Room; +import com.docusign.rooms.model.RoomForCreate; + +public final class CreateRoomWithTemplateService { + public static Room createRoomFromModel( + RoomsApi roomsApi, + String accountId, + RoomForCreate roomForCreate) throws ApiException { + ApiResponse response = roomsApi.createRoomWithHttpInfo(accountId, roomForCreate); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } + + public static RoomForCreate createRoom(Integer roleId, String roomName, Integer templateId) { + //ds-snippet-start:Rooms2Step5 + return new RoomForCreate() + .name(roomName) + .roleId(roleId) + .templateId(templateId) + .fieldData( + new FieldDataForCreate() + .putDataItem("address1", "123 EZ Street") + .putDataItem("address2", "unit 10") + .putDataItem("city", "Galaxian") + .putDataItem("state", "US-HI") + .putDataItem("postalCode", "11112") + .putDataItem("companyRoomStatus", "5") + .putDataItem("comments", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")); + //ds-snippet-end:Rooms2Step5 + } +} diff --git a/src/main/java/com/docusign/controller/rooms/services/ExportingDataFromRoomService.java b/src/main/java/com/docusign/controller/rooms/services/ExportingDataFromRoomService.java new file mode 100644 index 00000000..a7e59a4e --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/services/ExportingDataFromRoomService.java @@ -0,0 +1,31 @@ +package com.docusign.controller.rooms.services; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +import com.docusign.rooms.api.RoomsApi; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.client.ApiResponse; +import com.docusign.rooms.model.FieldData; + +public final class ExportingDataFromRoomService { + public static FieldData exportDataFromRoom( + RoomsApi roomsApi, + String accountId, + Integer roomId) throws ApiException { + ApiResponse response = roomsApi.getRoomFieldDataWithHttpInfo(accountId, roomId); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/rooms/services/ExternalFormSessionService.java b/src/main/java/com/docusign/controller/rooms/services/ExternalFormSessionService.java new file mode 100644 index 00000000..12a985fb --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/services/ExternalFormSessionService.java @@ -0,0 +1,78 @@ +package com.docusign.controller.rooms.services; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +import com.docusign.rooms.api.ExternalFormFillSessionsApi; +import com.docusign.rooms.api.RoomsApi; +import com.docusign.rooms.api.RoomsApi.GetDocumentsOptions; +import com.docusign.rooms.api.RoomsApi.GetRoomsOptions; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.client.ApiResponse; +import com.docusign.rooms.model.ExternalFormFillSession; +import com.docusign.rooms.model.ExternalFormFillSessionForCreate; +import com.docusign.rooms.model.RoomDocumentList; +import com.docusign.rooms.model.RoomSummaryList; + +public class ExternalFormSessionService { + public RoomDocumentList getDocuments( + RoomsApi roomsApi, + String accountId, + Integer roomId) throws ApiException { + ApiResponse response = roomsApi.getDocumentsWithHttpInfo( + accountId, + roomId, + (GetDocumentsOptions) null); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } + + public RoomSummaryList getRooms( + RoomsApi roomsApi, + String accountId) throws ApiException { + ApiResponse response = roomsApi.getRoomsWithHttpInfo(accountId, (GetRoomsOptions) null); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } + + public ExternalFormFillSession createSession( + ExternalFormFillSessionsApi externalFormFillSessionsApi, + String accountId, + ExternalFormFillSessionForCreate sessionForCreate) throws ApiException { + ApiResponse response = externalFormFillSessionsApi + .createExternalFormFillSessionWithHttpInfo(accountId, sessionForCreate); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/rooms/services/GetAdminRolesService.java b/src/main/java/com/docusign/controller/rooms/services/GetAdminRolesService.java new file mode 100644 index 00000000..e67efb0e --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/services/GetAdminRolesService.java @@ -0,0 +1,36 @@ +package com.docusign.controller.rooms.services; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +import com.docusign.rooms.api.RolesApi; +import com.docusign.rooms.api.RolesApi.GetRolesOptions; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.client.ApiResponse; +import com.docusign.rooms.model.RoleSummary; +import com.docusign.rooms.model.RoleSummaryList; + +public final class GetAdminRolesService { + public static RoleSummary getAdminRole(RolesApi rolesApi, String accountId) + throws ApiException { + ApiResponse roleSummaryList = rolesApi.getRolesWithHttpInfo(accountId, (GetRolesOptions) null); + + Map> headers = roleSummaryList.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return roleSummaryList.getData() + .getRoles() + .stream() + .filter(RoleSummary::isIsDefaultForAdmin) + .findFirst() + .get(); + } +} diff --git a/src/main/java/com/docusign/controller/rooms/services/GetFormSummaryListService.java b/src/main/java/com/docusign/controller/rooms/services/GetFormSummaryListService.java new file mode 100644 index 00000000..305bf1c8 --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/services/GetFormSummaryListService.java @@ -0,0 +1,51 @@ +package com.docusign.controller.rooms.services; + +import com.docusign.rooms.api.FormLibrariesApi; +import com.docusign.rooms.api.FormLibrariesApi.GetFormLibrariesOptions; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.client.ApiResponse; +import com.docusign.rooms.model.FormLibrarySummary; +import com.docusign.rooms.model.FormLibrarySummaryList; +import com.docusign.rooms.model.FormSummary; +import com.docusign.rooms.model.FormSummaryList; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public final class GetFormSummaryListService { + public static List getFormSummaryList( + FormLibrariesApi formLibrariesApi, + String accountId) throws ApiException { + ApiResponse formLibrarySummaryList = formLibrariesApi + .getFormLibrariesWithHttpInfo(accountId, (GetFormLibrariesOptions) null); + + Map> headers = formLibrarySummaryList.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + List forms = new ArrayList<>(); + int counter = 0; // Counter variable + + for (FormLibrarySummary formLibrarySummary : formLibrarySummaryList.getData().getFormsLibrarySummaries()) { + FormSummaryList formSummaryList = formLibrariesApi.getFormLibraryForms( + accountId, + formLibrarySummary.getFormsLibraryId()); + forms.addAll(formSummaryList.getForms()); + counter += formSummaryList.getForms().size(); + + if (counter >= 3) { + break; + } + } + + return forms; + } +} diff --git a/src/main/java/com/docusign/controller/rooms/services/GetRoomsWithFiltersService.java b/src/main/java/com/docusign/controller/rooms/services/GetRoomsWithFiltersService.java new file mode 100644 index 00000000..75d432b8 --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/services/GetRoomsWithFiltersService.java @@ -0,0 +1,40 @@ +package com.docusign.controller.rooms.services; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +import com.docusign.rooms.api.RoomsApi; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.client.ApiResponse; +import com.docusign.rooms.model.RoomSummaryList; + +public final class GetRoomsWithFiltersService { + public static RoomSummaryList getRoomsWithFilters( + RoomsApi roomsApi, + String accountId, + String startDate, + String endDate) throws ApiException { + // Step 3. Prepare your request parameters + //ds-snippet-start:Rooms5Step3 + RoomsApi.GetRoomsOptions options = roomsApi.new GetRoomsOptions(); + options.setFieldDataChangedStartDate(startDate); + options.setFieldDataChangedEndDate(endDate); + //ds-snippet-end:Rooms5Step3 + + // Call the v2 Rooms API + ApiResponse response = roomsApi.getRoomsWithHttpInfo(accountId, options); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + } +} diff --git a/src/main/java/com/docusign/controller/rooms/services/GrantOfficeAccessToFormGroupService.java b/src/main/java/com/docusign/controller/rooms/services/GrantOfficeAccessToFormGroupService.java new file mode 100644 index 00000000..0f9044b2 --- /dev/null +++ b/src/main/java/com/docusign/controller/rooms/services/GrantOfficeAccessToFormGroupService.java @@ -0,0 +1,33 @@ +package com.docusign.controller.rooms.services; + +import com.docusign.rooms.api.FormGroupsApi; +import com.docusign.rooms.client.ApiException; +import com.docusign.rooms.client.ApiResponse; + +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public final class GrantOfficeAccessToFormGroupService { + public static void grantOfficeAccessToFormGroup( + FormGroupsApi formGroupsApi, + String accountId, + UUID formGroupId, + Integer officeId) throws ApiException { + ApiResponse response = formGroupsApi.grantOfficeAccessToFormGroupWithHttpInfo( + accountId, + formGroupId, + officeId); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + } +} diff --git a/src/main/java/com/docusign/controller/webForms/examples/AbstractWebFormsController.java b/src/main/java/com/docusign/controller/webForms/examples/AbstractWebFormsController.java new file mode 100644 index 00000000..d708b409 --- /dev/null +++ b/src/main/java/com/docusign/controller/webForms/examples/AbstractWebFormsController.java @@ -0,0 +1,60 @@ +package com.docusign.controller.webForms.examples; + +import com.docusign.DSConfiguration; +import com.docusign.core.controller.AbstractController; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.auth.OAuth; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Controller; + +/** + * Abstract base class for all controllers. + */ +@Controller +public abstract class AbstractWebFormsController extends AbstractController { + + private static final String EXAMPLE_PAGES_PATH = "pages/webforms/examples/"; + + protected Session session; + + protected User user; + + public AbstractWebFormsController(DSConfiguration config, String exampleName, Session session, User user) { + super(config, exampleName); + this.session = session; + this.user = user; + } + + /** + * Creates new instance of the Rooms API client. + * + * @param basePath URL to eSignature REST API + * @param userAccessToken user's access token + * @return an instance of the {@link ApiClient} + */ + + protected static ApiClient createESignApiClient(String basePath, String userAccessToken) { + ApiClient apiClient = new ApiClient(basePath); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + userAccessToken); + apiClient.addAuthorization("docusignAccessCode", new OAuth()); + return apiClient; + } + + protected static com.docusign.webforms.client.ApiClient createWebFormsApiClient( + String basePath, + String userAccessToken + ) { + //ds-snippet-start:WebFormsJavaStep2 + com.docusign.webforms.client.ApiClient apiClient = new com.docusign.webforms.client.ApiClient(basePath); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + userAccessToken); + apiClient.addAuthorization("docusignAccessCode", new com.docusign.webforms.client.auth.OAuth()); + //ds-snippet-end:WebFormsJavaStep2 + return apiClient; + } + + protected String getExamplePagesPath() { + return AbstractWebFormsController.EXAMPLE_PAGES_PATH; + } +} diff --git a/src/main/java/com/docusign/controller/webForms/examples/WEB001ControllerCreateAndEmbedForm.java b/src/main/java/com/docusign/controller/webForms/examples/WEB001ControllerCreateAndEmbedForm.java new file mode 100644 index 00000000..d31d96c6 --- /dev/null +++ b/src/main/java/com/docusign/controller/webForms/examples/WEB001ControllerCreateAndEmbedForm.java @@ -0,0 +1,119 @@ +package com.docusign.controller.webForms.examples; + +import java.io.IOException; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.view.RedirectView; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.CreateTemplateService; +import com.docusign.controller.webForms.services.CreateAndEmbedFormService; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeTemplate; +import com.docusign.esign.model.EnvelopeTemplateResults; +import com.docusign.esign.model.TemplateSummary; +import com.docusign.webforms.model.WebFormInstance; +import com.docusign.webforms.model.WebFormSummaryList; + +@Controller +@RequestMapping("/web001") +public class WEB001ControllerCreateAndEmbedForm extends AbstractWebFormsController { + + private static final String TEMPLATE_ID = "templateId"; + + private static final String TEMPLATE_NAME = "Web Form Example Template"; + + private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_Web_Form.pdf"; + + private static final String WEB_FORM_CONFIG = "web-form-config.json"; + + public static final String EMBED = "pages/webforms/examples/embed"; + + public static final String INSTANCE_TOKEN = "instanceToken"; + + private static final String EMDEDDED_BY_TEXT = "example"; + + public static final String URL = "url"; + + public static final String INTEGRATION_KEY = "integrationKey"; + + public WEB001ControllerCreateAndEmbedForm(DSConfiguration config, Session session, User user) { + super(config, "web001", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + model.addAttribute(TEMPLATE_ID, session.getWebformTemplateId()); + } + + @Override + protected Object doWork( + WorkArguments args, + ModelMap model, + HttpServletResponse response) throws ApiException, IOException, com.docusign.webforms.client.ApiException { + if (session.getWebformTemplateId() == null) { + ApiClient eSignApiClient = createESignApiClient(session.getBasePath(), user.getAccessToken()); + String accountId = session.getAccountId(); + + EnvelopeTemplateResults envelopeTemplateResults = CreateTemplateService.searchTemplatesByName( + eSignApiClient, + accountId, + TEMPLATE_NAME); + + if (Integer.parseInt(envelopeTemplateResults.getResultSetSize()) > 0) { + EnvelopeTemplate template = envelopeTemplateResults.getEnvelopeTemplates().get(0); + session.setWebformTemplateId(template.getTemplateId()); + } else { + TemplateSummary template = CreateTemplateService.createTemplate( + eSignApiClient, + accountId, + CreateAndEmbedFormService.prepareEnvelopeTemplate(TEMPLATE_NAME, DOCUMENT_FILE_NAME)); + + session.setWebformTemplateId(template.getTemplateId()); + } + + model.addAttribute(TEMPLATE_ID, session.getWebformTemplateId()); + CreateAndEmbedFormService.addTemplateIdToForm(WEB_FORM_CONFIG, session.getWebformTemplateId()); + + return new RedirectView("web001"); + } + + var webFormsApiClient = createWebFormsApiClient( + config.getWebFormsBasePath(), + user.getAccessToken()); + + WebFormSummaryList forms = CreateAndEmbedFormService.getForms( + webFormsApiClient, + session.getAccountId(), + TEMPLATE_NAME); + + if (forms.getItems() == null || forms.getItems().size() == 0) { + return new RedirectView("web001"); + } + + String formId = forms.getItems().get(0).getId(); + + WebFormInstance form = CreateAndEmbedFormService.createInstance( + webFormsApiClient, + session.getAccountId(), + formId); + + session.setWebformTemplateId(null); + model.addAttribute(EMDEDDED_BY_TEXT, getTextForCodeExampleByApiType()); + model.addAttribute(LAUNCHER_TEXTS, config.getCodeExamplesText().SupportingTexts); + model.addAttribute(INSTANCE_TOKEN, form.getInstanceToken()); + model.addAttribute(URL, form.getFormUrl()); + model.addAttribute(INTEGRATION_KEY, config.getUserId()); + + return EMBED; + } +} diff --git a/src/main/java/com/docusign/controller/webForms/examples/WEB002CreateRemoteInstance.java b/src/main/java/com/docusign/controller/webForms/examples/WEB002CreateRemoteInstance.java new file mode 100644 index 00000000..78d9a73c --- /dev/null +++ b/src/main/java/com/docusign/controller/webForms/examples/WEB002CreateRemoteInstance.java @@ -0,0 +1,122 @@ +package com.docusign.controller.webForms.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.services.CreateTemplateService; +import com.docusign.controller.webForms.services.CreateRemoteInstanceService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeTemplate; +import com.docusign.esign.model.EnvelopeTemplateResults; +import com.docusign.esign.model.TemplateSummary; +import com.docusign.webforms.model.WebFormInstance; +import com.docusign.webforms.model.WebFormSummaryList; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.view.RedirectView; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Controller +@RequestMapping("/web002") +public class WEB002CreateRemoteInstance extends AbstractWebFormsController { + + private static final String TEMPLATE_ID = "templateId"; + + private static final String TEMPLATE_NAME = "Web Form Example Template"; + + private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_Web_Form.pdf"; + + private static final String WEB_FORM_CONFIG = "web-form-config.json"; + + private final DSConfiguration configuration; + + public WEB002CreateRemoteInstance(DSConfiguration config, Session session, User user) { + super(config, "web002", session, user); + this.configuration = config; + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + model.addAttribute(TEMPLATE_ID, session.getWebformTemplateId()); + } + + @Override + protected Object doWork( + WorkArguments args, + ModelMap model, + HttpServletResponse response) throws ApiException, IOException, com.docusign.webforms.client.ApiException { + if (session.getIsWebFormsInitialRun()) { + handleInitialRun(model); + return new RedirectView("web002"); + } + + String accountId = session.getAccountId(); + var apiClient = createWebFormsApiClient( + config.getWebFormsBasePath(), + user.getAccessToken()); + + WebFormSummaryList forms = CreateRemoteInstanceService.getFormsByName( + apiClient, + accountId, + TEMPLATE_NAME); + + if (forms.getItems() == null || forms.getItems().isEmpty()) { + throw new ApiException(getTextForCodeExampleByApiType().CustomErrorTexts.get(0).ErrorMessage); + } + + String formId = forms.getItems().get(0).getId(); + + WebFormInstance form = CreateRemoteInstanceService.createInstance( + apiClient, + accountId, + formId, + configuration.getSignerEmail(), + configuration.getSignerName()); + + session.setIsWebFormsInitialRun(true); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText + .replaceFirst("\\{0}", form.getEnvelopes().get(0).getId()).replaceFirst("\\{1}", form.getId()) + ) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } + + private void handleInitialRun(ModelMap model) throws ApiException, IOException { + ApiClient apiClient = createESignApiClient(session.getBasePath(), user.getAccessToken()); + String accountId = session.getAccountId(); + + String templateId = findOrCreateTemplate(apiClient, accountId); + session.setWebformTemplateId(templateId); + session.setIsWebFormsInitialRun(false); + + model.addAttribute(TEMPLATE_ID, templateId); + CreateRemoteInstanceService.addTemplateIdToForm(WEB_FORM_CONFIG, templateId); + } + + private String findOrCreateTemplate(ApiClient apiClient, String accountId) throws ApiException, IOException { + EnvelopeTemplateResults templateResults = CreateTemplateService.searchTemplatesByName( + apiClient, + accountId, + TEMPLATE_NAME); + + if (templateResults.getEnvelopeTemplates() != null && !templateResults.getEnvelopeTemplates().isEmpty()) { + EnvelopeTemplate existingTemplate = templateResults.getEnvelopeTemplates().get(0); + return existingTemplate.getTemplateId(); + } + + TemplateSummary newTemplate = CreateTemplateService.createTemplate( + apiClient, + accountId, + CreateRemoteInstanceService.prepareEnvelopeTemplate(TEMPLATE_NAME, DOCUMENT_FILE_NAME) + ); + return newTemplate.getTemplateId(); + } +} diff --git a/src/main/java/com/docusign/controller/webForms/services/CreateAndEmbedFormService.java b/src/main/java/com/docusign/controller/webForms/services/CreateAndEmbedFormService.java new file mode 100644 index 00000000..c85d6ab0 --- /dev/null +++ b/src/main/java/com/docusign/controller/webForms/services/CreateAndEmbedFormService.java @@ -0,0 +1,192 @@ +package com.docusign.controller.webForms.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.model.*; +import com.docusign.webforms.api.FormInstanceManagementApi; +import com.docusign.webforms.api.FormManagementApi; +import com.docusign.webforms.client.ApiClient; +import com.docusign.webforms.client.ApiException; +import com.docusign.webforms.client.ApiResponse; +import com.docusign.webforms.model.CreateInstanceRequestBody; +import com.docusign.webforms.model.WebFormInstance; +import com.docusign.webforms.model.WebFormSummaryList; +import com.docusign.webforms.model.WebFormValues; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.Instant; +import java.util.List; +import java.util.Map; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.util.StreamUtils; + +public final class CreateAndEmbedFormService { + public static WebFormSummaryList getForms( + ApiClient apiClient, + String userAccessToken, + String search) throws ApiException { + //ds-snippet-start:WebForms1Step3 + FormManagementApi formManagementApi = new FormManagementApi(apiClient); + var option = formManagementApi.new ListFormsOptions(); + option.setSearch(search); + + ApiResponse response = formManagementApi.listFormsWithHttpInfo(userAccessToken, + option); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + //ds-snippet-end:WebForms1Step3 + } + + public static void addTemplateIdToForm(String fileName, String templateId) { + String targetString = "template-id"; + + try { + ClassPathResource resource = new ClassPathResource(fileName); + byte[] buffer = StreamUtils.copyToByteArray(resource.getInputStream()); + + String fileContent = new String(buffer); + String modifiedContent = fileContent.replace(targetString, templateId); + + var basePath = System.getProperty("user.dir"); + var configFile = Paths.get(basePath, "demo_documents", fileName); + + Files.createDirectories(Paths.get(basePath, "demo_documents")); + Files.write(configFile, modifiedContent.getBytes()); + } catch (IOException ex) { + System.out.println("An error occurred: " + ex.getMessage()); + } + } + + public static WebFormInstance createInstance( + ApiClient apiClient, + String accountId, + String formId) throws ApiException { + + //ds-snippet-start:WebForms1Step4 + WebFormValues formValues = new WebFormValues(); + + formValues.putAll(Map.of( + "PhoneNumber", "555-555-5555", + "Yes", new String[] { "Yes" }, + "Company", "Tally", + "JobTitle", "Programmer Writer")); + //ds-snippet-end:WebForms1Step4 + + //ds-snippet-start:WebForms1Step5 + FormInstanceManagementApi formManagementApi = new FormInstanceManagementApi(apiClient); + String clientUserId = "1234-5678-abcd-ijkl"; + + CreateInstanceRequestBody options = new CreateInstanceRequestBody() + .clientUserId(clientUserId) + .formValues(formValues) + .expirationOffset(24); + + ApiResponse response = formManagementApi.createInstanceWithHttpInfo(accountId, formId, + options); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + //ds-snippet-end:WebForms1Step5 + } + + public static EnvelopeTemplate prepareEnvelopeTemplate(String templateName, String documentPdf) + throws IOException { + Document document = EnvelopeHelpers.createDocumentFromFile( + documentPdf, + "World_Wide_Web_Form", + "1"); + + Signer signer = new Signer() + .roleName("signer") + .recipientId("1") + .routingOrder("1"); + + signer.tabs(new Tabs() + .checkboxTabs(List.of( + new Checkbox() + .documentId("1") + .tabLabel("Yes") + .anchorString("/SMS/") + .anchorUnits("pixels") + .anchorXOffset("0") + .anchorYOffset("0"))) + .signHereTabs(List.of( + new SignHere() + .documentId("1") + .tabLabel("Signature") + .anchorString("/SignHere/") + .anchorUnits("pixels") + .anchorXOffset("20") + .anchorYOffset("10"))) + .textTabs(List.of( + new Text() + .documentId("1") + .tabLabel("FullName") + .anchorString("/FullName/") + .anchorUnits("pixels") + .anchorXOffset("0") + .anchorYOffset("0"), + new Text() + .documentId("1") + .tabLabel("PhoneNumber") + .anchorString("/PhoneNumber/") + .anchorUnits("pixels") + .anchorXOffset("0") + .anchorYOffset("0"), + new Text() + .documentId("1") + .tabLabel("Company") + .anchorString("/Company/") + .anchorUnits("pixels") + .anchorXOffset("0") + .anchorYOffset("0"), + new Text() + .documentId("1") + .tabLabel("JobTitle") + .anchorString("/Title/") + .anchorUnits("pixels") + .anchorXOffset("0") + .anchorYOffset("0"))) + .dateSignedTabs(List.of( + new DateSigned() + .documentId("1") + .tabLabel("DateSigned") + .anchorString("/Date/") + .anchorUnits("pixels") + .anchorXOffset("0") + .anchorYOffset("0")))); + + Recipients recipients = new Recipients() + .signers(List.of(signer)); + + return new EnvelopeTemplate() + .description("Example template created via the API") + .name(templateName) + .shared("false") + .documents(List.of(document)) + .emailSubject("Please sign this document") + .recipients(recipients) + .status("created"); + } +} diff --git a/src/main/java/com/docusign/controller/webForms/services/CreateRemoteInstanceService.java b/src/main/java/com/docusign/controller/webForms/services/CreateRemoteInstanceService.java new file mode 100644 index 00000000..ed08bec1 --- /dev/null +++ b/src/main/java/com/docusign/controller/webForms/services/CreateRemoteInstanceService.java @@ -0,0 +1,181 @@ +package com.docusign.controller.webForms.services; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.model.*; +import com.docusign.webforms.api.FormInstanceManagementApi; +import com.docusign.webforms.api.FormManagementApi; +import com.docusign.webforms.client.ApiClient; +import com.docusign.webforms.client.ApiException; +import com.docusign.webforms.client.ApiResponse; +import com.docusign.webforms.model.*; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Instant; +import java.util.List; +import java.util.Map; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.util.StreamUtils; + +public final class CreateRemoteInstanceService { + + private static final String ROLE_SIGNER = "signer"; + + private static final String DOCUMENT_ID = "1"; + + private static final String UNITS = "pixels"; + + public static WebFormSummaryList getFormsByName( + ApiClient apiClient, + String userAccessToken, + String name) throws ApiException { + //ds-snippet-start:WebForms2Step3 + FormManagementApi formManagementApi = new FormManagementApi(apiClient); + var option = formManagementApi.new ListFormsOptions(); + option.setSearch(name); + + ApiResponse response = formManagementApi.listFormsWithHttpInfo(userAccessToken, + option); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + //ds-snippet-end:WebForms2Step3 + } + + public static void addTemplateIdToForm(String fileName, String templateId) { + try { + ClassPathResource resource = new ClassPathResource(fileName); + byte[] buffer = StreamUtils.copyToByteArray(resource.getInputStream()); + + String fileContent = new String(buffer); + String modifiedContent = fileContent.replace("template-id", templateId); + + Path basePath = Paths.get(System.getProperty("user.dir"), "demo_documents"); + Files.createDirectories(basePath); + Files.writeString(basePath.resolve(fileName), modifiedContent); + } catch (IOException ex) { + System.out.println("An error occurred: " + ex.getMessage()); + } + } + + public static WebFormInstance createInstance( + ApiClient apiClient, + String accountId, + String formId, + String signerEmail, + String signerName) throws ApiException { + //ds-snippet-start:WebForms2Step4 + WebFormValues formValues = new WebFormValues(); + formValues.putAll(Map.of( + "PhoneNumber", "555-555-5555", + "Yes", new String[] { "Yes" }, + "Company", "Tally", + "JobTitle", "Programmer Writer")); + + var recipient = new CreateInstanceRequestBodyRecipients() + .email(signerEmail) + .name(signerName) + .roleName(ROLE_SIGNER); + + CreateInstanceRequestBody options = new CreateInstanceRequestBody() + .sendOption(SendOption.NOW) + .formValues(formValues) + .recipients(List.of(recipient)); + //ds-snippet-end:WebForms2Step4 + + //ds-snippet-start:WebForms2Step5 + ApiResponse response = new FormInstanceManagementApi(apiClient) + .createInstanceWithHttpInfo(accountId, formId, options); + + Map> headers = response.getHeaders(); + List remaining = headers.get("X-RateLimit-Remaining"); + List reset = headers.get("X-RateLimit-Reset"); + + if (remaining != null & reset != null) { + Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0))); + System.out.println("API calls remaining: " + remaining); + System.out.println("Next Reset: " + resetInstant); + } + + return response.getData(); + //ds-snippet-end:WebForms2Step5 + } + + public static EnvelopeTemplate prepareEnvelopeTemplate(String templateName, String documentPdf) + throws IOException { + Document document = EnvelopeHelpers.createDocumentFromFile(documentPdf, "World_Wide_Web_Form", + DOCUMENT_ID); + Signer signer = createSigner(); + Recipients recipients = new Recipients().signers(List.of(signer)); + + return new EnvelopeTemplate() + .description("Example template created via the API") + .name(templateName) + .shared("false") + .documents(List.of(document)) + .emailSubject("Please sign this document") + .recipients(recipients) + .status("created"); + } + + private static Signer createSigner() { + Signer signer = new Signer() + .roleName(ROLE_SIGNER) + .recipientId(DOCUMENT_ID) + .routingOrder("1"); + + signer.tabs(new Tabs() + .checkboxTabs(List.of( + new Checkbox() + .documentId(DOCUMENT_ID) + .tabLabel("Yes") + .anchorString("/SMS/") + .anchorUnits(UNITS) + .anchorXOffset("0") + .anchorYOffset("0"))) + .signHereTabs(List.of( + new SignHere() + .documentId(DOCUMENT_ID) + .tabLabel("Signature") + .anchorString("/SignHere/") + .anchorUnits(UNITS) + .anchorXOffset("20") + .anchorYOffset("10"))) + .textTabs(List.of( + createText("FullName", "/FullName/"), + createText("PhoneNumber", "/PhoneNumber/"), + createText("Company", "/Company/"), + createText("JobTitle", "/Title/"))) + .dateSignedTabs(List.of( + new DateSigned() + .documentId(DOCUMENT_ID) + .tabLabel("DateSigned") + .anchorString("/Date/") + .anchorUnits(UNITS) + .anchorXOffset("0") + .anchorYOffset("0")))); + return signer; + } + + private static Text createText(String tabLabel, String anchor) { + return new Text() + .documentId(DOCUMENT_ID) + .tabLabel(tabLabel) + .anchorString(anchor) + .anchorUnits(UNITS) + .anchorXOffset("0") + .anchorYOffset("0"); + } +} diff --git a/src/main/java/com/docusign/controller/workspaces/examples/AbstractWorkspacesController.java b/src/main/java/com/docusign/controller/workspaces/examples/AbstractWorkspacesController.java new file mode 100644 index 00000000..d1bfbedc --- /dev/null +++ b/src/main/java/com/docusign/controller/workspaces/examples/AbstractWorkspacesController.java @@ -0,0 +1,33 @@ +package com.docusign.controller.workspaces.examples; + +import com.docusign.DSConfiguration; +import com.docusign.core.controller.AbstractController; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.auth.OAuth; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Controller; + +/** + * Abstract base class for all controllers. + */ +@Controller +public abstract class AbstractWorkspacesController extends AbstractController { + + private static final String EXAMPLE_PAGES_PATH = "pages/workspaces/examples/"; + + protected Session session; + + protected User user; + + public AbstractWorkspacesController(DSConfiguration config, String exampleName, Session session, User user) { + super(config, exampleName); + this.session = session; + this.user = user; + } + + protected String getExamplePagesPath() { + return AbstractWorkspacesController.EXAMPLE_PAGES_PATH; + } +} diff --git a/src/main/java/com/docusign/controller/workspaces/examples/Work001CreateWorkspaceController.java b/src/main/java/com/docusign/controller/workspaces/examples/Work001CreateWorkspaceController.java new file mode 100644 index 00000000..0041444e --- /dev/null +++ b/src/main/java/com/docusign/controller/workspaces/examples/Work001CreateWorkspaceController.java @@ -0,0 +1,60 @@ +package com.docusign.controller.workspaces.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.workspaces.services.CreateWorkspaceService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.datatype.joda.JodaModule; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import java.text.SimpleDateFormat; + +import javax.servlet.http.HttpServletResponse; + +/** + * This example demonstrates how to create a new Workspace. + */ +@Controller +@RequestMapping("/work001") +public class Work001CreateWorkspaceController extends AbstractWorkspacesController { + + public Work001CreateWorkspaceController(DSConfiguration config, Session session, User user) { + super(config, "work001", session, user); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + var accountId = session.getAccountId(); + + //ds-snippet-start:Workspaces1Step2 + var accessToken = user.getAccessToken(); + //ds-snippet-end:Workspaces1Step2 + + //ds-snippet-start:Workspaces1Step3 + var workspaceName = args.getWorkspaceName(); + //ds-snippet-end:Workspaces1Step3 + + //ds-snippet-start:Workspaces1Step4 + var workspace = CreateWorkspaceService.createWorkspace(accessToken, accountId, workspaceName); + //ds-snippet-end:Workspaces1Step4 + + var workspaceId = workspace.createWorkspaceResponse().get().workspaceId().orElse(""); + var creatorId = workspace.createWorkspaceResponse().get().createdByUserId().orElse(""); + session.setWorkspaceId(workspaceId); + session.setCreatorId(creatorId); + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText.replaceFirst("\\{0}", workspaceId)) + .withJsonObject(workspace.createWorkspaceResponse().get()) + .addToModel(model, config); + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/workspaces/examples/Work002AddDocumentToWorkspaceController.java b/src/main/java/com/docusign/controller/workspaces/examples/Work002AddDocumentToWorkspaceController.java new file mode 100644 index 00000000..e4998e86 --- /dev/null +++ b/src/main/java/com/docusign/controller/workspaces/examples/Work002AddDocumentToWorkspaceController.java @@ -0,0 +1,68 @@ +package com.docusign.controller.workspaces.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.workspaces.services.AddDocumentToWorkspaceService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import java.nio.file.Paths; + +import javax.servlet.http.HttpServletResponse; + +/** + * This example demonstrates how to add a Document to the Workspace. + */ +@Controller +@RequestMapping("/work002") +public class Work002AddDocumentToWorkspaceController extends AbstractWorkspacesController { + private static final String MODEL_WORKSPACE_OK = "workspaceOk"; + + private static final String MODEL_DOCUMENT_FOLDER = "documentFolder"; + + public Work002AddDocumentToWorkspaceController(DSConfiguration config, Session session, User user) { + super(config, "work002", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + + model.addAttribute(MODEL_WORKSPACE_OK, session.getWorkspaceId() != null && !session.getWorkspaceId().isEmpty()); + model.addAttribute(MODEL_DOCUMENT_FOLDER, config.getCodeExamplesText().SupportingTexts.HelpingTexts.SelectPDFFileFromFolder.replaceFirst("\\{0}", Paths.get("src", "main", "resources").toAbsolutePath().toString())); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + var accountId = session.getAccountId(); + + //ds-snippet-start:Workspaces2Step2 + var accessToken = user.getAccessToken(); + //ds-snippet-end:Workspaces2Step2 + + var workspaceId = session.getWorkspaceId(); + + //ds-snippet-start:Workspaces2Step3 + var documentName = args.getDocumentName(); + var documentPath = args.getDocumentPath(); + //ds-snippet-end:Workspaces2Step3 + + //ds-snippet-start:Workspaces2Step4 + var results = AddDocumentToWorkspaceService.addDocumentToWorkspace(accessToken, accountId, workspaceId, documentPath, documentName); + //ds-snippet-end:Workspaces2Step4 + + var documentId = results.createWorkspaceDocumentResponse().get().documentId().orElse(""); + session.setDocumentId(documentId); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText.replaceFirst("\\{0}", documentId)) + .withJsonObject(results.createWorkspaceDocumentResponse().get()) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/workspaces/examples/Work003SendEnvelopeWithRecipientController.java b/src/main/java/com/docusign/controller/workspaces/examples/Work003SendEnvelopeWithRecipientController.java new file mode 100644 index 00000000..0f6350ba --- /dev/null +++ b/src/main/java/com/docusign/controller/workspaces/examples/Work003SendEnvelopeWithRecipientController.java @@ -0,0 +1,58 @@ +package com.docusign.controller.workspaces.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.workspaces.services.SendEnvelopeWithRecipientInfoService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +/** + * This example demonstrates how to create and send a Workspace Envelope. + */ +@Controller +@RequestMapping("/work003") +public class Work003SendEnvelopeWithRecipientController extends AbstractWorkspacesController { + private static final String MODEL_WORKSPACE_OK = "workspaceOk"; + + private static final String MODEL_DOCUMENT_OK = "documentOk"; + + public Work003SendEnvelopeWithRecipientController(DSConfiguration config, Session session, User user) { + super(config, "work003", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + + model.addAttribute(MODEL_WORKSPACE_OK, session.getWorkspaceId() != null && !session.getWorkspaceId().isEmpty()); + model.addAttribute(MODEL_DOCUMENT_OK, session.getDocumentId() != null && !session.getDocumentId().isEmpty()); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + var accountId = session.getAccountId(); + var accessToken = user.getAccessToken(); + var basePath = session.getBasePath(); + var workspaceId = session.getWorkspaceId(); + var documentId = session.getDocumentId(); + var signerEmail = args.getSignerEmail(); + var signerName = args.getSignerName(); + var envelope = SendEnvelopeWithRecipientInfoService.createWorkspaceEnvelope(accessToken, accountId, workspaceId, documentId); + var envelopeId = envelope.createWorkspaceEnvelopeResponse().get().envelopeId().get(); + var results = SendEnvelopeWithRecipientInfoService.sendEnvelope(accessToken, basePath, accountId, envelopeId, signerEmail, signerName); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText.replaceFirst("\\{0}", envelopeId)) + .withJsonObject(results) + .addToModel(model, config); + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/workspaces/examples/Work005CreateUploadRequestController.java b/src/main/java/com/docusign/controller/workspaces/examples/Work005CreateUploadRequestController.java new file mode 100644 index 00000000..47d64a6c --- /dev/null +++ b/src/main/java/com/docusign/controller/workspaces/examples/Work005CreateUploadRequestController.java @@ -0,0 +1,66 @@ +package com.docusign.controller.workspaces.examples; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.controller.workspaces.services.CreateUploadRequestService; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletResponse; + +/** + * This example demonstrates how to create upload request. + */ +@Controller +@RequestMapping("/work005") +public class Work005CreateUploadRequestController extends AbstractWorkspacesController { + private static final String MODEL_WORKSPACE_OK = "workspaceOk"; + + private static final String MODEL_CREATOR_OK = "creatorOk"; + + public Work005CreateUploadRequestController(DSConfiguration config, Session session, User user) { + super(config, "work005", session, user); + } + + @Override + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + super.onInitModel(args, model); + + model.addAttribute(MODEL_WORKSPACE_OK, session.getWorkspaceId() != null && !session.getWorkspaceId().isEmpty()); + model.addAttribute(MODEL_CREATOR_OK, session.getCreatorId() != null && !session.getCreatorId().isEmpty()); + } + + @Override + protected Object doWork(WorkArguments args, ModelMap model, HttpServletResponse response) throws Exception { + var accountId = session.getAccountId(); + var accessToken = user.getAccessToken(); + var workspaceId = session.getWorkspaceId(); + var creatorId = session.getCreatorId(); + var assigneeEmail = args.getAssigneeEmail(); + + try{ + var results = CreateUploadRequestService.createUploadRequest( + accessToken, + accountId, + workspaceId, + creatorId, + assigneeEmail); + + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().ResultsPageText.replaceFirst( + "\\{0}", + results.getWorkspaceUploadRequestResponse().get().uploadRequestId())) + .addToModel(model, config); + } catch (Exception e) { + DoneExample.createDefault(getTextForCodeExampleByApiType().ExampleName) + .withMessage(getTextForCodeExampleByApiType().CustomErrorTexts.get(0).ErrorMessage) + .addToModel(model, config); + } + + return DONE_EXAMPLE_PAGE; + } +} diff --git a/src/main/java/com/docusign/controller/workspaces/services/AddDocumentToWorkspaceService.java b/src/main/java/com/docusign/controller/workspaces/services/AddDocumentToWorkspaceService.java new file mode 100644 index 00000000..b92a6f73 --- /dev/null +++ b/src/main/java/com/docusign/controller/workspaces/services/AddDocumentToWorkspaceService.java @@ -0,0 +1,39 @@ +package com.docusign.controller.workspaces.services; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.util.StreamUtils; + +import com.docusign.iam.sdk.IamClient; +import com.docusign.iam.sdk.models.components.AddWorkspaceDocumentRequest; +import com.docusign.iam.sdk.models.components.AddWorkspaceDocumentRequestFile; +import com.docusign.iam.sdk.models.operations.AddWorkspaceDocumentResponse; + +public final class AddDocumentToWorkspaceService { + private static IamClient createIamClient(String accessToken) { + return IamClient.builder().accessToken(accessToken).build(); + } + + public static AddWorkspaceDocumentResponse addDocumentToWorkspace( + String accessToken, + String accountId, + String workspaceId, + String documentPath, + String documentName) throws Exception { + + var resource = new ClassPathResource(documentPath); + var documentBytes = StreamUtils.copyToByteArray(resource.getInputStream()); + + var workspaceDocumentFile = new AddWorkspaceDocumentRequestFile(documentName, documentBytes); + var addWorkspaceDocumentRequest = new AddWorkspaceDocumentRequest(); + addWorkspaceDocumentRequest.withFile(workspaceDocumentFile); + + return createIamClient(accessToken) + .workspaces() + .workspaceDocuments() + .addWorkspaceDocument() + .accountId(accountId) + .workspaceId(workspaceId) + .addWorkspaceDocumentRequest(addWorkspaceDocumentRequest) + .call(); + } +} diff --git a/src/main/java/com/docusign/controller/workspaces/services/CreateUploadRequestService.java b/src/main/java/com/docusign/controller/workspaces/services/CreateUploadRequestService.java new file mode 100644 index 00000000..ae06eea1 --- /dev/null +++ b/src/main/java/com/docusign/controller/workspaces/services/CreateUploadRequestService.java @@ -0,0 +1,53 @@ +package com.docusign.controller.workspaces.services; + +import com.docusign.iam.sdk.IamClient; +import com.docusign.iam.sdk.models.components.*; +import com.docusign.iam.sdk.models.operations.CreateWorkspaceUploadRequestResponse; +import java.time.OffsetDateTime; +import java.util.Arrays; + +public final class CreateUploadRequestService { + private static IamClient createIamClient(String accessToken) { + return IamClient.builder().accessToken(accessToken).build(); + } + + public static CreateWorkspaceUploadRequestResponse createUploadRequest( + String accessToken, + String accountId, + String workspaceId, + String creatorId, + String assigneeEmail) throws Exception { + //ds-snippet-start:Workspaces5Step3 + OffsetDateTime dueDate = OffsetDateTime.now().plusDays(7); + + var assignmentFoAssignee = new CreateWorkspaceUploadRequestAssignment( + WorkspaceUploadRequestResponsibilityType.ASSIGNEE) + .withFirstName("Test") + .withLastName("User") + .withEmail(assigneeEmail); + var assignmentForCreator = new CreateWorkspaceUploadRequestAssignment( + WorkspaceUploadRequestResponsibilityType.WATCHER) + .withAssigneeUserId(creatorId); + var assignments = Arrays.asList( + assignmentFoAssignee, + assignmentForCreator); + + var createWorkspaceUploadRequestBody = new CreateWorkspaceUploadRequestBody(dueDate, + WorkspaceUploadRequestStatus.DRAFT) + .withName("Upload Request example " + dueDate) + .withDescription("This is an example upload request created via the workspaces API") + .withAssignments(assignments); + //ds-snippet-end:Workspaces5Step3 + + //ds-snippet-start:Workspaces5Step4 + return createIamClient(accessToken) + .workspaces() + .workspaceUploadRequest() + .createWorkspaceUploadRequest() + .accountId(accountId) + .workspaceId(workspaceId) + .createWorkspaceUploadRequestBody(createWorkspaceUploadRequestBody) + .call(); + //ds-snippet-end:Workspaces5Step4 + } +} diff --git a/src/main/java/com/docusign/controller/workspaces/services/CreateWorkspaceService.java b/src/main/java/com/docusign/controller/workspaces/services/CreateWorkspaceService.java new file mode 100644 index 00000000..e9f79012 --- /dev/null +++ b/src/main/java/com/docusign/controller/workspaces/services/CreateWorkspaceService.java @@ -0,0 +1,29 @@ +package com.docusign.controller.workspaces.services; + +import com.docusign.iam.sdk.IamClient; +import com.docusign.iam.sdk.models.components.CreateWorkspaceBody; +import com.docusign.iam.sdk.models.operations.CreateWorkspaceResponse; + +public final class CreateWorkspaceService { + //ds-snippet-start:WorkspacesStep2 + private static IamClient createIamClient(String accessToken) { + return IamClient.builder().accessToken(accessToken).build(); + } + //ds-snippet-end:WorkspacesStep2 + + public static CreateWorkspaceResponse createWorkspace( + String accessToken, + String accountId, + String name) throws Exception { + var createWorkspaceBody = new CreateWorkspaceBody(); + createWorkspaceBody.withName(name); + + return createIamClient(accessToken) + .workspaces() + .workspaces() + .createWorkspace() + .accountId(accountId) + .createWorkspaceBody(createWorkspaceBody) + .call(); + } +} diff --git a/src/main/java/com/docusign/controller/workspaces/services/SendEnvelopeWithRecipientInfoService.java b/src/main/java/com/docusign/controller/workspaces/services/SendEnvelopeWithRecipientInfoService.java new file mode 100644 index 00000000..8d04bf88 --- /dev/null +++ b/src/main/java/com/docusign/controller/workspaces/services/SendEnvelopeWithRecipientInfoService.java @@ -0,0 +1,100 @@ +package com.docusign.controller.workspaces.services; + +import java.util.Arrays; + +import org.springframework.http.HttpHeaders; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.Envelope; +import com.docusign.esign.model.EnvelopeUpdateSummary; +import com.docusign.esign.model.Signer; +import com.docusign.iam.sdk.IamClient; +import com.docusign.iam.sdk.models.components.WorkspaceEnvelopeForCreate; +import com.docusign.iam.sdk.models.operations.CreateWorkspaceEnvelopeResponse; + +public final class SendEnvelopeWithRecipientInfoService { + private static final String ENVELOPE_NAME = "Example Workspace Envelope"; + + private static final String EMAIL_SUBJECT = "Please sign this document"; + + private static final String ANCHOR_STRING = "/sn1/"; + + private static final int ANCHOR_OFFSET_Y = 10; + + private static final int ANCHOR_OFFSET_X = 20; + + //ds-snippet-start:Workspaces3Step2 + private static IamClient createIamClient(String accessToken) { + return IamClient.builder().accessToken(accessToken).build(); + } + //ds-snippet-end:Workspaces3Step2 + + public static CreateWorkspaceEnvelopeResponse createWorkspaceEnvelope( + String accessToken, + String accountId, + String workspaceId, + String documentId) throws Exception { + + //ds-snippet-start:Workspaces3Step3 + var workspaceEnvelopeForCreate = new WorkspaceEnvelopeForCreate(); + workspaceEnvelopeForCreate.withEnvelopeName(ENVELOPE_NAME); + workspaceEnvelopeForCreate.withDocumentIds(Arrays.asList(documentId)); + //ds-snippet-end:Workspaces3Step3 + + //ds-snippet-start:Workspaces3Step4 + return createIamClient(accessToken) + .workspaces() + .workspaces() + .createWorkspaceEnvelope() + .accountId(accountId) + .workspaceId(workspaceId) + .workspaceEnvelopeForCreate(workspaceEnvelopeForCreate) + .call(); + //ds-snippet-end:Workspaces3Step4 + } + + //ds-snippet-start:Workspaces3Step5 + private static Envelope makeEnvelope( + String signerEmail, + String signerName + ) { + var signerTabs = EnvelopeHelpers.createSignerTabs(EnvelopeHelpers.createSignHere(ANCHOR_STRING, ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X)); + + var signer = new Signer(); + signer.setEmail(signerEmail); + signer.setName(signerName); + signer.setRecipientId("1"); + signer.setRoutingOrder("1"); + signer.setTabs(signerTabs); + + var envelope = new Envelope(); + envelope.setRecipients(EnvelopeHelpers.createSingleRecipient(signer)); + envelope.setEmailSubject(EMAIL_SUBJECT); + envelope.setStatus("sent"); + + return envelope; + } + //ds-snippet-end:Workspaces3Step5 + + //ds-snippet-start:Workspaces3Step6 + public static EnvelopeUpdateSummary sendEnvelope( + String accessToken, + String basePath, + String accountId, + String envelopeId, + String signerEmail, + String signerName + ) throws ApiException { + var client = new ApiClient(basePath); + client.addDefaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken); + var envelopesApi = new EnvelopesApi(client); + + var envelope = makeEnvelope(signerEmail, signerName); + + return envelopesApi.update(accountId, envelopeId, envelope); + } + //ds-snippet-end:Workspaces3Step6 +} diff --git a/src/main/java/com/docusign/common/DiffField.java b/src/main/java/com/docusign/core/common/DiffField.java similarity index 92% rename from src/main/java/com/docusign/common/DiffField.java rename to src/main/java/com/docusign/core/common/DiffField.java index 19ae5588..bf290006 100644 --- a/src/main/java/com/docusign/common/DiffField.java +++ b/src/main/java/com/docusign/core/common/DiffField.java @@ -1,11 +1,10 @@ -package com.docusign.common; - -import java.lang.reflect.Field; -import java.util.Locale; +package com.docusign.core.common; +import lombok.Value; import org.apache.commons.lang3.StringUtils; -import lombok.Value; +import java.lang.reflect.Field; +import java.util.Locale; /** @@ -17,13 +16,16 @@ public class DiffField { private String name; + private String leftValue; + private String rightValue; /** * Creates an instance of the DiffField by a {@link Field} and two objects. + * * @param field the object which provides information about a single field of a class - * @param left the first comparing object, can be null + * @param left the first comparing object, can be null * @param right the second comparing object, can be null * @return created object containing field name and string representation of values * @throws IllegalAccessException when an application tries to reflectively get a field @@ -36,8 +38,9 @@ public static DiffField create(Field field, Object left, Object right) throws Il /** * Creates an instance of the DiffField by {@link Field} and two objects. * Field name is formatted to better readability. + * * @param field the object which provides information about a single field of a class - * @param left the first comparing object, can be null + * @param left the first comparing object, can be null * @param right the second comparing object, can be null * @return created object containing field name and string representation of values * @throws IllegalAccessException when an application tries to reflectively get a field @@ -52,6 +55,7 @@ public static DiffField createWithFormattedName(Field field, Object left, Object * Convert a member name represented as string in a Camel style for better * readability. E.g. name 'permissionProfileName' will be transformed to * "permission profile name" string. + * * @param name the name of the field * @return formatted name */ diff --git a/src/main/java/com/docusign/common/DocumentType.java b/src/main/java/com/docusign/core/common/DocumentType.java similarity index 90% rename from src/main/java/com/docusign/common/DocumentType.java rename to src/main/java/com/docusign/core/common/DocumentType.java index 9d099802..1a59d912 100644 --- a/src/main/java/com/docusign/common/DocumentType.java +++ b/src/main/java/com/docusign/core/common/DocumentType.java @@ -1,6 +1,6 @@ -package com.docusign.common; +package com.docusign.core.common; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MediaType; /** * This enumeration represents supported document types for signing. @@ -11,6 +11,7 @@ public enum DocumentType { PDF("pdf", "application/pdf"); private final String defaultFileExtention; + private final String mime; DocumentType(String defaultFileExtention, String mime) { diff --git a/src/main/java/com/docusign/common/Languages.java b/src/main/java/com/docusign/core/common/Languages.java similarity index 97% rename from src/main/java/com/docusign/common/Languages.java rename to src/main/java/com/docusign/core/common/Languages.java index e7dea874..5607d140 100644 --- a/src/main/java/com/docusign/common/Languages.java +++ b/src/main/java/com/docusign/core/common/Languages.java @@ -1,9 +1,10 @@ -package com.docusign.common; +package com.docusign.core.common; + +import lombok.Value; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import lombok.Value; /** @@ -13,8 +14,8 @@ public final class Languages { private static final List SUPPORTED_LANGUAGES = createList(); - private Languages() {} - + private Languages() { + } public static List getSupportedLanguages() { return Collections.unmodifiableList(SUPPORTED_LANGUAGES); @@ -72,6 +73,8 @@ private static List createList() { @Value public static class Lang { private String code; + private String name; + } } diff --git a/src/main/java/com/docusign/common/Utils.java b/src/main/java/com/docusign/core/common/Utils.java similarity index 68% rename from src/main/java/com/docusign/common/Utils.java rename to src/main/java/com/docusign/core/common/Utils.java index dd9fe265..a1fbb11b 100644 --- a/src/main/java/com/docusign/common/Utils.java +++ b/src/main/java/com/docusign/core/common/Utils.java @@ -1,4 +1,11 @@ -package com.docusign.common; +package com.docusign.core.common; + +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.model.AccountInformation; +import org.apache.commons.codec.binary.StringUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.http.HttpHeaders; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -6,25 +13,24 @@ import java.util.List; import java.util.stream.Collectors; -import org.apache.commons.codec.binary.StringUtils; -import org.apache.commons.lang3.ObjectUtils; - public final class Utils { - private Utils() {} + private Utils() { + } /** * Examines member values of simple Java objects. All values will be * represented as string. This functions creates a list of all non static * field values. One of the comparing object can be equal null * but not both. - * @param left the first comparing object - * @param right the second comparing object + * + * @param left the first comparing object + * @param right the second comparing object * @param formatName whether format member names * @return list of {@link DiffField} objects * @throws IllegalArgumentException if both of comparable objects is - * null or if objects belong to different classes + * null or if objects belong to different classes */ public static List compareFields(Object left, Object right, boolean formatName) { if (left == null && right == null) { @@ -60,12 +66,13 @@ public static List compareFields(Object left, Object right, boolean f * be represented as string. This functions creates a list of all non * static field values. One of the comparing object can be equal * null but not both. - * @param left the first comparing object - * @param right the second comparing object + * + * @param left the first comparing object + * @param right the second comparing object * @param formatName whether format member names * @return list of {@link DiffField} objects * @throws IllegalArgumentException if both of comparable objects is - * null or if objects belong to different classes + * null or if objects belong to different classes */ public static List findDifferentFields(Object left, Object right, boolean formatName) { return compareFields(left, right, formatName) @@ -73,4 +80,18 @@ public static List findDifferentFields(Object left, Object right, boo .filter(field -> !StringUtils.equals(field.getLeftValue(), field.getRightValue())) .collect(Collectors.toList()); } + + public static Boolean isCfr(String basePath, String accessToken, String accountId) throws Exception { + if (accessToken == null) { + + } + ApiClient apiClient = new ApiClient(basePath); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken); + AccountsApi accountsApi = new AccountsApi(apiClient); + + AccountInformation accountInfo = accountsApi.getAccountInformation(accountId); + String isEnabled = accountInfo.getStatus21CFRPart11(); + + return isEnabled != null && isEnabled.equals("enabled"); + } } diff --git a/src/main/java/com/docusign/core/controller/AbstractController.java b/src/main/java/com/docusign/core/controller/AbstractController.java new file mode 100644 index 00000000..f8ca6597 --- /dev/null +++ b/src/main/java/com/docusign/core/controller/AbstractController.java @@ -0,0 +1,261 @@ +package com.docusign.core.controller; + +import com.docusign.DSConfiguration; +import com.docusign.common.WorkArguments; +import com.docusign.core.model.ApiType; +import com.docusign.core.model.AuthType; +import com.docusign.core.model.DoneExample; +import com.docusign.core.model.Session; +import com.docusign.core.model.manifestModels.CodeExampleText; +import com.docusign.core.model.manifestModels.ManifestGroup; +import com.docusign.esign.client.auth.OAuth; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; + +import javax.servlet.http.HttpServletResponse; +import java.time.Instant; +import java.util.List; +import java.util.Objects; + +/** + * Abstract base class for all controllers. It handles all requests which are + * registered by the derived classes and delegates an example specific action + * back to the appropriate controllers. If a user had not been authorized, it + * redirects him onto an authentication page. Derived classes must override an + * abstract method {@link #doWork(WorkArguments, ModelMap, HttpServletResponse)} + * to do something. This method is called from the POST request. Optionally you + * can override method {@link #onInitModel(WorkArguments, ModelMap)} to add + * example specific attributes into a page. + */ +@Controller +public abstract class AbstractController { + + protected static final String BEARER_AUTHENTICATION = "Bearer "; + + protected static final String DONE_EXAMPLE_PAGE = "pages/example_done"; + + protected static final String DONE_EXAMPLE_PAGE_COMPARE = "pages/example_done_compare"; + + protected static final String EXAMPLE_PENDING_PAGE = "pages/example_pending"; + + protected static final String ERROR_PAGE = "error"; + + protected static final String LAUNCHER_TEXTS = "launcherTexts"; + + private static final String REDIRECT_PREFIX = "redirect:"; + + protected static final String REDIRECT_AUTHENTICATION_PAGE = REDIRECT_PREFIX + "/ds/mustAuthenticate"; + + protected static final String REDIRECT_CFR_QUICKSTART = REDIRECT_PREFIX + "/eg041"; + + private static final String EXAMPLE_TEXT = "example"; + + protected final String exampleName; + + protected final DSConfiguration config; + + private final String pagePath; + + @Autowired + protected Session session; + + protected String title; + + @Autowired + private OAuth2AuthorizedClientService authorizedClientService; + + private CodeExampleText codeExampleText; + + public AbstractController(DSConfiguration config, String exampleName) { + this.config = config; + this.exampleName = exampleName; + this.pagePath = this.getExamplePagesPath() + exampleName; + } + + public CodeExampleText getTextForCodeExampleByApiType() { + ApiType apiType = ApiType.giveTypeByName(this.exampleName); + if (codeExampleText != null) { + return codeExampleText; + } + + config.setSelectedApiType(apiType.toString()); + codeExampleText = getTextForCodeExample(); + + return codeExampleText; + } + + protected abstract String getExamplePagesPath(); + + @GetMapping + public String get(WorkArguments args, ModelMap model) { + if (ApiType.giveTypeByName(this.exampleName) != ApiType.CONNECT && isTokenExpired()) { + return REDIRECT_AUTHENTICATION_PAGE; + } + + if (ApiType.giveTypeByName(this.exampleName) == ApiType.MONITOR + && session.getAuthTypeSelected() != AuthType.JWT) { + session.setMonitorExampleRedirect("/" + this.exampleName); + return REDIRECT_AUTHENTICATION_PAGE; + } + + try { + onInitModel(args, model); + return pagePath; + } catch (Exception exception) { + if (config.getQuickstart().equals("true") + && exception.getMessage() == config.getCodeExamplesText().getSupportingTexts().getCFRError()) { + config.setQuickstart("false"); + return handleRedirectToCfr(model); + } else { + return handleException(exception, model); + } + } + } + + @PostMapping + public Object create(WorkArguments args, ModelMap model, HttpServletResponse response) { + if (ApiType.giveTypeByName(this.exampleName) != ApiType.CONNECT && isTokenExpired()) { + return REDIRECT_AUTHENTICATION_PAGE; + } + + try { + return doWork(args, model, response); + } catch (Exception exception) { + return handleException(exception, model); + } + } + + /** + * This method is called from the GET request and it should initialize a + * model. Override this method if it is necessary to add example specific + * attributes into the model. + * + * @param args the session attributes + * @param model the model data + */ + protected void onInitModel(WorkArguments args, ModelMap model) throws Exception { + this.title = getTextForCodeExampleByApiType().ExampleName; + + this.setTheCurrentApiTypeAndBaseUrl(); + Class clazz = Objects.requireNonNullElse(getClass().getEnclosingClass(), getClass()); + String srcPath = String.join("", config.getExampleUrl(), clazz.getName().replace('.', '/'), ".java"); + String viewSourceFile = config.getCodeExamplesText().SupportingTexts + .getViewSourceFile().replaceFirst( + "\\{0}", + "" + clazz.getSimpleName() + ".java" + ""); + model.addAttribute("csrfToken", ""); + model.addAttribute("title", title); + model.addAttribute("viewSourceFile", viewSourceFile); + model.addAttribute("documentation", config.getDocumentationPath() + exampleName); + model.addAttribute(EXAMPLE_TEXT, getTextForCodeExampleByApiType()); + model.addAttribute(LAUNCHER_TEXTS, config.getCodeExamplesText().SupportingTexts); + } + + public void setTheCurrentApiTypeAndBaseUrl() { + config.setSelectedApiType(ApiType.giveTypeByName(this.exampleName).toString()); + String basePath = session.getOauthAccount() != null + ? this.config.getBaseUrl(config.getSelectedApiIndex(), session.getOauthAccount()) + + config.getSelectedApiIndex().getBaseUrlSuffix() + : null; + session.setBasePath(basePath); + } + + /** + * This method is called from the POST request. Example pages must override + * it. Overridden method should return an Object means URL to redirect. + * + * @param args the work arguments got from the current page + * @param model page model holder + * @param response for HTTP-specific functionality in sending a response + * @return {@link Object}. Possible types and values: null, + * {@link String} representation of the URL or Spring RedirectView + * object, + * (see {@link org.springframework.web.servlet.view.RedirectView + * RedirectView}) + * @throws Exception if calling API has failed or if I/O operation has failed + */ + protected abstract Object doWork(WorkArguments args, ModelMap model, + HttpServletResponse response) throws Exception; + + private String handleException(Exception exception, ModelMap model) { + model.addAttribute(LAUNCHER_TEXTS, config.getCodeExamplesText().SupportingTexts); + String stackTrace = ExceptionUtils.getStackTrace(exception); + String exceptionMessage = ""; + String fixingInstructions = ""; + + if (exception != null) { + exceptionMessage = exception.getMessage(); + if (model.getAttribute("caseForInstructions") != null) { + fixingInstructions = exceptionMessage.contains((CharSequence) model.getAttribute("caseForInstructions")) + ? (String) model.getAttribute("fixingInstructions") + : null; + } + } + new DoneExample() + .withTitle(exampleName) + .withName(title) + .withMessage(exceptionMessage) + .withFixingInstructions(fixingInstructions) + .withStackTracePrinted(stackTrace) + .addToModel(model, config); + return ERROR_PAGE; + } + + private String handleRedirectToCfr(ModelMap model) { + return REDIRECT_CFR_QUICKSTART; + } + + private boolean isTokenExpired() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + boolean tokenExpired; + OAuth2AuthenticationToken oauth = (OAuth2AuthenticationToken) authentication; + OAuth2User oauthUser = oauth.getPrincipal(); + OAuth2AuthorizedClient oauthClient = authorizedClientService.loadAuthorizedClient( + oauth.getAuthorizedClientRegistrationId(), + oauthUser.getName()); + + if (oauthClient != null) { + OAuth2AccessToken accessToken = oauthClient.getAccessToken(); + tokenExpired = accessToken != null && accessToken.getExpiresAt().isBefore(Instant.now()); + } else { + OAuth.OAuthToken accessToken = oauthUser.getAttribute("access_token"); + tokenExpired = accessToken != null && this.session.getTokenExpirationTime() < System.currentTimeMillis(); + } + + session.setRefreshToken(tokenExpired); + + return tokenExpired; + } + + protected CodeExampleText getTextForCodeExample() { + List manifestGroups = config.getCodeExamplesText().APIs.stream() + .filter(x -> ApiType.giveTypeByName(this.exampleName).name().trim().equalsIgnoreCase(x.Name.trim())) + .findFirst() + .orElse(null).Groups; + + int exampleNumberToSearch = Integer.parseInt(this.exampleName.replaceAll("\\D+", "")); + + for (ManifestGroup group : manifestGroups) { + CodeExampleText codeExampleText = group.Examples.stream() + .filter(x -> x.ExampleNumber == exampleNumberToSearch) + .findFirst() + .orElse(null); + + if (codeExampleText != null) { + return codeExampleText; + } + } + return null; + } +} diff --git a/src/main/java/com/docusign/controller/GlobalControllerAdvice.java b/src/main/java/com/docusign/core/controller/GlobalControllerAdvice.java similarity index 54% rename from src/main/java/com/docusign/controller/GlobalControllerAdvice.java rename to src/main/java/com/docusign/core/controller/GlobalControllerAdvice.java index 3bb8a174..856df68b 100644 --- a/src/main/java/com/docusign/controller/GlobalControllerAdvice.java +++ b/src/main/java/com/docusign/core/controller/GlobalControllerAdvice.java @@ -1,33 +1,26 @@ -package com.docusign.controller; +package com.docusign.core.controller; import com.docusign.DSConfiguration; +import com.docusign.core.model.*; +import com.docusign.core.utils.AccountsConverter; import com.docusign.esign.client.auth.OAuth; -import com.docusign.model.AuthType; -import com.docusign.model.AuthTypeItem; -import com.docusign.model.Locals; -import com.docusign.model.Session; -import com.docusign.model.User; - -import com.docusign.utils.AccountsConverter; -import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.context.WebApplicationContext; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Optional; - +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; /** * This class provides common model attributes for all pages. If you want to @@ -48,16 +41,25 @@ @Scope(WebApplicationContext.SCOPE_SESSION) public class GlobalControllerAdvice { - private static final String BASE_URI_SUFFIX = "/restapi"; private static final String ERROR_ACCOUNT_NOT_FOUND = "Could not find account information for the user"; + private static final String PATH_TO_HOMEPAGE = "/pages/esignature/index"; + private final DSConfiguration config; + private final Session session; + private final User user; + private Optional account; - private AuthType authTypeSelected = AuthType.AGC; + + private final AuthType authTypeSelected = AuthType.AGC; + + private final ApiType apiTypeSelected = ApiType.ESIGNATURE; @Autowired + private OAuth2AuthorizedClientService authorizedClientService; + public GlobalControllerAdvice(DSConfiguration config, Session session, User user, Optional account) { this.config = config; this.session = session; @@ -65,6 +67,35 @@ public GlobalControllerAdvice(DSConfiguration config, Session session, User user this.account = account; } + private static List getOAuthAccounts(OAuth2User user) { + List> oauthAccounts = user.getAttribute("accounts"); + if (oauthAccounts == null) { + return new ArrayList<>(); + } + + return oauthAccounts.stream() + .map(AccountsConverter::convert) + .collect(Collectors.toList()); + } + + private static OAuth.Account getDefaultAccount(List accounts) { + for (OAuth.Account oauthAccount : accounts) { + if ("true".equals(oauthAccount.getIsDefault())) { + return oauthAccount; + } + } + return null; + } + + private static OAuth.Account getAccountById(List accounts, String accountId) { + for (OAuth.Account oauthAccount : accounts) { + if (StringUtils.equals(oauthAccount.getAccountId(), accountId)) { + return oauthAccount; + } + } + return null; + } + @ModelAttribute("authTypes") public List authTypes() { return AuthTypeItem.list(); @@ -75,6 +106,16 @@ public AuthTypeItem authTypeSelected() { return AuthTypeItem.convert(authTypeSelected); } + @ModelAttribute("apiTypes") + public List apiTypes() { + return ApiTypeItem.list(); + } + + @ModelAttribute("apiTypeSelected") + public ApiTypeItem apiTypeSelected() { + return ApiTypeItem.convert(apiTypeSelected); + } + @ModelAttribute("documentOptions") public List populateDocumentOptions() { return new ArrayList<>(); @@ -86,66 +127,56 @@ public boolean populateShowDoc() { } @ModelAttribute("locals") - public Locals populateLocals() { + public Locals populateLocals() throws IOException { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (!(authentication instanceof OAuth2Authentication)) { + session.setApiIndexPath(PATH_TO_HOMEPAGE); + + if (!(authentication instanceof OAuth2AuthenticationToken)) { return new Locals(config, session, null, ""); } - OAuth2Authentication oauth = (OAuth2Authentication) authentication; - OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) oauth.getDetails(); - Authentication oauthUser = oauth.getUserAuthentication(); + OAuth2AuthenticationToken oauth = (OAuth2AuthenticationToken) authentication; + OAuth2User oauthUser = oauth.getPrincipal(); + OAuth2AuthorizedClient oauthClient = authorizedClientService.loadAuthorizedClient( + oauth.getAuthorizedClientRegistrationId(), + oauthUser.getName() + ); - if (oauthUser != null && oauthUser.isAuthenticated()) { - user.setName(oauthUser.getName()); - user.setAccessToken(details.getTokenValue()); + if (oauth.isAuthenticated()) { + user.setName(oauthUser.getAttribute("name")); + + if (oauthClient != null) { + user.setAccessToken(oauthClient.getAccessToken().getTokenValue()); + } else { + user.setAccessToken(((OAuth.OAuthToken) oauthUser.getAttribute("access_token")).getAccessToken()); + } if (account.isEmpty()) { - account = Optional.of(getDefaultAccountInfo(getOAuthAccounts(oauth))); + account = Optional.ofNullable(getDefaultAccountInfo(getOAuthAccounts(oauthUser))); } OAuth.Account oauthAccount = account.orElseThrow(() -> new NoSuchElementException(ERROR_ACCOUNT_NOT_FOUND)); + session.setOauthAccount(oauthAccount); session.setAccountId(oauthAccount.getAccountId()); session.setAccountName(oauthAccount.getAccountName()); - session.setBasePath(oauthAccount.getBaseUri() + BASE_URI_SUFFIX); + + //TODO set this more efficiently with more APIs as they're added in + String basePath = this.config.getBaseUrl(config.getSelectedApiIndex(), oauthAccount) + config.getSelectedApiIndex().getBaseUrlSuffix(); + session.setBasePath(basePath); } return new Locals(config, session, user, ""); } - @SuppressWarnings("unchecked") - private static List getOAuthAccounts(OAuth2Authentication oauth) { - Map userAuthenticationDetails = (Map) oauth.getUserAuthentication().getDetails(); - List> oauthAccounts = (ArrayList>) userAuthenticationDetails.get("accounts"); - return oauthAccounts.stream() - .map(AccountsConverter::convert) - .collect(Collectors.toList()); - } - private OAuth.Account getDefaultAccountInfo(List accounts) { - if (StringUtils.isBlank(config.getTargetAccountId())) { - return getDefaultAccount(accounts); - } - - return getAccountById(accounts); - } - - private static OAuth.Account getDefaultAccount(List accounts) { - for (OAuth.Account oauthAccount : accounts) { - if ("true".equals(oauthAccount.getIsDefault())) { - return oauthAccount; - } - } - return null; - } - - private OAuth.Account getAccountById(List accounts) { - for (OAuth.Account oauthAccount : accounts) { - if (StringUtils.equals(oauthAccount.getAccountId(), config.getTargetAccountId())) { - return oauthAccount; + String targetAccountId = config.getTargetAccountId(); + if (StringUtils.isNotBlank(targetAccountId)) { + OAuth.Account account = getAccountById(accounts, targetAccountId); + if (account != null) { + return account; } } - return null; + return getDefaultAccount(accounts); } } diff --git a/src/main/java/com/docusign/core/controller/IndexController.java b/src/main/java/com/docusign/core/controller/IndexController.java new file mode 100644 index 00000000..7f82439c --- /dev/null +++ b/src/main/java/com/docusign/core/controller/IndexController.java @@ -0,0 +1,252 @@ +package com.docusign.core.controller; + +import com.docusign.DSConfiguration; +import com.docusign.common.ApiIndex; +import com.docusign.core.common.Utils; +import com.docusign.core.model.ApiType; +import com.docusign.core.model.AuthType; +import com.docusign.core.model.Session; +import com.docusign.core.model.User; +import com.docusign.core.security.acg.ACGAuthenticationMethod; +import com.docusign.core.security.jwt.JWTAuthenticationMethod; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.web.savedrequest.RequestCache; +import org.springframework.security.web.savedrequest.SavedRequest; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.view.RedirectView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; + +@Controller +public class IndexController { + + public static final String LOCATION_HEADER = "Location"; + + private static final String ATTR_ENVELOPE_ID = "qpEnvelopeId"; + + private static final String ATTR_STATE = "state"; + + private static final String ATTR_EVENT = "event"; + + private static final String ATTR_TITLE = "title"; + + private static final String LAUNCHER_TEXTS = "launcherTexts"; + + private static final String CODE_EXAMPLE_GROUPS = "codeExampleGroups"; + + private static final String API_DATA = "APIData"; + + private static final String STATUS_CFR = "statusCFR"; + + @Autowired + private Session session; + + @Autowired + private User user; + + @Autowired + private RequestCache requestCache; + + @Autowired + private DSConfiguration config; + + @GetMapping(path = "/") + public String index(ModelMap model, HttpServletResponse response) throws Exception { + model.addAttribute(ATTR_TITLE, "Home"); + + Boolean isCFR = false; + + if (this.config.isShareAccessExampleScenario()) { + this.config.setShareAccessExampleScenario(false); + this.config.setAdditionalRedirect(true); + + response.setStatus(response.SC_MOVED_TEMPORARILY); + response.setHeader(LOCATION_HEADER, "/ds/mustAuthenticate"); + return null; + } + + if (this.config.isAdditionalRedirect()) { + this.config.setAdditionalRedirect(false); + + response.setStatus(response.SC_MOVED_TEMPORARILY); + response.setHeader(LOCATION_HEADER, "/eg043/listEnvelopes"); + return null; + } + + if (user.getAccessToken() != null && config.getSelectedApiType().equals(ApiType.ESIGNATURE)) { + try { + isCFR = Utils.isCfr(session.getBasePath(), user.getAccessToken(), session.getAccountId()); + } catch (Exception exception) { + return exception.toString(); + } + } + + if (config.getQuickstart().equals("true") && config.getSelectedApiIndex().equals(ApiIndex.ESIGNATURE) && + !(SecurityContextHolder.getContext().getAuthentication() instanceof OAuth2AuthenticationToken)) { + String site = ApiIndex.ESIGNATURE.getPathOfFirstExample(); + response.setStatus(response.SC_MOVED_TEMPORARILY); + response.setHeader(LOCATION_HEADER, site); + return null; + } + + if (isCFR) { + session.setStatusCFR("enabled"); + model.addAttribute(STATUS_CFR, "enabled"); + } + model.addAttribute(LAUNCHER_TEXTS, config.getCodeExamplesText().SupportingTexts); + model.addAttribute(CODE_EXAMPLE_GROUPS, config.getCodeExamplesText().APIs.toArray()); + model.addAttribute(API_DATA, config.loadFileData(config.getCodeExamplesManifest())); + return session.getApiIndexPath(); + } + + @GetMapping(path = "/ds/mustAuthenticate") + public ModelAndView mustAuthenticateController(ModelMap model, HttpServletRequest req, HttpServletResponse resp) + throws IOException { + model.addAttribute(LAUNCHER_TEXTS, config.getCodeExamplesText().SupportingTexts); + model.addAttribute(ATTR_TITLE, config.getCodeExamplesText().SupportingTexts.LoginPage.LoginButton); + + String redirectURL = getRedirectURLForJWTAuthentication(req, resp); + + if (config.getIsConsentRedirectActivated()) { + config.setIsConsentRedirectActivated(false); + this.session.setAuthTypeSelected(AuthType.JWT); + + return new ModelAndView( + new JWTAuthenticationMethod().loginUsingJWT(config, session, redirectURL, ApiType.getScopeList())); + } + + boolean isRedirectToMonitor = redirectURL.toLowerCase().contains("/m") && + !redirectURL.toLowerCase().contains("/mae"); + if (session.isRefreshToken() || config.getQuickstart().equals("true")) { + config.setQuickstart("false"); + + if (isRedirectToMonitor || session.getMonitorExampleRedirect() != null) { + return checkForMonitorRedirects(redirectURL); + } + + return new ModelAndView(getRedirectView(session.getAuthTypeSelected())); + } else if (isRedirectToMonitor || session.getMonitorExampleRedirect() != null) { + return checkForMonitorRedirects(redirectURL); + } else { + return new ModelAndView("pages/ds_must_authenticate"); + } + } + + private ModelAndView checkForMonitorRedirects(String redirectURL) { + this.session.setAuthTypeSelected(AuthType.JWT); + redirectURL = redirectURL != "/" ? redirectURL : session.getMonitorExampleRedirect(); + this.session.setMonitorExampleRedirect(null); + return new ModelAndView( + new JWTAuthenticationMethod().loginUsingJWT(config, session, redirectURL, ApiType.getScopeList())); + } + + @GetMapping("/pkce") + public RedirectView pkce(String code, String state, HttpServletRequest req, HttpServletResponse resp) + throws Exception { + String redirectURL = getRedirectURLForJWTAuthentication(req, resp); + RedirectView redirect; + try { + redirect = new ACGAuthenticationMethod().exchangeCodeForToken(code, config, session, redirectURL, + ApiType.getScopeList()); + } catch (Exception e) { + redirect = getRedirectView(AuthType.AGC); + this.session.setIsPKCEWorking(false); + } + + return redirect; + } + + @PostMapping("/ds/authenticate") + public RedirectView authenticate(ModelMap model, @RequestBody MultiValueMap formParams, + HttpServletRequest req, HttpServletResponse resp) throws Exception { + if (!formParams.containsKey("selectAuthType")) { + model.addAttribute("message", "Select option with selectAuthType name must be provided."); + return new RedirectView("pages/error"); + } + + String redirectURL = getRedirectURLForJWTAuthentication(req, resp); + + List selectAuthTypeObject = formParams.get("selectAuthType"); + AuthType authTypeSelected = AuthType.valueOf(selectAuthTypeObject.get(0)); + + if (authTypeSelected.equals(AuthType.JWT)) { + this.session.setAuthTypeSelected(AuthType.JWT); + return new JWTAuthenticationMethod().loginUsingJWT(config, session, redirectURL, ApiType.getScopeList()); + } else { + this.session.setAuthTypeSelected(AuthType.AGC); + if (this.session.getIsPKCEWorking()) { + return new ACGAuthenticationMethod().initiateAuthorization(config, ApiType.getScopeList()); + } else { + return getRedirectView(authTypeSelected); + } + } + } + + private String getRedirectURLForJWTAuthentication(HttpServletRequest req, HttpServletResponse resp) { + SavedRequest savedRequest = requestCache.getRequest(req, resp); + + String[] examplesCodes = new String[] { + ApiIndex.CLICK.getExamplesPathCode(), + ApiIndex.ESIGNATURE.getExamplesPathCode(), + ApiIndex.MONITOR.getExamplesPathCode(), + ApiIndex.ADMIN.getExamplesPathCode(), + ApiIndex.ROOMS.getExamplesPathCode(), + ApiIndex.NOTARY.getExamplesPathCode(), + ApiIndex.MAESTRO.getExamplesPathCode(), + ApiIndex.CONNECTEDFIELDS.getExamplesPathCode() + }; + + if (savedRequest != null) { + Integer indexOfExampleCodeInRedirect = StringUtils.indexOfAny(savedRequest.getRedirectUrl(), examplesCodes); + + if (indexOfExampleCodeInRedirect != -1) { + Boolean hasNumbers = savedRequest.getRedirectUrl().substring(indexOfExampleCodeInRedirect) + .matches(".*\\d.*"); + + return "GET".equals(savedRequest.getMethod()) && hasNumbers ? savedRequest.getRedirectUrl() : "/"; + } + } + + return "/"; + } + + @GetMapping(path = "/ds-return") + public String returnController(@RequestParam(value = ATTR_STATE, required = false) String state, + @RequestParam(value = ATTR_EVENT, required = false) String event, + @RequestParam(required = false) String envelopeId, ModelMap model) { + model.addAttribute(LAUNCHER_TEXTS, config.getCodeExamplesText().SupportingTexts); + model.addAttribute(ATTR_TITLE, "Return from DocuSign"); + model.addAttribute(ATTR_EVENT, event); + model.addAttribute(ATTR_STATE, state); + model.addAttribute(ATTR_ENVELOPE_ID, envelopeId); + return "pages/ds_return"; + } + + private RedirectView getRedirectView(AuthType authTypeSelected) { + session.setAuthTypeSelected(authTypeSelected); + RedirectView redirect = new RedirectView(getLoginPath(authTypeSelected)); + redirect.setExposeModelAttributes(false); + return redirect; + } + + private String getLoginPath(AuthType authTypeSelected) { + String loginPath = config.getAcgRedirectURL(); + if (authTypeSelected.equals(AuthType.JWT)) { + loginPath = config.getJwtRedirectURL(); + } + return loginPath; + } +} \ No newline at end of file diff --git a/src/main/java/com/docusign/exception/LauncherException.java b/src/main/java/com/docusign/core/exception/LauncherException.java similarity index 84% rename from src/main/java/com/docusign/exception/LauncherException.java rename to src/main/java/com/docusign/core/exception/LauncherException.java index a7eae46d..536e07a1 100644 --- a/src/main/java/com/docusign/exception/LauncherException.java +++ b/src/main/java/com/docusign/core/exception/LauncherException.java @@ -1,4 +1,4 @@ -package com.docusign.exception; +package com.docusign.core.exception; public class LauncherException extends Exception { diff --git a/src/main/java/com/docusign/model/AccountRoleSettingsPatch.java b/src/main/java/com/docusign/core/model/AccountRoleSettingsPatch.java similarity index 54% rename from src/main/java/com/docusign/model/AccountRoleSettingsPatch.java rename to src/main/java/com/docusign/core/model/AccountRoleSettingsPatch.java index 8696d76d..f232e4ce 100644 --- a/src/main/java/com/docusign/model/AccountRoleSettingsPatch.java +++ b/src/main/java/com/docusign/core/model/AccountRoleSettingsPatch.java @@ -1,27 +1,15 @@ -package com.docusign.model; +package com.docusign.core.model; import com.docusign.esign.model.AccountRoleSettings; import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModelProperty; public class AccountRoleSettingsPatch extends AccountRoleSettings { @JsonProperty("signingUiVersion") - private String signingUiVersion = null; + private String signingUiVersion = ""; public AccountRoleSettings signingUiVersion(String signingUiVersion) { this.signingUiVersion = signingUiVersion; return this; } - - /** - * - * @return signingUiVersion - **/ - @ApiModelProperty(example = "null", value = "") - public String getSigningUiVersion() { - return signingUiVersion; - } - - } diff --git a/src/main/java/com/docusign/core/model/ApiType.java b/src/main/java/com/docusign/core/model/ApiType.java new file mode 100644 index 00000000..0ef262a3 --- /dev/null +++ b/src/main/java/com/docusign/core/model/ApiType.java @@ -0,0 +1,63 @@ +package com.docusign.core.model; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public enum ApiType { + ESIGNATURE("eSignature API", new String[] { "signature" }, "eg"), + ROOMS("Rooms API", new String[] { "signature", "dtr.rooms.read", "dtr.rooms.write", "dtr.documents.read", + "dtr.documents.write", "dtr.profile.read", "dtr.profile.write", "dtr.company.read", + "dtr.company.write", "room_forms" }, "r"), + CONNECT("Connect", new String[] {}, "con"), + CONNECTEDFIELDS("Connected Fields API", new String[] { "signature", "adm_store_unified_repo_read" }, "cf"), + CLICK("Click API", new String[] { "click.manage", "click.send" }, "c"), + MONITOR("Monitor API", new String[] { "signature", "impersonation" }, "m"), + ADMIN("Admin API", new String[] { "user_write", "signature", "impersonation", "group_read", "organization_read", + "permission_read", "user_read", "account_read", "domain_read", "identity_provider_read", "user_data_redact", + "asset_group_account_read", "asset_group_account_clone_write", "asset_group_account_clone_read", + "organization_sub_account_read", "organization_sub_account_write" }, "a"), + WEBFORMS("WebForms API", + new String[] { "signature", "webforms_read", "webforms_instance_read", "webforms_instance_write" }, "web"), + NAVIGATOR("Navigator API", new String[] { "signature", "adm_store_unified_repo_read" }, "nav"), + MAESTRO("Maestro API", new String[] { "signature", "aow_manage" }, "mae"), + NOTARY("Notary API", new String[] { "signature", "adm_store_unified_repo_read", "document_uploader_write", "document_uploader_read" }, "n"), + WORKSPACES("Workspaces API", new String[] { "signature", "dtr.company.read", "dtr.rooms.read", "dtr.rooms.write", + "dtr.documents.write" }, "work"); + + final String value; + + final String[] scopes; + + final String codeName; + + ApiType(String value, String[] scopes, String codeName) { + this.value = value; + this.scopes = scopes; + this.codeName = codeName; + } + + public static ApiType giveTypeByName(String exampleName) { + String exampleCode = exampleName.replaceAll("[^A-Za-z]", ""); + return Arrays.stream(ApiType.values()) + .filter(x -> exampleCode.equalsIgnoreCase(x.getCodeName())) + .findFirst() + .get(); + } + + public static List getScopeList() { + List scopes = new ArrayList<>(); + for (ApiType scope : ApiType.values()) { + scopes.addAll(Arrays.asList(scope.getScopes())); + } + return scopes; + } + + public String[] getScopes() { + return scopes; + } + + public String getCodeName() { + return codeName; + } +} \ No newline at end of file diff --git a/src/main/java/com/docusign/core/model/ApiTypeItem.java b/src/main/java/com/docusign/core/model/ApiTypeItem.java new file mode 100644 index 00000000..9af9cf24 --- /dev/null +++ b/src/main/java/com/docusign/core/model/ApiTypeItem.java @@ -0,0 +1,47 @@ +package com.docusign.core.model; + +import java.util.EnumSet; +import java.util.List; +import java.util.stream.Collectors; + +public class ApiTypeItem { + + private String key; + + private String value; + + public ApiTypeItem(String key, String value) { + this.key = key; + this.value = value; + } + + public static ApiTypeItem convert(ApiType apiType) { + return new ApiTypeItem(apiType.name(), apiType.value); + } + + public static ApiType convert(ApiTypeItem apiType) { + return ApiType.valueOf(apiType.key); + } + + public static List list() { + return EnumSet.allOf(ApiType.class).stream() + .map(ApiTypeItem::convert) + .collect(Collectors.toList()); + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/src/main/java/com/docusign/model/AuthType.java b/src/main/java/com/docusign/core/model/AuthType.java similarity index 87% rename from src/main/java/com/docusign/model/AuthType.java rename to src/main/java/com/docusign/core/model/AuthType.java index 03dec8ac..1fbbaeb8 100644 --- a/src/main/java/com/docusign/model/AuthType.java +++ b/src/main/java/com/docusign/core/model/AuthType.java @@ -1,4 +1,4 @@ -package com.docusign.model; +package com.docusign.core.model; public enum AuthType { //Authorization Code Grant diff --git a/src/main/java/com/docusign/model/AuthTypeItem.java b/src/main/java/com/docusign/core/model/AuthTypeItem.java similarity index 96% rename from src/main/java/com/docusign/model/AuthTypeItem.java rename to src/main/java/com/docusign/core/model/AuthTypeItem.java index c27c38bf..3701422a 100644 --- a/src/main/java/com/docusign/model/AuthTypeItem.java +++ b/src/main/java/com/docusign/core/model/AuthTypeItem.java @@ -1,4 +1,4 @@ -package com.docusign.model; +package com.docusign.core.model; import java.util.EnumSet; import java.util.List; @@ -7,6 +7,7 @@ public class AuthTypeItem { private String key; + private String value; public AuthTypeItem(String key, String value) { @@ -14,6 +15,20 @@ public AuthTypeItem(String key, String value) { this.value = value; } + public static AuthTypeItem convert(AuthType authType) { + return new AuthTypeItem(authType.name(), authType.value); + } + + public static AuthType convert(AuthTypeItem authType) { + return AuthType.valueOf(authType.key); + } + + public static List list() { + return EnumSet.allOf(AuthType.class).stream() + .map(AuthTypeItem::convert) + .collect(Collectors.toList()); + } + public String getKey() { return key; } @@ -29,18 +44,4 @@ public String getValue() { public void setValue(String value) { this.value = value; } - - public static AuthTypeItem convert(AuthType authType) { - return new AuthTypeItem(authType.name(), authType.value); - } - - public static AuthType convert(AuthTypeItem authType) { - return AuthType.valueOf(authType.key); - } - - public static List list() { - return EnumSet.allOf(AuthType.class).stream() - .map(AuthTypeItem::convert) - .collect(Collectors.toList()); - } } diff --git a/src/main/java/com/docusign/core/model/BulkUploadJobInfo.java b/src/main/java/com/docusign/core/model/BulkUploadJobInfo.java new file mode 100644 index 00000000..89b36aec --- /dev/null +++ b/src/main/java/com/docusign/core/model/BulkUploadJobInfo.java @@ -0,0 +1,23 @@ +package com.docusign.core.model; + +import java.util.Objects; +import java.util.List; + +public final class BulkUploadJobInfo { + private final String jobId; + + private final List uploadUrls; + + public BulkUploadJobInfo(String jobId, List uploadUrls) { + this.jobId = Objects.requireNonNull(jobId, "jobId must not be null"); + this.uploadUrls = Objects.requireNonNull(uploadUrls, "uploadUrls must not be null"); + } + + public String getJobId() { + return jobId; + } + + public List getUploadUrls() { + return uploadUrls; + } +} diff --git a/src/main/java/com/docusign/core/model/DoneExample.java b/src/main/java/com/docusign/core/model/DoneExample.java new file mode 100644 index 00000000..498ce297 --- /dev/null +++ b/src/main/java/com/docusign/core/model/DoneExample.java @@ -0,0 +1,163 @@ +package com.docusign.core.model; + +import com.docusign.DSConfiguration; +import com.docusign.core.common.DiffField; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.datatype.joda.JodaModule; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.With; +import org.springframework.ui.ModelMap; + +import java.text.SimpleDateFormat; + + +/** + * Model which is used in 'done' pages. + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@With +public class DoneExample { + public static final int JSON_INDENT_FACTOR = 4; + + private static final String MODEL_DONE_ATTRIBUTE = "done"; + + private static final String DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ssz"; + + private static final String LAUNCHER_TEXTS = "launcherTexts"; + + private String formFillUrl; + + private String title; + + private String name; + + private String message; + + private String redirect; + + private String json; + + private StackTraceElement[] stackTrace; + + private String stackTracePrinted; + + private String fixingInstructions; + + private Iterable diff; + + /** + * Creates default DoneExample object. This method initializes title and + * name members by the same value. + * + * @param title the title text + * @return created instance of this class + */ + public static DoneExample createDefault(String title) { + return new DoneExample() + .withTitle(title) + .withName(title); + } + + /** + * Creates DoneExample object with title. This method initializes title. + * + * @param String title + * @return created instance of this class + */ + public DoneExample withTitle(String title) { + this.title = title; + return this; + } + + /** + * Creates DoneExample object with name. This method initializes name. + * + * @param String name + * @return created instance of this class + */ + public DoneExample withName(String name) { + this.name = name; + return this; + } + + /** + * Creates DoneExample object with message. This method initializes message. + * + * @param String message + * @return created instance of this class + */ + public DoneExample withMessage(String message) { + this.message = message; + return this; + } + + public DoneExample withFixingInstructions(String fixingInstructions) { + this.fixingInstructions = fixingInstructions; + return this; + } + + /** + * Creates DoneExample object with stackTrace. This method initializes error stack trace. + * + * @param StackTraceElement[] stackTrace + * @return created instance of this class + */ + public DoneExample withStackTrace(StackTraceElement[] stackTrace) { + this.stackTrace = stackTrace; + return this; + } + + public DoneExample withStackTracePrinted(String stackTracePrinted) { + this.stackTracePrinted = stackTracePrinted; + return this; + } + + /** + * Creates a JSON text from the object and applies it to member + * + * @param object the object to convert to JSON string + * @return this object + */ + public DoneExample withJsonObject(Object object) { + if (object != null) { + ObjectWriter writer = new ObjectMapper() + .registerModule(new JavaTimeModule()) + .registerModule(new JodaModule()) + .setDateFormat(new SimpleDateFormat(DATETIME_PATTERN)) + .setDefaultPrettyPrinter(new DefaultPrettyPrinter()) + .writerWithDefaultPrettyPrinter(); + try { + json = writer.writeValueAsString(object); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + return this; + } + + public DoneExample withFormFill(String url) { + if (url != null) { + this.formFillUrl = url; + } + + return this; + } + + /** + * Adds this object to model map using name 'done' + * + * @param model the model object to add + */ + public void addToModel(ModelMap model, DSConfiguration config) { + model.addAttribute(MODEL_DONE_ATTRIBUTE, this); + model.addAttribute(LAUNCHER_TEXTS, config.getCodeExamplesText().SupportingTexts); + } +} diff --git a/src/main/java/com/docusign/model/EnvelopeDocumentInfo.java b/src/main/java/com/docusign/core/model/EnvelopeDocumentInfo.java similarity index 88% rename from src/main/java/com/docusign/model/EnvelopeDocumentInfo.java rename to src/main/java/com/docusign/core/model/EnvelopeDocumentInfo.java index 1525b3ea..fb87615f 100644 --- a/src/main/java/com/docusign/model/EnvelopeDocumentInfo.java +++ b/src/main/java/com/docusign/core/model/EnvelopeDocumentInfo.java @@ -1,15 +1,17 @@ -package com.docusign.model; - -import java.io.Serializable; +package com.docusign.core.model; import lombok.Value; +import java.io.Serializable; + @Value public class EnvelopeDocumentInfo implements Serializable { private static final long serialVersionUID = 8423772017910727550L; private String name; + private String type; + private String documentId; } diff --git a/src/main/java/com/docusign/model/Locals.java b/src/main/java/com/docusign/core/model/Locals.java similarity index 88% rename from src/main/java/com/docusign/model/Locals.java rename to src/main/java/com/docusign/core/model/Locals.java index 9c1200d0..82a1f5f7 100644 --- a/src/main/java/com/docusign/model/Locals.java +++ b/src/main/java/com/docusign/core/model/Locals.java @@ -1,15 +1,17 @@ -package com.docusign.model; +package com.docusign.core.model; +import com.docusign.DSConfiguration; import lombok.AllArgsConstructor; import lombok.Data; -import com.docusign.DSConfiguration; - @Data @AllArgsConstructor public class Locals { private DSConfiguration dsConfig; + private Session session; + private User user; + private String messages; } diff --git a/src/main/java/com/docusign/model/OptionItem.java b/src/main/java/com/docusign/core/model/OptionItem.java similarity index 83% rename from src/main/java/com/docusign/model/OptionItem.java rename to src/main/java/com/docusign/core/model/OptionItem.java index 09b3fec7..71621e67 100644 --- a/src/main/java/com/docusign/model/OptionItem.java +++ b/src/main/java/com/docusign/core/model/OptionItem.java @@ -1,4 +1,4 @@ -package com.docusign.model; +package com.docusign.core.model; import lombok.AllArgsConstructor; import lombok.Data; @@ -8,5 +8,6 @@ @AllArgsConstructor public class OptionItem { private String text; + private String documentId; } diff --git a/src/main/java/com/docusign/core/model/Session.java b/src/main/java/com/docusign/core/model/Session.java new file mode 100644 index 00000000..35bb67e1 --- /dev/null +++ b/src/main/java/com/docusign/core/model/Session.java @@ -0,0 +1,94 @@ +package com.docusign.core.model; + +import com.docusign.esign.client.auth.OAuth; +import com.docusign.iam.sdk.models.components.TabInfo; +import lombok.Data; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.stereotype.Component; +import org.springframework.web.context.WebApplicationContext; + +import java.io.Serializable; +import java.util.List; +import java.util.UUID; + +@Component +@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) +@Data +public class Session implements Serializable { + private static final long serialVersionUID = 2695379118371574037L; + + public UUID bulkListId; + + public Long tokenExpirationTime; + + private String accountId; + + private String createdUserId; + + private String accountName; + + private String basePath; + + private String roomsBasePath; + + private String envelopeId; + + private String templateId; + + private String templateName; + + private String statusCFR; + + private List envelopeDocuments; + + private String permissionProfileId; + + private String permissionProfileName; + + private String apiIndexPath; + + private AuthType authTypeSelected = AuthType.AGC; + + private boolean refreshToken; + + private String clickwrapId; + + private String clickwrapVersionNumber; + + private String exportId; + + private String importId; + + private String webformTemplateId; + + private String emailAddress; + + private UUID orgId; + + private OAuth.Account oauthAccount; + + private String monitorExampleRedirect; + + private String workflowId; + + private List extensionApps; + + private String instanceId; + + private Boolean isPKCEWorking = true; + + private Boolean isWorkflowPublished = false; + + private Boolean isWebFormsInitialRun = true; + + private String workspaceId; + + private String creatorId; + + private String documentId; + + private String bulkJobId; + + private List bulkUploadUrls; +} diff --git a/src/main/java/com/docusign/model/User.java b/src/main/java/com/docusign/core/model/User.java similarity index 94% rename from src/main/java/com/docusign/model/User.java rename to src/main/java/com/docusign/core/model/User.java index 5fa6b558..6e4ac15d 100644 --- a/src/main/java/com/docusign/model/User.java +++ b/src/main/java/com/docusign/core/model/User.java @@ -1,14 +1,13 @@ -package com.docusign.model; +package com.docusign.core.model; import lombok.Data; - -import java.io.Serializable; - import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.stereotype.Component; import org.springframework.web.context.WebApplicationContext; +import java.io.Serializable; + @Component @Scope(value = WebApplicationContext.SCOPE_SESSION, @@ -18,5 +17,6 @@ public class User implements Serializable { private static final long serialVersionUID = 8959083682339598499L; private String name; + private String accessToken; } diff --git a/src/main/java/com/docusign/core/model/manifestModels/APIs.java b/src/main/java/com/docusign/core/model/manifestModels/APIs.java new file mode 100644 index 00000000..5cae44b3 --- /dev/null +++ b/src/main/java/com/docusign/core/model/manifestModels/APIs.java @@ -0,0 +1,15 @@ +package com.docusign.core.model.manifestModels; + +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +public class APIs { + public String Name; + + public List Groups = new ArrayList(); +} diff --git a/src/main/java/com/docusign/core/model/manifestModels/AdditionalPage.java b/src/main/java/com/docusign/core/model/manifestModels/AdditionalPage.java new file mode 100644 index 00000000..8ff04d08 --- /dev/null +++ b/src/main/java/com/docusign/core/model/manifestModels/AdditionalPage.java @@ -0,0 +1,12 @@ +package com.docusign.core.model.manifestModels; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class AdditionalPage { + public String Name; + + public String ResultsPageText; +} diff --git a/src/main/java/com/docusign/core/model/manifestModels/CodeExampleText.java b/src/main/java/com/docusign/core/model/manifestModels/CodeExampleText.java new file mode 100644 index 00000000..e3ad7124 --- /dev/null +++ b/src/main/java/com/docusign/core/model/manifestModels/CodeExampleText.java @@ -0,0 +1,35 @@ +package com.docusign.core.model.manifestModels; + +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +public class CodeExampleText { + public int ExampleNumber; + + public String ExampleName; + + public String CFREnabled; + + public String ExampleDescription; + + public String Notes; + + public String ResultsPageText; + + public String SkipForLanguages; + + public List LinksToAPIMethod = new ArrayList<>(); + + public List CustomErrorTexts = new ArrayList<>(); + + public List RedirectsToOtherCodeExamples = new ArrayList<>(); + + public List Forms = new ArrayList<>(); + + public List AdditionalPage = new ArrayList<>(); +} diff --git a/src/main/java/com/docusign/core/model/manifestModels/CustomErrorTexts.java b/src/main/java/com/docusign/core/model/manifestModels/CustomErrorTexts.java new file mode 100644 index 00000000..056719dc --- /dev/null +++ b/src/main/java/com/docusign/core/model/manifestModels/CustomErrorTexts.java @@ -0,0 +1,12 @@ +package com.docusign.core.model.manifestModels; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class CustomErrorTexts { + public String ErrorMessageCheck; + + public String ErrorMessage; +} diff --git a/src/main/java/com/docusign/core/model/manifestModels/Forms.java b/src/main/java/com/docusign/core/model/manifestModels/Forms.java new file mode 100644 index 00000000..e18ac68f --- /dev/null +++ b/src/main/java/com/docusign/core/model/manifestModels/Forms.java @@ -0,0 +1,15 @@ +package com.docusign.core.model.manifestModels; + +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +public class Forms { + public String FormName; + + public List Inputs = new ArrayList<>(); +} diff --git a/src/main/java/com/docusign/core/model/manifestModels/HelpingTexts.java b/src/main/java/com/docusign/core/model/manifestModels/HelpingTexts.java new file mode 100644 index 00000000..1d62631f --- /dev/null +++ b/src/main/java/com/docusign/core/model/manifestModels/HelpingTexts.java @@ -0,0 +1,50 @@ +package com.docusign.core.model.manifestModels; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class HelpingTexts { + public String EmailWontBeShared; + + public String SaveAgentActivationCode; + + public String PhoneNumberWontBeShared; + + public String CCEmailShouldDifferFromSigner; + + public String AccessCodeText; + + public String CountryCodeText; + + public String ChooseDateInTheFuture; + + public String PhoneNumberWillBeNotified; + + public String EmailAddressOfUserToDelete; + + public String UserIDOfUserToDelete; + + public String DynamicContentValue; + + public String DynamicContentNote; + + public String EmbedClickwrapURL; + + public String NOTAGREED; + + public String AGREED; + + public String SubmitButtonDeleteText; + + public String SubmitButtonRestoreText; + + public String EnvelopeWillBeRestored; + + public String DefaultEnvelopeId; + + public String SpecifyNameWithExtension; + + public String SelectPDFFileFromFolder; +} diff --git a/src/main/java/com/docusign/core/model/manifestModels/Inputs.java b/src/main/java/com/docusign/core/model/manifestModels/Inputs.java new file mode 100644 index 00000000..c0b997b2 --- /dev/null +++ b/src/main/java/com/docusign/core/model/manifestModels/Inputs.java @@ -0,0 +1,12 @@ +package com.docusign.core.model.manifestModels; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class Inputs { + public String InputName; + + public String InputPlaceholder; +} diff --git a/src/main/java/com/docusign/core/model/manifestModels/LinkToAPIMethods.java b/src/main/java/com/docusign/core/model/manifestModels/LinkToAPIMethods.java new file mode 100644 index 00000000..93d905fb --- /dev/null +++ b/src/main/java/com/docusign/core/model/manifestModels/LinkToAPIMethods.java @@ -0,0 +1,12 @@ +package com.docusign.core.model.manifestModels; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class LinkToAPIMethods { + public String Path; + + public String PathName; +} diff --git a/src/main/java/com/docusign/core/model/manifestModels/LoginPage.java b/src/main/java/com/docusign/core/model/manifestModels/LoginPage.java new file mode 100644 index 00000000..2b9ee96f --- /dev/null +++ b/src/main/java/com/docusign/core/model/manifestModels/LoginPage.java @@ -0,0 +1,14 @@ +package com.docusign.core.model.manifestModels; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class LoginPage { + public String LoginHeader; + + public String LoginButton; + + public String LoginHelperText; +} diff --git a/src/main/java/com/docusign/core/model/manifestModels/ManifestGroup.java b/src/main/java/com/docusign/core/model/manifestModels/ManifestGroup.java new file mode 100644 index 00000000..b09bc3ed --- /dev/null +++ b/src/main/java/com/docusign/core/model/manifestModels/ManifestGroup.java @@ -0,0 +1,15 @@ +package com.docusign.core.model.manifestModels; + +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +public class ManifestGroup { + public List Examples = new ArrayList<>(); + + public String Name; +} diff --git a/src/main/java/com/docusign/core/model/manifestModels/ManifestStructure.java b/src/main/java/com/docusign/core/model/manifestModels/ManifestStructure.java new file mode 100644 index 00000000..33d11773 --- /dev/null +++ b/src/main/java/com/docusign/core/model/manifestModels/ManifestStructure.java @@ -0,0 +1,15 @@ +package com.docusign.core.model.manifestModels; + +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +public class ManifestStructure { + public SupportingTexts SupportingTexts; + + public List APIs = new ArrayList(); +} diff --git a/src/main/java/com/docusign/core/model/manifestModels/RedirectsToOtherCodeExamples.java b/src/main/java/com/docusign/core/model/manifestModels/RedirectsToOtherCodeExamples.java new file mode 100644 index 00000000..10bb8803 --- /dev/null +++ b/src/main/java/com/docusign/core/model/manifestModels/RedirectsToOtherCodeExamples.java @@ -0,0 +1,12 @@ +package com.docusign.core.model.manifestModels; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class RedirectsToOtherCodeExamples { + public Integer CodeExampleToRedirectTo; + + public String RedirectText; +} diff --git a/src/main/java/com/docusign/core/model/manifestModels/SelectAPIPage.java b/src/main/java/com/docusign/core/model/manifestModels/SelectAPIPage.java new file mode 100644 index 00000000..61f84666 --- /dev/null +++ b/src/main/java/com/docusign/core/model/manifestModels/SelectAPIPage.java @@ -0,0 +1,12 @@ +package com.docusign.core.model.manifestModels; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class SelectAPIPage { + public String SelectAPIHeader; + + public String SelectAPIButton; +} diff --git a/src/main/java/com/docusign/core/model/manifestModels/SupportingTexts.java b/src/main/java/com/docusign/core/model/manifestModels/SupportingTexts.java new file mode 100644 index 00000000..598149c5 --- /dev/null +++ b/src/main/java/com/docusign/core/model/manifestModels/SupportingTexts.java @@ -0,0 +1,44 @@ +package com.docusign.core.model.manifestModels; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class SupportingTexts { + public String HomePageText; + + public String ContactSupportToEnableFeature; + + public String ViewSourceFile; + + public String APIMethodUsed; + + public String APIMethodUsedPlural; + + public String SubmitButton; + + public String ContinueButton; + + public String HomeButton; + + public String LoginButton; + + public String LogoutButton; + + public String SearchFailed; + + public String ChangeAPITypeButton; + + public String WelcomeText; + + public String CFRError; + + public String IdenticalEmailsNotAllowedErrorMessage; + + public LoginPage LoginPage; + + public SelectAPIPage SelectAPIPage; + + public HelpingTexts HelpingTexts; +} diff --git a/src/main/java/com/docusign/core/security/CustomAuthenticationFailureHandler.java b/src/main/java/com/docusign/core/security/CustomAuthenticationFailureHandler.java new file mode 100644 index 00000000..7168ed91 --- /dev/null +++ b/src/main/java/com/docusign/core/security/CustomAuthenticationFailureHandler.java @@ -0,0 +1,24 @@ +package com.docusign.core.security; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.AuthenticationFailureHandler; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler { + + @Override + public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, + AuthenticationException exception) throws IOException, ServletException { + String code = request.getParameter("code"); + String state = request.getParameter("state"); + + if (code != null) { + response.sendRedirect("/pkce?code=" + code + "&state=" + state); + } else { + response.sendRedirect("/login?error=true"); + } + } +} diff --git a/src/main/java/com/docusign/core/security/JWTOAuth2User.java b/src/main/java/com/docusign/core/security/JWTOAuth2User.java new file mode 100644 index 00000000..245844ba --- /dev/null +++ b/src/main/java/com/docusign/core/security/JWTOAuth2User.java @@ -0,0 +1,130 @@ +package com.docusign.core.security; + +import com.docusign.esign.client.auth.OAuth; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.oauth2.core.user.OAuth2User; + +import java.util.*; + +public class JWTOAuth2User implements OAuth2User { + private List authorities; + + private Map attributes; + + private String sub; + + private String name; + + private String givenName; + + private String familyName; + + private OAuth.OAuthToken accessToken; + + private String email; + + private List > accounts; + + private String created; + + @Override + public Collection getAuthorities() { + return this.authorities; + } + + public void setAuthorities(List < String > scopes) { + String authoritiesString = "ROLE_USER"; + for (String scope: scopes) { + authoritiesString += ",SCOPE_" + scope; + } + authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(authoritiesString); + } + + @Override + public Map getAttributes() { + if (this.attributes == null) { + this.attributes = new HashMap <> (); + this.attributes.put("sub", this.getSub()); + this.attributes.put("name", this.getName()); + this.attributes.put("given_name", this.getGivenName()); + this.attributes.put("family_name", this.getFamilyName()); + this.attributes.put("created", this.getCreated()); + this.attributes.put("email", this.getEmail()); + this.attributes.put("accounts", this.getAccounts()); + this.attributes.put("access_token", this.getAccessToken()); + } + return attributes; + } + + public String getSub() { + return this.sub; + } + + public void setSub(String sub) { + this.sub = sub; + } + + @Override + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getGivenName() { + return this.givenName; + } + + public void setGivenName(String givenName) { + this.givenName = givenName; + } + + public OAuth.OAuthToken getAccessToken() { + return this.accessToken; + } + + public void setAccessToken(OAuth.OAuthToken accessToken) { + this.accessToken = accessToken; + } + + public String getFamilyName() { + return this.familyName; + } + + public void setFamilyName(String familyName) { + this.familyName = familyName; + } + + public String getCreated() { + return this.created; + } + + public void setCreated(String created) { + this.created = created; + } + + public String getEmail() { + return this.email; + } + + public void setEmail(String email) { + this.email = email; + } + + public List > getAccounts() { + return this.accounts; + } + + public void setAccounts(List accounts) { + this.accounts = new ArrayList <> (); + for (OAuth.Account account: accounts) { + ObjectMapper mapObject = new ObjectMapper(); + Map mapObj = mapObject.convertValue(account, Map.class); + this.accounts.add(mapObj); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/docusign/core/security/SecurityHelpers.java b/src/main/java/com/docusign/core/security/SecurityHelpers.java new file mode 100644 index 00000000..39a06b25 --- /dev/null +++ b/src/main/java/com/docusign/core/security/SecurityHelpers.java @@ -0,0 +1,61 @@ +package com.docusign.core.security; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.List; +import java.util.Random; + +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import com.docusign.core.model.Session; +import com.docusign.esign.client.auth.OAuth; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class SecurityHelpers { + public static String generateCodeVerifier() { + byte[] randomBytes = new byte[32]; + new Random().nextBytes(randomBytes); + return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes); + } + + public static String generateCodeChallenge(String codeVerifier) throws NoSuchAlgorithmException { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest(codeVerifier.getBytes(StandardCharsets.UTF_8)); + return Base64.getUrlEncoder().withoutPadding().encodeToString(hash); + } + + public static String parseJsonField(String jsonResponse, String field) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + JsonNode jsonNode = mapper.readTree(jsonResponse); + return jsonNode.get(field).asText(); + } + + public static void setSpringSecurityAuthentication( + List scopes, + String oAuthToken, + OAuth.UserInfo userInfo, + String accountId, + Session session, + String expiresIn) { + JWTOAuth2User principal = new JWTOAuth2User(); + principal.setAuthorities(scopes); + principal.setCreated(userInfo.getCreated()); + principal.setName(userInfo.getName()); + principal.setGivenName(userInfo.getGivenName()); + principal.setFamilyName(userInfo.getFamilyName()); + principal.setSub(userInfo.getSub()); + principal.setEmail(userInfo.getEmail()); + principal.setAccounts(userInfo.getAccounts()); + principal.setAccessToken(new OAuth.OAuthToken().accessToken(oAuthToken)); + + session.setTokenExpirationTime(System.currentTimeMillis() + Integer.parseInt(expiresIn) * 1000L); + + OAuth2AuthenticationToken token = new OAuth2AuthenticationToken(principal, principal.getAuthorities(), + accountId); + SecurityContextHolder.getContext().setAuthentication(token); + } +} diff --git a/src/main/java/com/docusign/core/security/acg/ACGAuthenticationMethod.java b/src/main/java/com/docusign/core/security/acg/ACGAuthenticationMethod.java new file mode 100644 index 00000000..37919feb --- /dev/null +++ b/src/main/java/com/docusign/core/security/acg/ACGAuthenticationMethod.java @@ -0,0 +1,97 @@ +package com.docusign.core.security.acg; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.net.URI; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.Base64; +import java.util.List; +import org.springframework.web.servlet.view.RedirectView; + +import com.docusign.DSConfiguration; +import com.docusign.core.model.Session; +import com.docusign.core.security.SecurityHelpers; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.auth.OAuth; + +public class ACGAuthenticationMethod { + private static final String REDIRECT_URI = "/login/oauth2/code/acg"; + + private static final String STATE = "random_state_string"; + + private static String codeVerifier; + + private static String codeChallenge; + + public RedirectView initiateAuthorization(DSConfiguration configuration, List scopes) throws Exception { + codeVerifier = SecurityHelpers.generateCodeVerifier(); + codeChallenge = SecurityHelpers.generateCodeChallenge(codeVerifier); + + String authorizationURL = String.format( + "%s&redirect_uri=%s&scope=%s&client_id=%s&state=%s&response_type=code&code_challenge=%s&code_challenge_method=S256", + configuration.getAuthorizationEndpoint(), + URLEncoder.encode(configuration.getAppUrl() + REDIRECT_URI, StandardCharsets.UTF_8), + URLEncoder.encode(String.join(" ", scopes), StandardCharsets.UTF_8), configuration.getUserId(), STATE, + codeChallenge); + + return new RedirectView(authorizationURL); + } + + public RedirectView exchangeCodeForToken( + String oAuthToken, + DSConfiguration configuration, + Session session, + String redirect, + List scopes) throws Exception { + String requestBody = buildRequestBody(oAuthToken); + String authHeader = generateAuthHeader(configuration); + + HttpClient client = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(configuration.getTokenEndpoint())) + .header("Authorization", "Basic " + authHeader) + .header("Content-Type", "application/x-www-form-urlencoded") + .POST(HttpRequest.BodyPublishers.ofString(requestBody)) + .build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode() == 200) { + processTokenResponse(response.body(), configuration, session, scopes); + } else { + throw new IOException("Failed to exchange code for token. Status code: " + response.statusCode()); + } + + return new RedirectView(redirect); + } + + private String buildRequestBody(String oAuthToken) throws IOException { + return "grant_type=authorization_code" + + "&code=" + URLEncoder.encode(oAuthToken, StandardCharsets.UTF_8) + + "&redirect_uri=" + URLEncoder.encode(REDIRECT_URI, StandardCharsets.UTF_8) + + "&code_verifier=" + URLEncoder.encode(codeVerifier, StandardCharsets.UTF_8); + } + + private String generateAuthHeader(DSConfiguration configuration) { + return Base64.getEncoder().encodeToString( + (configuration.getUserId() + ":" + configuration.getSecretUserId()).getBytes(StandardCharsets.UTF_8)); + } + + private void processTokenResponse(String responseBody, DSConfiguration configuration, Session session, + List scopes) + throws Exception { + ApiClient apiClient = new ApiClient(configuration.getBasePath()); + String accessToken = SecurityHelpers.parseJsonField(responseBody, "access_token"); + String expiresIn = SecurityHelpers.parseJsonField(responseBody, "expires_in"); + + OAuth.UserInfo userInfo = apiClient.getUserInfo(accessToken); + String accountId = userInfo.getAccounts().size() > 0 ? userInfo.getAccounts().get(0).getAccountId() : ""; + + SecurityHelpers.setSpringSecurityAuthentication(scopes, accessToken, userInfo, + accountId, session, + expiresIn); + } +} \ No newline at end of file diff --git a/src/main/java/com/docusign/core/security/jwt/JWTAuthenticationMethod.java b/src/main/java/com/docusign/core/security/jwt/JWTAuthenticationMethod.java new file mode 100644 index 00000000..f3c668c6 --- /dev/null +++ b/src/main/java/com/docusign/core/security/jwt/JWTAuthenticationMethod.java @@ -0,0 +1,82 @@ +package com.docusign.core.security.jwt; + +import com.docusign.core.security.SecurityHelpers; + +import com.docusign.DSConfiguration; +import com.docusign.core.model.Session; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.client.auth.OAuth; +import org.springframework.web.servlet.view.RedirectView; + +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; + +public class JWTAuthenticationMethod { + + public static final String CONSENT_REQUIRED = "consent_required"; + + public static final String REQUEST_CONSENT_LINK = "https://%s/oauth/auth?prompt=login&response_type=code&scope=%s&client_id=%s&redirect_uri=%s"; + + public static final String CONSENT_REDIRECT_URL = "/login/oauth2/code/jwt"; + + private static final long TOKEN_EXPIRATION_IN_SECONDS = 3600; + + public RedirectView loginUsingJWT( + DSConfiguration configuration, + Session session, + String redirectURL, + List scopes) { + try { + ApiClient apiClient = new ApiClient(configuration.getBasePath()); + byte[] privateKeyBytes = Files.readAllBytes(Paths.get(configuration.getPrivateKeyPath())); + + OAuth.OAuthToken oAuthToken = apiClient.requestJWTUserToken( + configuration.getUserId(), + configuration.getImpersonatedUserId(), + scopes, + privateKeyBytes, + TOKEN_EXPIRATION_IN_SECONDS); + String accessToken = oAuthToken.getAccessToken(); + OAuth.UserInfo userInfo = apiClient.getUserInfo(accessToken); + String accountId = userInfo.getAccounts().size() > 0 + ? userInfo.getAccounts().get(0).getAccountId() + : ""; + + SecurityHelpers.setSpringSecurityAuthentication(scopes, oAuthToken.getAccessToken(), + userInfo, + accountId, session, oAuthToken.getExpiresIn().toString()); + } catch (ApiException | IOException exp) { + if (exp.getMessage().contains(CONSENT_REQUIRED)) { + String consent_scopes = String.join("%20", scopes) + "%20impersonation"; + + var consent_url = String.format( + REQUEST_CONSENT_LINK, + configuration.getBaseURL(), + consent_scopes, + configuration.getUserId(), + URLEncoder.encode(configuration.getAppUrl() + CONSENT_REDIRECT_URL, + StandardCharsets.UTF_8)); + + System.err.println("\nC O N S E N T R E Q U I R E D" + + "\nAsk the user who will be impersonated to run the following URL: " + + "\n" + consent_url + + "\n\nIt will ask the user to login and to approve access by your application." + + + "\nAlternatively, an Administrator can use Organization Administration to" + + + "\npre-approve one or more users."); + + configuration.setIsConsentRedirectActivated(true); + + return new RedirectView(consent_url); + } + } + + return new RedirectView(redirectURL); + } +} diff --git a/src/main/java/com/docusign/utils/AccountsConverter.java b/src/main/java/com/docusign/core/utils/AccountsConverter.java similarity index 96% rename from src/main/java/com/docusign/utils/AccountsConverter.java rename to src/main/java/com/docusign/core/utils/AccountsConverter.java index b01c5a98..b9886b78 100644 --- a/src/main/java/com/docusign/utils/AccountsConverter.java +++ b/src/main/java/com/docusign/core/utils/AccountsConverter.java @@ -1,6 +1,7 @@ -package com.docusign.utils; +package com.docusign.core.utils; import com.docusign.esign.client.auth.OAuth; + import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/main/java/com/docusign/core/utils/DateUtils.java b/src/main/java/com/docusign/core/utils/DateUtils.java new file mode 100644 index 00000000..0e280b02 --- /dev/null +++ b/src/main/java/com/docusign/core/utils/DateUtils.java @@ -0,0 +1,9 @@ +package com.docusign.core.utils; + +import java.time.format.DateTimeFormatter; + +public class DateUtils { + public static final DateTimeFormatter DATE_WITH_SLASH = DateTimeFormatter.ofPattern("yyyy/MM/dd"); + + public static final DateTimeFormatter DATE_WITH_LINES = DateTimeFormatter.ofPattern("yyyy-MM-dd"); +} diff --git a/src/main/java/com/docusign/core/utils/FileUtils.java b/src/main/java/com/docusign/core/utils/FileUtils.java new file mode 100644 index 00000000..1ae11711 --- /dev/null +++ b/src/main/java/com/docusign/core/utils/FileUtils.java @@ -0,0 +1,25 @@ +package com.docusign.core.utils; + +import org.springframework.util.StreamUtils; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +public class FileUtils { + /** + * Loads a file content and copy it into a byte array. + * + * @param path the absolute path within the class path + * @return the new byte array that has been loaded from the file + * @throws IOException in case of I/O errors + */ + public byte[] readFile(String path) throws IOException { + InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path); + if (inputStream == null) { + throw new FileNotFoundException("File not found: " + path); + } + + return StreamUtils.copyToByteArray(inputStream); + } +} diff --git a/src/main/java/com/docusign/model/DoneExample.java b/src/main/java/com/docusign/model/DoneExample.java deleted file mode 100644 index a6d41836..00000000 --- a/src/main/java/com/docusign/model/DoneExample.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.docusign.model; - -import org.json.JSONObject; -import org.springframework.ui.ModelMap; - -import com.docusign.common.DiffField; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.With; - - -/** - * Model which is used in 'done' pages. - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -@With -public class DoneExample { - private static final String MODEL_DONE_ATTRIBUTE = "done"; - public static final int JSON_INDENT_FACTOR = 4; - - private String title; - private String name; - private String message; - private String json; - private StackTraceElement[] stackTrace; - private Iterable diff; - - - /** - * Creates default DoneExample object. This method initializes title and - * name members by the same value. - * @param title the title text - * @return created instance of this class - */ - public static DoneExample createDefault(String title) { - return new DoneExample() - .withTitle(title) - .withName(title); - } - - /** - * Creates a JSON text from the object and applies it to member - * @param object the object to convert to JSON string - * @return this object - */ - public DoneExample withJsonObject(Object object) { - if (object != null) { - JSONObject jsonObject = new JSONObject(object); - json = jsonObject.toString(JSON_INDENT_FACTOR); - } - return this; - } - - /** - * Adds this object to model map using name 'done' - * @param model the model object to add - */ - public void addToModel(ModelMap model) { - model.addAttribute(MODEL_DONE_ATTRIBUTE, this); - } -} diff --git a/src/main/java/com/docusign/security/OAuthProperties.java b/src/main/java/com/docusign/security/OAuthProperties.java deleted file mode 100644 index 0f8b0d77..00000000 --- a/src/main/java/com/docusign/security/OAuthProperties.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.docusign.security; - -import lombok.Getter; -import lombok.Setter; -import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2SsoProperties; - -@Getter -@Setter -public class OAuthProperties extends OAuth2SsoProperties { - - private String redirectUrl; - - public String getLoginPath() { - return super.getLoginPath() + redirectUrl; - } -} diff --git a/src/main/java/com/docusign/security/jwt/JWTAuthorizationCodeResourceDetails.java b/src/main/java/com/docusign/security/jwt/JWTAuthorizationCodeResourceDetails.java deleted file mode 100644 index 541c0a53..00000000 --- a/src/main/java/com/docusign/security/jwt/JWTAuthorizationCodeResourceDetails.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.docusign.security.jwt; - -import com.docusign.esign.client.ApiClient; -import com.docusign.exception.LauncherException; -import java.io.IOException; -import lombok.Getter; -import lombok.Setter; -import org.springframework.core.io.FileSystemResource; -import org.springframework.security.oauth2.client.token.grant.redirect.AbstractRedirectResourceDetails; -import org.springframework.util.FileCopyUtils; - -@Getter -@Setter -public class JWTAuthorizationCodeResourceDetails extends AbstractRedirectResourceDetails { - - private String privateKeyPath; - private String impersonatedUserGuid; - private String baseUrl; - - private FileSystemResource rsaPrivateKey; - private final ApiClient apiClient = new ApiClient(); - - public byte[] getRsaBytes() throws LauncherException { - if (rsaPrivateKey == null) { - rsaPrivateKey = new FileSystemResource(privateKeyPath); - } - try { - return FileCopyUtils.copyToByteArray(rsaPrivateKey.getInputStream()); - } catch (IOException e) { - throw new LauncherException("Error reading rsa file. Check configuration"); - } - } - - public ApiClient getApiClient() { - return apiClient; - } -} diff --git a/src/main/java/com/docusign/security/jwt/JWTOAuth2RestTemplate.java b/src/main/java/com/docusign/security/jwt/JWTOAuth2RestTemplate.java deleted file mode 100644 index a0dd6793..00000000 --- a/src/main/java/com/docusign/security/jwt/JWTOAuth2RestTemplate.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.docusign.security.jwt; - -import com.docusign.esign.client.ApiClient; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.client.auth.OAuth; -import com.docusign.esign.client.auth.OAuth.OAuthToken; -import com.docusign.exception.LauncherException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.oauth2.client.OAuth2ClientContext; -import org.springframework.security.oauth2.client.OAuth2RestTemplate; -import org.springframework.security.oauth2.client.http.AccessTokenRequiredException; -import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException; -import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; -import org.springframework.security.oauth2.common.OAuth2AccessToken; - -public class JWTOAuth2RestTemplate extends OAuth2RestTemplate { - - private static final Logger logger = LoggerFactory.getLogger(JWTOAuth2RestTemplate.class); - private static final long TOKEN_EXPIRATION_IN_SECONDS = 3600; - - private final JWTAuthorizationCodeResourceDetails resource; - private final OAuth2ClientContext context; - private ApiClient apiClient; - - public JWTOAuth2RestTemplate(JWTAuthorizationCodeResourceDetails resource, OAuth2ClientContext context) { - super(resource, context); - this.resource = resource; - this.context = context; - apiClient = resource.getApiClient(); - } - - @Override - public OAuth2AccessToken getAccessToken() throws UserRedirectRequiredException { - OAuth2AccessToken accessToken = context.getAccessToken(); - - if (accessToken == null || accessToken.isExpired()) { - try { - accessToken = accessToken(); - context.setAccessToken(accessToken); - } catch (Exception e) { - context.setAccessToken(null); - throw e; - } - } - return accessToken; - } - - private OAuth2AccessToken accessToken() { - logger.info("Fetching an access token via JWT grant..."); - List scopes = new ArrayList<>(); - // Only signature scope is needed. Impersonation scope is implied. - scopes.add(OAuth.Scope_SIGNATURE); - byte[] privateKeyBytes; - try { - privateKeyBytes = resource.getRsaBytes(); - } catch (LauncherException e) { - throw new AccessTokenRequiredException(e.getMessage(), resource); - } - apiClient.setOAuthBasePath(resource.getBaseUrl()); - OAuthToken oAuthToken; - try { - oAuthToken = apiClient.requestJWTUserToken( - resource.getClientId(), - resource.getImpersonatedUserGuid(), - scopes, - privateKeyBytes, - TOKEN_EXPIRATION_IN_SECONDS); - } catch (IOException | ApiException e) { - throw new AccessTokenRequiredException(e.getMessage(), resource); - } - apiClient.setAccessToken(oAuthToken.getAccessToken(), oAuthToken.getExpiresIn()); - logger.info("Done. Continuing..."); - return convert(oAuthToken); - } - - private static OAuth2AccessToken convert(OAuthToken oAuthToken) { - DefaultOAuth2AccessToken accessToken = new DefaultOAuth2AccessToken(oAuthToken.getAccessToken()); - accessToken.setExpiration(new Date(System.currentTimeMillis() + (oAuthToken.getExpiresIn() * 1000))); - accessToken.setTokenType(oAuthToken.getTokenType()); - return accessToken; - } - -} diff --git a/src/main/java/com/docusign/security/jwt/JWTUserInfoTokenService.java b/src/main/java/com/docusign/security/jwt/JWTUserInfoTokenService.java deleted file mode 100644 index dc684c72..00000000 --- a/src/main/java/com/docusign/security/jwt/JWTUserInfoTokenService.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.docusign.security.jwt; - -import com.docusign.esign.client.ApiClient; -import com.docusign.esign.client.ApiException; -import com.docusign.esign.client.auth.OAuth.Account; -import com.docusign.esign.client.auth.OAuth.UserInfo; -import com.docusign.utils.AccountsConverter; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import org.springframework.security.authentication.AuthenticationServiceException; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.security.oauth2.provider.OAuth2Request; -import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices; - -public class JWTUserInfoTokenService implements ResourceServerTokenServices { - - private static final String AUTHORITIES = "ROLE_USER"; - - private final JWTAuthorizationCodeResourceDetails resource; - private ApiClient apiClient; - - public JWTUserInfoTokenService(JWTAuthorizationCodeResourceDetails resource) { - this.resource = resource; - apiClient = resource.getApiClient(); - } - - @Override - public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException { - UserInfo userInfo; - try { - userInfo = apiClient.getUserInfo(apiClient.getAccessToken()); - } catch (ApiException e) { - throw new AuthenticationServiceException("Cannot authenticate", e); - } - return convert(userInfo, resource.getClientId()); - } - - @Override - public OAuth2AccessToken readAccessToken(String accessToken) { - throw new UnsupportedOperationException("Not supported: read access token"); - } - - private static OAuth2Authentication convert(UserInfo userInfo, String clientId) { - List accounts = userInfo.getAccounts(); - Object principal = userInfo.getName() == null ? "unknown" : userInfo.getName(); - List authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(AUTHORITIES); - OAuth2Request request = new OAuth2Request(null, clientId, null, true, null, - null, null, null, null); - UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken( - principal, "N/A", authorities); - Map details = new LinkedHashMap<>(); - List> accountsAsMap = accounts.stream() - .map(AccountsConverter::convert) - .collect(Collectors.toList()); - details.put("accounts", accountsAsMap); - token.setDetails(details); - return new OAuth2Authentication(request, token); - } -} diff --git a/src/main/resources/Id.jpg b/src/main/resources/Id.jpg new file mode 100644 index 00000000..423ddde8 Binary files /dev/null and b/src/main/resources/Id.jpg differ diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..6886d440 --- /dev/null +++ b/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.env.PropertySourceLoader=\ +com.docusign.JsonPropertySourceLoader \ No newline at end of file diff --git a/src/main/resources/Offer_Letter_Dynamic_Table.docx b/src/main/resources/Offer_Letter_Dynamic_Table.docx new file mode 100644 index 00000000..8c109bee Binary files /dev/null and b/src/main/resources/Offer_Letter_Dynamic_Table.docx differ diff --git a/src/main/resources/TermsOfService.pdf b/src/main/resources/TermsOfService.pdf new file mode 100644 index 00000000..827e04a8 Binary files /dev/null and b/src/main/resources/TermsOfService.pdf differ diff --git a/src/main/resources/Welcome.txt b/src/main/resources/Welcome.txt new file mode 100644 index 00000000..797f3bda --- /dev/null +++ b/src/main/resources/Welcome.txt @@ -0,0 +1,11 @@ + + + + + Welcome to the DocuSign Recruiting Event + + + Please Sign in! + + + \ No newline at end of file diff --git a/src/main/resources/Welcome1.txt b/src/main/resources/Welcome1.txt new file mode 100644 index 00000000..642eb799 --- /dev/null +++ b/src/main/resources/Welcome1.txt @@ -0,0 +1,3 @@ +Thanks for reviewing this! + +We'll move forward as soon as we hear back. \ No newline at end of file diff --git a/src/main/resources/World_Wide_Corp_Web_Form.pdf b/src/main/resources/World_Wide_Corp_Web_Form.pdf new file mode 100644 index 00000000..b6af1fa0 Binary files /dev/null and b/src/main/resources/World_Wide_Corp_Web_Form.pdf differ diff --git a/src/main/resources/application.example.json b/src/main/resources/application.example.json new file mode 100644 index 00000000..8e01adca --- /dev/null +++ b/src/main/resources/application.example.json @@ -0,0 +1,78 @@ +{ + "quickstart": "{QUICKSTART_VALUE}", + "quickACG": "{QUICK_ACG_VALUE}", + "DS_SIGNER_NAME": "{SIGNER_NAME}", + "DS_SIGNER_EMAIL": "{SIGNER_EMAIL}", + "DS_APP_URL": "http://localhost:8080", + "DS_TARGET_ACCOUNT_ID": "{DS_TARGET_ACCOUNT_ID}", + "DS_BASE_PATH": "https://demo.docusign.net", + "DS_ROOMS_BASE_PATH": "https://demo.rooms.docusign.com", + "DS_CLICK_BASE_PATH": "https://demo.docusign.net", + "DS_MONITOR_BASE_PATH": "https://lens-d.docusign.net", + "DS_ADMIN_BASE_PATH": "https://api-d.docusign.net", + "DS_WEBFORMS_BASE_PATH": "https://apps-d.docusign.com/api/webforms", + + "Gateway_Name": "{DS_PAYMENT_GATEWAY_NAME}", + "Gateway_Account_Id": "{GATEWAY_ACCOUNT_ID}", + "Gateway_Display_Name": "{DS_PAYMENT_GATEWAY_DISPLAY_NAME}", + + "authorization.code.grant.sso.redirect-url": "/oauth2/authorization/acg", + "jwt.grant.sso.redirect-url": "/oauth2/authorization/jwt", + "jwt.grant.client.base-url": "account-d.docusign.com", + "spring": { + "security": { + "oauth2": { + "client": { + "registration": { + "acg": { + "client-id": "{INTEGRATION_KEY_AUTH_CODE}", + "client-secret": "{SECRET_KEY}", + "client-authentication-method": "client_secret_basic", + "authorization-grant-type": "authorization_code", + "redirect-uri": "{baseUrl}/login/oauth2/code/acg", + "scope": "user_write, signature, impersonation, group_read, organization_read, permission_read, user_read, account_read, domain_read, identity_provider_read, user_data_redact, click.manage, click.send, dtr.rooms.read, dtr.rooms.write, dtr.documents.read, dtr.documents.write, dtr.profile.read, dtr.profile.write, dtr.company.read, dtr.company.write, room_forms, asset_group_account_read, asset_group_account_clone_write, asset_group_account_clone_read, webforms_read, webforms_instance_read, webforms_instance_write, aow_manage, organization_sub_account_write, organization_sub_account_read, adm_store_unified_repo_read, document_uploader_write, document_uploader_read" + }, + "jwt": { + "client-id": "{INTEGRATION_KEY_JWT}", + "impersonated-user-guid": "{IMPERSONATED_USER_ID}", + "private-key-path": "src/main/resources/private.key", + "authorization-grant-type": "authorization_code", + "redirect-uri": "{baseUrl}/login/oauth2/code/jwt" + } + }, + "provider": { + "acg": { + "authorization-uri": "https://account-d.docusign.com/oauth/auth?prompt=login", + "token-uri": "https://account-d.docusign.com/oauth/token", + "user-info-uri": "https://account-d.docusign.com/oauth/userinfo", + "user-name-attribute": "sub" + }, + "jwt": { + "authorization-uri": "https://account-d.docusign.com/oauth/auth?prompt=login", + "token-uri": "https://account-d.docusign.com/oauth/token", + "user-info-uri": "https://account-d.docusign.com/oauth/userinfo", + "user-name-attribute": "sub" + } + } + } + } + } + }, + + "common.client.resource.user-info-uri": "https://account-d.docusign.com/oauth/userinfo", + "com.docusign.github.example-uri": "https://github.com/docusign/code-examples-java/blob/master/src/main/java/", + "com.docusign.documentation-path": "", + + "CodeExamplesManifest": "https://raw.githubusercontent.com/docusign/code-examples-csharp/master/manifest/CodeExamplesManifest.json", + + "server.tomcat.additional-tld-skip-patterns": "*jaxb*.jar", + "server.servlet.session.tracking-modes": "cookie", + "server.servlet.session.persistent": false, + "server.error.include-stacktrace": "always", + "server.error.whitelabel.enabled": false, + + "spring.session.store-type": "none", + "spring.mvc.view.prefix": "/WEB-INF/templates/views/", + "spring.mvc.view.suffix": ".jsp", + "spring.jmx.enabled": false +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index e8834828..00000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1,51 +0,0 @@ -DS_SIGNER_EMAIL={SIGNER_EMAIL} -DS_SIGNER_NAME={SIGNER_NAME} -# Set if you want a specific DocuSign AccountId, If null, the user's default account will be used. -DS_TARGET_ACCOUNT_ID={IMPERSONATED_USER_GUID} -# The client id (Integrator Key) must include a Redirect URI of /login appended -# to the DS_APP_URL. Eg http://localhost:8080/login -DS_APP_URL=http://localhost:8080 - -# Optional settings for a payment gateway -Gateway_Account_Id={DS_PAYMENT_GATEWAY_ID} -Gateway_Name={DS_PAYMENT_GATEWAY_NAME} -Gateway_Display_Name={DS_PAYMENT_GATEWAY_DISPLAY_NAME} - -spring.jmx.enabled=false -# this option is needed for preventing annoying warning related to missing JAXB -# dependecies which had been excluded from the Java 11 -server.tomcat.additional-tld-skip-patterns=*jaxb*.jar - -server.servlet.session.tracking-modes=cookie -server.servlet.session.persistent=false -spring.session.store-type=none -server.error.whitelabel.enabled=false -server.error.include-stacktrace=always - -spring.mvc.view.prefix=/WEB-INF/templates/views/ -spring.mvc.view.suffix=.jsp - -# location of the source code of examples -com.docusign.github.example-uri=https://github.com/docusign/eg-03-java-auth-code-grant/blob/master/src/main/java/ -com.docusign.documentation-path= - -#JWT Grant client: -jwt.grant.client.client-id={JWT_API_ACCOUNT_ID} -jwt.grant.client.impersonated-user-guid={JWT_USER_IMPERSONATED_GUID} -jwt.grant.client.base-url=account-d.docusign.com -jwt.grant.client.scope=signature impersonation -jwt.grant.client.private-key-path=src/main/resources/private.key -#To distinguish authentication. Add to redirect urls -jwt.grant.sso.redirect-url=&type=jwt - -#Authorization Code Grant (acg) client: -authorization.code.grant.client.client-id={INTEGRATION_ID} -authorization.code.grant.client.client-secret={INTEGRATION_SECRET} -authorization.code.grant.client.user-authorization-uri=https://account-d.docusign.com/oauth/auth?prompt=login -authorization.code.grant.client.access-token-uri=https://account-d.docusign.com/oauth/token -authorization.code.grant.client.scope=signature -#To distinguish authentication. Add to redirect urls -authorization.code.grant.sso.redirect-url=&type=acg - -#User info -common.client.resource.user-info-uri=https://account-d.docusign.com/oauth/userinfo diff --git a/src/main/resources/applicationJsonMissingError.html b/src/main/resources/applicationJsonMissingError.html new file mode 100644 index 00000000..58dca646 --- /dev/null +++ b/src/main/resources/applicationJsonMissingError.html @@ -0,0 +1,74 @@ + + + + + + + + + + Error finding the application.json file + + + + + + + + + + + + + + +
+
+

Problem: an error occurred

+ +

Error information:

+

Message: While trying to launch the code examples, the application.json file could not been found.

+

Please, create the file and fill it in using the + template, then restart a launcher.

+
+
+ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/doc_1.html b/src/main/resources/doc_1.html new file mode 100644 index 00000000..f11b1d6b --- /dev/null +++ b/src/main/resources/doc_1.html @@ -0,0 +1,21 @@ + + + + + + +

World Wide Corp

+

Order Processing Division

+

Ordered by {USER_FULLNAME}

+

Email: {USER_EMAIL}

+

Copy to: {CC_NAME}, {CC_EMAIL}

+

+Candy bonbon pastry jujubes lollipop wafer biscuit biscuit. Topping brownie sesame snaps sweet roll pie. Croissant danish biscuit soufflé caramels jujubes jelly. Dragée danish caramels lemon drops dragée. Gummi bears cupcake biscuit tiramisu sugar plum pastry. Dragée gummies applicake pudding liquorice. Donut jujubes oat cake jelly-o. Dessert bear claw chocolate cake gummies lollipop sugar plum ice cream gummies cheesecake. +

+ +

Agreed: **signature_1**/

+ + diff --git a/src/main/resources/maestro-workflow-definition.json b/src/main/resources/maestro-workflow-definition.json new file mode 100644 index 00000000..73b33a73 --- /dev/null +++ b/src/main/resources/maestro-workflow-definition.json @@ -0,0 +1,522 @@ +{ + "workflowDefinition":{ + "workflowName":"Example workflow - send invite to signer", + "workflowDescription":"", + "accountId":"ACCOUNT_ID", + "documentVersion":"1.0.0", + "schemaVersion":"1.0.0", + "participants":{ + "SIGNER_ID":{ + "participantRole":"Signer" + }, + "CC_ID":{ + "participantRole":"CC" + } + }, + "trigger":{ + "name":"Get_URL", + "type":"Http", + "httpType":"Get", + "id":"TRIGGER_ID", + "input":{ + "metadata":{ + "customAttributes":{ + + } + }, + "payload":{ + "dacId_TRIGGER_ID":{ + "source":"step", + "propertyName":"dacId", + "stepId":"TRIGGER_ID" + }, + "id_TRIGGER_ID":{ + "source":"step", + "propertyName":"id", + "stepId":"TRIGGER_ID" + }, + "signerName_TRIGGER_ID":{ + "source":"step", + "propertyName":"signerName", + "stepId":"TRIGGER_ID" + }, + "signerEmail_TRIGGER_ID":{ + "source":"step", + "propertyName":"signerEmail", + "stepId":"TRIGGER_ID" + }, + "ccName_TRIGGER_ID":{ + "source":"step", + "propertyName":"ccName", + "stepId":"TRIGGER_ID" + }, + "ccEmail_TRIGGER_ID":{ + "source":"step", + "propertyName":"ccEmail", + "stepId":"TRIGGER_ID" + } + }, + "participants":{ + + } + }, + "output":{ + "dacId_TRIGGER_ID":{ + "source":"step", + "propertyName":"dacId", + "stepId":"TRIGGER_ID" + } + }, + "type":"API" + }, + "variables":{ + "dacId_TRIGGER_ID":{ + "source":"step", + "propertyName":"dacId", + "stepId":"TRIGGER_ID" + }, + "id_TRIGGER_ID":{ + "source":"step", + "propertyName":"id", + "stepId":"TRIGGER_ID" + }, + "signerName_TRIGGER_ID":{ + "source":"step", + "propertyName":"signerName", + "stepId":"TRIGGER_ID" + }, + "signerEmail_TRIGGER_ID":{ + "source":"step", + "propertyName":"signerEmail", + "stepId":"TRIGGER_ID" + }, + "ccName_TRIGGER_ID":{ + "source":"step", + "propertyName":"ccName", + "stepId":"TRIGGER_ID" + }, + "ccEmail_TRIGGER_ID":{ + "source":"step", + "propertyName":"ccEmail", + "stepId":"TRIGGER_ID" + }, + "envelopeId_step2":{ + "source":"step", + "propertyName":"envelopeId", + "stepId":"step2", + "type":"String" + }, + "combinedDocumentsBase64_step2":{ + "source":"step", + "propertyName":"combinedDocumentsBase64", + "stepId":"step2", + "type":"File" + }, + "fields.signer.text.value_step2":{ + "source":"step", + "propertyName":"fields.signer.text.value", + "stepId":"step2", + "type":"String" + } + }, + "steps":[ + { + "id":"step2", + "name":"Get Signatures", + "moduleName":"ESign", + "configurationProgress":"Completed", + "type":"DS-Sign", + "config":{ + "participantId":"SIGNER_ID" + }, + "input":{ + "isEmbeddedSign":true, + "documents":[ + { + "type":"FromDSTemplate", + "eSignTemplateId":"TEMPLATE_ID" + } + ], + "emailSubject":"Please sign this document", + "emailBlurb":"", + "recipients":{ + "signers":[ + { + "defaultRecipient":"false", + "tabs":{ + "signHereTabs":[ + { + "stampType":"signature", + "name":"SignHere", + "tabLabel":"Sign Here", + "scaleValue":"1", + "optional":"false", + "documentId":"1", + "recipientId":"1", + "pageNumber":"1", + "xPosition":"191", + "yPosition":"148", + "tabId":"1", + "tabType":"signhere" + } + ], + "textTabs":[ + { + "requireAll":"false", + "value":"", + "required":"false", + "locked":"false", + "concealValueOnDocument":"false", + "disableAutoSize":"false", + "tabLabel":"text", + "font":"helvetica", + "fontSize":"size14", + "localePolicy":{ + + }, + "documentId":"1", + "recipientId":"1", + "pageNumber":"1", + "xPosition":"153", + "yPosition":"230", + "width":"84", + "height":"23", + "tabId":"2", + "tabType":"text" + } + ], + "checkboxTabs":[ + { + "name":"", + "tabLabel":"ckAuthorization", + "selected":"false", + "selectedOriginal":"false", + "requireInitialOnSharedChange":"false", + "required":"true", + "locked":"false", + "documentId":"1", + "recipientId":"1", + "pageNumber":"1", + "xPosition":"75", + "yPosition":"417", + "width":"0", + "height":"0", + "tabId":"3", + "tabType":"checkbox" + }, + { + "name":"", + "tabLabel":"ckAuthentication", + "selected":"false", + "selectedOriginal":"false", + "requireInitialOnSharedChange":"false", + "required":"true", + "locked":"false", + "documentId":"1", + "recipientId":"1", + "pageNumber":"1", + "xPosition":"75", + "yPosition":"447", + "width":"0", + "height":"0", + "tabId":"4", + "tabType":"checkbox" + }, + { + "name":"", + "tabLabel":"ckAgreement", + "selected":"false", + "selectedOriginal":"false", + "requireInitialOnSharedChange":"false", + "required":"true", + "locked":"false", + "documentId":"1", + "recipientId":"1", + "pageNumber":"1", + "xPosition":"75", + "yPosition":"478", + "width":"0", + "height":"0", + "tabId":"5", + "tabType":"checkbox" + }, + { + "name":"", + "tabLabel":"ckAcknowledgement", + "selected":"false", + "selectedOriginal":"false", + "requireInitialOnSharedChange":"false", + "required":"true", + "locked":"false", + "documentId":"1", + "recipientId":"1", + "pageNumber":"1", + "xPosition":"75", + "yPosition":"508", + "width":"0", + "height":"0", + "tabId":"6", + "tabType":"checkbox" + } + ], + "radioGroupTabs":[ + { + "documentId":"1", + "recipientId":"1", + "groupName":"radio1", + "radios":[ + { + "pageNumber":"1", + "xPosition":"142", + "yPosition":"384", + "value":"white", + "selected":"false", + "tabId":"7", + "required":"false", + "locked":"false", + "bold":"false", + "italic":"false", + "underline":"false", + "fontColor":"black", + "fontSize":"size7" + }, + { + "pageNumber":"1", + "xPosition":"74", + "yPosition":"384", + "value":"red", + "selected":"false", + "tabId":"8", + "required":"false", + "locked":"false", + "bold":"false", + "italic":"false", + "underline":"false", + "fontColor":"black", + "fontSize":"size7" + }, + { + "pageNumber":"1", + "xPosition":"220", + "yPosition":"384", + "value":"blue", + "selected":"false", + "tabId":"9", + "required":"false", + "locked":"false", + "bold":"false", + "italic":"false", + "underline":"false", + "fontColor":"black", + "fontSize":"size7" + } + ], + "shared":"false", + "requireInitialOnSharedChange":"false", + "requireAll":"false", + "tabType":"radiogroup", + "value":"", + "originalValue":"" + } + ], + "listTabs":[ + { + "listItems":[ + { + "text":"Red", + "value":"red", + "selected":"false" + }, + { + "text":"Orange", + "value":"orange", + "selected":"false" + }, + { + "text":"Yellow", + "value":"yellow", + "selected":"false" + }, + { + "text":"Green", + "value":"green", + "selected":"false" + }, + { + "text":"Blue", + "value":"blue", + "selected":"false" + }, + { + "text":"Indigo", + "value":"indigo", + "selected":"false" + }, + { + "text":"Violet", + "value":"violet", + "selected":"false" + } + ], + "value":"", + "originalValue":"", + "required":"false", + "locked":"false", + "requireAll":"false", + "tabLabel":"list", + "font":"helvetica", + "fontSize":"size14", + "localePolicy":{ + + }, + "documentId":"1", + "recipientId":"1", + "pageNumber":"1", + "xPosition":"142", + "yPosition":"291", + "width":"78", + "height":"0", + "tabId":"10", + "tabType":"list" + } + ], + "numericalTabs":[ + { + "validationType":"currency", + "value":"", + "required":"false", + "locked":"false", + "concealValueOnDocument":"false", + "disableAutoSize":"false", + "tabLabel":"numericalCurrency", + "font":"helvetica", + "fontSize":"size14", + "localePolicy":{ + "cultureName":"en-US", + "currencyPositiveFormat":"csym_1_comma_234_comma_567_period_89", + "currencyNegativeFormat":"opar_csym_1_comma_234_comma_567_period_89_cpar", + "currencyCode":"usd" + }, + "documentId":"1", + "recipientId":"1", + "pageNumber":"1", + "xPosition":"163", + "yPosition":"260", + "width":"84", + "height":"0", + "tabId":"11", + "tabType":"numerical" + } + ] + }, + "signInEachLocation":"false", + "agentCanEditEmail":"false", + "agentCanEditName":"false", + "requireUploadSignature":"false", + "name":{ + "source":"step", + "propertyName":"signerName", + "stepId":"TRIGGER_ID" + }, + "email":{ + "source":"step", + "propertyName":"signerEmail", + "stepId":"TRIGGER_ID" + }, + "recipientId":"1", + "recipientIdGuid":"00000000-0000-0000-0000-000000000000", + "accessCode":"", + "requireIdLookup":"false", + "routingOrder":"1", + "note":"", + "roleName":"signer", + "completedCount":"0", + "deliveryMethod":"email", + "templateLocked":"false", + "templateRequired":"false", + "inheritEmailNotificationConfiguration":"false", + "recipientType":"signer" + } + ], + "carbonCopies":[ + { + "agentCanEditEmail":"false", + "agentCanEditName":"false", + "name":{ + "source":"step", + "propertyName":"ccName", + "stepId":"TRIGGER_ID" + }, + "email":{ + "source":"step", + "propertyName":"ccEmail", + "stepId":"TRIGGER_ID" + }, + "recipientId":"2", + "recipientIdGuid":"00000000-0000-0000-0000-000000000000", + "accessCode":"", + "requireIdLookup":"false", + "routingOrder":"2", + "note":"", + "roleName":"cc", + "completedCount":"0", + "deliveryMethod":"email", + "templateLocked":"false", + "templateRequired":"false", + "inheritEmailNotificationConfiguration":"false", + "recipientType":"carboncopy" + } + ], + "certifiedDeliveries":[ + + ] + } + }, + "output":{ + "envelopeId_step2":{ + "source":"step", + "propertyName":"envelopeId", + "stepId":"step2", + "type":"String" + }, + "combinedDocumentsBase64_step2":{ + "source":"step", + "propertyName":"combinedDocumentsBase64", + "stepId":"step2", + "type":"File" + }, + "fields.signer.text.value_step2":{ + "source":"step", + "propertyName":"fields.signer.text.value", + "stepId":"step2", + "type":"String" + } + } + }, + { + "id":"step3", + "name":"Show a Confirmation Screen", + "moduleName":"ShowConfirmationScreen", + "configurationProgress":"Completed", + "type":"DS-ShowScreenStep", + "config":{ + "participantId":"SIGNER_ID" + }, + "input":{ + "httpType":"Post", + "payload":{ + "participantId":"SIGNER_ID", + "confirmationMessage":{ + "title":"Tasks complete", + "description":"You have completed all your workflow tasks." + } + } + }, + "output":{ + + }, + "triggerType":"API" + } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/order_form.html b/src/main/resources/order_form.html index cddf3704..15b87ddb 100644 --- a/src/main/resources/order_form.html +++ b/src/main/resources/order_form.html @@ -29,7 +29,7 @@

Ordered by {signerName}

Harmonica - /l1q/ + /l1q/ $5 @@ -39,7 +39,7 @@

Ordered by {signerName}

Xylophone - /l2q/ + /l2q/ $150 diff --git a/src/main/resources/public/assets/banner-code.png b/src/main/resources/public/assets/banner-code.png new file mode 100644 index 00000000..5c89023d Binary files /dev/null and b/src/main/resources/public/assets/banner-code.png differ diff --git a/src/main/resources/public/assets/css.css b/src/main/resources/public/assets/css.css index 40080201..ebd7bee3 100644 --- a/src/main/resources/public/assets/css.css +++ b/src/main/resources/public/assets/css.css @@ -6,35 +6,65 @@ body { #index-page h4 { z-index: -100; } + #index-page h4::before { z-index: -100; - display: block; - content: " "; - margin-top: -4rem; - height: 4rem; - visibility: hidden; + display: block; + content: " "; + margin-top: -4rem; + height: 4rem; + visibility: hidden; pointer-events: none; } +#content { + margin: 0 20px 0 20px; +} + .jumbotron { - background: #888888; - padding: 3em; + background-image: url(/assets/banner-code.png) !important; + background-position: right; + min-height: 500px; + padding-top: 0 !important; + padding-bottom: 0 !important; + padding-left: 30px !important; + padding-right: 30px !important; + margin: -24px !important; color: white; - margin: 1em auto 1.5em; } +} .jumbotron p { margin-top: 1em; font-size: 1.45em; } +.btn-docu { + + background-color: #00BAA1; + color: #FFF; + border-color: #121517; +} + +.btn-docu:hover, +.btn-docu:focus, +.btn-docu:active, +.btn-docu.active, +.open .dropdown-toggle.btn-docu { + background-color: #02d6ba; + color: #FFF; + border-color: #050607; +} + hr.styled { - overflow: visible; /* For IE */ + overflow: visible; + /* For IE */ padding: 0; border: none; - border-top: medium double #333; - color: #333; + border-top: medium double 0; + color: #000; text-align: center; } + hr.styled:after { content: "§"; display: inline-block; @@ -45,38 +75,42 @@ hr.styled:after { background: white; } +.feedback, +.hidden { + display: none; +} -.feedback, .hidden {display: none;} -span.feedback {margin-left:2em;} +span.feedback { + margin-left: 2em; +} -form.eg {max-width: 30em;} -form.eg label {font-weight: 550;} +form.eg { + max-width: 30em; +} + +form.eg label { + font-weight: 550; +} pre.json-display { background-color: ghostwhite; border: 1px solid silver; padding: 10px 20px; - } +} + .json-key { color: brown; - } +} + .json-value { color: navy; - } +} + .json-string { color: olive; - } - -table, th, td { - background-color: #f4f4fb; - padding-left: 7px; - padding-right: 7px; - caption-side: top; } -th { - border-bottom: 1px solid black; -} + /* From http://tobiasahlin.com/spinkit/ */ @@ -88,7 +122,7 @@ th { font-size: 10px; } -.spinner > div { +.spinner>div { background-color: blueviolet; height: 100%; width: 6px; @@ -119,16 +153,54 @@ th { } @-webkit-keyframes sk-stretchdelay { - 0%, 40%, 100% { -webkit-transform: scaleY(0.4) } - 20% { -webkit-transform: scaleY(1.0) } + + 0%, + 40%, + 100% { + -webkit-transform: scaleY(0.4) + } + + 20% { + -webkit-transform: scaleY(1.0) + } } @keyframes sk-stretchdelay { - 0%, 40%, 100% { + + 0%, + 40%, + 100% { transform: scaleY(0.4); -webkit-transform: scaleY(0.4); - } 20% { + } + + 20% { transform: scaleY(1.0); -webkit-transform: scaleY(1.0); } } + +.your-class div { + float: left; + margin-left: 10px; +} + +.has-search .form-control { + padding-left: 2.375rem; +} + +.has-search .form-control-feedback { + position: absolute; + z-index: 2; + display: block; + width: 2.375rem; + height: 2.375rem; + line-height: 2.375rem; + text-align: center; + pointer-events: none; + color: #aaa; +} + +form .form-group .validation-error { + color: red !important; +} diff --git a/src/main/resources/public/assets/favicon.ico b/src/main/resources/public/assets/favicon.ico deleted file mode 100644 index b3b2dc49..00000000 Binary files a/src/main/resources/public/assets/favicon.ico and /dev/null differ diff --git a/src/main/resources/public/assets/favicon.png b/src/main/resources/public/assets/favicon.png new file mode 100644 index 00000000..fefff552 Binary files /dev/null and b/src/main/resources/public/assets/favicon.png differ diff --git a/src/main/resources/public/assets/search.js b/src/main/resources/public/assets/search.js new file mode 100644 index 00000000..8f0ad0f0 --- /dev/null +++ b/src/main/resources/public/assets/search.js @@ -0,0 +1,284 @@ +let DS_SEARCH = (function () { + const API_TYPES = { + ESIGNATURE: 'esignature', + MONITOR: 'monitor', + CLICK: 'click', + ROOMS: 'rooms', + ADMIN: 'admin', + CONNECT: 'connect', + WEBFORMS: 'webforms', + NOTARY: 'notary', + NAVIGATOR: 'navigator', + MAESTRO: "maestro", + CONNECTEDFIELDS: 'connectedfields', + WORKSPACES: 'workspaces', + }; + + let processJSONData = function () { + let json_raw = $("#api_json_data").text() + , json = json_raw ? JSON.parse(json_raw) : false; + + return json; + } + + let processCFR11Value = function () { + let json_raw = $("#cfr11_data").text(); + + return json_raw; + } + + function checkIfExampleMatches(example, matches) { + const name = example.ExampleName; + const description = example.ExampleDescription; + const pathNames = example.LinksToAPIMethod?.map(a => a.PathName); + + for (let i = 0; i < matches.length; i++) { + if (name === matches[i].value || description === matches[i].value || pathNames.indexOf(matches[i].value) > -1) { + return true; + } + } + + return false; + } + + function clearNonMatchingExamples(examples, matches) { + for (let i = examples.length - 1; i >= 0; i--) { + if (!checkIfExampleMatches(examples[i], matches)) { + examples.splice(i, 1); + } + } + } + + function clearResultsAfterMatching(api, matches) { + const groups = api.Groups; + + for (let i = groups.length - 1; i >= 0; i--) { + const group = groups[i]; + clearNonMatchingExamples(group.Examples, matches); + + if (group.Examples.length === 0) { + groups.splice(i, 1); + } + } + } + + let findCodeExamplesByKeywords = function (json, pattern) { + const options = { + isCaseSensitive: false, + threshold: -0.0, + includeMatches: true, + ignoreLocation: true, + useExtendedSearch: true, + keys: [ + "Groups.Examples.ExampleName", + "Groups.Examples.ExampleDescription", + "Groups.Examples.LinksToAPIMethod.PathName" + ] + }; + + let clearJSON = JSON.stringify(json).replace(/<\/?[^>]+(>|$)/g, ""); + const fuse = new Fuse(JSON.parse(clearJSON), options); + + var searchResults = fuse.search(JSON.stringify(pattern)); + + + + searchResults.forEach(searchResult => { + return clearResultsAfterMatching(searchResult.item, searchResult.matches) + }); + + return searchResults; + } + + let getExamplesByAPIType = function (apiType, codeExamples) { + let codeExamplesByAPI = codeExamples.find(x => x.Name.toLowerCase() === apiType); + + if (codeExamplesByAPI != null) { + return [codeExamplesByAPI]; + } else { + return null; + } + } + + let getEnteredAPIType = function (inputValue) { + const inputLength = inputValue.length; + + for (const key in API_TYPES) { + if (Object.hasOwnProperty.call(API_TYPES, key)) { + const apiType = API_TYPES[key]; + const comparedValue = apiType.substr(0, inputLength); + + if (inputValue === comparedValue) { + return apiType; + } + } + } + + return null; + } + + function getLinkForApiType(apiName) { + switch (apiName) { + case API_TYPES.ADMIN: + return "a"; + case API_TYPES.CLICK: + return "c"; + case API_TYPES.ROOMS: + return "r"; + case API_TYPES.MONITOR: + return "m"; + case API_TYPES.MAESTRO: + return "mae"; + case API_TYPES.ESIGNATURE: + return "eg"; + case API_TYPES.CONNECT: + return "con"; + case API_TYPES.WEBFORMS: + return "web"; + case API_TYPES.NOTARY: + return "n"; + case API_TYPES.NAVIGATOR: + return "nav"; + case API_TYPES.CONNECTEDFIELDS: + return "cf"; + case API_TYPES.WORKSPACES: + return "work"; + } + } + + let addCodeExampleToHomepage = function (codeExamples) { + var cfrPart11 = processCFR11Value(); + + codeExamples.forEach( + element => { + let linkToCodeExample = getLinkForApiType(element.Name.toLowerCase()); + + element.Groups.forEach( + group => { + $("#filtered_code_examples").append("

" + group.Name + "

"); + + group.Examples.forEach( + example => { + if (!example.SkipForLanguages || !example.SkipForLanguages.toLowerCase().includes("java")) { + if (element.Name.toLowerCase() !== API_TYPES.ESIGNATURE.toLowerCase() || + ((example.CFREnabled == "AllAccounts") || + ((cfrPart11 == "True") && (example.CFREnabled == "CFROnly")) || + ((cfrPart11 != "True") && (example.CFREnabled == "NonCFR")))) { + $("#filtered_code_examples").append( + "

" + + "" + + example.ExampleName + + "

" + ); + + $("#filtered_code_examples").append("

" + example.ExampleDescription + "

"); + + $("#filtered_code_examples").append("

"); + if (example.LinksToAPIMethod != undefined && example.LinksToAPIMethod?.length !== 0) { + if (example.LinksToAPIMethod.length == 1) { + $("#filtered_code_examples").append(processJSONData().SupportingTexts.APIMethodUsed); + } + else { + $("#filtered_code_examples").append(processJSONData().SupportingTexts.APIMethodUsedPlural); + } + + for (let index = 0; index < example.LinksToAPIMethod.length; index++) { + $("#filtered_code_examples").append( + " " + + example.LinksToAPIMethod[index].PathName + + "" + ); + + if (index + 1 === example.LinksToAPIMethod.length) { + $("#filtered_code_examples").append(""); + } + else if (index + 1 === example.LinksToAPIMethod.length - 1) { + $("#filtered_code_examples").append(" and "); + } + else { + $("#filtered_code_examples").append(", "); + } + + } + } + + $("#filtered_code_examples").append("

"); + } + } + } + ); + } + ); + } + ); + } + + let textCouldNotBeFound = function () { + $("#filtered_code_examples").append(processJSONData().SupportingTexts.SearchFailed); + } + + return { + processJSONData: processJSONData, + getEnteredAPIType: getEnteredAPIType, + getExamplesByAPIType: getExamplesByAPIType, + findCodeExamplesByKeywords: findCodeExamplesByKeywords, + textCouldNotBeFound: textCouldNotBeFound, + addCodeExampleToHomepage: addCodeExampleToHomepage + } +})(); + +const input = document.getElementById('code_example_search'); +const log = document.getElementById('values'); + +input.addEventListener('input', updateValue); + +function updateValue(esearchPattern) { + document.getElementById('filtered_code_examples').innerHTML = ""; + + const inputValue = esearchPattern.target.value.toLowerCase(); + const json = DS_SEARCH.processJSONData().APIs; + + if (inputValue === "") { + DS_SEARCH.addCodeExampleToHomepage(json); + } + else { + const apiType = DS_SEARCH.getEnteredAPIType(inputValue); + + if (apiType !== null) { + const adminExamples = DS_SEARCH.getExamplesByAPIType(apiType, json); + DS_SEARCH.addCodeExampleToHomepage(adminExamples); + } + else { + const result = DS_SEARCH.findCodeExamplesByKeywords(json, inputValue); + if (result.length < 1) { + DS_SEARCH.textCouldNotBeFound(); + } else { + result.forEach(x => { + var api = json.filter(api => { + return api.Name === x.item.Name; + })[0]; + + x.item.Groups.forEach((group, groupIndex) => { + var unfilteredGroup = api.Groups.filter(apiGroup => { + return apiGroup.Name === group.Name; + })[0]; + + group.Examples.forEach((example, index) => { + var clearedExample = unfilteredGroup.Examples.filter(apiExample => { + return apiExample.ExampleNumber === example.ExampleNumber; + })[0]; + x.item.Groups[groupIndex].Examples[index] = clearedExample; + }); + }); + + DS_SEARCH.addCodeExampleToHomepage([x.item]); + }); + } + } + } +} diff --git a/src/main/resources/public/assets/site.js b/src/main/resources/public/assets/site.js new file mode 100644 index 00000000..87a53af5 --- /dev/null +++ b/src/main/resources/public/assets/site.js @@ -0,0 +1,23 @@ +$(document).ready(function () { + $("#Products").on("change", function () { + $list = $("#PermissionProfilesFiltered"); + $.ajax({ + url: "/a008/getPermissionProfiles", + type: "GET", + data: { productId: $("#Products").val() }, + traditional: true, + dataType: "json", + success: function (result) { + console.log(result) + $list.empty(); + $.each(result, function (i, item) { + console.log(item) + $list.append(''); + }); + }, + error: function () { + console.warn("Issues with calling the getPermissionProfiles endpoint. Please, check the solution."); + } + }); + }); +}); diff --git a/src/main/resources/web-form-config.json b/src/main/resources/web-form-config.json new file mode 100644 index 00000000..da29f308 --- /dev/null +++ b/src/main/resources/web-form-config.json @@ -0,0 +1,673 @@ +{ + "id": "608a6c8a-16b2-4419-92f4-d06bc3af6e53", + "accountId": "85443307-xxxx-xxxx-xxxx-87671e153075", + "isPublished": true, + "isEnabled": true, + "hasDraftChanges": false, + "formState": "active", + "formProperties": { + "name": "Web Form Example Template", + "isPrivateAccess": false, + "allowSending": true + }, + "formMetadata": { + "source": "templates", + "createdDateTime": "2025-08-19T21:15:03.323Z", + "publishedSlug": "d12c1e15b310d55b4e530edfd64c1b63", + "owner": { + "userId": "53d98270-xxxx-xxxx-xxxx-6d080391b538", + "userName": "Raileen Del Rosario" + }, + "lastModifiedDateTime": "2025-08-19T21:18:40.409Z", + "lastModifiedBy": { + "userId": "53d98270-xxxx-xxxx-xxxx-6d080391b538", + "userName": "Raileen Del Rosario" + }, + "publishedComponentNames": { + "signer_name": "TextBox", + "signer_email": "Email", + "FullName": "TextBox", + "PhoneNumber": "TextBox", + "Yes": "CheckboxGroup", + "Company": "TextBox", + "JobTitle": "TextBox", + "$recipients": { + "41f3109b-ff3a-4c48-a40c-eac994ad0988": { + "components": { + "signer_name": { + "type": "TextBox" + }, + "signer_email": { + "type": "Email" + }, + "FullName": { + "type": "TextBox" + }, + "PhoneNumber": { + "type": "TextBox" + }, + "Yes": { + "type": "CheckboxGroup" + }, + "Company": { + "type": "TextBox" + }, + "JobTitle": { + "type": "TextBox" + } + } + } + } + }, + "admModelNamespace": "docusign.forms._85443307_664c_4c85_882f_87671e153075._608a6c8a_16b2_4419_92f4_d06bc3af6e53", + "formContentModifiedBy": { + "userId": "53d98270-xxxx-xxxx-xxxx-6d080391b538", + "userName": "Raileen Del Rosario" + }, + "formContentModifiedDateTime": "2025-08-19T21:18:09.337Z", + "admModelVersion": "1.0.0", + "type": "hasEsignTemplate", + "formPropertiesModifiedBy": { + "userId": "53d98270-xxxx-xxxx-xxxx-6d080391b538", + "userName": "Raileen Del Rosario" + }, + "formPropertiesModifiedDateTime": "2025-08-19T21:15:39.578Z", + "sender": { + "userId": "53d98270-xxxx-xxxx-xxxx-6d080391b538", + "userName": "Raileen Del Rosario" + }, + "lastSenderConsentDateTime": "2025-08-19T21:18:34.468Z", + "lastPublishedBy": { + "userId": "53d98270-xxxx-xxxx-xxxx-6d080391b538", + "userName": "Raileen Del Rosario" + }, + "lastPublishedDateTime": "2025-08-19T21:18:40.409Z", + "lastEnabledBy": { + "userId": "53d98270-xxxx-xxxx-xxxx-6d080391b538", + "userName": "Raileen Del Rosario" + }, + "lastEnabledDateTime": "2025-08-19T21:18:40.409Z" + }, + "formContent": { + "components": { + "Root_Of_Journey": { + "children": [ + "View_41f3109b-ff3a-4c48-a40c-eac994ad0988" + ], + "componentKey": "Root_Of_Journey", + "componentName": "Root_Of_Journey", + "componentRules": {}, + "componentType": "Root", + "schemaVersion": 2, + "text": "" + }, + "View_41f3109b-ff3a-4c48-a40c-eac994ad0988": { + "children": [ + "Welcome_qXWJJEvM", + "Step_69uweXrH", + "Summary_2KLFQRxQ", + "ESignAction_7XmnXEcI", + "Thankyou_feHjbCWS" + ], + "componentKey": "View_41f3109b-ff3a-4c48-a40c-eac994ad0988", + "componentType": "View", + "isEnabled": true, + "isSender": false, + "roleName": "signer" + }, + "Welcome_qXWJJEvM": { + "startButtonText": "Start", + "subText": "Part-Time Work Application", + "text": "Welcome", + "componentKey": "Welcome_qXWJJEvM", + "componentType": "Welcome" + }, + "Step_69uweXrH": { + "children": [ + "TextBox_OWBHFHgL", + "Email_cJoe6lNy", + "TextBox_FPT2Gs29", + "TextBox_BOTyRGju", + "CheckboxGroup_MyyHfWle", + "TextBox_mwg3Cl1O", + "TextBox_AHodbvx_" + ], + "componentKey": "Step_69uweXrH", + "componentName": "Step_69uweXrH", + "componentType": "Step", + "text": "Part-Time Work Application" + }, + "Summary_2KLFQRxQ": { + "subText": "Please review the information you have entered:", + "text": "Summary", + "componentKey": "Summary_2KLFQRxQ", + "componentType": "Summary" + }, + "ESignAction_7XmnXEcI": { + "componentKey": "ESignAction_7XmnXEcI", + "componentType": "ESignAction", + "documentInfoMap": { + "Document_fRTvNpa8": { + "documentId": "1", + "name": "World_Wide_Web_Form", + "order": "1" + } + }, + "enableDocumentFieldEditing": true, + "primaryRecipientId": "1", + "recipientInfoMap": { + "1": { + "emailComponentKey": "Email_cJoe6lNy", + "emailFromTemplate": "", + "nameComponentKey": "TextBox_OWBHFHgL", + "nameFromTemplate": "", + "recipientId": "1", + "recipientType": "signer", + "roleName": "signer", + "routingOrder": "1", + "recipientViewId": "41f3109b-ff3a-4c48-a40c-eac994ad0988" + } + }, + "requireRemoteSigning": false, + "tabInfoMap": { + "c995df10-9141-4686-b9bf-f1dfc4121d33": { + "componentKey": "TextBox_FPT2Gs29", + "locked": "false", + "recipientId": "1", + "tabId": "c995df10-9141-4686-b9bf-f1dfc4121d33", + "tabLabel": "FullName", + "tabType": "text" + }, + "71ccfefa-5469-493e-b0c7-886c65b84742": { + "componentKey": "TextBox_BOTyRGju", + "locked": "false", + "recipientId": "1", + "tabId": "71ccfefa-5469-493e-b0c7-886c65b84742", + "tabLabel": "PhoneNumber", + "tabType": "text" + }, + "184f8a65-f2be-48b9-a30e-15592c59b335": { + "componentKey": "TextBox_mwg3Cl1O", + "locked": "false", + "recipientId": "1", + "tabId": "184f8a65-f2be-48b9-a30e-15592c59b335", + "tabLabel": "Company", + "tabType": "text" + }, + "e7d30733-ce70-4fee-93a0-ea10ecc014b1": { + "componentKey": "TextBox_AHodbvx_", + "locked": "false", + "recipientId": "1", + "tabId": "e7d30733-ce70-4fee-93a0-ea10ecc014b1", + "tabLabel": "JobTitle", + "tabType": "text" + }, + "0f1e242d-550d-4729-a141-de0dce1d1b6c": { + "componentKey": "CheckboxGroup_MyyHfWle", + "locked": "false", + "name": "Yes", + "recipientId": "1", + "selected": "false", + "tabId": "0f1e242d-550d-4729-a141-de0dce1d1b6c", + "tabLabel": "Yes", + "tabType": "checkbox" + } + }, + "templateInfoMap": { + "2230c545-1680-47aa-8581-7d2284093f46": { + "lastModified": "2025-08-19T21:15:03.9670000Z", + "name": "Web Form Copy - Web Form Example Template", + "owner": { + "userName": "Raileen Del Rosario", + "userId": "53d98270-xxxx-xxxx-xxxx-6d080391b538", + "email": "example@email.com" + }, + "templateId": "e8af8a0d-f7ab-4cd2-b6f5-c84d5ecc1bf8" + } + } + }, + "Thankyou_feHjbCWS": { + "confirmationButtonText": "Done", + "confirmationButtonUrl": "", + "showConfirmationButton": false, + "subText": "We've received your form.", + "text": "Thank you", + "componentKey": "Thankyou_feHjbCWS", + "componentType": "Thankyou" + }, + "TextBox_OWBHFHgL": { + "componentKey": "TextBox_OWBHFHgL", + "componentName": "signer_name", + "componentType": "TextBox", + "description": "", + "label": "Signer Name", + "maxLength": 4000, + "multiLine": false, + "placeholder": "", + "required": true + }, + "Email_cJoe6lNy": { + "componentKey": "Email_cJoe6lNy", + "componentName": "signer_email", + "componentType": "Email", + "description": "", + "label": "Signer Email", + "maxLength": 4000, + "multiLine": false, + "placeholder": "", + "required": true + }, + "TextBox_FPT2Gs29": { + "componentKey": "TextBox_FPT2Gs29", + "componentName": "FullName", + "componentType": "TextBox", + "description": "", + "label": "Full Name", + "maxLength": 4000, + "multiLine": false, + "placeholder": "", + "required": true + }, + "TextBox_BOTyRGju": { + "componentKey": "TextBox_BOTyRGju", + "componentName": "PhoneNumber", + "componentType": "TextBox", + "description": "", + "label": "Phone Number", + "maxLength": 4000, + "multiLine": false, + "placeholder": "", + "required": true + }, + "CheckboxGroup_MyyHfWle": { + "componentKey": "CheckboxGroup_MyyHfWle", + "componentName": "Yes", + "componentType": "CheckboxGroup", + "description": "", + "label": "I prefer to be contacted by text.", + "options": [ + { + "label": "Yes", + "optionKey": "i_BVfm2G", + "selected": false, + "value": "Yes" + } + ] + }, + "TextBox_mwg3Cl1O": { + "componentKey": "TextBox_mwg3Cl1O", + "componentName": "Company", + "componentType": "TextBox", + "description": "", + "label": "Company", + "maxLength": 4000, + "multiLine": false, + "placeholder": "", + "required": true + }, + "TextBox_AHodbvx_": { + "componentKey": "TextBox_AHodbvx_", + "componentName": "JobTitle", + "componentType": "TextBox", + "description": "", + "label": "Job Title", + "maxLength": 4000, + "multiLine": false, + "placeholder": "", + "required": true + } + }, + "isStandalone": false, + "templates": [ + { + "originalTemplateId": "e8af8a0d-f7ab-4cd2-b6f5-c84d5ecc1bf8", + "clonedTemplateId": "e8af8a0d-f7ab-4cd2-b6f5-c84d5ecc1bf8", + "importedDateTime": "2025-08-19T21:15:05.277Z", + "recipientIds": [ + "1" + ] + } + ] + }, + "formLocale": "en", + "versionId": 1, + "eSignTemplates": [ + { + "templateId": "e8af8a0d-f7ab-4cd2-b6f5-c84d5ecc1bf8", + "uri": "/templates/e8af8a0d-f7ab-4cd2-b6f5-c84d5ecc1bf8", + "name": "Web Form Copy - Web Form Example Template", + "shared": "false", + "passwordProtected": "false", + "description": "Example template created via the API", + "created": "2025-08-19T21:15:03.7170000Z", + "lastModified": "2025-08-19T21:18:40.2070000Z", + "lastModifiedBy": { + "userName": "Raileen Del Rosario", + "userId": "53d98270-xxxx-xxxx-xxxx-6d080391b538", + "email": "example@email.com", + "uri": "/users/53d98270-xxxx-xxxx-xxxx-6d080391b538" + }, + "lastUsed": "2025-08-19T21:15:03.9830000Z", + "owner": { + "userName": "Raileen Del Rosario", + "userId": "53d98270-xxxx-xxxx-xxxx-6d080391b538", + "email": "example@email.com" + }, + "pageCount": "1", + "folderId": "cf5522c4-cac6-4f81-9a57-d5fe179cae1c", + "folderName": "Deleted Items", + "folderIds": [ + "cf5522c4-cac6-4f81-9a57-d5fe179cae1c" + ], + "autoMatch": "true", + "autoMatchSpecifiedByUser": "false", + "documents": [ + { + "documentId": "1", + "uri": "/envelopes/2230c545-1680-47aa-8581-7d2284093f46/documents/1", + "name": "World_Wide_Web_Form", + "order": "1", + "pages": "1", + "documentBase64": "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MDc6MDA8L3htcDpDcmVhdGVEYXRlPg0KICAgICAgPHhtcDpNb2RpZnlEYXRlPjIwMjUtMDgtMTlUMTQ6MTg6NDAtMDc6MDA8L3htcDpNb2RpZnlEYXRlPg0KICAgICAgPHhtcDpNZXRhZGF0YURhdGU+MjAyNS0wOC0xOVQxNDoxODo0MC0wNzowMDwveG1wOk1ldGFkYXRhRGF0ZT4NCiAgICA8L3JkZjpEZXNjcmlwdGlvbj4NCiAgICA8cmRmOkRlc2NyaXB0aW9uIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgcmRmOmFib3V0PSIiPg0KICAgICAgPGRjOmNyZWF0b3I+DQogICAgICAgIDxyZGY6U2VxIC8+DQogICAgICA8L2RjOmNyZWF0b3I+DQogICAgICA8ZGM6dGl0bGU+DQogICAgICAgIDxyZGY6QWx0Pg0KICAgICAgICAgIDxyZGY6bGkgeG1sOmxhbmc9IngtZGVmYXVsdCI+V29ybGRfV2lkZV9Db3JwX1dlYl9Gb3JtPC9yZGY6bGk+DQogICAgICAgIDwvcmRmOkFsdD4NCiAgICAgIDwvZGM6dGl0bGU+DQogICAgICA8ZGM6Zm9ybWF0PmFwcGxpY2F0aW9uL3BkZjwvZGM6Zm9ybWF0Pg0KICAgIDwvcmRmOkRlc2NyaXB0aW9uPg0KICA8L3JkZjpSREY+DQo8L3g6eG1wbWV0YT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPD94cGFja2V0IGVuZD0idyI/PgplbmRzdHJlYW0KZW5kb2JqCjM2IDAgb2JqCjw8L0ZpbHRlci9GbGF0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", + "display": "inline", + "includeInDownload": "true", + "signerMustAcknowledge": "no_interaction", + "templateLocked": "false", + "templateRequired": "false" + } + ], + "emailSubject": "Please sign this document", + "emailBlurb": "", + "signingLocation": "Online", + "authoritativeCopy": "false", + "enforceSignerVisibility": "false", + "enableWetSign": "true", + "allowMarkup": "false", + "allowReassign": "true", + "customFields": { + "textCustomFields": [ + { + "fieldId": "11230853228", + "name": "ModelNamespace", + "show": "false", + "required": "false", + "value": "docusign.forms._85443307_664c_4c85_882f_87671e153075._608a6c8a_16b2_4419_92f4_d06bc3af6e53" + }, + { + "fieldId": "11230853229", + "name": "ModelVersion", + "show": "false", + "required": "false", + "value": "1" + }, + { + "fieldId": "11230853230", + "name": "ModelAccount", + "show": "false", + "required": "false", + "value": "85443307-664c-4c85-882f-87671e153075" + } + ], + "listCustomFields": [] + }, + "recipients": { + "signers": [ + { + "defaultRecipient": "false", + "tabs": { + "signHereTabs": [ + { + "stampType": "signature", + "name": "SignHere", + "tabLabel": "Signature", + "scaleValue": "1", + "optional": "false", + "documentId": "1", + "recipientId": "1", + "pageNumber": "1", + "xPosition": "126", + "yPosition": "374", + "anchorString": "/SignHere/", + "anchorXOffset": "20", + "anchorYOffset": "10", + "anchorUnits": "pixels", + "anchorCaseSensitive": "false", + "anchorMatchWholeWord": "true", + "anchorHorizontalAlignment": "left", + "anchorTabProcessorVersion": "v1_3", + "tabId": "be01d0ca-1057-455f-9af6-95f6074b5cf6", + "tabType": "signhere" + } + ], + "dateSignedTabs": [ + { + "name": "DateSigned", + "value": "", + "tabLabel": "DateSigned", + "localePolicy": {}, + "documentId": "1", + "recipientId": "1", + "pageNumber": "1", + "xPosition": "409", + "yPosition": "396", + "anchorString": "/Date/", + "anchorXOffset": "20", + "anchorYOffset": "10", + "anchorUnits": "pixels", + "anchorCaseSensitive": "false", + "anchorMatchWholeWord": "true", + "anchorHorizontalAlignment": "left", + "anchorTabProcessorVersion": "v1_3", + "tabId": "a0276278-95a3-4de2-a374-15e92510112e", + "tabType": "datesigned" + } + ], + "textTabs": [ + { + "requireAll": "false", + "value": "", + "originalValue": "", + "required": "true", + "locked": "false", + "concealValueOnDocument": "false", + "disableAutoSize": "false", + "maxLength": "4000", + "tabLabel": "FullName", + "bold": "false", + "italic": "false", + "underline": "false", + "localePolicy": {}, + "documentId": "1", + "recipientId": "1", + "pageNumber": "1", + "xPosition": "145", + "yPosition": "234", + "width": "0", + "height": "0", + "anchorString": "/FullName/", + "anchorXOffset": "20", + "anchorYOffset": "10", + "anchorUnits": "pixels", + "anchorCaseSensitive": "false", + "anchorMatchWholeWord": "true", + "anchorHorizontalAlignment": "left", + "anchorTabProcessorVersion": "v1_3", + "tabId": "c995df10-9141-4686-b9bf-f1dfc4121d33", + "mergeFieldXml": "{\"adm\":{\"path\":\"ADM.Form.FullName\"}}", + "tabType": "text" + }, + { + "requireAll": "false", + "value": "", + "originalValue": "", + "required": "true", + "locked": "false", + "concealValueOnDocument": "false", + "disableAutoSize": "false", + "maxLength": "4000", + "tabLabel": "PhoneNumber", + "bold": "false", + "italic": "false", + "underline": "false", + "localePolicy": {}, + "documentId": "1", + "recipientId": "1", + "pageNumber": "1", + "xPosition": "167", + "yPosition": "261", + "width": "0", + "height": "0", + "anchorString": "/PhoneNumber/", + "anchorXOffset": "20", + "anchorYOffset": "10", + "anchorUnits": "pixels", + "anchorCaseSensitive": "false", + "anchorMatchWholeWord": "true", + "anchorHorizontalAlignment": "left", + "anchorTabProcessorVersion": "v1_3", + "tabId": "71ccfefa-5469-493e-b0c7-886c65b84742", + "mergeFieldXml": "{\"adm\":{\"path\":\"ADM.Form.PhoneNumber\"}}", + "tabType": "text" + }, + { + "requireAll": "false", + "value": "", + "originalValue": "", + "required": "true", + "locked": "false", + "concealValueOnDocument": "false", + "disableAutoSize": "false", + "maxLength": "4000", + "tabLabel": "Company", + "bold": "false", + "italic": "false", + "underline": "false", + "localePolicy": {}, + "documentId": "1", + "recipientId": "1", + "pageNumber": "1", + "xPosition": "182", + "yPosition": "315", + "width": "0", + "height": "0", + "anchorString": "/Company/", + "anchorXOffset": "20", + "anchorYOffset": "10", + "anchorUnits": "pixels", + "anchorCaseSensitive": "false", + "anchorMatchWholeWord": "true", + "anchorHorizontalAlignment": "left", + "anchorTabProcessorVersion": "v1_3", + "tabId": "184f8a65-f2be-48b9-a30e-15592c59b335", + "mergeFieldXml": "{\"adm\":{\"path\":\"ADM.Form.Company\"}}", + "tabType": "text" + }, + { + "requireAll": "false", + "value": "", + "originalValue": "", + "required": "true", + "locked": "false", + "concealValueOnDocument": "false", + "disableAutoSize": "false", + "maxLength": "4000", + "tabLabel": "JobTitle", + "bold": "false", + "italic": "false", + "underline": "false", + "localePolicy": {}, + "documentId": "1", + "recipientId": "1", + "pageNumber": "1", + "xPosition": "137", + "yPosition": "342", + "width": "0", + "height": "0", + "anchorString": "/Title/", + "anchorXOffset": "20", + "anchorYOffset": "10", + "anchorUnits": "pixels", + "anchorCaseSensitive": "false", + "anchorMatchWholeWord": "true", + "anchorHorizontalAlignment": "left", + "anchorTabProcessorVersion": "v1_3", + "tabId": "e7d30733-ce70-4fee-93a0-ea10ecc014b1", + "mergeFieldXml": "{\"adm\":{\"path\":\"ADM.Form.JobTitle\"}}", + "tabType": "text" + } + ], + "checkboxTabs": [ + { + "name": "Yes", + "tabLabel": "Yes", + "selected": "false", + "selectedOriginal": "false", + "requireInitialOnSharedChange": "false", + "bold": "false", + "italic": "false", + "underline": "false", + "required": "true", + "locked": "false", + "documentId": "1", + "recipientId": "1", + "pageNumber": "1", + "xPosition": "237", + "yPosition": "288", + "width": "0", + "height": "0", + "anchorString": "/SMS/", + "anchorXOffset": "20", + "anchorYOffset": "10", + "anchorUnits": "pixels", + "anchorCaseSensitive": "false", + "anchorMatchWholeWord": "true", + "anchorHorizontalAlignment": "left", + "anchorTabProcessorVersion": "v1_3", + "tabId": "0f1e242d-550d-4729-a141-de0dce1d1b6c", + "mergeFieldXml": "{\"adm\":{\"path\":\"ADM.Form.Yes.Yes\"}}", + "tabType": "checkbox" + } + ] + }, + "signInEachLocation": "false", + "agentCanEditEmail": "false", + "agentCanEditName": "false", + "requireUploadSignature": "false", + "name": "", + "email": "", + "recipientId": "1", + "recipientIdGuid": "00000000-0000-0000-0000-000000000000", + "accessCode": "", + "requireIdLookup": "false", + "routingOrder": "1", + "note": "", + "roleName": "signer", + "completedCount": "0", + "deliveryMethod": "email", + "templateLocked": "false", + "templateRequired": "false", + "inheritEmailNotificationConfiguration": "false", + "recipientType": "signer" + } + ], + "agents": [], + "editors": [], + "intermediaries": [], + "carbonCopies": [], + "certifiedDeliveries": [], + "inPersonSigners": [], + "seals": [], + "witnesses": [], + "notaries": [], + "recipientCount": "1" + }, + "envelopeIdStamping": "true", + "autoNavigation": "true", + "uSigState": "esign", + "allowComments": "true", + "disableResponsiveDocument": "true", + "anySigner": null, + "envelopeLocation": "current_site" + } + ] +} \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/error.jsp b/src/main/webapp/WEB-INF/templates/views/error.jsp index 49417655..6f186765 100644 --- a/src/main/webapp/WEB-INF/templates/views/error.jsp +++ b/src/main/webapp/WEB-INF/templates/views/error.jsp @@ -1,16 +1,32 @@ <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> -

${done.title}. ${done.name}

-

The example "${done.name}" is failed. Error information:

-

Message:
${done.message}

-

Stack trace:

-
    - -
  • ${item.className}.${item.methodName}(${item.fileName}:${item.lineNumber})
  • -
    -
+<%-- Used for consent redirect sequence --%> + + +<%-- using ' ' instead of ':' to prevent issue with delimiter and redirect url --%> + + -

Continue

+
+ +

Problem: an error occurred

+ + +

Error information:

+

Message: ${done.message}

+
+

${done.fixingInstructions}

+
+ +

Oops, we have encountered a problem.

+

Message: ${done.message}

+

Dump: ${done.stackTracePrinted}

+ +

Please check your account configuration. If you are unable to resolve the problem, open a new issue on GitHub.

+
+ +

${launcherTexts.getContinueButton()}

diff --git a/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a001.jsp b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a001.jsp new file mode 100644 index 00000000..ec589a8d --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a001.jsp @@ -0,0 +1,109 @@ +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> + + + + + + + + + + +

1. ${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + + +

+ ${viewSourceFile} +

+ +
+
+ + + +
+ +
+ + + +
+ +
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+ +
+ + + +
+ +
+ + + +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a002.jsp b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a002.jsp new file mode 100644 index 00000000..4084edf7 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a002.jsp @@ -0,0 +1,137 @@ +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> + + + + + + + + + + + +

2. ${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example. +

+
+ + + + +

+ ${viewSourceFile} +

+ +
+
+ + + +
+ +
+ + + +
+ +
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+ +
+ + + +
+ +
+ + + +
+ + +
+ + + +
+ + + + +
+ + +
+
+ + +
+
+
+
+ \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a003.jsp b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a003.jsp new file mode 100644 index 00000000..ef35411f --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a003.jsp @@ -0,0 +1,21 @@ +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> + + +

3. ${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a003a.jsp b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a003a.jsp new file mode 100644 index 00000000..f198d1b9 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a003a.jsp @@ -0,0 +1,31 @@ +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> + + +

3a. ${example.getExampleName()}

+

${example.getAdditionalPage().get(0).getResultsPageText()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + + +
+ + +
+
+ +

+ Problem: please first bulk export user data using Send an envelope with a remote (email) signer and cc recipient..
+ Thank you. +

+
+
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a004.jsp b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a004.jsp new file mode 100644 index 00000000..4932f958 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a004.jsp @@ -0,0 +1,21 @@ +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> + + +

4. ${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a004a.jsp b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a004a.jsp new file mode 100644 index 00000000..a16c293d --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a004a.jsp @@ -0,0 +1,31 @@ +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> + + +

4a. ${example.getExampleName()}

+

${example.getAdditionalPage().get(0).getResultsPageText()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + + +
+ + +
+
+ +

+ Problem: please first bulk import user data example 4.
+ Thank you. +

+
+
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a005.jsp b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a005.jsp new file mode 100644 index 00000000..c2e8cc10 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a005.jsp @@ -0,0 +1,24 @@ +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> + + + +

5. ${example.getExampleName()}

+

${example.getExampleDescription()}

+ + + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a006.jsp b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a006.jsp new file mode 100644 index 00000000..c7cc375f --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a006.jsp @@ -0,0 +1,40 @@ +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> + + + + + +

6. ${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + + +
+ + +
+
diff --git a/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a007.jsp b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a007.jsp new file mode 100644 index 00000000..d2c18597 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a007.jsp @@ -0,0 +1,38 @@ +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> + + + + + +

7. ${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + + +
+ + +
+
diff --git a/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a008.jsp b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a008.jsp new file mode 100644 index 00000000..48cb4fcc --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a008.jsp @@ -0,0 +1,67 @@ +<%@ page import="com.docusign.core.model.manifestModels.CodeExampleText" %> +<%@ page import="java.util.Arrays" %> +<%@ page import="com.docusign.core.model.manifestModels.RedirectsToOtherCodeExamples" %> +<%@ page import="java.util.ArrayList" %> +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> + + + + + + + + +

8. ${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + + +

${example.getForms().get(formNumber).getFormName().replaceFirst("\\{0}", emailAddress)}

+ +
+
+ + + +
+ +
+ + + +
+ + + +
+
+ +

+ ${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToSecondCodeExample)} +

+
+
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a009.jsp b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a009.jsp new file mode 100644 index 00000000..1cba8d96 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a009.jsp @@ -0,0 +1,50 @@ +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> + + + + + + + +

9. ${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + + +

${example.getForms().get(formNumber).getFormName().replaceFirst("\\{0}", emailAddress)}

+ +
+
+ + + +
+ + + +
+
+ +

+ ${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToSecondCodeExample)} +

+
+
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a010.jsp b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a010.jsp new file mode 100644 index 00000000..1c10750f --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a010.jsp @@ -0,0 +1,39 @@ +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> + + + + + +

10. ${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailAddressOfUserToDelete()} + +
+ + + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a011.jsp b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a011.jsp new file mode 100644 index 00000000..c8d1f037 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a011.jsp @@ -0,0 +1,40 @@ +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> + + + + + +

11. ${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getUserIDOfUserToDelete()} + +
+ + + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a012.jsp b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a012.jsp new file mode 100644 index 00000000..83e2a7fa --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a012.jsp @@ -0,0 +1,94 @@ +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> + + + + + + + + + +

12. ${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ + + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a013.jsp b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a013.jsp new file mode 100644 index 00000000..66e79c6d --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/admin/examples/a013.jsp @@ -0,0 +1,67 @@ +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> + + + + + + + +

13. ${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + +
+ +
+ + + +
+ +
+ + + +
+ + + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c001.jsp b/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c001.jsp new file mode 100644 index 00000000..4ae83857 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c001.jsp @@ -0,0 +1,31 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

+ ${viewSourceFile} +

+ +
+
+ + + +
+ + +
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c002.jsp b/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c002.jsp new file mode 100644 index 00000000..8531398a --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c002.jsp @@ -0,0 +1,43 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

+ ${viewSourceFile} +

+ + + +

${example.getForms().get(formNumber).getFormName()}

+
+
+ + + +
+ + +
+
+ +

+ ${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToFirstCodeExample)} +

+
+
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c003.jsp b/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c003.jsp new file mode 100644 index 00000000..32aa9e0d --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c003.jsp @@ -0,0 +1,53 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

+ ${viewSourceFile} +

+ + + +
+
+ + + +
+
+ + + +
+ + +
+
+ +

+ ${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToFirstCodeExample)} +

+
+
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c004.jsp b/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c004.jsp new file mode 100644 index 00000000..9e7e2561 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c004.jsp @@ -0,0 +1,19 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

+ ${viewSourceFile} +

+ + +
+ + +
+ + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c005.jsp b/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c005.jsp new file mode 100644 index 00000000..12090083 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c005.jsp @@ -0,0 +1,44 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

+ ${viewSourceFile} +

+ + + +

${example.getForms().get(formNumber).getFormName()}

+
+
+ + + +
+ + +
+
+ +

+ ${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToFirstCodeExample)} +

+
+
+ + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c006.jsp b/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c006.jsp new file mode 100644 index 00000000..d150a654 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/click/examples/c006.jsp @@ -0,0 +1,114 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

+ ${viewSourceFile} +

+ + + +

${example.getForms().get(formNumber).getFormName()}

+
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+ + +
+
+ + + +

+ ${example.getRedirectsToOtherCodeExamples().get(redirectNumberTo2).getRedirectText().replaceFirst("\\{0}", redirectToSecondCodeExample)} +

+
+ +

+ ${example.getRedirectsToOtherCodeExamples().get(redirectNumberTo1).getRedirectText().replaceFirst("\\{0}", redirectToFirstCodeExample)} +

+
+
+
+
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/connect/examples/con001.jsp b/src/main/webapp/WEB-INF/templates/views/pages/connect/examples/con001.jsp new file mode 100644 index 00000000..bfa8aa83 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/connect/examples/con001.jsp @@ -0,0 +1,52 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +

+ Prerequisites: See How to validate a webhook message using HMAC. +

+ +
+
+ + + +
+
+ + + +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/connectedfields/examples/cf001.jsp b/src/main/webapp/WEB-INF/templates/views/pages/connectedfields/examples/cf001.jsp new file mode 100644 index 00000000..9309ba75 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/connectedfields/examples/cf001.jsp @@ -0,0 +1,59 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + +
+ + +
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/ds_must_authenticate.jsp b/src/main/webapp/WEB-INF/templates/views/pages/ds_must_authenticate.jsp index aa857c4b..5e210c05 100644 --- a/src/main/webapp/WEB-INF/templates/views/pages/ds_must_authenticate.jsp +++ b/src/main/webapp/WEB-INF/templates/views/pages/ds_must_authenticate.jsp @@ -1,19 +1,22 @@ - <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -
-

Please Authenticate with DocuSign

-

Please choose your authentication type

-
+ + +
+ ${launcherTexts.getLoginPage().getLoginHeader()} + +
-

- +

+

+

+
-

You need to authenticate with DocuSign to continue your request.

+

${launcherTexts.getLoginPage().getLoginHelperText()}

diff --git a/src/main/webapp/WEB-INF/templates/views/pages/ds_restart.jsp b/src/main/webapp/WEB-INF/templates/views/pages/ds_restart.jsp new file mode 100644 index 00000000..5adae759 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/ds_restart.jsp @@ -0,0 +1,14 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + +
+
+

Please restart the app to finish switching to a new API.

+

+ Quit the current app with Control + C, then run + mvn package followed by + java -Dspring.profiles.active=dev -jar target/code-examples-java-1.0-SNAPSHOT.war + again or rerun it using the Run button in IntelliJ Ultimate or Eclipse. +

+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/ds_return.jsp b/src/main/webapp/WEB-INF/templates/views/pages/ds_return.jsp index 393bdc79..3189b7e3 100644 --- a/src/main/webapp/WEB-INF/templates/views/pages/ds_return.jsp +++ b/src/main/webapp/WEB-INF/templates/views/pages/ds_return.jsp @@ -1,17 +1,17 @@ <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -

Returned data from DocuSign!

+

Returned data from Docusign!

Data:

-

event: ${event}. This event parameter is supplied by DocuSign via the redirect URL. +

event: ${event}. This event parameter is supplied by Docusign via the redirect URL. Since it could have been spoofed, don't make business decisions based on its value. Instead, query DocuSign as appropriate.

-

envelopeId: ${qpEnvelopeId}. The envelopeId parameter is supplied by DocuSign.

+

envelopeId: ${qpEnvelopeId}. The envelopeId parameter is supplied by Docusign.

@@ -20,6 +20,6 @@ -

Continue

+

${launcherTexts.getContinueButton()}

diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg001.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg001.jsp new file mode 100644 index 00000000..4f6762a4 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg001.jsp @@ -0,0 +1,56 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg002.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg002.jsp new file mode 100644 index 00000000..c91be407 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg002.jsp @@ -0,0 +1,87 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getCCEmailShouldDifferFromSigner()} + +
+
+ + + +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg003.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg003.jsp new file mode 100644 index 00000000..0727ba23 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg003.jsp @@ -0,0 +1,21 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg004.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg004.jsp new file mode 100644 index 00000000..80878ef4 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg004.jsp @@ -0,0 +1,43 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + + +

+ ${viewSourceFile} +

+ + + +

+ ${example.getForms().get(formNumber).getFormName()} +

+ +
+ + +
+
+ +

${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToSecondCodeExample)}

+ +
+ +
+
+
+ + + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg005.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg005.jsp new file mode 100644 index 00000000..d950776f --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg005.jsp @@ -0,0 +1,42 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + + +

+ ${example.getForms().get(formNumber).getFormName()} +

+ +
+ + +
+
+ +

${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToSecondCodeExample)}

+ +
+ +
+
+
+ + + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg006.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg006.jsp new file mode 100644 index 00000000..0da48cac --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg006.jsp @@ -0,0 +1,41 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + + +

+ ${viewSourceFile} +

+ + + +

+ ${example.getForms().get(formNumber).getFormName()} +

+ +
+ + +
+
+ +

${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToSecondCodeExample)}

+ +
+ +
+
+
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg007.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg007.jsp new file mode 100644 index 00000000..45d14e81 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg007.jsp @@ -0,0 +1,63 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + + +

+ ${viewSourceFile} +

+ + + +

${example.getRedirectsToOtherCodeExamples().get(redirectSecondNumber).getRedirectText().replaceFirst("\\{0}", redirectToSecondCodeExample)}

+ +
+ +
+
+ +

${example.getRedirectsToOtherCodeExamples().get(redirectSixNumber).getRedirectText().replaceFirst("\\{0}", redirectToSixthCodeExample)}

+ +
+ +
+
+ +

${example.getForms().get(formNumber).getFormName()}

+ +
+
+ + + +
+ + +
+
+
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg008.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg008.jsp new file mode 100644 index 00000000..b86dbe03 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg008.jsp @@ -0,0 +1,22 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + + +

+ ${viewSourceFile} +

+ +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg009.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg009.jsp new file mode 100644 index 00000000..5da55c55 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg009.jsp @@ -0,0 +1,118 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + + +

${example.getForms().get(formNumber).getFormName()}

+ +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getCCEmailShouldDifferFromSigner()} + +
+
+ + + +
+ + + +
+
+ +

+ ${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToEigthCodeExample)} +

+ +
+ +
+
+
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg010.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg010.jsp new file mode 100644 index 00000000..a66a5380 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg010.jsp @@ -0,0 +1,88 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getCCEmailShouldDifferFromSigner()} + +
+
+ + + +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg011.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg011.jsp new file mode 100644 index 00000000..85b8c54b --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg011.jsp @@ -0,0 +1,99 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + + +

+ ${viewSourceFile} +

+ +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getCCEmailShouldDifferFromSigner()} + +
+
+ + + +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg012.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg012.jsp new file mode 100644 index 00000000..bf2cf05d --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg012.jsp @@ -0,0 +1,44 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + + +

+ ${viewSourceFile} +

+ +

${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToSecondCodeExample)}

+
+ + +
+
+ + + +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg013.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg013.jsp new file mode 100644 index 00000000..7d8c1864 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg013.jsp @@ -0,0 +1,140 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + + + + +

${example.getExampleName()}

+ + +

${example.getExampleDescription()}

+
+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + +

${example.getForms().get(formNumber).getFormName()}

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getCCEmailShouldDifferFromSigner()} + +
+
+ + + +
+

+


+

+
+ + + +
+
+ + + +
+ + +
+
+ +

${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToEigthCodeExample)}

+ +
+ +
+
+
+ + + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg014.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg014.jsp new file mode 100644 index 00000000..65114bca --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg014.jsp @@ -0,0 +1,97 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+

${example.getNotes()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getCCEmailShouldDifferFromSigner()}} + +
+
+ + + +
+ + +
+
+ +

${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText()}

+
+
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg015.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg015.jsp new file mode 100644 index 00000000..3326b3e0 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg015.jsp @@ -0,0 +1,39 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + + +

${example.getForms().get(formNumber).getFormName()}

+ +
+ + +
+
+ +

${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToNinthCodeExample)}

+ +
+ +
+
+
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg016.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg016.jsp new file mode 100644 index 00000000..3a5b7eee --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg016.jsp @@ -0,0 +1,60 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+ + + +
+ + + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg017.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg017.jsp new file mode 100644 index 00000000..84b1b749 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg017.jsp @@ -0,0 +1,114 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + +

+ ${viewSourceFile} +

+ + + +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getCCEmailShouldDifferFromSigner()} + +
+
+ + + +
+ + +
+ +
+ +

${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToEightCodeExample)}

+ +
+ +
+
+
+ + + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg018.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg018.jsp new file mode 100644 index 00000000..dbfbff5d --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg018.jsp @@ -0,0 +1,41 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + + +

+ ${example.getForms().get(formNumber).getFormName().replaceFirst("\\{0}", redirectTo16CodeExample)} +

+
+ + +
+
+ +

${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectTo16CodeExample)}

+ +
+ +
+
+
+ + + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg019.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg019.jsp new file mode 100644 index 00000000..cd8f573b --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg019.jsp @@ -0,0 +1,75 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getAccessCodeText()} + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg020.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg020.jsp new file mode 100644 index 00000000..1fd87cb9 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg020.jsp @@ -0,0 +1,87 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg022.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg022.jsp new file mode 100644 index 00000000..43ad1610 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg022.jsp @@ -0,0 +1,56 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg023.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg023.jsp new file mode 100644 index 00000000..84b677bd --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg023.jsp @@ -0,0 +1,55 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg024.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg024.jsp new file mode 100644 index 00000000..b2c39bb4 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg024.jsp @@ -0,0 +1,39 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + +
+
+ + + +
+ + +
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg025.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg025.jsp similarity index 51% rename from src/main/webapp/WEB-INF/templates/views/pages/examples/eg025.jsp rename to src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg025.jsp index 1383dad5..b656914b 100644 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg025.jsp +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg025.jsp @@ -1,30 +1,30 @@ <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - + -

25. ${title}.

+ + + -

- Permission profiles are collections of account settings that determine the behavior and actions - available to the user groups to which they're applied. This code example demonstrates how to - the permission profile for the group with the eSignature REST API. -

+

${example.getExampleName()}

+

${example.getExampleDescription()}

Documentation about this example.

-

API method used: - Groups::update. -

+

- View source file ${sourceFile} on GitHub. + ${viewSourceFile}

- + + @@ -42,7 +45,7 @@
- +
- \ No newline at end of file + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg026.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg026.jsp new file mode 100644 index 00000000..958ff8f9 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg026.jsp @@ -0,0 +1,50 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + +
+
+ + + +
+ + + +
+ + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg027.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg027.jsp new file mode 100644 index 00000000..d415e620 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg027.jsp @@ -0,0 +1,39 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+

${example.getNotes()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + +
+
+ + + +
+ + + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg028.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg028.jsp new file mode 100644 index 00000000..cdd0a010 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg028.jsp @@ -0,0 +1,54 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + +
+

+ ${example.getForms().get(formNumber).getFormName()} +

+
+ + + +
+
+ + + +
+ + +
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg029.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg029.jsp new file mode 100644 index 00000000..a2bd1245 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg029.jsp @@ -0,0 +1,89 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

+ Documentation about + this example. +

+
+ + + +

+ ${viewSourceFile} +

+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + + + + ${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectTo28CodeExample)} + + +
+ + +
+
+ +

${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectTo28CodeExample)}

+ +
+ +
+
+
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg030.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg030.jsp new file mode 100644 index 00000000..bf15152d --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg030.jsp @@ -0,0 +1,122 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> + + + + + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

+ Documentation about this example. +

+
+ + + +

+ ${viewSourceFile} +

+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getCCEmailShouldDifferFromSigner()} + +
+
+ + + +
+
+ + +
+ + +
+
+ + +

${example.getRedirectsToOtherCodeExamples().get(redirect8Number).getRedirectText().replaceFirst("\\{0}", redirectTo8CodeExample)}

+
+ +
+
+ +

${example.getRedirectsToOtherCodeExamples().get(redirect28Number).getRedirectText().replaceFirst("\\{0}", redirectTo28CodeExample)}

+
+ +
+
+
+
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg031.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg031.jsp new file mode 100644 index 00000000..a13dbd41 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg031.jsp @@ -0,0 +1,150 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + +
+
+
+
${example.getForms().get(firstFormNumber).getFormName()}
+
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + +
+
+ +
+
${example.getForms().get(secondFormNumber).getFormName()}
+
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+
+
+
+ + +
+
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg032.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg032.jsp new file mode 100644 index 00000000..85e0f506 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg032.jsp @@ -0,0 +1,96 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + +
+

${example.getForms().get(firstFormNumber).getFormName()}

+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+ +

${example.getForms().get(secondFormNumber).getFormName()}

+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+ + + +
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg033.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg033.jsp new file mode 100644 index 00000000..3e007452 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg033.jsp @@ -0,0 +1,23 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + +
+ + +
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg034.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg034.jsp new file mode 100644 index 00000000..dbcd32f7 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg034.jsp @@ -0,0 +1,124 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + +

+ ${viewSourceFile} +

+ + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+ +
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+ +
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+ + + +
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg035.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg035.jsp new file mode 100644 index 00000000..4b740837 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg035.jsp @@ -0,0 +1,77 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getChooseDateInTheFuture()}} + +
+ + +
+
+
+
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg036.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg036.jsp new file mode 100644 index 00000000..995c3c13 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg036.jsp @@ -0,0 +1,105 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getCCEmailShouldDifferFromSigner()} + +
+
+ + + +
+
+ + + +
+ + +
+
+
+
+ + + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg037.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg037.jsp new file mode 100644 index 00000000..418de37a --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg037.jsp @@ -0,0 +1,135 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+
+ ${example.getForms().get(formNumber).getInputs().get(sms).getInputName()}   + ${example.getForms().get(formNumber).getInputs().get(whatsapp).getInputName()}
+
+
+ + + + + + ${launcherTexts.getHelpingTexts().getCountryCodeText()} + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getPhoneNumberWillBeNotified()} ${launcherTexts.getHelpingTexts().getPhoneNumberWontBeShared()} + +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getCountryCodeText()} + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getPhoneNumberWillBeNotified()} ${launcherTexts.getHelpingTexts().getPhoneNumberWontBeShared()} + +
+
+ + + +
+ + +
+ +
+
+
+ + + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg038.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg038.jsp new file mode 100644 index 00000000..0ac3f520 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg038.jsp @@ -0,0 +1,88 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getCCEmailShouldDifferFromSigner()} + +
+
+ + + +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg039.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg039.jsp new file mode 100644 index 00000000..9bc998b7 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg039.jsp @@ -0,0 +1,36 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg040.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg040.jsp new file mode 100644 index 00000000..ec89d099 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg040.jsp @@ -0,0 +1,119 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getCCEmailShouldDifferFromSigner()} + +
+
+ + + +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg041.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg041.jsp new file mode 100644 index 00000000..609ba33c --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg041.jsp @@ -0,0 +1,91 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getCountryCodeText()} + +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getPhoneNumberWillBeNotified()} ${launcherTexts.getHelpingTexts().getPhoneNumberWontBeShared()} + +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg042.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg042.jsp new file mode 100644 index 00000000..6d3ec92e --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg042.jsp @@ -0,0 +1,128 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+

+ ${example.getForms().get(formNumber).getFormName()} +

+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ + + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg043.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg043.jsp new file mode 100644 index 00000000..f2f0b41d --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg043.jsp @@ -0,0 +1,72 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + +
+
+ + + +
+
+ + + + + + + ${launcherTexts.getHelpingTexts().getSaveAgentActivationCode()} + +
+ + + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg044.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg044.jsp new file mode 100644 index 00000000..8f8d0178 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg044.jsp @@ -0,0 +1,91 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+ +
+ + ${example.getForms().get(phoneFormNumber).getFormName()} + + + +
+ + +
+
+ + +
+ + + + Provide a phone number to enable phone authentication for the signer + +
+
+ + + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg045.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg045.jsp new file mode 100644 index 00000000..3c56bce6 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg045.jsp @@ -0,0 +1,44 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ + +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getDefaultEnvelopeId()} + +
+ + + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg045RestoreEnvelope.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg045RestoreEnvelope.jsp new file mode 100644 index 00000000..64a85a98 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg045RestoreEnvelope.jsp @@ -0,0 +1,30 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+

${restoreText}

+ +
+
+ + + +
+ + + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg046.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg046.jsp new file mode 100644 index 00000000..d79fe9ff --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/eg046.jsp @@ -0,0 +1,178 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+
+ ${example.getForms().get(formNumber).getInputs().get(sms).getInputName()}   + ${example.getForms().get(formNumber).getInputs().get(whatsapp).getInputName()}
+
+ +
+ + + +
+ +
+ + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+ +
+ + + + + + ${launcherTexts.getHelpingTexts().getCountryCodeText()} + +
+ +
+ + + + + + ${launcherTexts.getHelpingTexts().getPhoneNumberWillBeNotified()} ${launcherTexts.getHelpingTexts().getPhoneNumberWontBeShared()} + +
+ +
+ + + +
+ +
+ + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+ +
+ + + + + + ${launcherTexts.getHelpingTexts().getCountryCodeText()} + +
+ +
+ + + + + + ${launcherTexts.getHelpingTexts().getPhoneNumberWillBeNotified()} ${launcherTexts.getHelpingTexts().getPhoneNumberWontBeShared()} + +
+ + + +
+ +
+
+
+ + + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/embed.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/embed.jsp new file mode 100644 index 00000000..c76f5c03 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/embed.jsp @@ -0,0 +1,103 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + +
+

The document has been embedded with focused view.

+
+ + + + + + + + Signing + + + +
+ + + + + + + + + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/quickEmbeddedSigning.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/quickEmbeddedSigning.jsp new file mode 100644 index 00000000..90bbe52b --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/examples/quickEmbeddedSigning.jsp @@ -0,0 +1,121 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + + + + + + + ${title} + + + + + + + + + + + + +
+ +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ +

+ + + ${launcherTexts.getAPIMethodUsed()} + + + ${launcherTexts.getAPIMethodUsedPlural()} + + + + + ${link.getPathName()} + + + + . + + + and + + + , + + + +

+ +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+ + +
+
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/esignature/index.jsp b/src/main/webapp/WEB-INF/templates/views/pages/esignature/index.jsp new file mode 100644 index 00000000..885212ee --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/esignature/index.jsp @@ -0,0 +1,143 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + +
+ +
+ + + + + + +
+

Java Launcher

+

${launcherTexts.getHomePageText()}

+
+
+
+ + +
+ +

Documentation on using OAuth Authorization Code Grant from a + Java application.

+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

${group.getName()}

+ + + + +

+ + ${example.getExampleName()} + +

+ +

${example.getExampleDescription()}

+ +

+ + + + ${launcherTexts.getAPIMethodUsed()} + + + ${launcherTexts.getAPIMethodUsedPlural()} + + + + + + ${link.getPathName()} + + + + + . + + + and + + + , + + + + +

+
+
+
+
+
+
+ +
+ + + + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/example_done.jsp b/src/main/webapp/WEB-INF/templates/views/pages/example_done.jsp index 9f1609f7..d976fcff 100644 --- a/src/main/webapp/WEB-INF/templates/views/pages/example_done.jsp +++ b/src/main/webapp/WEB-INF/templates/views/pages/example_done.jsp @@ -7,11 +7,47 @@ -

-

${done.json}
-

+ + + + + +

+ ${formattedJson} +

+
+ +

+

${done.json}
+

+
+
+
+ + + + + + + + + + + + + +
+ +
-

Continue

+ + +

${launcherTexts.getContinueButton()}

+
+ +

${launcherTexts.getContinueButton()}

+
+
diff --git a/src/main/webapp/WEB-INF/templates/views/pages/example_done_compare.jsp b/src/main/webapp/WEB-INF/templates/views/pages/example_done_compare.jsp index d5b5edd7..238602e2 100644 --- a/src/main/webapp/WEB-INF/templates/views/pages/example_done_compare.jsp +++ b/src/main/webapp/WEB-INF/templates/views/pages/example_done_compare.jsp @@ -23,6 +23,6 @@ -

Continue

+

${launcherTexts.getContinueButton()}

diff --git a/src/main/webapp/WEB-INF/templates/views/pages/example_pending.jsp b/src/main/webapp/WEB-INF/templates/views/pages/example_pending.jsp new file mode 100644 index 00000000..1357b250 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/example_pending.jsp @@ -0,0 +1,8 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + +

${done.name}

+

${done.message}

+ + + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg001.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg001.jsp deleted file mode 100644 index 1a689fbe..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg001.jsp +++ /dev/null @@ -1,40 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

1. Embedded Signing Ceremony

-

This example sends an envelope, and then uses an embedded signing ceremony for the first signer.

-

Embedded signing provides a smoother user experience for the signer: the DocuSign signing ceremony is initiated from - your website.

- -

Documentation about this example.

-
- - -

API methods used: - Envelopes::create - and - EnvelopeViews::createRecipient. -

-

- View source file ${sourceFile} on GitHub. -

- -
-
- - - We'll never share your email with anyone else. -
-
- - -
- - -
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg002.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg002.jsp deleted file mode 100644 index 6958c6f3..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg002.jsp +++ /dev/null @@ -1,53 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

2. Send an envelope with a remote (email) signer and cc recipient

-

The envelope includes a pdf, Word, and HTML document. Anchor text - (AutoPlace) - is used to position the signing fields in the documents. -

-

This is a general example of creating and sending an envelope (a signing request) to multiple recipients, - with multiple documents, and with signature fields for the documents.

- -

Documentation about this example.

-
- -

API method used: - Envelopes::create. -

- -

- View source file ${sourceFile} on GitHub. -

- -
-
- - - We'll never share your email with anyone else. -
-
- - -
-
- - - The email and/or name for the cc recipient must be different - from the signer. - -
-
- - -
- - -
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg003.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg003.jsp deleted file mode 100644 index e8dfd42d..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg003.jsp +++ /dev/null @@ -1,25 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

3. List envelopes in the user's account

-

List the envelopes created in the last 30 days.

-

This example demonstrates how to query DocuSign about envelopes sent by the current user.

- -

Documentation about this example.

-
- - -

API method used: - Envelopes::listStatusChanges. -

-

- View source file ${sourceFile} on GitHub. -

- -
- - -
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg004.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg004.jsp deleted file mode 100644 index 051abe61..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg004.jsp +++ /dev/null @@ -1,48 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

4. Get an envelope's basic information and status

-

List the basic information about an envelope, including its overall status. - Additional API/SDK methods may be used to get additional information about the - envelope, its documents, recipients, etc.

- -

This example demonstrates how to obtain the latest information about - an envelope from DocuSign. Often an alternative is to use Connect - to enable DocuSign to proactively send your application updates when the - status of an envelope changes. -

- - -

Documentation about this example.

-
- - -

API method used: - Envelopes::get. -

- -

- View source file ${sourceFile} on GitHub. -

- - - -

The envelope you created via example 2 will be queried.

- -
- - -
-
- -

Problem: please first create an envelope using example 2.
- Thank you.

- -
- -
-
-
- - - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg005.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg005.jsp deleted file mode 100644 index f0cff895..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg005.jsp +++ /dev/null @@ -1,40 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

5. List an envelope's recipients and their status

-

List the envelope's recipients, including their current status.

- - -

Documentation about this example.

-
- - -

API method used: - EnvelopeRecipients::list. -

-

- View source file ${sourceFile} on GitHub. -

- - - -

The envelope you created via example 2 will be queried.

- -
- - -
-
- -

Problem: please first create an envelope using example 2.
- Thank you.

- -
- -
-
-
- - - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg006.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg006.jsp deleted file mode 100644 index a0341084..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg006.jsp +++ /dev/null @@ -1,43 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

6. List an envelope's documents

-

List the envelope's documents. A Certificate of Completion document - is also associated with every envelope. -

- -

This method is often used to dynamically create a list of an envelope's documents - in preparation for enabling your user to download one or more of the documents.

- -

Documentation about this example.

-
- - -

API method used: - EnvelopeDocuments::list. -

- -

- View source file ${sourceFile} on GitHub. -

- - - -

The envelope you created via example 2 will be queried.

- -
- - -
-
- -

Problem: please first create an envelope using example 2.
- Thank you.

- -
- -
-
-
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg007.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg007.jsp deleted file mode 100644 index 89eed27e..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg007.jsp +++ /dev/null @@ -1,71 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

7. Download a document from an envelope

-

An envelope's documents can be downloaded one by one or as a complete set.

-

Document download options:

-
    -
  • Combined: a PDF with the combined content of all documents and the - certificate -
  • -
  • Zip Archive: a ZIP archive that contains all of the PDF documents, - the certificate, and any .WAV files used for voice authentication. -
  • -
  • The envelope's individual documents
  • -
  • The envelope's Certificate of Completion
  • -
- -

Documentation about this example.

-
- - -

API method used: - EnvelopeDocuments::get. -

- -

- View source file ${sourceFile} on GitHub. -

- - - -

Problem: please first create an envelope using example 2.
- You will then need to use example 6 to create the list of documents.
- Thank you.

- -
- -
-
- -

Problem: please first create a list of the envelope's documents using - example 6.
- Thank you.

- -
- -
-
- -

Please choose a document.
- The document list is from your results for example 6.

- -
-
- - -
- - -
-
-
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg008.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg008.jsp deleted file mode 100644 index fd249303..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg008.jsp +++ /dev/null @@ -1,34 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

8. Create a template

-

Create a template with two roles, signer and cc. - The template includes three documents. -

- -

Templates are usually created using the DocuSign web tool. This example creates - a template that will later be used by other examples in this launcher.

- -

This example first lists the user's templates and only creates a new template if one does not already exist in your - account. -

- -

Documentation about this example.

-
- - -

API methods used: - Templates::list, - Templates::create. -

- -

- View source file ${sourceFile} on GitHub. -

- -
- - -
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg009.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg009.jsp deleted file mode 100644 index 227dfc8b..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg009.jsp +++ /dev/null @@ -1,79 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

9. Send an envelope using a template

-

The envelope is defined by the template. - The signer and cc recipient name and email are used to fill in the template's roles.

- -

This example demonstrates a common pattern for DocuSign integrations: envelopes will - be sent programmatically, based on a template. If the template definition needs to be - updated, the DocuSign web tool can be used to easily update the template, thus - avoiding the need to make software changes. -

- - -

Documentation about this example.

-
- - -

API method used: - Envelopes::create. -

-

- View source file ${sourceFile} on GitHub. -

- - - -

The template you created via example 8 will be used.

- -
-
- -
-
- - - We'll never share your email with anyone else. - -
-
- - -
-
- - - The email and/or name for the cc recipient must be - different from the signer. - -
-
- - -
- - -
-
- -

Problem: please first create the template using example 8.
- Thank you.

- -
- -
-
-
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg010.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg010.jsp deleted file mode 100644 index 008fd01c..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg010.jsp +++ /dev/null @@ -1,53 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

10. Send an envelope using binary document transfer

-

The envelope includes a pdf, Word, and HTML document.

-

Multipart data transfer is used to send the documents in binary format to DocuSign. - Binary transfer is 33% more efficient than base64 encoding and is recommended for documents over 15M Bytes. -

- -

Since binary transfer is not yet supported by the SDK, this example uses the API directly and - demonstrates how to do so.

- -

Documentation about this example.

-
- - -

API method used: - Envelopes::create. -

- -

- View source file ${sourceFile} on GitHub. -

- -
-
- - - We'll never share your email with anyone else. -
-
- - -
-
- - - The email and/or name for the cc recipient must be different from the signer. -
-
- - -
- - -
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg011.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg011.jsp deleted file mode 100644 index c67e4034..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg011.jsp +++ /dev/null @@ -1,66 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

11. Embedded Sending

-

An envelope will be created in draft mode. Your browser will then be redirected to - the DocuSign web tool where the envelope can be (optionally) updated and then sent.

-

The envelope includes a pdf, Word, and HTML document. Anchor text - (AutoPlace) - is used to position the signing fields in the documents.

-

DocuSign recommends that you enhance your application as needed to avoid the need - for the embedded sender view. -

-

For example, if the sender view is used to optionally - add additional documents to the envelope, enhance your app to provide the - needed feature (see example 13 for adding additional documents programmatically). -

- -

Documentation about this example.

-
- - -

API methods used: - Envelopes::create and - EnvelopeViews::createSender. -

- -

- View source file ${sourceFile} on GitHub. -

- -
-
- - -
-
- - - We'll never share your email with anyone else. -
-
- - -
-
- - - The email and/or name for the cc recipient must be different from the signer. -
-
- - -
- - -
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg012.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg012.jsp deleted file mode 100644 index 97134c97..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg012.jsp +++ /dev/null @@ -1,47 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

12. Embedded DocuSign web tool

-

Redirect the user to the DocuSign web tool.

-

Use this API call to open the DocuSign web tool, the NDSE (New DocuSign Signing Experience), - with the user already logged in.

-

The starting view can be either an envelope's documents or the web tool's front page.

-

The user does not necessarily return from the NDSE, so using this API call is often a final - step for your application. - Or you can open the NDSE in a new tab for the user. -

- - -

Documentation about this example.

-
- - -

API method used: - EnvelopeViews::createConsole. -

- -

- View source file ${sourceFile} on GitHub. -

- -

Optional: to use the Envelope's document view please first create an envelope using - example 2.

-
- - -
-
- - -
- - -
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg013.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg013.jsp deleted file mode 100644 index 3739cb36..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg013.jsp +++ /dev/null @@ -1,116 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

13. Embedded Signing Ceremony from a template with an added document

- -

This example sends an envelope based on a template.

-

In addition to the template's document(s), the example adds an - additional document to the envelope by using the - Composite - Templates - feature.

-

In this example, the additional document is an HTML document that - includes order details with information from the form below.

-

This example then enables you to sign the envelope using embedded signing.

-

Embedded signing provides a smoother user experience for a signer who is - already logged into your web application since the DocuSign - signing ceremony is initiated from your website.

-
- - -

Documentation about this example.

-
- - -

API methods used: - Envelopes::create - and - EnvelopeViews::createRecipient. -

-

- View source file ${sourceFile} on GitHub. -

- - -

The template you created via example 8 will be used.

- -
-
- -
-
- - - We'll never share your email with anyone else. - -
-
- - -
-
- - - The email and/or name for the cc recipient must be - different - from the signer. - -
-
- - -
-

-


-

-
- - -
-
- - -
- - -
-
- -

Problem: please first create the template using example 8.
- Thank you.

- -
- -
-
-
- - - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg014.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg014.jsp deleted file mode 100644 index 37e49588..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg014.jsp +++ /dev/null @@ -1,64 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

14. Send an envelope with an order form, including a payment field.

- -
Note: This example will only work if the sender's DocuSign account - is set up with a DocuSign payment gateway. Since the Payment Gateway ID - is set in the configuration file, you will need to run your - own instance of this project to set it. -
- -

Anchor strings - (AutoPlace) - are used to position the fields in the documents. -

- - -

Documentation about this example.

-
- -

API method used: - Envelopes::create. -

- -

- View source file ${sourceFile} on GitHub. -

- - - -
-
- - - We'll never share your email with anyone else. -
-
- - -
-
- - - The email for the cc recipient must be different from the signer's email. -
-
- - -
- - -
-
- -

Problem: please set the DS_PAYMENT_GATEWAY_ID value in the configuration file.

-
-
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg015.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg015.jsp deleted file mode 100644 index 7f451ab3..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg015.jsp +++ /dev/null @@ -1,51 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

15. Get the tab data from an envelope.

- -

Get the tab (field) values from an envelope for all of the envelope's recipients.

- -

- This method is used to read the updated tab values from - the envelope. The method can be used after the envelope is complete or while it is - still in progress. -

- - - - -

Documentation about this example.

-
- -

- API method used: - EnvelopeFormData::get. -

- -

- View source file ${sourceFile} on GitHub. -

- - - -

- The last envelope you created with this example launcher will be queried. - Recommendation: use example 9, then this example, since example 9 includes many tabs of different types. -

- -
- - -
-
- -

Problem: please first create an envelope using example 9.
- Thank you.

- -
- -
-
-
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg016.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg016.jsp deleted file mode 100644 index aaa47d98..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg016.jsp +++ /dev/null @@ -1,56 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

16. Set tab values for an envelope.

- -

- This example creates an example with both read-only tabs (fields) and tabs that can - be updated by the recipient. -

-

The example also sets custom metadata in the envelope via the envelope custom fields feature.

- - - - -

Documentation about this example.

-
- -

- API method used: - EnvelopeFormData::get. -

- -

- View source file ${sourceFile} on GitHub. -

- - -
-
- - - We'll never share your email with anyone else. -
-
- - -
-
- - - The email for the cc recipient must be different from the signer's email. -
-
- - -
- - -
- - - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg017.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg017.jsp deleted file mode 100644 index 50aeba3f..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg017.jsp +++ /dev/null @@ -1,64 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - - -

17. Set template tab values

-

- This example sets the value of a template's tabs. It includes setting - radio button and checkbox tabs. -

-

The example also sets custom metadata in the envelope via the envelope custom fields feature.

- - -

Documentation about this example.

-
- -

API method used: - Envelopes::create. -

-

- View source file ${sourceFile} on GitHub. -

- - - -

The template you created via example 8 will be used.

-
-
- - - We'll never share your email with anyone else. -
-
- - -
-
- - - The email for the cc recipient must be different from the signer's email. -
-
- - -
- - -
- -
- -

Problem: please first create the template using example 8.
- Thank you.

- -
- -
-
-
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg018.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg018.jsp deleted file mode 100644 index 0a90c072..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg018.jsp +++ /dev/null @@ -1,52 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

18. Get the custom field data for an envelope

-

- Get the data values associated with the envelope itself. The custom data fields enable you to - add additional meta-data to the envelope. The custom data fields can be set by the Sender - via the DocuSign web tool, or can be set programmatically. The data can be included in the - envelope's certificate of completion. -

- -

- This method is used to read the custom field values from - an envelope. -

- - -

Documentation about this example.

-
- - -

- API method used: - EnvelopeCustomFields::list. -

-

- View source file ${sourceFile} on GitHub. -

- - - -

- The last envelope you created with this example launcher will be queried. - Recommendation: use example 9, then this example, since example 9 includes many tabs of different types. -

-
- - -
-
- -

Problem: please first create an envelope using example 9.
- Thank you.

- -
- -
-
-
- - - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg019.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg019.jsp deleted file mode 100644 index e0955e80..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg019.jsp +++ /dev/null @@ -1,51 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

19. Send an envelope with a recipient using Access Code Authentication.

- -

- The envelope includes a pdf document. Anchor text - (AutoPlace) - is used to position the signing fields in the documents. -

-

- This is a general example of creating and sending an envelope (a signing request) using An Access Code for Recipient Authentication. -

- - -

Documentation about this example.

-
- -

API method used: - Envelopes::create. -

- -

- View source file ${sourceFile} on GitHub. -

- - -
-
- - - Provide this string to a recipient that is different such as in person or by mail or via different email. -
-
- - - We'll never share your email with anyone else. -
-
- - -
- - -
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg020.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg020.jsp deleted file mode 100644 index c0daa432..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg020.jsp +++ /dev/null @@ -1,36 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

20. Send an envelope with a recipient using SMS Authentication.

- - -

Documentation about this example.

-
- -

API method used: - Envelopes::create. -

- -

- View source file ${sourceFile} on GitHub. -

- - -
-
- - - We'll never share your email with anyone else. -
-
- - -
- - -
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg021.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg021.jsp deleted file mode 100644 index 85007e4d..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg021.jsp +++ /dev/null @@ -1,36 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

21. Send an envelope with a recipient using Phone Authentication.

- - -

Documentation about this example.

-
- -

API method used: - Envelopes::create. -

- -

- View source file ${sourceFile} on GitHub. -

- - -
-
- - - We'll never share your email with anyone else. -
-
- - -
- - -
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg022.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg022.jsp deleted file mode 100644 index 667e08c9..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg022.jsp +++ /dev/null @@ -1,36 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

22. Send an envelope with a recipient using Knowledge-Based Authentication.

- - -

Documentation about this example.

-
- -

API method used: - Envelopes::create. -

- -

- View source file ${sourceFile} on GitHub. -

- - -
-
- - - We'll never share your email with anyone else. -
-
- - -
- - -
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg023.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg023.jsp deleted file mode 100644 index cc628383..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg023.jsp +++ /dev/null @@ -1,45 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

23. Requiring Id Verification for a Recipient

- -

- The envelope includes a pdf document. Anchor text - (AutoPlace) - is used to position the signing fields in the documents. -

-

- This is a general example of creating and sending an envelope (a signing request) using ID Verification for Recipient Authentication. -

- - -

Documentation about this example.

-
- -

- API method used: - Envelopes::create. -

- -

- View source file ${sourceFile} on GitHub. -

- -
-
- - - We'll never share your email with anyone else. -
-
- - -
- - -
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg024.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg024.jsp deleted file mode 100644 index dbd066d9..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg024.jsp +++ /dev/null @@ -1,34 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

24. ${title}.

- -

-Permission profiles are collections of account settings that determine the behavior and actions -available to the user groups to which they're applied. This code example demonstrates how to -create a permission profile with the eSignature REST API. -

- - -

Documentation about this example.

-
- -

API method used: - AccountPermissionProfiles::create. -

- -

- View source file ${sourceFile} on GitHub. -

- - -
-
- - -
- - -
- - \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg026.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg026.jsp deleted file mode 100644 index e71c0566..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg026.jsp +++ /dev/null @@ -1,66 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

26. ${title}.

- -

-This code example demonstrates how to edit individual permission settings on a permissions profile -with the eSignature REST API. -

- - -

Documentation about this example.

-
- -

API method used: - AccountPermissionProfiles::update. -

- -

- View source file ${sourceFile} on GitHub. -

- - -
-
- - -
- -<%--
--%> -<%-- --%> -<%-- --%> -<%--
--%> -<%-- --%> -<%--

There is no account role settings is defined

--%> -<%--
--%> -<%-- --%> -<%-- --%> -<%-- --%> -<%-- --%> -<%-- --%> -<%-- --%> -<%-- --%> -<%-- --%> -<%--
${property.name}${property.leftValue}
--%> - - -
- - - - \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg027.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg027.jsp deleted file mode 100644 index c427e350..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg027.jsp +++ /dev/null @@ -1,39 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

27. ${title}.

- -

- Permission profiles are collections of account settings that determine the behavior and actions - available to the user groups to which they're applied. This code example demonstrates how to - delete a permission profile with the eSignature REST API. -

- - -

Documentation about this example.

-
- -

API method used: - AccountPermissionProfiles::update. -

- -

- View source file ${sourceFile} on GitHub. -

- - -
-
- - -
- - - -
- - \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg028.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg028.jsp deleted file mode 100644 index 131aed33..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg028.jsp +++ /dev/null @@ -1,50 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

28. Creating a brand.

- -

- The brand includes a Brand Name Configure Brands. -

-

- DocuSign enables you to customize the eSignature sending and signing experience with your own - branding elements-logo, colors, and more-stored as a collection of settings called a brand in - your DocuSign account. This code example demonstrates how to create a brand with the - eSignature REST API that you subsequently apply to a DocuSign envelope. -

- - -

Documentation about this example.

-
- -

API method used: - AccountBrands::create. -

- -

- View source file ${sourceFile} on GitHub. -

- - -
-

- New brand -

-
- - -
-
- - -
- - -
- - \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg029.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg029.jsp deleted file mode 100644 index 00924592..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg029.jsp +++ /dev/null @@ -1,74 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> - - -

29. Applying a brand to an envelope

-

- The envelope includes a pdf document. Anchor text (AutoPlace) - is used to position the signing fields in the documents. -

-

- DocuSign enables you to customize the eSignature sending and signing experience with your own - branding elements-logo, colors, and more-stored as a collection of settings called a brand in - your DocuSign account. This code example demonstrates how to create a brand with the eSignature - REST API that you subsequently apply to a DocuSign envelope. -

- -

- Documentation about - this example. -

-
- - -

- API method used: Envelopes::create. -

-

- View source file ${sourceFile} - on GitHub. -

- - - -
-
- We'll never - share your email with anyone else. -
-
- -
-
- - - - There are no brands - created in your account. Create ones at the 'Create brand' page. - - -
- - -
-
- -

Problem: please first create the brand(s) using example 24.
Thank you.

-
- -
-
-
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg030.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg030.jsp deleted file mode 100644 index 8f816b41..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg030.jsp +++ /dev/null @@ -1,102 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> - - -

30. Applying a brand to a template

-

This code example demonstrates how to apply a brand to an template.

-

- The envelope is defined by the template. The signer and cc recipient - name and email are used to fill in the template's roles. -

- -

- This example demonstrates a common pattern for DocuSign integrations: envelopes will be sent - programmatically, based on a template. If the template definition needs to be updated, the - DocuSign web tool can be used to easily update the template, thus avoiding the need to make - software changes. -

- -

- Documentation about this example. -

-
- - -

- API method used: Envelopes::create. -

-

- View source file ${sourceFile} on GitHub. -

- - - -

The template you created via example 8 and brands created via - example 24 will be used.

-
-
- We'll never - share your email with anyone else. -
-
- -
-
- - The email - and/or name for the cc recipient must be different from the signer. -
-
- -
-
- -
-
- - -
- - -
-
- - -

Problem: please create the template using example 8.

-
- -

Problem: please create the brand using example 24.

-
- -
- -
-
- -
- -
-
-
-
- - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg031.jsp b/src/main/webapp/WEB-INF/templates/views/pages/examples/eg031.jsp deleted file mode 100644 index 654ef489..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/examples/eg031.jsp +++ /dev/null @@ -1,87 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - -

31. ${title}.

- -

- This code example demonstrates how to send envelopes in bulk to multiple recipients with the - eSignature API. To accomplish the task, you will first create a bulk send recipients list, - and then create an envelope. From there, you will combine the envelope and bulk list to - initiate bulk send. Method BulkSend::createBulkSendList creates a bulk send list that you can - use to send an envelope to up to 1,000 recipients at once. -

- - -

Documentation about this example.

-
- -

API methods used: - EnvelopeRecipients::create, - Envelopes::create, - BulkEnvelopes::get, - EnvelopeCustomFields::create, - BulkSend::createBulkSendList - EnvelopeRecipients::create. -

- -

- View source file ${sourceFile} on GitHub. -

- - -
-
- - - We'll never share your email with anyone else. -
-
- - -
-
- - - The email and/or name for the cc recipient must be different - from the signer. - -
-
- - -
- -
- - - We'll never share your email with anyone else. -
-
- - -
-
- - - The email and/or name for the cc recipient must be different - from the signer. - -
-
- - -
- - - -
- - \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/index.jsp b/src/main/webapp/WEB-INF/templates/views/pages/index.jsp deleted file mode 100644 index a99c03c3..00000000 --- a/src/main/webapp/WEB-INF/templates/views/pages/index.jsp +++ /dev/null @@ -1,252 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - - - -
-

Welcome!

-

Welcome to the DocuSign Java Example Launcher - using OAuth2.

-
-
- -
-

Welcome

-

This launcher both demonstrates use of common OAuth2 grant flows and multiple usage examples from the DocuSign eSignature REST API.

- -

Documentation on using OAuth Authorization Code Grant from a Java application.

-
- -

Basic Examples

- -

1. Embedded Signing Ceremony

-

This example sends an envelope, and then uses an embedded signing ceremony for the first signer. - With embedded signing, the DocuSign signing ceremony is initiated from your website. -

-

API methods used: - Envelopes::create and - EnvelopeViews::createRecipient. -

- -

2. Send an envelope with a remote (email) signer and cc recipient

-

The envelope includes a pdf, Word, and HTML document. Anchor text - (AutoPlace) - is used to position the signing fields in the documents. -

-

API method used: - Envelopes::create. -

- -

3. List envelopes in the user's account

-

List the envelopes created in the last 30 days. -

-

API method used: - Envelopes::listStatusChanges. -

- -

4. Get an envelope's basic information and status

-

List the basic information about an envelope, including its overall status. - Additional API/SDK methods may be used to get additional information about the - envelope, its documents, recipients, etc. -

-

API method used: - Envelopes::get. -

- -

5. List an envelope's recipients and their status

-

List the envelope's recipients, including their current status. -

-

API method used: - EnvelopeRecipients::list. -

- -

6. List an envelope's documents

-

List the envelope's documents. A Certificate of Completion document - is also associated with every envelope. -

-

API method used: - EnvelopeDocuments::list. -

- -

7. Download a document from an envelope

-

An envelope's documents can be downloaded one by one or as a complete set. -

-

API method used: - EnvelopeDocuments::get. -

- -

8. Create a template

-

Create a template with two roles, signer and cc.

-

API methods used: - Templates::list, - Templates::create. -

- -

9. Send an envelope using a template

-

The envelope is defined by the template. - The signer and cc recipient name and email are used to fill in the template's roles.

-

API method used: - Envelopes::create. -

- -

10. Send an envelope using binary document transfer

-

The envelope includes a pdf, Word, and HTML document.

-

Multipart data transfer is used to send the documents in binary format to DocuSign. - Binary transfer is 33% more efficient than base64 encoding and is recommended for documents over 15M Bytes. - Binary transfer is not yet supported by the SDK. -

-

API method used: - Envelopes::create. -

- -

11. Embedded sending

-

An envelope will be created in draft mode. The DocuSign - web tool (NDSE) will then be shown, enabling further updates - to the envelope before it is sent. -

-

API methods used: - Envelopes::create, - EnvelopeViews::createSender. - -

12. Embedded DocuSign web tool

-

Redirect the user to the DocuSign web tool.

-

API method used: - EnvelopeViews::createConsole. -

- -

13. Embedded Signing Ceremony from a template with an added document

-

This example sends an envelope based on a template.

-

In addition to the template's document(s), the example adds an - additional document to the envelope by using the - Composite Templates - feature.

-

API methods used: - Envelopes::create and - EnvelopeViews::createRecipient. -

- -

14. Send an envelope with an order form and payment field

-

Anchor text - (AutoPlace) - is used to position the fields in the documents. -

-

API method used: - Envelopes::create. -

- - - -

Tabs Examples

-

15. Get the tab data from an envelope

-

This example retrieves the tab (field) values from an envelope.

-

- API method used: - EnvelopeFormData::get. -

- -

16. Set tab values for an envelope

-

This example sets the tab (field) values for an envelope including tabs that can and cannot be changed by the signer.

-

- API method used: - Envelopes::create and - EnvelopeViews::createRecipient. -

- -

17. Set template tab values

-

This example sets the tab (field) values for a template being used by an envelope.

-

- API method used: - Envelopes::create and - EnvelopeViews::createRecipient. -

- -

18. List envelope custom metadata field values

-

This example lists the envelope's custom metadata field values.

-

- API method used: - EnvelopeCustomFields::list. -

- - -

19. Send an envelope with Access Code Authentication

-

This example sends and envelope that requires an access-code for the purpose of multi-factor authentication.

-

API method used: - Envelopes::create. -

- -

20. Send an envelope with SMS Authentication

-

This example sends and envelope that requires entering in a six digit code from an text message for the purpose of multi-factor authentication.

-

API method used: - Envelopes::create. -

- -

21. Send an envelope with Phone Authentication

-

This example sends and envelope that requires entering in a voice-based response code for the purpose of multi-factor authentication.

-

API method used: - Envelopes::create. -

- -

22. Send an envelope with Knowledge-Based Authentication

-

This example sends and envelope that requires passing a Public records check to validate identity for the purpose of multi-factor authentication.

-

API method used: - Envelopes::create. -

- -

23. Send an envelope with ID Verification Authentication

-

Submit an envelope that requires verification of a government issued identity.

-

- API method used: - Envelopes::create. -

- -

24. Creating a Permission Profile

-

- Coming Soon -

- -

25. Setting a permission profile

-

This example allows you to set a permission profile on an existing user group.

-

API method used: - Groups::update. -

- -

26. Modify a Permission Profile

-

- Coming Soon -

- -

27. Deleting a permission profile

-

This example lists all available permissions profiles and allows you to delete any without associated users. Please note that you cannot remove "Everyone" nor "Administrator" permission profiles.

-

API method used: - AccountPermissionProfiles::create. -

- -

28. Create a brand

-

This example will create an account brand that can be used to apply customization to your envelopes such as your own logo, colors, and text elements.

-

API method used: - AccountBrands::create. -

- -

29. Applying a brand to an envelope

-

This example will show you how to create an envelope using any of the created brands on your account.

-

API method used: - Envelopes::create. -

- -

30. Applying a brand to a template

-

This example will show you how to create an envelope using a brand

-

API method used: - Envelopes::create. -

- -

31. Bulk sending envelopes to multiple recipients

-

- Coming Soon -

-
- - - - - - diff --git a/src/main/webapp/WEB-INF/templates/views/pages/links_to_api_methods.jsp b/src/main/webapp/WEB-INF/templates/views/pages/links_to_api_methods.jsp new file mode 100644 index 00000000..158ef8ff --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/links_to_api_methods.jsp @@ -0,0 +1,30 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + +

+ + + + ${launcherTexts.getAPIMethodUsed()} + + + ${launcherTexts.getAPIMethodUsedPlural()} + + + + + ${link.getPathName()} + + + + . + + + and + + + , + + + + +

diff --git a/src/main/webapp/WEB-INF/templates/views/pages/maestro/examples/embed.jsp b/src/main/webapp/WEB-INF/templates/views/pages/maestro/examples/embed.jsp new file mode 100644 index 00000000..ad984bc0 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/maestro/examples/embed.jsp @@ -0,0 +1,19 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + +

${example.getExampleName()}

+

${example.getResultsPageText()}

+ + + + + + +

${launcherTexts.getContinueButton()}

+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/maestro/examples/mae001.jsp b/src/main/webapp/WEB-INF/templates/views/pages/maestro/examples/mae001.jsp new file mode 100644 index 00000000..2c48bfba --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/maestro/examples/mae001.jsp @@ -0,0 +1,136 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + + + +

${example.getExampleName()}

+ + + +

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ + + +

+ ${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToEightCodeExample)} +

+ +
+ +
+
+ +

${example.getForms().get(formNumber).getFormName()}

+ +
+
+ + + +
+ +
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+ +
+ + + +
+ +
+ + + + + + ${launcherTexts.getHelpingTexts().getCCEmailShouldDifferFromSigner()} + +
+ +
+ + + +
+ + + +
+
+
+
+ +

+ ${publishLink} +

+
+ +
+
+
+ + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/maestro/examples/mae002.jsp b/src/main/webapp/WEB-INF/templates/views/pages/maestro/examples/mae002.jsp new file mode 100644 index 00000000..64a592de --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/maestro/examples/mae002.jsp @@ -0,0 +1,34 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + +

${example.getExampleName()}

+ + + +

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+ +
+
+ +

+ ${example.getCustomErrorTexts().get(0).getErrorMessage()} +

+
+ +
+
+
+ + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/maestro/examples/mae003.jsp b/src/main/webapp/WEB-INF/templates/views/pages/maestro/examples/mae003.jsp new file mode 100644 index 00000000..64a592de --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/maestro/examples/mae003.jsp @@ -0,0 +1,34 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + +

${example.getExampleName()}

+ + + +

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+ +
+
+ +

+ ${example.getCustomErrorTexts().get(0).getErrorMessage()} +

+
+ +
+
+
+ + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/maestro/examples/mae004.jsp b/src/main/webapp/WEB-INF/templates/views/pages/maestro/examples/mae004.jsp new file mode 100644 index 00000000..64a592de --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/maestro/examples/mae004.jsp @@ -0,0 +1,34 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + +

${example.getExampleName()}

+ + + +

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+ +
+
+ +

+ ${example.getCustomErrorTexts().get(0).getErrorMessage()} +

+
+ +
+
+
+ + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/monitor/examples/m001.jsp b/src/main/webapp/WEB-INF/templates/views/pages/monitor/examples/m001.jsp new file mode 100644 index 00000000..3c554970 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/monitor/examples/m001.jsp @@ -0,0 +1,21 @@ +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core' %> + + +

1. ${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/monitor/examples/m002.jsp b/src/main/webapp/WEB-INF/templates/views/pages/monitor/examples/m002.jsp new file mode 100644 index 00000000..990a6fd9 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/monitor/examples/m002.jsp @@ -0,0 +1,49 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + +

2. ${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

+ ${viewSourceFile} +

+ +

+ ${example.getForms().get(formNumber).getFormName()} +

+ +
+ +
+ + + +
+
+ + + +
+ + +
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/navigator/examples/nav001.jsp b/src/main/webapp/WEB-INF/templates/views/pages/navigator/examples/nav001.jsp new file mode 100644 index 00000000..9b4fb39a --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/navigator/examples/nav001.jsp @@ -0,0 +1,25 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+ + +
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/navigator/examples/nav002.jsp b/src/main/webapp/WEB-INF/templates/views/pages/navigator/examples/nav002.jsp new file mode 100644 index 00000000..feebd660 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/navigator/examples/nav002.jsp @@ -0,0 +1,35 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + +
+ + +
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/navigator/examples/nav003.jsp b/src/main/webapp/WEB-INF/templates/views/pages/navigator/examples/nav003.jsp new file mode 100644 index 00000000..9a6e17c3 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/navigator/examples/nav003.jsp @@ -0,0 +1,23 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/navigator/examples/nav003CompleteUpload.jsp b/src/main/webapp/WEB-INF/templates/views/pages/navigator/examples/nav003CompleteUpload.jsp new file mode 100644 index 00000000..2630f97e --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/navigator/examples/nav003CompleteUpload.jsp @@ -0,0 +1,14 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + +

${example.getExampleName()}

+

${example.getAdditionalPage().get(0).getResultsPageText()}

+ +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/navigator/examples/nav003UploadDocuments.jsp b/src/main/webapp/WEB-INF/templates/views/pages/navigator/examples/nav003UploadDocuments.jsp new file mode 100644 index 00000000..71b3061c --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/navigator/examples/nav003UploadDocuments.jsp @@ -0,0 +1,14 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + +

${example.getExampleName()}

+

${example.getResultsPageText()}

+ +
+ + +
+ + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/notary/examples/n004.jsp b/src/main/webapp/WEB-INF/templates/views/pages/notary/examples/n004.jsp new file mode 100644 index 00000000..0dbfc662 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/notary/examples/n004.jsp @@ -0,0 +1,47 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

Documentation about this example.

+
+ + + +

+ ${viewSourceFile} +

+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+
+ + + +
+ + +
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r001.jsp b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r001.jsp new file mode 100644 index 00000000..7c855526 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r001.jsp @@ -0,0 +1,32 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

+ ${viewSourceFile} +

+ + +
+
+ + + +
+ + +
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r002.jsp b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r002.jsp new file mode 100644 index 00000000..06f60a40 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r002.jsp @@ -0,0 +1,52 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+

+ ${viewSourceFile} +

+ + + + +

+ ${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText()} +

+
+ +
+
+ + + +
+
+ + + +
+ + +
+
+
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r003.jsp b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r003.jsp new file mode 100644 index 00000000..e043d89c --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r003.jsp @@ -0,0 +1,41 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+

+ ${viewSourceFile} +

+ + + + +

+ ${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToFirstCodeExample)} +

+
+ +
+
+ + + +
+ + +
+
+
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r004.jsp b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r004.jsp new file mode 100644 index 00000000..0d74b7b7 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r004.jsp @@ -0,0 +1,65 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+

+ ${viewSourceFile} +

+ + + +
+ + +
+ + + +
+
+ + ${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToFirstCodeExample)} + +
+ + +
+ + + + + + + +

Problem: this room have already all the form

+
+
+
+
+
+ + +
+ + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r005.jsp b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r005.jsp new file mode 100644 index 00000000..0217f06c --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r005.jsp @@ -0,0 +1,46 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+

+ ${viewSourceFile} +

+ + +
+ +
+ + + +
+
+ + + +
+ + + +
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r006.jsp b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r006.jsp new file mode 100644 index 00000000..64086a46 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r006.jsp @@ -0,0 +1,81 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+

+ ${viewSourceFile} +

+ + + + + ${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToFirstCodeExample)} + +
+ +
+
+ + +
+
+
+

${example.getForms().get(formNumber).getFormName()}

+ + + +
+ + +
+
+
+
+ + + ${example.getRedirectsToOtherCodeExamples().get(redirectNoDocumentsNumber).getRedirectText().replaceFirst("\\{0}", redirectToForthCodeExample)} +
+ +
+
+ + +
+
+
+

${example.getForms().get(formDocumentsNumber).getFormName()}

+ + + +
+ + + +
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r007.jsp b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r007.jsp new file mode 100644 index 00000000..5ba4a75f --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r007.jsp @@ -0,0 +1,31 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+

+ ${viewSourceFile} +

+ + +
+
+ + + +
+ + +
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r008.jsp b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r008.jsp new file mode 100644 index 00000000..dd253d60 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r008.jsp @@ -0,0 +1,54 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+

+ ${viewSourceFile} +

+ + + +
+ + + ${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToSeventhCodeExample)} + + +

Problem: cannot find any offices

+
+ +
+ + +
+
+ + +
+ + +
+
+
+ + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r009.jsp b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r009.jsp new file mode 100644 index 00000000..00794187 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/rooms/examples/r009.jsp @@ -0,0 +1,56 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+

+ ${viewSourceFile} +

+ + + +
+ + + ${example.getRedirectsToOtherCodeExamples().get(redirectNumber).getRedirectText().replaceFirst("\\{0}", redirectToSeventhCodeExample)} + + +

Problem: cannot find any forms, please first create a form

+
+ +
+ + + +
+
+ + + +
+ + +
+
+
+ + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/webforms/examples/embed.jsp b/src/main/webapp/WEB-INF/templates/views/pages/webforms/examples/embed.jsp new file mode 100644 index 00000000..9e9109f7 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/webforms/examples/embed.jsp @@ -0,0 +1,85 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + +
+
+ + +
${page.getResultsPageText()}
+
+
+ +
+

Web Form will render here

+
+
+
+ + + +

${launcherTexts.getContinueButton()}

+ + + + + + + + + + + + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/webforms/examples/web001.jsp b/src/main/webapp/WEB-INF/templates/views/pages/webforms/examples/web001.jsp new file mode 100644 index 00000000..842148d8 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/webforms/examples/web001.jsp @@ -0,0 +1,31 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + +

${example.getExampleName()}

+ + +

${example.getExampleDescription()}

+ +

+ ${viewSourceFile} +

+
+ + +
+
+ + + +

${page.getResultsPageText().replaceFirst("\\{0}", "src/main/resources")}

+
+
+
+ + +
+
+
+ + + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/webforms/examples/web002.jsp b/src/main/webapp/WEB-INF/templates/views/pages/webforms/examples/web002.jsp new file mode 100644 index 00000000..5c7a6b98 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/webforms/examples/web002.jsp @@ -0,0 +1,32 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + +

${example.getExampleName()}

+ + +

${example.getExampleDescription()}

+ + +

+ ${viewSourceFile} +

+
+ + +
+
+ + + +

${page.getResultsPageText().replaceFirst("\\{0}", "src/main/resources")}

+
+
+
+ + +
+
+
+ + + diff --git a/src/main/webapp/WEB-INF/templates/views/pages/workspaces/examples/work001.jsp b/src/main/webapp/WEB-INF/templates/views/pages/workspaces/examples/work001.jsp new file mode 100644 index 00000000..66313d2e --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/workspaces/examples/work001.jsp @@ -0,0 +1,31 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

+ ${viewSourceFile} +

+ +
+
+ + + +
+ + +
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/workspaces/examples/work002.jsp b/src/main/webapp/WEB-INF/templates/views/pages/workspaces/examples/work002.jsp new file mode 100644 index 00000000..76360e9a --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/workspaces/examples/work002.jsp @@ -0,0 +1,101 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

+ ${viewSourceFile} +

+ + + +

+ ${example.getRedirectsToOtherCodeExamples().get(redirectToFirstCodeExampleNumber).getRedirectText().replaceFirst("\\{0}", redirectToFirstCodeExample)} +

+
+ +
+
+ + + + + + + ${launcherTexts.getHelpingTexts().getSpecifyNameWithExtension()} + +
+
+ + + + + + + ${documentFolder} + +
+ + +
+ + +
+
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/workspaces/examples/work003.jsp b/src/main/webapp/WEB-INF/templates/views/pages/workspaces/examples/work003.jsp new file mode 100644 index 00000000..42548525 --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/workspaces/examples/work003.jsp @@ -0,0 +1,63 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

+ ${viewSourceFile} +

+ + + +

+ ${example.getRedirectsToOtherCodeExamples().get(redirectToFirstCodeExampleNumber).getRedirectText().replaceFirst("\\{0}", redirectToFirstCodeExample)} +

+
+ +

+ ${example.getRedirectsToOtherCodeExamples().get(redirectToSecondCodeExampleNumber).getRedirectText().replaceFirst("\\{0}", redirectToSecondCodeExample)} +

+
+ +
+
+ + + +
+
+ + + +
+ + +
+
+
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/pages/workspaces/examples/work005.jsp b/src/main/webapp/WEB-INF/templates/views/pages/workspaces/examples/work005.jsp new file mode 100644 index 00000000..35be0fdf --- /dev/null +++ b/src/main/webapp/WEB-INF/templates/views/pages/workspaces/examples/work005.jsp @@ -0,0 +1,52 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + +

${example.getExampleName()}

+

${example.getExampleDescription()}

+ +

+ ${viewSourceFile} +

+ + + +

+ ${example.getRedirectsToOtherCodeExamples().get(noWorkspaceRedirect).getRedirectText().replaceFirst("\\{0}", redirectToFirstCodeExample)} +

+
+ +

+ ${example.getRedirectsToOtherCodeExamples().get(noCreatorIdRedirect).getRedirectText().replaceFirst("\\{0}", redirectToFirstCodeExample)} +

+
+ +
+
+ + + + + + ${launcherTexts.getHelpingTexts().getEmailWontBeShared()} + +
+ + +
+
+
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/views/partials/foot.jsp b/src/main/webapp/WEB-INF/templates/views/partials/foot.jsp index bbe98422..2ed8a460 100644 --- a/src/main/webapp/WEB-INF/templates/views/partials/foot.jsp +++ b/src/main/webapp/WEB-INF/templates/views/partials/foot.jsp @@ -18,10 +18,19 @@ integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"> - + + + + + + diff --git a/src/main/webapp/WEB-INF/templates/views/partials/head.jsp b/src/main/webapp/WEB-INF/templates/views/partials/head.jsp index 349c038b..3b03f8ee 100644 --- a/src/main/webapp/WEB-INF/templates/views/partials/head.jsp +++ b/src/main/webapp/WEB-INF/templates/views/partials/head.jsp @@ -7,7 +7,7 @@ - + ${title} @@ -20,7 +20,7 @@ - -
- - -

- DocuSign Account: ${locals.session.accountName}. -

-
- - @@ -77,6 +69,7 @@
- + -
+
+
\ No newline at end of file diff --git a/src/test/java/tests/Click/ActivateClickwrapTest.java b/src/test/java/tests/Click/ActivateClickwrapTest.java new file mode 100644 index 00000000..fa8911aa --- /dev/null +++ b/src/test/java/tests/Click/ActivateClickwrapTest.java @@ -0,0 +1,56 @@ +package tests.Click; + +import com.docusign.click.api.AccountsApi; +import com.docusign.click.client.ApiClient; +import com.docusign.click.client.ApiException; +import com.docusign.click.model.ClickwrapVersionSummaryResponse; +import com.docusign.controller.click.services.ActivateClickwrapService; +import com.docusign.core.model.ApiType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import tests.common.JWTLoginMethodTest; +import tests.common.TestConfig; + +import java.io.IOException; + +public final class ActivateClickwrapTest { + private static final String BEARER_AUTHENTICATION = "Bearer "; + + private static final String basePathAddition = "/clickapi"; + + private final ApiClient apiClient; + + private final AccountsApi accountsApi; + + private final TestConfig testConfig; + + public ActivateClickwrapTest() throws IOException, ApiException { + JWTLoginMethodTest.RequestJWTUserToken_CorrectInputValues_ReturnOAuthToken(ApiType.CLICK); + this.testConfig = TestConfig.getInstance(); + + this.apiClient = new ApiClient(testConfig.getBasePath() + basePathAddition); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + testConfig.getAccessToken()); + this.accountsApi = new AccountsApi(apiClient); + CreateClickwrapTest createClickwrapTest = new CreateClickwrapTest(); + createClickwrapTest.CreateClickwrap_CorrectInputValues_ReturnsClickwrapVersionSummaryResponse(); + } + + @Test + public void ActivateClickwrap_CorrectInputValues_ReturnsClickwrapVersionSummaryResponse() throws ApiException { + // Arrange + var statusActive = "active"; + + // Act + ClickwrapVersionSummaryResponse clickwrapVersionSummaryResponse = ActivateClickwrapService.activateClickwrap( + this.accountsApi, + testConfig.getAccountId(), + testConfig.getInactiveClickwrap().getClickwrapId(), + testConfig.getInactiveClickwrap().getVersionNumber() + ); + + // Assert + Assertions.assertNotNull(clickwrapVersionSummaryResponse); + Assertions.assertEquals(statusActive, clickwrapVersionSummaryResponse.getStatus()); + } +} diff --git a/src/test/java/tests/Click/CreateClickwrapTest.java b/src/test/java/tests/Click/CreateClickwrapTest.java new file mode 100644 index 00000000..3561ef16 --- /dev/null +++ b/src/test/java/tests/Click/CreateClickwrapTest.java @@ -0,0 +1,111 @@ +package tests.Click; + +import com.docusign.click.api.AccountsApi; +import com.docusign.click.client.ApiClient; +import com.docusign.click.client.ApiException; +import com.docusign.click.model.ClickwrapRequest; +import com.docusign.click.model.ClickwrapVersionSummaryResponse; +import com.docusign.click.model.DisplaySettings; +import com.docusign.click.model.Document; +import com.docusign.controller.click.examples.ClickwrapHelper; +import com.docusign.controller.click.services.CreateClickwrapService; +import com.docusign.core.model.ApiType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import tests.common.JWTLoginMethodTest; +import tests.common.TestConfig; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Random; + +public final class CreateClickwrapTest { + private static final String BEARER_AUTHENTICATION = "Bearer "; + + private static final String DOCUMENT_FILE_NAME = "TermsOfService.pdf"; + + private static final Integer DOCUMENT_ORDER = 0; + + private static final String DOCUMENT_NAME = "Terms of Service"; + + private static final String basePathAddition = "/clickapi"; + + private final ApiClient apiClient; + + private final AccountsApi accountsApi; + + private final TestConfig testConfig; + + public CreateClickwrapTest() throws IOException { + JWTLoginMethodTest.RequestJWTUserToken_CorrectInputValues_ReturnOAuthToken(ApiType.CLICK); + this.testConfig = TestConfig.getInstance(); + + this.apiClient = new ApiClient(testConfig.getBasePath() + basePathAddition); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + testConfig.getAccessToken()); + this.accountsApi = new AccountsApi(apiClient); + } + + @Test + public void CreateClickwrapRequest_CorrectInputValues_ReturnsClickwrapRequest() throws IOException { + // Arrange + String clickwrapName = "Clickwrap name"; + String displayName = "Terms of Service"; + String consentButtonText = "I Agree"; + String format = "modal"; + String documentDisplay = "document"; + + Document document = new ClickwrapHelper().createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, DOCUMENT_ORDER); + DisplaySettings displaySettings = new DisplaySettings() + .displayName(displayName) + .consentButtonText(consentButtonText) + .downloadable(true) + .format(format) + .mustRead(true) + .requireAccept(true) + .documentDisplay(documentDisplay); + + ClickwrapRequest expectedClickwrapRequest = new ClickwrapRequest() + .addDocumentsItem(document) + .clickwrapName(clickwrapName) + .requireReacceptance(true) + .displaySettings(displaySettings); + + // Act + ClickwrapRequest clickwrapRequest = CreateClickwrapService.createClickwrapRequest( + clickwrapName, + DOCUMENT_FILE_NAME, + DOCUMENT_NAME, + DOCUMENT_ORDER); + + // Assert + Assertions.assertNotNull(clickwrapRequest); + Assertions.assertEquals(expectedClickwrapRequest, clickwrapRequest); + } + + @Test + public void CreateClickwrap_CorrectInputValues_ReturnsClickwrapVersionSummaryResponse() throws ApiException, IOException { + // Arrange + byte[] byteArray = new byte[8]; + new Random().nextBytes(byteArray); + String clickwrapName = new String(byteArray, StandardCharsets.UTF_8); + + ClickwrapRequest clickwrapRequest = CreateClickwrapService.createClickwrapRequest( + clickwrapName, + DOCUMENT_FILE_NAME, + DOCUMENT_NAME, + DOCUMENT_ORDER); + + // Act + ClickwrapVersionSummaryResponse clickwrapVersionSummaryResponse = CreateClickwrapService.createClickwrap( + this.accountsApi, + testConfig.getAccountId(), + clickwrapRequest); + + testConfig.setInactiveClickwrap(clickwrapVersionSummaryResponse); + + // Assert + Assertions.assertNotNull(clickwrapVersionSummaryResponse); + Assertions.assertEquals(clickwrapName, clickwrapVersionSummaryResponse.getClickwrapName()); + } +} diff --git a/src/test/java/tests/common/JWTLoginMethodTest.java b/src/test/java/tests/common/JWTLoginMethodTest.java new file mode 100644 index 00000000..27ebea62 --- /dev/null +++ b/src/test/java/tests/common/JWTLoginMethodTest.java @@ -0,0 +1,73 @@ +package tests.common; + +import com.docusign.core.model.ApiType; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.client.auth.OAuth; +import org.junit.jupiter.api.Assertions; + +import java.awt.*; +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; + +public final class JWTLoginMethodTest { + + private static final String RedirectUrl = "https://developers.docusign.com/platform/auth/consent"; + + private static final String CONSENT_REQUIRED_MESSAGE = "Consent required, please provide consent in browser window and then run this app again."; + + private static final String CONSENT_REQUIRED_KEYWORD = "consent_required"; + + public static void RequestJWTUserToken_CorrectInputValues_ReturnOAuthToken(ApiType apiType) throws IOException { + TestConfig testConfig = TestConfig.getInstance(); + + try { + ApiClient apiClient = new ApiClient(testConfig.getHost()); + List scopes = Arrays.asList(apiType.getScopes()); + + byte[] privateKeyBytes = Files.exists(Path.of(testConfig.getPrivateKeyPath())) ? + Files.readAllBytes(Paths.get(testConfig.getPrivateKeyPath())) + : testConfig.getPrivateKey().getBytes(); + + OAuth.OAuthToken oAuthToken = apiClient.requestJWTUserToken( + testConfig.getClientId(), + testConfig.getImpersonatedUserId(), + scopes, + privateKeyBytes, + 3600); + String accessToken = oAuthToken.getAccessToken(); + OAuth.UserInfo userInfo = apiClient.getUserInfo(accessToken); + String accountId = userInfo.getAccounts().get(0).getAccountId(); + + Assertions.assertNotNull(accessToken); + Assertions.assertNotNull(accountId); + testConfig.setAccessToken(accessToken); + testConfig.setAccountId(accountId); + } catch (ApiException exp) { + if (exp.getMessage().contains(CONSENT_REQUIRED_KEYWORD)) { + try { + String scopes = "impersonation%20"; + for (String scope : apiType.getScopes()) { + scopes += scope + "%20"; + } + System.out.println(CONSENT_REQUIRED_MESSAGE); + Desktop.getDesktop().browse(new URI( + "https://account-d.docusign.com/oauth/auth?response_type=code&scope=" + + scopes + + "&client_id=" + + testConfig.getClientId() + + "&redirect_uri=" + + JWTLoginMethodTest.RedirectUrl)); + } catch (Exception e) { + System.out.print("Error!!! "); + System.out.print(e.getMessage()); + } + } + } + } +} diff --git a/src/test/java/tests/common/TestConfig.java b/src/test/java/tests/common/TestConfig.java new file mode 100644 index 00000000..562722ed --- /dev/null +++ b/src/test/java/tests/common/TestConfig.java @@ -0,0 +1,112 @@ +package tests.common; + +import com.docusign.click.model.ClickwrapVersionSummaryResponse; +import com.docusign.esign.model.Brand; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import lombok.Getter; +import lombok.Setter; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +@Getter +@Setter +public class TestConfig { + private static TestConfig single_instance = null; + + public String PathToDocuments; + + private String ClientId; + + private String Host; + + private String AccountId; + + private String SignerEmail; + + private String SignerName; + + private String ImpersonatedUserId; + + private String OAuthBasePath; + + private String PrivateKeyPath; + + private String PrivateKey; + + private String AccessToken; + + private String BasePath; + + private String BatchId; + + private String TemplateId; + + private ClickwrapVersionSummaryResponse inactiveClickwrap; + + private Brand brand; + + public TestConfig() throws IOException { + PathToDocuments = System.getProperty("user.dir") + "//src//main//resources//"; + Host = "https://demo.docusign.net"; + OAuthBasePath = "account-d.docusign.com"; + PrivateKeyPath = PathToDocuments + "private.key"; + BasePath = "https://demo.docusign.net"; + + try { + var isFilePresentInTheRepository = Files.exists(Path.of(PathToDocuments + "application.json")); + + if (isFilePresentInTheRepository) { + String source = new String(Files.readAllBytes(Paths.get(PathToDocuments + "application.json"))); + + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + JsonObject originalJsonValue = gson.fromJson(source, JsonObject.class); + JsonObject jwtConfigurationValues = originalJsonValue + .getAsJsonObject("spring") + .getAsJsonObject("security") + .getAsJsonObject("oauth2") + .getAsJsonObject("client") + .getAsJsonObject("registration") + .getAsJsonObject("jwt") + .getAsJsonObject(); + + Object impersonatedUserId = jwtConfigurationValues.get("impersonated-user-guid").toString(); + Object clientId = jwtConfigurationValues.get("client-id").toString(); + Object signerEmail = new JSONObject(source).get("DS_SIGNER_EMAIL"); + Object signerName = new JSONObject(source).get("DS_SIGNER_NAME"); + + if (impersonatedUserId == null || clientId == null || signerEmail == null || signerName == null) { + throw new JSONException("The wrong format of the application.json file."); + } + + ImpersonatedUserId = impersonatedUserId.toString().replace("\"", ""); + ClientId = clientId.toString().replace("\"", ""); + SignerEmail = signerEmail.toString(); + SignerName = signerName.toString(); + } else { + ImpersonatedUserId = System.getenv("IMPERSONATED_USER_ID"); + ClientId = System.getenv("CLIENT_ID"); + SignerEmail = System.getenv("SIGNER_EMAIL"); + SignerName = System.getenv("SIGNER_NAME"); + PrivateKey = System.getenv("PRIVATE_KEY"); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public static TestConfig getInstance() throws IOException { + if (single_instance == null) { + single_instance = new TestConfig(); + } + + return single_instance; + } +} diff --git a/src/test/java/tests/eSignature/AddDocToTemplateTest.java b/src/test/java/tests/eSignature/AddDocToTemplateTest.java new file mode 100644 index 00000000..6b200845 --- /dev/null +++ b/src/test/java/tests/eSignature/AddDocToTemplateTest.java @@ -0,0 +1,228 @@ +package tests.eSignature; + +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.controller.eSignature.services.AddDocToTemplateService; +import com.docusign.core.common.DocumentType; +import com.docusign.core.model.ApiType; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import tests.common.JWTLoginMethodTest; +import tests.common.TestConfig; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collections; + +public final class AddDocToTemplateTest { + private static final String BEARER_AUTHENTICATION = "Bearer "; + + private static final String HTML_DOCUMENT_FILE_NAME = "templates/candy-bonbon2.ftl"; + + private static final String HTML_DOCUMENT_NAME = "Appendix 1--Sales order"; + + private static final int ANCHOR_OFFSET_Y = 10; + + private static final int ANCHOR_OFFSET_X = 20; + + private static final String basePathAddition = "/restapi"; + + private final String SIGNER_CLIENT_ID = "1000"; + + private final String RedirectUrl = "https://developers.docusign.com/platform/auth/consent"; + + private final ApiClient apiClient; + + private final EnvelopesApi envelopesApi; + + private final TestConfig testConfig; + + public AddDocToTemplateTest() throws IOException, ApiException { + JWTLoginMethodTest.RequestJWTUserToken_CorrectInputValues_ReturnOAuthToken(ApiType.ESIGNATURE); + this.testConfig = TestConfig.getInstance(); + + this.apiClient = new ApiClient(testConfig.getBasePath() + basePathAddition); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + testConfig.getAccessToken()); + this.envelopesApi = new EnvelopesApi(apiClient); + + CreateNewTemplateTest createNewTemplateTest = new CreateNewTemplateTest(); + createNewTemplateTest.CreateTemplate_CorrectInputValues_TemplateSummary(); + } + + @Test + public void AddDocumentToTemplate_CorrectInputValues_ViewUrl() throws ApiException, IOException { + // Arrange + String ccEmail = "cc@gmail.com"; + String ccName = "cc"; + String item = "kiwi"; + String quantity = "1"; + + WorkArguments args = new WorkArguments(); + args.setSignerEmail(testConfig.getSignerEmail()); + args.setSignerName(testConfig.getSignerName()); + args.setCcEmail(ccEmail); + args.setCcName(ccName); + args.setItem(item); + args.setQuantity(quantity); + + // Act + ViewUrl embeddedEnvelope = AddDocToTemplateService.addDocumentToTemplate( + envelopesApi, + testConfig.getSignerEmail(), + testConfig.getSignerName(), + SIGNER_CLIENT_ID, + ccEmail, + ccName, + testConfig.getTemplateId(), + testConfig.getAccountId(), + RedirectUrl, + RedirectUrl, + args + ); + + // Assert + Assertions.assertNotNull(embeddedEnvelope); + } + + @Test + public void MakeRecipientViewRequest_CorrectInputValues_RecipientViewRequest() { + // Arrange + String pingFrequency = "600"; + String authenticationMethod = "none"; + + RecipientViewRequest expectedViewRequest = new RecipientViewRequest(); + expectedViewRequest.setReturnUrl(RedirectUrl); + expectedViewRequest.setAuthenticationMethod(authenticationMethod); + expectedViewRequest.setEmail(testConfig.getSignerEmail()); + expectedViewRequest.setUserName(testConfig.getSignerName()); + expectedViewRequest.setClientUserId(SIGNER_CLIENT_ID); + expectedViewRequest.setPingFrequency(pingFrequency); + expectedViewRequest.setPingUrl(RedirectUrl); + + // Act + RecipientViewRequest recipientViewRequest = AddDocToTemplateService.makeRecipientViewRequest( + RedirectUrl, + testConfig.getSignerEmail(), + testConfig.getSignerName(), + RedirectUrl + ); + + // Assert + Assertions.assertNotNull(recipientViewRequest); + Assertions.assertEquals(expectedViewRequest, recipientViewRequest); + } + + @Test + public void MakeEnvelope_CorrectInputValues_EnvelopeDefinition() throws IOException { + // Arrange + String ccEmail = "cc@gmail.com"; + String ccName = "cc"; + String item = "kiwi"; + String defaultIdOne = "1"; + String defaultIdTwo = "2"; + String anchorString = "**signature_1**"; + + WorkArguments args = new WorkArguments(); + args.setSignerEmail(testConfig.getSignerEmail()); + args.setSignerName(testConfig.getSignerName()); + args.setCcEmail(ccEmail); + args.setCcName(ccName); + args.setItem(item); + args.setQuantity(defaultIdOne); + + CarbonCopy cc = new CarbonCopy(); + cc.setEmail(ccEmail); + cc.setName(ccName); + cc.setRoleName(EnvelopeHelpers.CC_ROLE_NAME); + cc.setRecipientId(defaultIdTwo); + + CompositeTemplate compositeTemplate = new CompositeTemplate(); + compositeTemplate.setCompositeTemplateId(defaultIdOne); + ServerTemplate serverTemplates = new ServerTemplate(); + serverTemplates.setSequence(defaultIdOne); + serverTemplates.setTemplateId(testConfig.getTemplateId()); + compositeTemplate.setServerTemplates(Collections.singletonList(serverTemplates)); + + InlineTemplate inlineTemplate = new InlineTemplate(); + inlineTemplate.setSequence(defaultIdTwo); + inlineTemplate.setRecipients(EnvelopeHelpers.createRecipients( + AddDocToTemplateService.createSigner( + testConfig.getSignerEmail(), + testConfig.getSignerName(), + SIGNER_CLIENT_ID + ), + cc)); + compositeTemplate.setInlineTemplates(Collections.singletonList(inlineTemplate)); + + Tabs signer1Tabs = EnvelopeHelpers.createSingleSignerTab( + anchorString, + ANCHOR_OFFSET_Y, + ANCHOR_OFFSET_X); + Signer signer1AddedDoc = AddDocToTemplateService.createSigner( + testConfig.getSignerEmail(), + testConfig.getSignerName(), + SIGNER_CLIENT_ID + ); + signer1AddedDoc.setTabs(signer1Tabs); + + byte[] htmlDoc = EnvelopeHelpers.createHtmlFromTemplateFile(HTML_DOCUMENT_FILE_NAME, "args", args) + .getBytes(StandardCharsets.UTF_8); + + CompositeTemplate compTemplate2 = new CompositeTemplate(); + compTemplate2.setCompositeTemplateId(defaultIdTwo); + InlineTemplate inlineTemplate2 = new InlineTemplate(); + inlineTemplate2.setSequence(defaultIdOne); + inlineTemplate2.setRecipients(EnvelopeHelpers.createRecipients(signer1AddedDoc, cc)); + compTemplate2.setInlineTemplates(Collections.singletonList(inlineTemplate2)); + compTemplate2.setDocument(EnvelopeHelpers.createDocument(htmlDoc, HTML_DOCUMENT_NAME, + DocumentType.HTML.getDefaultFileExtention(), defaultIdOne)); + + EnvelopeDefinition expectedEnvelopeDefinition = new EnvelopeDefinition(); + expectedEnvelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + expectedEnvelopeDefinition.setCompositeTemplates(Arrays.asList(compositeTemplate, compTemplate2)); + + // Act + EnvelopeDefinition envelopeDefinition = AddDocToTemplateService.makeEnvelope( + testConfig.getSignerEmail(), + testConfig.getSignerName(), + SIGNER_CLIENT_ID, + ccEmail, + ccName, + testConfig.getTemplateId(), + args + ); + + // Assert + Assertions.assertNotNull(envelopeDefinition); + Assertions.assertEquals(expectedEnvelopeDefinition, envelopeDefinition); + } + + @Test + public void CreateSigner_CorrectInputValues_Signer() { + // Arrange + String recipientId = "1"; + Signer expectedSigner = new Signer(); + expectedSigner.setEmail(testConfig.getSignerEmail()); + expectedSigner.setName(testConfig.getSignerName()); + expectedSigner.setRoleName(EnvelopeHelpers.SIGNER_ROLE_NAME); + expectedSigner.setRecipientId(recipientId); + expectedSigner.setClientUserId(SIGNER_CLIENT_ID); + + // Act + Signer signer = AddDocToTemplateService.createSigner( + testConfig.getSignerEmail(), + testConfig.getSignerName(), + SIGNER_CLIENT_ID + ); + + // Assert + Assertions.assertNotNull(signer); + Assertions.assertEquals(expectedSigner, signer); + } +} diff --git a/src/test/java/tests/eSignature/ApplyBrandToEnvelopeTest.java b/src/test/java/tests/eSignature/ApplyBrandToEnvelopeTest.java new file mode 100644 index 00000000..e8ecb30e --- /dev/null +++ b/src/test/java/tests/eSignature/ApplyBrandToEnvelopeTest.java @@ -0,0 +1,120 @@ +package tests.eSignature; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.controller.eSignature.services.ApplyBrandToEnvelopeService; +import com.docusign.core.model.ApiType; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import tests.common.JWTLoginMethodTest; +import tests.common.TestConfig; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +public final class ApplyBrandToEnvelopeTest { + private static final String BEARER_AUTHENTICATION = "Bearer "; + + private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String DOCUMENT_NAME = "EG025 Lorem Ipsum"; + + private static final int ANCHOR_OFFSET_Y = 10; + + private static final int ANCHOR_OFFSET_X = 20; + + private static final String basePathAddition = "/restapi"; + + private final ApiClient apiClient; + + private final AccountsApi accountsApi; + + private final EnvelopesApi envelopesApi; + + private final TestConfig testConfig; + + public ApplyBrandToEnvelopeTest() throws IOException { + JWTLoginMethodTest.RequestJWTUserToken_CorrectInputValues_ReturnOAuthToken(ApiType.ESIGNATURE); + this.testConfig = TestConfig.getInstance(); + + this.apiClient = new ApiClient(testConfig.getBasePath() + basePathAddition); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + testConfig.getAccessToken()); + + this.accountsApi = new AccountsApi(apiClient); + this.envelopesApi = new EnvelopesApi(apiClient); + } + + @Test + public void GetBrands_CorrectInputValues_ReturnsBrandsResponse() throws ApiException { + // Act + BrandsResponse brand = ApplyBrandToEnvelopeService.getBrands( + this.accountsApi, + testConfig.getAccountId()); + + testConfig.setBrand(brand.getBrands().stream().findFirst().get()); + + // Assert + Assertions.assertNotNull(brand); + Assertions.assertNotNull(brand.getBrands()); + } + + @Test + public void MakeEnvelope_CorrectInputValues_ReturnsEnvelopeDefinition() throws IOException { + // Arrange + String defaultID = "1"; + String emailSubject = "EG029. Please Sign"; + String anchorString = "/sn1/"; + Document document = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, defaultID); + + Tabs tabs = EnvelopeHelpers.createSingleSignerTab(anchorString, ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X); + Signer signer = new Signer() + .email(testConfig.getSignerEmail()) + .name(testConfig.getSignerName()) + .recipientId(defaultID) + .routingOrder(defaultID) + .tabs(tabs); + + Recipients recipients = new Recipients(); + recipients.setSigners(Collections.singletonList(signer)); + + EnvelopeDefinition expectedEnvelopeDefinition = new EnvelopeDefinition() + .emailSubject(emailSubject) + .documents(List.of(document)) + .recipients(recipients) + .brandId(testConfig.getBrand().getBrandId()) + .status(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + // Act + EnvelopeDefinition envelopeDefinition = ApplyBrandToEnvelopeService.makeEnvelope( + testConfig.getSignerEmail(), + testConfig.getSignerName(), + testConfig.getBrand().getBrandId()); + + // Assert + Assertions.assertNotNull(envelopeDefinition); + Assertions.assertEquals(expectedEnvelopeDefinition, envelopeDefinition); + } + + @Test + public void ApplyBrandToEnvelope_CorrectInputValues_ReturnsEnvelopeSummary() throws ApiException, IOException { + // Arrange + EnvelopeDefinition envelopeDefinition = ApplyBrandToEnvelopeService.makeEnvelope( + testConfig.getSignerEmail(), + testConfig.getSignerName(), + testConfig.getBrand().getBrandId()); + + // Act + EnvelopeSummary envelopeSummary = ApplyBrandToEnvelopeService.applyBrandToEnvelope( + this.envelopesApi, + testConfig.getAccountId(), + envelopeDefinition); + + // Assert + Assertions.assertNotNull(envelopeSummary); + } +} diff --git a/src/test/java/tests/eSignature/BulkSendEnvelopesTest.java b/src/test/java/tests/eSignature/BulkSendEnvelopesTest.java new file mode 100644 index 00000000..3f779b80 --- /dev/null +++ b/src/test/java/tests/eSignature/BulkSendEnvelopesTest.java @@ -0,0 +1,294 @@ +package tests.eSignature; + +import com.docusign.controller.eSignature.examples.DsModelUtils; +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.controller.eSignature.services.BulkSendEnvelopesService; +import com.docusign.core.model.ApiType; +import com.docusign.esign.api.BulkEnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import tests.common.JWTLoginMethodTest; +import tests.common.TestConfig; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +public final class BulkSendEnvelopesTest { + private static final String BEARER_AUTHENTICATION = "Bearer "; + + private static final long BULK_REQUEST_DELAY = 15L; + + private static final String BULK_SIGNER_EMAIL_PLACEHOLDER = "MultiBulkRecipients-%s@docusign.com"; + + private static final String BULK_SIGNER_NAME_PLACEHOLDER = "Multi Bulk Recipients::%s"; + + private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String DOCUMENT_NAME = "Lorem Ipsum"; + + private static final int ANCHOR_OFFSET_Y = -5; + + private static final int ANCHOR_OFFSET_X = 15; + + private static final String basePathAddition = "/restapi"; + + private final ApiClient apiClient; + + private final BulkEnvelopesApi bulkEnvelopesApi; + + private final TestConfig testConfig; + + public BulkSendEnvelopesTest() throws IOException { + JWTLoginMethodTest.RequestJWTUserToken_CorrectInputValues_ReturnOAuthToken(ApiType.ESIGNATURE); + this.testConfig = TestConfig.getInstance(); + + this.apiClient = new ApiClient(testConfig.getBasePath() + basePathAddition); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + testConfig.getAccessToken()); + + this.bulkEnvelopesApi = new BulkEnvelopesApi(apiClient); + } + + @Test + public void CreateCCPlaceholder_CorrectInputValues_ReturnsCarbonCopy() { + // Arrange + String roleName = "cc"; + String routingOrder = "1"; + String recipientId = "1"; + CarbonCopy expectedCarbonCopy = new CarbonCopy() + .name(String.format(BULK_SIGNER_NAME_PLACEHOLDER, roleName)) + .email(String.format(BULK_SIGNER_EMAIL_PLACEHOLDER, roleName)) + .roleName(roleName) + .note("") + .routingOrder(routingOrder) + .status(EnvelopeHelpers.SIGNER_STATUS_CREATED) + .deliveryMethod(EnvelopeHelpers.DELIVERY_METHOD_EMAIL) + .recipientId(recipientId) + .recipientType(roleName); + + // Act + CarbonCopy carbonCopy = BulkSendEnvelopesService.createCCPlaceholder( + roleName, + recipientId, + routingOrder); + + // Assert + Assertions.assertNotNull(carbonCopy); + Assertions.assertEquals(expectedCarbonCopy, carbonCopy); + } + + @Test + public void CreateSignerPlaceholder_CorrectInputValues_ReturnsSigner() { + // Arrange + String roleName = "signer"; + String routingOrder = "1"; + String recipientId = "1"; + String anchorString = "/sn1/"; + Signer expectedSigner = new Signer() + .name(String.format(BULK_SIGNER_NAME_PLACEHOLDER, roleName)) + .email(String.format(BULK_SIGNER_EMAIL_PLACEHOLDER, roleName)) + .roleName(roleName) + .note("") + .routingOrder(routingOrder) + .status(EnvelopeHelpers.SIGNER_STATUS_CREATED) + .deliveryMethod(EnvelopeHelpers.DELIVERY_METHOD_EMAIL) + .recipientId(recipientId) + .recipientType(roleName) + .tabs(EnvelopeHelpers.createSingleSignerTab(anchorString, ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X)); + + // Act + Signer signer = BulkSendEnvelopesService.createSignerPlaceholder( + roleName, + recipientId, + routingOrder); + + // Assert + Assertions.assertNotNull(signer); + Assertions.assertEquals(expectedSigner, signer); + } + + @Test + public void CreateRecipients_CorrectInputValues_ReturnsRecipients() { + // Arrange + String defaultId = "1"; + String defaultIdTwo = "2"; + Signer signer = BulkSendEnvelopesService.createSignerPlaceholder(EnvelopeHelpers.SIGNER_ROLE_NAME, defaultId, defaultId); + CarbonCopy carbonCopy = BulkSendEnvelopesService.createCCPlaceholder(EnvelopeHelpers.CC_ROLE_NAME, defaultIdTwo, defaultIdTwo); + Recipients expectedRecipients = new Recipients() + .signers(List.of(signer)) + .carbonCopies(List.of(carbonCopy)); + + // Act + Recipients recipients = BulkSendEnvelopesService.createRecipients(); + + // Assert + Assertions.assertNotNull(recipients); + Assertions.assertEquals(expectedRecipients, recipients); + } + + @Test + public void CreateCustomFields_CorrectInputValues_ReturnsCustomFields() { + // Arrange + String bulkListId = "1"; + String mailingListId = "mailingListId"; + TextCustomField textCustomField = new TextCustomField() + .name(mailingListId) + .required(DsModelUtils.FALSE) + .show(DsModelUtils.FALSE) + .value(bulkListId); + + CustomFields expectedCustomFields = new CustomFields() + .listCustomFields(Collections.emptyList()) + .textCustomFields(List.of(textCustomField)); + + // Act + CustomFields customFields = BulkSendEnvelopesService.createCustomFields(bulkListId); + + // Assert + Assertions.assertNotNull(customFields); + Assertions.assertEquals(expectedCustomFields, customFields); + } + + @Test + public void MakeEnvelope_CorrectInputValues_ReturnsEnvelopeDefinition() throws IOException { + // Arrange + String docId = "1"; + String emailSubject = "EG031 Please sign"; + Document document = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, docId); + EnvelopeDefinition expectedEnvelopeDefinition = new EnvelopeDefinition() + .documents(List.of(document)) + .envelopeIdStamping(DsModelUtils.TRUE) + .emailSubject(emailSubject) + .status(EnvelopeHelpers.ENVELOPE_STATUS_CREATED) + .recipients(BulkSendEnvelopesService.createRecipients()); + + // Act + EnvelopeDefinition envelopeDefinition = BulkSendEnvelopesService.makeEnvelope(); + + // Assert + Assertions.assertNotNull(envelopeDefinition); + Assertions.assertEquals(expectedEnvelopeDefinition, envelopeDefinition); + } + + @Test + public void CreateBulkSending_CorrectInputValues_ReturnsBulkSendingCopy() { + // Arrange + String ccName = "CC"; + String ccEmail = "cc@gmail.com"; + + BulkSendingCopyRecipient recipient1 = new BulkSendingCopyRecipient() + .name(testConfig.getSignerName()) + .email(testConfig.getSignerEmail()) + .tabs(Collections.emptyList()) + .roleName(EnvelopeHelpers.SIGNER_ROLE_NAME); + + BulkSendingCopyRecipient recipient2 = new BulkSendingCopyRecipient() + .name(ccName) + .email(ccEmail) + .tabs(Collections.emptyList()) + .roleName(EnvelopeHelpers.CC_ROLE_NAME); + + BulkSendingCopy expectedBulkSendingCopy = new BulkSendingCopy() + .recipients(List.of(recipient1, recipient2)) + .customFields(Collections.emptyList()); + + // Act + BulkSendingCopy bulkSendingCopy = BulkSendEnvelopesService.createBulkSending( + testConfig.getSignerName(), + testConfig.getSignerEmail(), + ccName, + ccEmail + ); + + // Assert + Assertions.assertNotNull(bulkSendingCopy); + Assertions.assertEquals(expectedBulkSendingCopy, bulkSendingCopy); + } + + @Test + public void GetSendingList_CorrectInputValues_ReturnsBulkSendingList() { + // Arrange + String ccName = "CC"; + String ccEmail = "cc@gmail.com"; + String cc2Name = "CC 2"; + String cc2Email = "cc2@gmail.com"; + String signer2Name = "Signer 2"; + String signer2Email = "signer2@gmail.com"; + String fileName = "sample.csv"; + + List copies = List.of( + BulkSendEnvelopesService.createBulkSending(testConfig.getSignerName(), testConfig.getSignerEmail(), ccName, ccEmail), + BulkSendEnvelopesService.createBulkSending(signer2Name, signer2Email, cc2Name, cc2Email) + ); + BulkSendingList expectedBulkSendingList = new BulkSendingList() + .name(fileName) + .bulkCopies(copies); + + // Act + BulkSendingList bulkSendingList = BulkSendEnvelopesService.getSendingList( + testConfig.getSignerName(), + testConfig.getSignerEmail(), + ccName, + ccEmail, + signer2Name, + signer2Email, + cc2Name, + cc2Email + ); + + // Assert + Assertions.assertNotNull(bulkSendingList); + Assertions.assertEquals(expectedBulkSendingList, bulkSendingList); + } + + @Test + public void BulkSendEnvelopes_CorrectInputValues_ReturnsString() throws ApiException, IOException { + // Arrange + String ccName = "CC"; + String ccEmail = "cc@gmail.com"; + String cc2Name = "CC 2"; + String cc2Email = "cc2@gmail.com"; + String signer2Name = "Signer 2"; + String signer2Email = "signer2@gmail.com"; + + // Act + String batchId = BulkSendEnvelopesService.bulkSendEnvelopes( + this.bulkEnvelopesApi, + this.apiClient, + testConfig.getSignerName(), + testConfig.getSignerEmail(), + ccName, + ccEmail, + signer2Name, + signer2Email, + cc2Name, + cc2Email, + testConfig.getAccountId() + ); + testConfig.setBatchId(batchId); + + // Assert + Assertions.assertNotNull(batchId); + } + + @Test + public void GetBulkSendBatchStatus_CorrectInputValues_ReturnsBulkSendBatchStatus() throws ApiException, IOException, InterruptedException { + // Arrange + BulkSendEnvelopes_CorrectInputValues_ReturnsString(); + + // Act + BulkSendBatchStatus bulkSendBatchStatus = BulkSendEnvelopesService.getBulkSendBatchStatus( + this.bulkEnvelopesApi, + testConfig.getAccountId(), + testConfig.getBatchId(), + BULK_REQUEST_DELAY + ); + + // Assert + Assertions.assertNotNull(bulkSendBatchStatus); + } +} diff --git a/src/test/java/tests/eSignature/CreateBrandTest.java b/src/test/java/tests/eSignature/CreateBrandTest.java new file mode 100644 index 00000000..f4461cea --- /dev/null +++ b/src/test/java/tests/eSignature/CreateBrandTest.java @@ -0,0 +1,58 @@ +package tests.eSignature; + +import com.docusign.controller.eSignature.services.CreateBrandService; +import com.docusign.core.model.ApiType; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.BrandsResponse; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import tests.common.JWTLoginMethodTest; +import tests.common.TestConfig; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Random; + +public final class CreateBrandTest { + private static final String BEARER_AUTHENTICATION = "Bearer "; + + private static final String basePathAddition = "/restapi"; + + private final ApiClient apiClient; + + private final AccountsApi accountsApi; + + private final TestConfig testConfig; + + public CreateBrandTest() throws IOException { + JWTLoginMethodTest.RequestJWTUserToken_CorrectInputValues_ReturnOAuthToken(ApiType.ESIGNATURE); + this.testConfig = TestConfig.getInstance(); + + this.apiClient = new ApiClient(testConfig.getBasePath() + basePathAddition); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + testConfig.getAccessToken()); + this.accountsApi = new AccountsApi(apiClient); + } + + @Test + public void CreateBrand_CorrectInputValues_ReturnsBrandsResponse() throws ApiException { + // Arrange + byte[] array = new byte[8]; + new Random().nextBytes(array); + var brandName = new String(array, StandardCharsets.UTF_8); + var defaultBrandLanguage = "en"; + + // Act + BrandsResponse brand = CreateBrandService.createBrand( + this.accountsApi, + brandName, + defaultBrandLanguage, + testConfig.getAccountId()); + + // Assert + Assertions.assertNotNull(brand); + Assertions.assertNotNull(brand.getBrands()); + } +} diff --git a/src/test/java/tests/eSignature/CreateNewTemplateTest.java b/src/test/java/tests/eSignature/CreateNewTemplateTest.java new file mode 100644 index 00000000..f1be7f68 --- /dev/null +++ b/src/test/java/tests/eSignature/CreateNewTemplateTest.java @@ -0,0 +1,331 @@ +package tests.eSignature; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.controller.eSignature.services.CreateTemplateService; +import com.docusign.core.model.ApiType; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import tests.common.JWTLoginMethodTest; +import tests.common.TestConfig; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Locale; + +public final class CreateNewTemplateTest { + private static final String BEARER_AUTHENTICATION = "Bearer "; + + private static final String TEMPLATE_NAME = "Example Signer and CC template v2"; + + private static final String PDF_DOCUMENT_FILE_NAME = "World_Wide_Corp_fields.pdf"; + + private static final String PDF_DOCUMENT_NAME = "Lorem Ipsum"; + + private static final String DOCUMENT_ID = "1"; + + private static final String PAGE_NUMBER = "1"; + + private static final String FALSE = "false"; + + private static final String basePathAddition = "/restapi"; + + private final ApiClient apiClient; + + private final EnvelopesApi envelopesApi; + + private final TestConfig testConfig; + + public CreateNewTemplateTest() throws IOException { + JWTLoginMethodTest.RequestJWTUserToken_CorrectInputValues_ReturnOAuthToken(ApiType.ESIGNATURE); + this.testConfig = TestConfig.getInstance(); + + this.apiClient = new ApiClient(testConfig.getBasePath() + basePathAddition); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + testConfig.getAccessToken()); + this.envelopesApi = new EnvelopesApi(apiClient); + } + + @Test + public void SearchTemplatesByName_CorrectInputValues_EnvelopeTemplateResults() throws ApiException { + // Act + EnvelopeTemplateResults envelopeTemplateResults = CreateTemplateService.searchTemplatesByName( + apiClient, + testConfig.getAccountId(), + TEMPLATE_NAME); + + // Assert + Assertions.assertNotNull(envelopeTemplateResults); + Assertions.assertTrue(Integer.parseInt(envelopeTemplateResults.getResultSetSize()) > 0); + + EnvelopeTemplate template = envelopeTemplateResults.getEnvelopeTemplates().get(0); + testConfig.setTemplateId(template.getTemplateId()); + } + + @Test + public void CreateTemplate_CorrectInputValues_TemplateSummary() throws IOException, ApiException { + // Arrange + EnvelopeTemplate envelopeTemplate = CreateTemplateService.makeTemplate(TEMPLATE_NAME); + + // Act + TemplateSummary template = CreateTemplateService.createTemplate( + apiClient, + testConfig.getAccountId(), + envelopeTemplate + ); + + // Assert + Assertions.assertNotNull(template); + Assertions.assertNotNull(template.getTemplateId()); + + testConfig.setTemplateId(template.getTemplateId()); + } + + @Test + public void MakeRecipientViewRequest_CorrectInputValues_RecipientViewRequest() throws ApiException { + // Act + EnvelopeTemplateResults envelopeTemplateResults = CreateTemplateService.searchTemplatesByName( + apiClient, + testConfig.getAccountId(), + TEMPLATE_NAME); + + // Assert + Assertions.assertNotNull(envelopeTemplateResults); + Assertions.assertTrue(Integer.parseInt(envelopeTemplateResults.getResultSetSize()) > 0); + + EnvelopeTemplate template = envelopeTemplateResults.getEnvelopeTemplates().get(0); + testConfig.setTemplateId(template.getTemplateId()); + } + + @Test + public void MakeTemplate_CorrectInputValues_EnvelopeTemplate() throws IOException { + // Assert + String defaultIdOne = "1"; + Document doc = EnvelopeHelpers.createDocumentFromFile(PDF_DOCUMENT_FILE_NAME, PDF_DOCUMENT_NAME, defaultIdOne); + String emailSubject = "Please sign this document"; + String description = "Example template created via the API"; + String falseString = "false"; + String textXPosition = "153"; + String checkboxXPosition = "75"; + String defaultIdTwo = "2"; + + Tabs signerTabs = new Tabs(); + signerTabs.setCheckboxTabs(Arrays.asList( + CreateTemplateService.createCheckbox("ckAuthorization", checkboxXPosition, "417"), + CreateTemplateService.createCheckbox("ckAuthentication", checkboxXPosition, "447"), + CreateTemplateService.createCheckbox("ckAgreement", checkboxXPosition, "478"), + CreateTemplateService.createCheckbox("ckAcknowledgement", checkboxXPosition, "508"))); + + signerTabs.setListTabs(Collections.singletonList(CreateTemplateService.createList())); + signerTabs.setRadioGroupTabs(Collections.singletonList(CreateTemplateService.createRadioGroup())); + signerTabs.setSignHereTabs(Collections.singletonList(CreateTemplateService.createSignHere())); + signerTabs.textTabs(java.util.List.of( + CreateTemplateService.createText("text", textXPosition, "230") + )); + signerTabs.numericalTabs(java.util.List.of( + CreateTemplateService.createNumerical("numericalCurrency", textXPosition, "260") + )); + + Signer signer = new Signer(); + signer.setRoleName(EnvelopeHelpers.SIGNER_ROLE_NAME); + signer.setRecipientId(defaultIdOne); + signer.setRoutingOrder(defaultIdOne); + signer.setTabs(signerTabs); + + CarbonCopy cc = new CarbonCopy(); + cc.setRoleName(EnvelopeHelpers.CC_ROLE_NAME); + cc.setRoutingOrder(defaultIdTwo); + cc.setRecipientId(defaultIdTwo); + + EnvelopeTemplate expectedEnvelopeTemplate = new EnvelopeTemplate(); + expectedEnvelopeTemplate.setDocuments(Collections.singletonList(doc)); + expectedEnvelopeTemplate.setEmailSubject(emailSubject); + expectedEnvelopeTemplate.setName(TEMPLATE_NAME); + expectedEnvelopeTemplate.setDescription(description); + expectedEnvelopeTemplate.setShared(falseString); + expectedEnvelopeTemplate.setRecipients(EnvelopeHelpers.createRecipients(signer, cc)); + expectedEnvelopeTemplate.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_CREATED); + + // Act + EnvelopeTemplate envelopeTemplate = CreateTemplateService.makeTemplate(TEMPLATE_NAME); + + // Assert + Assertions.assertNotNull(envelopeTemplate); + Assertions.assertEquals(expectedEnvelopeTemplate, envelopeTemplate); + } + + @Test + public void CreateList_CorrectInputValues_List() { + // Arrange + List expectedList = new List(); + expectedList.setDocumentId(DOCUMENT_ID); + expectedList.setPageNumber(PAGE_NUMBER); + expectedList.setXPosition("142"); + expectedList.setYPosition("291"); + expectedList.setFont("helvetica"); + expectedList.setFontSize("size14"); + expectedList.setTabLabel("list"); + expectedList.setRequired(FALSE); + expectedList.setListItems(Arrays.asList( + CreateTemplateService.createListItem("Red"), + CreateTemplateService.createListItem("Orange"), + CreateTemplateService.createListItem("Yellow"), + CreateTemplateService.createListItem("Green"), + CreateTemplateService.createListItem("Blue"), + CreateTemplateService.createListItem("Indigo"), + CreateTemplateService.createListItem("Violet") + )); + + // Act + List list = CreateTemplateService.createList(); + + // Assert + Assertions.assertNotNull(list); + Assertions.assertEquals(expectedList, list); + } + + @Test + public void CreateListItem_CorrectInputValues_ListItem() { + // Arrange + String color = "blue"; + + ListItem expectedListItem = new ListItem(); + expectedListItem.setText(color); + expectedListItem.setValue(color.toLowerCase(Locale.ENGLISH)); + + // Act + ListItem listItem = CreateTemplateService.createListItem(color); + + // Assert + Assertions.assertNotNull(listItem); + Assertions.assertEquals(expectedListItem, listItem); + } + + @Test + public void CreateRadioGroup_CorrectInputValues_RadioGroup() { + // Arrange + String white = "white"; + String red = "red"; + String blue = "blue"; + String blueXPosition = "220"; + String redXPosition = "74"; + String whiteXPosition = "142"; + String groupName = "radio1"; + + RadioGroup expectedRadioGroup = new RadioGroup(); + expectedRadioGroup.setDocumentId(DOCUMENT_ID); + expectedRadioGroup.setGroupName(groupName); + + expectedRadioGroup.setRadios(Arrays.asList( + CreateTemplateService.createRadio(white, whiteXPosition), + CreateTemplateService.createRadio(red, redXPosition), + CreateTemplateService.createRadio(blue, blueXPosition) + )); + + // Act + RadioGroup radioGroup = CreateTemplateService.createRadioGroup(); + + // Assert + Assertions.assertNotNull(radioGroup); + Assertions.assertEquals(expectedRadioGroup, radioGroup); + } + + @Test + public void CreateRadio_CorrectInputValues_Radio() { + // Arrange + String value = "blue"; + String xPosition = "111"; + String yPosition = "384"; + + Radio expectedRadio = new Radio(); + expectedRadio.setPageNumber(PAGE_NUMBER); + expectedRadio.setValue(value); + expectedRadio.setXPosition(xPosition); + expectedRadio.setYPosition(yPosition); + expectedRadio.setRequired(FALSE); + + // Act + Radio radio = CreateTemplateService.createRadio(value, xPosition); + + // Assert + Assertions.assertNotNull(radio); + Assertions.assertEquals(expectedRadio, radio); + } + + @Test + public void CreateCheckbox_CorrectInputValues_Checkbox() { + // Arrange + String label = "blue"; + String yPosition = "111"; + String xPosition = "111"; + + Checkbox expectedCheckBox = new Checkbox(); + expectedCheckBox.setDocumentId(DOCUMENT_ID); + expectedCheckBox.setPageNumber(PAGE_NUMBER); + expectedCheckBox.setXPosition(xPosition); + expectedCheckBox.setYPosition(yPosition); + expectedCheckBox.setTabLabel(label); + + // Act + Checkbox check = CreateTemplateService.createCheckbox(label, xPosition, yPosition); + + // Assert + Assertions.assertNotNull(check); + Assertions.assertEquals(expectedCheckBox, check); + } + + @Test + public void CreateText_CorrectInputValues_Text() { + // Arrange + String xPosition = "1"; + String yPosition = "5"; + String label = "blue"; + String font = "helvetica"; + String fontSize = "size14"; + String height = "23"; + String width = "84"; + + Text expectedText = new Text(); + expectedText.setDocumentId(DOCUMENT_ID); + expectedText.setPageNumber(PAGE_NUMBER); + expectedText.setXPosition(xPosition); + expectedText.setYPosition(yPosition); + expectedText.setFont(font); + expectedText.setFontSize(fontSize); + expectedText.setTabLabel(label); + expectedText.setHeight(height); + expectedText.setWidth(width); + expectedText.setRequired(FALSE); + + // Act + Text text = CreateTemplateService.createText(label, xPosition, yPosition); + + // Assert + Assertions.assertNotNull(text); + Assertions.assertEquals(expectedText, text); + } + + @Test + public void CreateSignHere_CorrectInputValues_SignHere() { + // Arrange + String xPosition = "191"; + String yPosition = "148"; + + SignHere expectedSignHere = new SignHere(); + expectedSignHere.setDocumentId(DOCUMENT_ID); + expectedSignHere.setPageNumber(PAGE_NUMBER); + expectedSignHere.setXPosition(xPosition); + expectedSignHere.setYPosition(yPosition); + + // Act + SignHere signHere = CreateTemplateService.createSignHere(); + + // Assert + Assertions.assertNotNull(signHere); + Assertions.assertEquals(expectedSignHere, signHere); + } +} diff --git a/src/test/java/tests/eSignature/EmbeddedSigningTest.java b/src/test/java/tests/eSignature/EmbeddedSigningTest.java new file mode 100644 index 00000000..c0e77116 --- /dev/null +++ b/src/test/java/tests/eSignature/EmbeddedSigningTest.java @@ -0,0 +1,166 @@ +package tests.eSignature; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.controller.eSignature.services.EmbeddedSigningService; +import com.docusign.core.model.ApiType; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import tests.common.JWTLoginMethodTest; +import tests.common.TestConfig; + +import java.io.IOException; +import java.util.Collections; + +public final class EmbeddedSigningTest { + private static final String BEARER_AUTHENTICATION = "Bearer "; + + private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String DOCUMENT_NAME = "Lorem Ipsum"; + + private static final int ANCHOR_OFFSET_Y = 20; + + private static final int ANCHOR_OFFSET_X = 10; + + private static final String SIGNER_CLIENT_ID = "1000"; + + private static final String basePathAddition = "/restapi"; + + private final String RedirectUrl = "https://developers.docusign.com/platform/auth/consent"; + + private final ApiClient apiClient; + + private final TestConfig testConfig; + + public EmbeddedSigningTest() throws IOException { + JWTLoginMethodTest.RequestJWTUserToken_CorrectInputValues_ReturnOAuthToken(ApiType.ESIGNATURE); + this.testConfig = TestConfig.getInstance(); + + this.apiClient = new ApiClient(testConfig.getBasePath() + basePathAddition); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + testConfig.getAccessToken()); + } + + @Test + public void MakeEnvelope_CorrectInputValues_EnvelopeDefinition() throws IOException { + // Arrange + String anchorString = "/sn1/"; + String emailSubject = "Please sign this document"; + String docId = "3"; + String recipientId = "1"; + EnvelopeDefinition expectedEnvelopeDefinition = new EnvelopeDefinition(); + + Signer signer = new Signer(); + signer.setEmail(testConfig.getSignerEmail()); + signer.setName(testConfig.getSignerName()); + signer.clientUserId(SIGNER_CLIENT_ID); + signer.recipientId(recipientId); + signer.setTabs(EnvelopeHelpers.createSingleSignerTab(anchorString, ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X)); + Recipients recipients = new Recipients(); + recipients.setSigners(Collections.singletonList(signer)); + + expectedEnvelopeDefinition.setEmailSubject(emailSubject); + expectedEnvelopeDefinition.setRecipients(recipients); + Document doc = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, docId); + expectedEnvelopeDefinition.setDocuments(Collections.singletonList(doc)); + expectedEnvelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + + // Act + EnvelopeDefinition envelopeDefinition = EmbeddedSigningService.makeEnvelope( + testConfig.getSignerEmail(), + testConfig.getSignerName(), + SIGNER_CLIENT_ID, + ANCHOR_OFFSET_Y, + ANCHOR_OFFSET_X, + DOCUMENT_FILE_NAME, + DOCUMENT_NAME); + + // Assert + Assertions.assertNotNull(envelopeDefinition); + Assertions.assertEquals(expectedEnvelopeDefinition, envelopeDefinition); + } + + @Test + public void MakeRecipientViewRequest_CorrectInputValues_RecipientViewRequest() { + //Arrange + RecipientViewRequest expectedViewRequest = new RecipientViewRequest(); + String stateValue = "?state=123"; + String authenticationMethod = "none"; + String pingFrequency = "600"; + + expectedViewRequest.setReturnUrl(RedirectUrl + stateValue); + expectedViewRequest.setAuthenticationMethod(authenticationMethod); + expectedViewRequest.setEmail(testConfig.getSignerEmail()); + expectedViewRequest.setUserName(testConfig.getSignerName()); + expectedViewRequest.setClientUserId(SIGNER_CLIENT_ID); + expectedViewRequest.setPingFrequency(pingFrequency); + expectedViewRequest.setPingUrl(RedirectUrl); + + // Act + RecipientViewRequest viewRequest = EmbeddedSigningService.makeRecipientViewRequest( + testConfig.getSignerEmail(), + testConfig.getSignerName(), + SIGNER_CLIENT_ID, + RedirectUrl, + RedirectUrl); + + // Assert + Assertions.assertNotNull(viewRequest); + Assertions.assertEquals(expectedViewRequest, viewRequest); + } + + @Test + public void CreateEnvelope_CorrectInputValues_EnvelopeId() throws IOException, ApiException { + //Arrange + EnvelopeDefinition envelope = EmbeddedSigningService.makeEnvelope( + testConfig.getSignerEmail(), + testConfig.getSignerName(), + SIGNER_CLIENT_ID, + ANCHOR_OFFSET_Y, + ANCHOR_OFFSET_X, + DOCUMENT_FILE_NAME, + DOCUMENT_NAME); + + // Act + String envelopeId = EmbeddedSigningService.createEnvelope(apiClient, testConfig.getAccountId(), envelope); + + // Assert + Assertions.assertNotNull(envelopeId); + } + + @Test + public void EmbeddedSigning_CorrectInputValues_ViewUrl() throws IOException, ApiException { + //Arrange + EnvelopeDefinition envelope = EmbeddedSigningService.makeEnvelope( + testConfig.getSignerEmail(), + testConfig.getSignerName(), + SIGNER_CLIENT_ID, + ANCHOR_OFFSET_Y, + ANCHOR_OFFSET_X, + DOCUMENT_FILE_NAME, + DOCUMENT_NAME); + + String envelopeId = EmbeddedSigningService.createEnvelope(apiClient, testConfig.getAccountId(), envelope); + + RecipientViewRequest viewRequest = EmbeddedSigningService.makeRecipientViewRequest( + testConfig.getSignerEmail(), + testConfig.getSignerName(), + SIGNER_CLIENT_ID, + RedirectUrl, + RedirectUrl); + + // Act + ViewUrl viewUrl = EmbeddedSigningService.embeddedSigning( + apiClient, + testConfig.getAccountId(), + envelopeId, + viewRequest + ); + + // Assert + Assertions.assertNotNull(viewUrl); + } +} diff --git a/src/test/java/tests/eSignature/PermissionCreateTest.java b/src/test/java/tests/eSignature/PermissionCreateTest.java new file mode 100644 index 00000000..49a5ff37 --- /dev/null +++ b/src/test/java/tests/eSignature/PermissionCreateTest.java @@ -0,0 +1,56 @@ +package tests.eSignature; + +import com.docusign.controller.eSignature.services.PermissionCreateService; +import com.docusign.core.model.ApiType; +import com.docusign.esign.api.AccountsApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.PermissionProfile; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import tests.common.JWTLoginMethodTest; +import tests.common.TestConfig; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Random; + +public final class PermissionCreateTest { + private static final String BEARER_AUTHENTICATION = "Bearer "; + + private static final String basePathAddition = "/restapi"; + + private final ApiClient apiClient; + + private final AccountsApi accountsApi; + + private final TestConfig testConfig; + + public PermissionCreateTest() throws IOException { + JWTLoginMethodTest.RequestJWTUserToken_CorrectInputValues_ReturnOAuthToken(ApiType.ESIGNATURE); + this.testConfig = TestConfig.getInstance(); + + this.apiClient = new ApiClient(testConfig.getBasePath() + basePathAddition); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + testConfig.getAccessToken()); + this.accountsApi = new AccountsApi(apiClient); + } + + @Test + public void CreateNewProfile_CorrectInputValues_ReturnsPermissionProfile() throws ApiException { + // Arrange + byte[] byteArray = new byte[8]; + new Random().nextBytes(byteArray); + var permissionName = new String(byteArray, StandardCharsets.UTF_8); + + // Act + PermissionProfile permissionProfile = PermissionCreateService.createNewProfile( + this.accountsApi, + testConfig.getAccountId(), + permissionName); + + // Assert + Assertions.assertNotNull(permissionProfile); + Assertions.assertEquals(permissionName, permissionProfile.getPermissionProfileName()); + } +} diff --git a/src/test/java/tests/eSignature/SetTabValuesTest.java b/src/test/java/tests/eSignature/SetTabValuesTest.java new file mode 100644 index 00000000..8f2ddf13 --- /dev/null +++ b/src/test/java/tests/eSignature/SetTabValuesTest.java @@ -0,0 +1,256 @@ +package tests.eSignature; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.controller.eSignature.services.SetTabValuesService; +import com.docusign.core.model.ApiType; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import tests.common.JWTLoginMethodTest; +import tests.common.TestConfig; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public final class SetTabValuesTest { + private static final String BEARER_AUTHENTICATION = "Bearer "; + + private static final String DOCUMENT_FILE_NAME = "World_Wide_Corp_salary.docx"; + + private static final String DOCUMENT_NAME = "Lorem Ipsum"; + + private static final String SIGNER_CLIENT_ID = "1000"; + + private static final String basePathAddition = "/restapi"; + + private final String RedirectUrl = "https://developers.docusign.com/platform/auth/consent"; + + private final ApiClient apiClient; + + private final EnvelopesApi envelopesApi; + + private final TestConfig testConfig; + + public SetTabValuesTest() throws IOException { + JWTLoginMethodTest.RequestJWTUserToken_CorrectInputValues_ReturnOAuthToken(ApiType.ESIGNATURE); + this.testConfig = TestConfig.getInstance(); + + this.apiClient = new ApiClient(testConfig.getBasePath() + basePathAddition); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + testConfig.getAccessToken()); + this.envelopesApi = new EnvelopesApi(apiClient); + } + + @Test + public void MakeEnvelopeWithTabValues_CorrectInputValues_EnvelopeDefinition() throws IOException { + // Arrange + String emailSubject = "Please sign this document from the Java SDK"; + String initialId = "1"; + Integer salary = 123000; + String salaryString = "salary"; + String fontSize = "size11"; + String font = "helvetica"; + String trueString = "true"; + String falseString = "false"; + + Signer signer = new Signer(); + signer.setEmail(testConfig.getSignerEmail()); + signer.setName(testConfig.getSignerName()); + signer.clientUserId(SIGNER_CLIENT_ID); + signer.recipientId(initialId); + + SignHere signHere = new SignHere(); + signHere.setAnchorString("/sn1"); + signHere.setAnchorUnits("pixels"); + signHere.setAnchorYOffset("10"); + signHere.setAnchorXOffset("20"); + + Text textLegal = new Text(); + textLegal.setAnchorString("/legal/"); + textLegal.setAnchorUnits("pixels"); + textLegal.setAnchorYOffset("-9"); + textLegal.setAnchorXOffset("5"); + textLegal.setFont(font); + textLegal.setFontSize(fontSize); + textLegal.setBold(trueString); + textLegal.setValue(testConfig.getSignerName()); + textLegal.setLocked(falseString); + textLegal.setTabId("legal_name"); + textLegal.setTabLabel("Legal Name"); + + Text textFamiliar = new Text(); + textFamiliar.setAnchorString("/familiar/"); + textFamiliar.setAnchorUnits("pixels"); + textFamiliar.setAnchorYOffset("-9"); + textFamiliar.setAnchorXOffset("5"); + textFamiliar.setFont(font); + textFamiliar.setFontSize(fontSize); + textFamiliar.setBold(trueString); + textFamiliar.setValue(testConfig.getSignerName()); + textFamiliar.setLocked(falseString); + textFamiliar.setTabId("familiar_name"); + textFamiliar.setTabLabel("Familiar Name"); + + Numerical numericalSalary = new Numerical(); + numericalSalary.setValidationType("Currency"); + numericalSalary.setPageNumber(initialId); + numericalSalary.setDocumentId(initialId); + numericalSalary.setXPosition("210"); + numericalSalary.setYPosition("235"); + numericalSalary.setHeight("20"); + numericalSalary.setWidth("70"); + numericalSalary.setFont(font); + numericalSalary.setFontSize(fontSize); + numericalSalary.setBold(trueString); + numericalSalary.setNumericalValue(String.format("%d", salary)); + numericalSalary.setTabId(salaryString); + numericalSalary.setTabLabel(salaryString); + + LocalePolicyTab localePolicyTab = new LocalePolicyTab(); + localePolicyTab.setCultureName("en-US"); + localePolicyTab.setCurrencyCode("usd"); + localePolicyTab.setCurrencyPositiveFormat("csym_1_comma_234_comma_567_period_89"); + localePolicyTab.setCurrencyNegativeFormat("minus_csym_1_comma_234_comma_567_period_89"); + localePolicyTab.setUseLongCurrencyFormat(trueString); + numericalSalary.setLocalePolicy(localePolicyTab); + + TextCustomField salaryCustomField = new TextCustomField(); + salaryCustomField.setName(salaryString); + salaryCustomField.setRequired(falseString); + salaryCustomField.setShow(trueString); + salaryCustomField.setValue(String.valueOf(salary)); + CustomFields cf = new CustomFields(); + cf.setTextCustomFields(Collections.singletonList(salaryCustomField)); + + Tabs tabs = new Tabs(); + tabs.setSignHereTabs(Collections.singletonList(signHere)); + tabs.setTextTabs(Arrays.asList(textLegal, textFamiliar)); + tabs.setNumericalTabs(List.of(numericalSalary)); + + signer.setTabs(tabs); + Recipients recipients = new Recipients(); + recipients.setSigners(Collections.singletonList(signer)); + + EnvelopeDefinition expectedEnvelopeDefinition = new EnvelopeDefinition(); + expectedEnvelopeDefinition.setEmailSubject(emailSubject); + expectedEnvelopeDefinition.setRecipients(recipients); + Document doc = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, initialId); + expectedEnvelopeDefinition.setDocuments(Collections.singletonList(doc)); + expectedEnvelopeDefinition.setCustomFields(cf); + expectedEnvelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + + // Act + EnvelopeDefinition envelopeDefinition = SetTabValuesService.makeEnvelope( + testConfig.getSignerEmail(), + testConfig.getSignerName()); + + // Assert + Assertions.assertNotNull(envelopeDefinition); + Assertions.assertEquals(expectedEnvelopeDefinition, envelopeDefinition); + } + + @Test + public void SetEmailAndSignerNameForRecipientViewRequest_CorrectInputValues_RecipientViewRequest() { + //Arrange + RecipientViewRequest expectedViewRequest = new RecipientViewRequest(); + String authenticationMethod = "none"; + String pingFrequency = "600"; + expectedViewRequest.setAuthenticationMethod(authenticationMethod); + expectedViewRequest.setEmail(testConfig.getSignerEmail()); + expectedViewRequest.setUserName(testConfig.getSignerName()); + expectedViewRequest.setClientUserId(SIGNER_CLIENT_ID); + expectedViewRequest.setPingFrequency(pingFrequency); + expectedViewRequest.setPingUrl(RedirectUrl); + + // Act + RecipientViewRequest viewRequest = SetTabValuesService.setEmailAndSignerNameForRecipientViewRequest( + new RecipientViewRequest(), + testConfig.getSignerEmail(), + testConfig.getSignerName(), + RedirectUrl); + + // Assert + Assertions.assertNotNull(viewRequest); + Assertions.assertEquals(expectedViewRequest, viewRequest); + } + + @Test + public void MakeRecipientViewRequest_CorrectInputValues_RecipientViewRequest() { + //Arrange + RecipientViewRequest expectedViewRequest = new RecipientViewRequest(); + String state = "?state=123"; + String pingFrequency = "600"; + String authenticationMethod = "none"; + + expectedViewRequest.setReturnUrl(RedirectUrl + state); + expectedViewRequest.setAuthenticationMethod(authenticationMethod); + expectedViewRequest.setEmail(testConfig.getSignerEmail()); + expectedViewRequest.setUserName(testConfig.getSignerName()); + expectedViewRequest.setClientUserId(SIGNER_CLIENT_ID); + expectedViewRequest.setPingFrequency(pingFrequency); + expectedViewRequest.setPingUrl(RedirectUrl); + + // Act + RecipientViewRequest viewRequest = SetTabValuesService.makeRecipientViewRequest( + testConfig.getSignerEmail(), + testConfig.getSignerName(), + RedirectUrl, + RedirectUrl); + + // Assert + Assertions.assertNotNull(viewRequest); + Assertions.assertEquals(expectedViewRequest, viewRequest); + } + + @Test + public void CreateEnvelope_CorrectInputValues_EnvelopeSummary() throws IOException, ApiException { + //Arrange + EnvelopeDefinition envelope = SetTabValuesService.makeEnvelope( + testConfig.getSignerEmail(), + testConfig.getSignerName()); + + // Act + EnvelopeSummary envelopeSummary = SetTabValuesService.createEnvelope( + envelopesApi, + testConfig.getAccountId(), + envelope); + + // Assert + Assertions.assertNotNull(envelopeSummary); + Assertions.assertNotNull(envelopeSummary.getEnvelopeId()); + } + + @Test + public void CreateRecipientView_CorrectInputValues_ViewUrl() throws IOException, ApiException { + //Arrange + EnvelopeDefinition envelope = SetTabValuesService.makeEnvelope( + testConfig.getSignerEmail(), + testConfig.getSignerName()); + + EnvelopeSummary envelopeSummary = SetTabValuesService.createEnvelope( + envelopesApi, + testConfig.getAccountId(), + envelope); + + RecipientViewRequest viewRequest = SetTabValuesService.makeRecipientViewRequest( + testConfig.getSignerEmail(), + testConfig.getSignerName(), + RedirectUrl, + RedirectUrl); + + // Act + ViewUrl viewUrl = SetTabValuesService.createRecipientView( + envelopesApi, + testConfig.getAccountId(), + envelopeSummary.getEnvelopeId(), + viewRequest); + + // Assert + Assertions.assertNotNull(viewUrl); + } +} diff --git a/src/test/java/tests/eSignature/SigningViaEmailTest.java b/src/test/java/tests/eSignature/SigningViaEmailTest.java new file mode 100644 index 00000000..5b611af3 --- /dev/null +++ b/src/test/java/tests/eSignature/SigningViaEmailTest.java @@ -0,0 +1,147 @@ +package tests.eSignature; + +import com.docusign.common.WorkArguments; +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.controller.eSignature.services.SigningViaEmailService; +import com.docusign.core.common.DocumentType; +import com.docusign.core.model.ApiType; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import tests.common.JWTLoginMethodTest; +import tests.common.TestConfig; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +public final class SigningViaEmailTest { + private static final String BEARER_AUTHENTICATION = "Bearer "; + + private static final String HTML_DOCUMENT_FILE_NAME = "templates/candy-bonbon.ftl"; + + private static final String HTML_DOCUMENT_NAME = "Order acknowledgement"; + + private static final String PDF_DOCUMENT_FILE_NAME = "World_Wide_Corp_lorem.pdf"; + + private static final String PDF_DOCUMENT_NAME = "Lorem Ipsum"; + + private static final String DOCX_DOCUMENT_FILE_NAME = "World_Wide_Corp_Battle_Plan_Trafalgar.docx"; + + private static final String DOCX_DOCUMENT_NAME = "Battle Plan"; + + private static final int ANCHOR_OFFSET_Y = 10; + + private static final int ANCHOR_OFFSET_X = 20; + + private static final String basePathAddition = "/restapi"; + + private final ApiClient apiClient; + + private final EnvelopesApi envelopesApi; + + private final TestConfig testConfig; + + public SigningViaEmailTest() throws IOException { + JWTLoginMethodTest.RequestJWTUserToken_CorrectInputValues_ReturnOAuthToken(ApiType.ESIGNATURE); + this.testConfig = TestConfig.getInstance(); + + this.apiClient = new ApiClient(testConfig.getBasePath() + basePathAddition); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + testConfig.getAccessToken()); + this.envelopesApi = new EnvelopesApi(apiClient); + } + + @Test + public void MakeEnvelopeWithCC_CorrectInputValues_EnvelopeDefinition() throws IOException { + // Arrange + String ccEmail = "cc@gmail.com"; + String ccName = "cc"; + String anchorStringOne = "**signature_1**"; + String anchorStringTwo = "/sn1/"; + String emailSubject = "Please sign this document set"; + String defaultIdOne = "1"; + String defaultIdTwo = "2"; + String defaultIdThree = "3"; + WorkArguments args = new WorkArguments(); + args.setSignerEmail(testConfig.getSignerEmail()); + args.setSignerName(testConfig.getSignerName()); + args.setCcEmail(ccEmail); + args.setCcName(ccName); + + Tabs signerTabs = EnvelopeHelpers.createSignerTabs( + EnvelopeHelpers.createSignHere(anchorStringOne, ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X), + EnvelopeHelpers.createSignHere(anchorStringTwo, ANCHOR_OFFSET_Y, ANCHOR_OFFSET_X)); + Signer signer = new Signer(); + signer.setEmail(testConfig.getSignerEmail()); + signer.setName(testConfig.getSignerName()); + signer.setRecipientId(defaultIdOne); + signer.setRoutingOrder(defaultIdOne); + signer.setTabs(signerTabs); + + CarbonCopy cc = new CarbonCopy(); + cc.setEmail(ccEmail); + cc.setName(ccName); + cc.setRecipientId(defaultIdTwo); + cc.setRoutingOrder(defaultIdTwo); + + byte[] htmlDocument = EnvelopeHelpers.createHtmlFromTemplateFile(HTML_DOCUMENT_FILE_NAME, "args", args) + .getBytes(StandardCharsets.UTF_8); + EnvelopeDefinition expectedEnvelopeDefinition = new EnvelopeDefinition(); + expectedEnvelopeDefinition.setEmailSubject(emailSubject); + expectedEnvelopeDefinition.setDocuments(Arrays.asList( + EnvelopeHelpers.createDocument(htmlDocument, HTML_DOCUMENT_NAME, + DocumentType.HTML.getDefaultFileExtention(), defaultIdOne), + EnvelopeHelpers.createDocumentFromFile(DOCX_DOCUMENT_FILE_NAME, DOCX_DOCUMENT_NAME, defaultIdTwo), + EnvelopeHelpers.createDocumentFromFile(PDF_DOCUMENT_FILE_NAME, PDF_DOCUMENT_NAME, defaultIdThree))); + expectedEnvelopeDefinition.setRecipients(EnvelopeHelpers.createRecipients(signer, cc)); + expectedEnvelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + + // Act + EnvelopeDefinition envelopeDefinition = SigningViaEmailService.makeEnvelope( + testConfig.getSignerEmail(), + testConfig.getSignerName(), + ccEmail, + ccName, + EnvelopeHelpers.ENVELOPE_STATUS_SENT, + args + ); + + // Assert + Assertions.assertNotNull(envelopeDefinition); + Assertions.assertEquals(expectedEnvelopeDefinition, envelopeDefinition); + } + + @Test + public void SigningViaEmail_CorrectInputValues_EnvelopeSummary() throws IOException, ApiException { + //Arrange + String ccEmail = "cc@gmail.com"; + String ccName = "cc"; + WorkArguments args = new WorkArguments(); + args.setSignerEmail(testConfig.getSignerEmail()); + args.setSignerName(testConfig.getSignerName()); + args.setCcEmail(ccEmail); + args.setCcName(ccName); + + EnvelopeDefinition envelope = SigningViaEmailService.makeEnvelope( + testConfig.getSignerEmail(), + testConfig.getSignerName(), + ccEmail, + ccName, + EnvelopeHelpers.ENVELOPE_STATUS_SENT, + args + ); + + // Act + EnvelopeSummary envelopeSummary = SigningViaEmailService.signingViaEmail( + envelopesApi, + testConfig.getAccountId(), + envelope); + + // Assert + Assertions.assertNotNull(envelopeSummary); + } +} diff --git a/src/test/java/tests/eSignature/UseTemplateTest.java b/src/test/java/tests/eSignature/UseTemplateTest.java new file mode 100644 index 00000000..9886843f --- /dev/null +++ b/src/test/java/tests/eSignature/UseTemplateTest.java @@ -0,0 +1,112 @@ +package tests.eSignature; + +import com.docusign.controller.eSignature.examples.EnvelopeHelpers; +import com.docusign.controller.eSignature.services.UseTemplateService; +import com.docusign.core.model.ApiType; +import com.docusign.esign.api.EnvelopesApi; +import com.docusign.esign.client.ApiClient; +import com.docusign.esign.client.ApiException; +import com.docusign.esign.model.EnvelopeDefinition; +import com.docusign.esign.model.EnvelopeSummary; +import com.docusign.esign.model.EnvelopeTemplateResults; +import com.docusign.esign.model.TemplateRole; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import tests.common.JWTLoginMethodTest; +import tests.common.TestConfig; + +import java.io.IOException; +import java.util.Arrays; + +public final class UseTemplateTest { + private static final String BEARER_AUTHENTICATION = "Bearer "; + + private static final String basePathAddition = "/restapi"; + + private final ApiClient apiClient; + + private final EnvelopesApi envelopesApi; + + private final TestConfig testConfig; + + public UseTemplateTest() throws IOException, ApiException { + JWTLoginMethodTest.RequestJWTUserToken_CorrectInputValues_ReturnOAuthToken(ApiType.ESIGNATURE); + this.testConfig = TestConfig.getInstance(); + + this.apiClient = new ApiClient(testConfig.getBasePath() + basePathAddition); + apiClient.addDefaultHeader(HttpHeaders.AUTHORIZATION, BEARER_AUTHENTICATION + testConfig.getAccessToken()); + this.envelopesApi = new EnvelopesApi(apiClient); + + CreateNewTemplateTest createNewTemplateTest = new CreateNewTemplateTest(); + createNewTemplateTest.CreateTemplate_CorrectInputValues_TemplateSummary(); + } + + @Test + public void ListTemplates_CorrectInputValues_EnvelopeTemplateResults() throws ApiException { + // Act + EnvelopeTemplateResults templates = UseTemplateService.listTemplates(apiClient, testConfig.getAccountId()); + + // Assert + Assertions.assertNotNull(templates); + } + + @Test + public void MakeEnvelopeFromTemplate_CorrectInputValues_EnvelopeDefinition() { + // Arrange + String ccEmail = "cc@gmail.com"; + String ccName = "cc"; + TemplateRole signer = new TemplateRole(); + signer.setEmail(testConfig.getSignerEmail()); + signer.setName(testConfig.getSignerName()); + signer.setRoleName(EnvelopeHelpers.SIGNER_ROLE_NAME); + + TemplateRole cc = new TemplateRole(); + cc.setEmail(ccEmail); + cc.setName(ccName); + cc.setRoleName(EnvelopeHelpers.CC_ROLE_NAME); + + EnvelopeDefinition expectedEnvelopeDefinition = new EnvelopeDefinition(); + expectedEnvelopeDefinition.setTemplateId(testConfig.getTemplateId()); + expectedEnvelopeDefinition.setTemplateRoles(Arrays.asList(signer, cc)); + expectedEnvelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT); + + // Act + EnvelopeDefinition envelopeDefinition = UseTemplateService.makeEnvelope( + testConfig.getSignerName(), + testConfig.getSignerEmail(), + ccEmail, + ccName, + testConfig.getTemplateId() + ); + + // Assert + Assertions.assertNotNull(envelopeDefinition); + Assertions.assertEquals(expectedEnvelopeDefinition, envelopeDefinition); + } + + @Test + public void CreateEnvelopeTemplate_CorrectInputValues_EnvelopeSummary() throws ApiException { + // Arrange + String ccEmail = "cc@gmail.com"; + String ccName = "cc"; + + EnvelopeDefinition envelopeDefinition = UseTemplateService.makeEnvelope( + testConfig.getSignerName(), + testConfig.getSignerEmail(), + ccEmail, + ccName, + testConfig.getTemplateId() + ); + + // Act + EnvelopeSummary envelopeSummary = UseTemplateService.createEnvelopeTemplate( + envelopesApi, + testConfig.getAccountId(), + envelopeDefinition); + + // Assert + Assertions.assertNotNull(envelopeSummary); + Assertions.assertNotNull(envelopeSummary.getEnvelopeId()); + } +}