From b91f282b77822ecdc68da9e85292c66ab3ce2bc4 Mon Sep 17 00:00:00 2001 From: an-tk Date: Sun, 7 Feb 2021 12:56:28 +0200 Subject: [PATCH 001/363] docusign_esign gem version update --- Gemfile | 2 +- Gemfile.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 9756654..2ef8df4 100644 --- a/Gemfile +++ b/Gemfile @@ -62,7 +62,7 @@ group :test do gem 'chromedriver-helper', '~> 2.1.1' end -gem 'docusign_esign', '~> 3.6' +gem 'docusign_esign', '~> 3.8.0.rc1' gem 'docusign_rooms', '~> 1.1.0.rc1' gem 'docusign_click' gem 'omniauth-oauth2', '~> 1.6' diff --git a/Gemfile.lock b/Gemfile.lock index 60cf976..0dac2dc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -91,7 +91,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.6.0) + docusign_esign (3.8.0.rc1) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) @@ -259,7 +259,7 @@ DEPENDENCIES chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) docusign_click - docusign_esign (~> 3.6) + docusign_esign (~> 3.8.0.rc1) docusign_rooms (~> 1.1.0.rc1) jbuilder (~> 2.10.0) listen (~> 3.2.1) @@ -284,4 +284,4 @@ RUBY VERSION ruby 2.7.1p83 BUNDLED WITH - 2.1.4 \ No newline at end of file + 2.1.4 From b21dc32080f92b63e0fd6bbfb55d4d0d9a2109c5 Mon Sep 17 00:00:00 2001 From: an-tk Date: Tue, 9 Feb 2021 10:08:31 +0200 Subject: [PATCH 002/363] Updated eSign31 example: added confirm successful batch send step --- .../e_sign/eg031_bulk_sending_envelopes_controller.rb | 4 +++- app/services/e_sign/eg031_bulk_sending_envelopes_service.rb | 3 +++ app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb b/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb index de78efb..6845419 100644 --- a/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb +++ b/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb @@ -11,7 +11,9 @@ def create # b) Display the JSON response @title = 'Bulk sending envelopes' @h1 = 'Bulk sending envelopes' - @message = "Confirming Bulk Send has initiated #{results}" + @message = 'Bulk send envelope was successfully performed!' + @json = results.to_json.to_json + render 'ds_common/example_done' rescue DocuSign_eSign::ApiError => e diff --git a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb index 4ca46a6..77809eb 100644 --- a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb +++ b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb @@ -56,6 +56,9 @@ def call bulk_send_request = DocuSign_eSign::BulkSendRequest.new(envelopeOrTemplateId: envelope_id) batch = bulk_envelopes_api.create_bulk_send_request(args[:account_id], bulk_list_id, bulk_send_request) batch_id = batch.batch_id + + # Step 8. Confirm successful batch send + bulk_envelopes_api.get_bulk_send_batch_status(args[:account_id], batch_id) end private diff --git a/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb b/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb index 1c9aaa7..184208f 100644 --- a/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb +++ b/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb @@ -1,4 +1,4 @@ -

31. Bulk sending envelopes to multiple recipients

+

31. Bulk sending envelopes to multiple recipients

Method BulkSend:createBulkSendList creates a bulk list that you can to use an envelope to up From b53078f7638eab19b1f47569f315895b5f164ee4 Mon Sep 17 00:00:00 2001 From: an-tk Date: Tue, 9 Feb 2021 13:15:13 +0200 Subject: [PATCH 003/363] Updated quickstart logic --- app/controllers/e_sign/eg001_embedded_signing_controller.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/controllers/e_sign/eg001_embedded_signing_controller.rb b/app/controllers/e_sign/eg001_embedded_signing_controller.rb index 57acf1c..3b00793 100644 --- a/app/controllers/e_sign/eg001_embedded_signing_controller.rb +++ b/app/controllers/e_sign/eg001_embedded_signing_controller.rb @@ -16,4 +16,9 @@ def create redirect_url = ESign::Eg001EmbeddedSigningService.new(session, request).call redirect_to redirect_url end + + def get + session[:been_here] = true + super + end end From ccec5ae7e4fcc14646eb83ebec49b7ffd9d02fd2 Mon Sep 17 00:00:00 2001 From: an-tk Date: Fri, 19 Feb 2021 20:56:01 +0200 Subject: [PATCH 004/363] Clean up eg031 --- .../e_sign/eg031_bulk_sending_envelopes_controller.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb b/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb index 6845419..b9ebf41 100644 --- a/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb +++ b/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb @@ -9,9 +9,9 @@ def create results = ESign::Eg031BulkSendingEnvelopesService.new(request, session).call # Step 4. a) Call the eSignature API # b) Display the JSON response - @title = 'Bulk sending envelopes' - @h1 = 'Bulk sending envelopes' - @message = 'Bulk send envelope was successfully performed!' + @title = 'Bulk sent' + @h1 = 'Bulk send envelope was successfully performed!' + @message = "Bulk request queued to #{results.queued} user lists." @json = results.to_json.to_json render 'ds_common/example_done' From c8d91d75390847289083cba7e218eedefec35a63 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Feb 2021 17:56:42 +0000 Subject: [PATCH 005/363] Bump nokogiri from 1.10.10 to 1.11.1 Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.10.10 to 1.11.1. - [Release notes](https://github.com/sparklemotion/nokogiri/releases) - [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md) - [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.10.10...v1.11.1) Signed-off-by: dependabot[bot] --- Gemfile.lock | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 60cf976..510e2ef 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -130,15 +130,16 @@ GEM method_source (0.9.2) mimemagic (0.3.5) mini_mime (1.0.2) - mini_portile2 (2.4.0) + mini_portile2 (2.5.0) minitest (5.14.2) msgpack (1.3.3) multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) nio4r (2.5.4) - nokogiri (1.10.10) - mini_portile2 (~> 2.4.0) + nokogiri (1.11.1) + mini_portile2 (~> 2.5.0) + racc (~> 1.4) oauth2 (1.4.4) faraday (>= 0.8, < 2.0) jwt (>= 1.0, < 3.0) @@ -164,6 +165,7 @@ GEM public_suffix (4.0.6) puma (4.3.6) nio4r (~> 2.0) + racc (1.5.2) rack (2.2.3) rack-test (1.1.0) rack (>= 1.0, < 3) From 7b62e6fe7414f233d228f01910d554f3f6d67f2d Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 25 Feb 2021 10:51:20 -0800 Subject: [PATCH 006/363] Various updates including adding step 8 of bulk send --- Gemfile | 2 +- Gemfile.lock | 6 +++--- README.md | 6 ++---- .../e_sign/eg001_embedded_signing_controller.rb | 5 +++++ .../e_sign/eg031_bulk_sending_envelopes_controller.rb | 8 +++++--- ...008_grant_office_access_to_form_group_controller.rb | 6 +++++- .../eg009_assign_form_to_form_group_controller.rb | 6 +++++- .../e_sign/eg031_bulk_sending_envelopes_service.rb | 3 +++ .../room_api/eg007_create_form_group_service.rb | 10 ++++++---- .../eg008_grant_office_access_to_form_group_service.rb | 6 ++++-- .../eg009_assign_form_to_form_group_service.rb | 9 ++++++--- .../e_sign/eg031_bulk_sending_envelopes/get.html.erb | 2 +- 12 files changed, 46 insertions(+), 23 deletions(-) diff --git a/Gemfile b/Gemfile index 9756654..2ef8df4 100644 --- a/Gemfile +++ b/Gemfile @@ -62,7 +62,7 @@ group :test do gem 'chromedriver-helper', '~> 2.1.1' end -gem 'docusign_esign', '~> 3.6' +gem 'docusign_esign', '~> 3.8.0.rc1' gem 'docusign_rooms', '~> 1.1.0.rc1' gem 'docusign_click' gem 'omniauth-oauth2', '~> 1.6' diff --git a/Gemfile.lock b/Gemfile.lock index 510e2ef..24b4da7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -91,7 +91,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.6.0) + docusign_esign (3.8.0.rc1) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) @@ -261,7 +261,7 @@ DEPENDENCIES chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) docusign_click - docusign_esign (~> 3.6) + docusign_esign (~> 3.8.0.rc1) docusign_rooms (~> 1.1.0.rc1) jbuilder (~> 2.10.0) listen (~> 3.2.1) @@ -286,4 +286,4 @@ RUBY VERSION ruby 2.7.1p83 BUNDLED WITH - 2.1.4 \ No newline at end of file + 2.1.4 diff --git a/README.md b/README.md index 6b66e61..ad77d74 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,6 @@ This repo is a Ruby on Rails application that demonstrates: For more information about the scopes used for obtaining authorization to use the eSignature API, see the [Required Scopes section](https://developers.docusign.com/docs/esign-rest-api/esign101/auth). -For more information about the scopes used for obtaining authorization to use the eSignature API, see the [Required Scopes section](https://developers.docusign.com/docs/esign-rest-api/esign101/auth). - 1. **Use embedded signing.** [Source.](app/services/e_sign/eg001_embedded_signing_service.rb) This example sends an envelope, and then uses embedded signing for the first signer. @@ -142,9 +140,9 @@ For more information about the scopes used for obtaining authorization to use th [Source.](app/services/e_sign/eg034_use_conditional_recipients_service.rb) This example demonstrates how to create an envelope where the workflow is routed to different recipients based on the value of a transaction. -1. **Request a signature by SMS** +1. **Request a signature by SMS delivery** [Source.](app/services/e_sign/eg035_sms_delivery_service.rb) - This code example demonstrates how to send a signature request for a signer to read and sign via an SMS message. + This code example demonstrates how to send a signature request via an SMS message using the [Envelopes: create](https://developers.docusign.com/esign-rest-api/reference/Envelopes/Envelopes/create) method. ## Rooms API diff --git a/app/controllers/e_sign/eg001_embedded_signing_controller.rb b/app/controllers/e_sign/eg001_embedded_signing_controller.rb index 57acf1c..3b00793 100644 --- a/app/controllers/e_sign/eg001_embedded_signing_controller.rb +++ b/app/controllers/e_sign/eg001_embedded_signing_controller.rb @@ -16,4 +16,9 @@ def create redirect_url = ESign::Eg001EmbeddedSigningService.new(session, request).call redirect_to redirect_url end + + def get + session[:been_here] = true + super + end end diff --git a/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb b/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb index de78efb..b9ebf41 100644 --- a/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb +++ b/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb @@ -9,9 +9,11 @@ def create results = ESign::Eg031BulkSendingEnvelopesService.new(request, session).call # Step 4. a) Call the eSignature API # b) Display the JSON response - @title = 'Bulk sending envelopes' - @h1 = 'Bulk sending envelopes' - @message = "Confirming Bulk Send has initiated #{results}" + @title = 'Bulk sent' + @h1 = 'Bulk send envelope was successfully performed!' + @message = "Bulk request queued to #{results.queued} user lists." + @json = results.to_json.to_json + render 'ds_common/example_done' rescue DocuSign_eSign::ApiError => e diff --git a/app/controllers/room_api/eg008_grant_office_access_to_form_group_controller.rb b/app/controllers/room_api/eg008_grant_office_access_to_form_group_controller.rb index ac9370b..d7eedee 100644 --- a/app/controllers/room_api/eg008_grant_office_access_to_form_group_controller.rb +++ b/app/controllers/room_api/eg008_grant_office_access_to_form_group_controller.rb @@ -19,9 +19,13 @@ def create def get super - # Step 3. Get an office ID + # Step 3 start @offices = RoomApi::GetDataService.new(session).get_offices + # Step 3 end + + # Step 4 start @form_groups = RoomApi::GetDataService.new(session).get_form_groups + # Step 4 end end private diff --git a/app/controllers/room_api/eg009_assign_form_to_form_group_controller.rb b/app/controllers/room_api/eg009_assign_form_to_form_group_controller.rb index 79ff9c9..4ecde46 100644 --- a/app/controllers/room_api/eg009_assign_form_to_form_group_controller.rb +++ b/app/controllers/room_api/eg009_assign_form_to_form_group_controller.rb @@ -19,9 +19,13 @@ def create def get super - # Step 3. Obtain the desired form ID + # Step 3 start @forms = RoomApi::GetDataService.new(session).get_form_libraries + # Step 3 end + + # Step 4 start @form_groups = RoomApi::GetDataService.new(session).get_form_groups + # Step 4 end end private diff --git a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb index 4ca46a6..77809eb 100644 --- a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb +++ b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb @@ -56,6 +56,9 @@ def call bulk_send_request = DocuSign_eSign::BulkSendRequest.new(envelopeOrTemplateId: envelope_id) batch = bulk_envelopes_api.create_bulk_send_request(args[:account_id], bulk_list_id, bulk_send_request) batch_id = batch.batch_id + + # Step 8. Confirm successful batch send + bulk_envelopes_api.get_bulk_send_batch_status(args[:account_id], batch_id) end private diff --git a/app/services/room_api/eg007_create_form_group_service.rb b/app/services/room_api/eg007_create_form_group_service.rb index 79c72fb..a6bd3d1 100644 --- a/app/services/room_api/eg007_create_form_group_service.rb +++ b/app/services/room_api/eg007_create_form_group_service.rb @@ -18,25 +18,27 @@ def call private def worker - # Step 2. Construct your API headers + # Step 2 start configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + # Step 2 end - # Step 4. Call the Rooms API + # Step 4 start rooms_api = DocuSign_Rooms::FormGroupsApi.new(api_client) - rooms_api.create_form_group(args[:account_id], body) + # Step 4 end end def body - #Step 3. Construct the request body + # Step 3 start DocuSign_Rooms::RoomForCreate.new( { name: args[:group_name] } ) + # Step 3 end end end diff --git a/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb b/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb index bd4e85a..b036f1a 100644 --- a/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb +++ b/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb @@ -19,20 +19,22 @@ def call private def worker - # Step 2. Construct your API headers + # Step 2 start configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + # Step 2 end - # Step 4. Call the Rooms API + # Step 5 start form_groups_api = DocuSign_Rooms::FormGroupsApi.new(api_client) begin response = form_groups_api.grant_office_access_to_form_group(args[:form_group_id], args[:office_id], args[:account_id]) rescue Exception => e return {exception: 'Failed to grant office access to a form group'} end + # Step 5 end response end end diff --git a/app/services/room_api/eg009_assign_form_to_form_group_service.rb b/app/services/room_api/eg009_assign_form_to_form_group_service.rb index efb93d1..a24d015 100644 --- a/app/services/room_api/eg009_assign_form_to_form_group_service.rb +++ b/app/services/room_api/eg009_assign_form_to_form_group_service.rb @@ -19,29 +19,32 @@ def call private def worker - # Step 2. Construct your API headers + # Step 2 start configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + # Step 2 end - # Step 5. Call the Rooms API + # Step 6 start form_groups_api = DocuSign_Rooms::FormGroupsApi.new(api_client) begin response = form_groups_api.assign_form_group_form(args[:form_group_id], args[:account_id], body) rescue Exception => e return { exception: 'Failed to assign a form to a form group' } end + # Step 6 end response end def body - # Step 4. Construct your request body + # Step 5 start DocuSign_Rooms::FormGroupFormToAssign.new( { formId: args[:form_id] } ) + # Step 5 end end end diff --git a/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb b/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb index 1c9aaa7..184208f 100644 --- a/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb +++ b/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb @@ -1,4 +1,4 @@ -

31. Bulk sending envelopes to multiple recipients

+

31. Bulk sending envelopes to multiple recipients

Method BulkSend:createBulkSendList creates a bulk list that you can to use an envelope to up From e77f00793c297a2346fc9d316b41ccf21ec5d66f Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 2 Mar 2021 15:56:28 -0800 Subject: [PATCH 007/363] Updating various packages to move forward with new versions --- Gemfile | 10 ++-- Gemfile.lock | 131 ++++++++++++++++++++++++++++----------------------- 2 files changed, 77 insertions(+), 64 deletions(-) diff --git a/Gemfile b/Gemfile index 2ef8df4..89d7d58 100644 --- a/Gemfile +++ b/Gemfile @@ -1,12 +1,12 @@ -# frozen_string_literal: true + # frozen_string_literal: true source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '2.7.1' +ruby '2.7.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 6.0.3.3' +gem 'rails', '~> 6.0.3.5' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4.2' # Use Puma as the app server @@ -64,8 +64,8 @@ end gem 'docusign_esign', '~> 3.8.0.rc1' gem 'docusign_rooms', '~> 1.1.0.rc1' -gem 'docusign_click' -gem 'omniauth-oauth2', '~> 1.6' +gem 'docusign_click', '~> 1.0.0' +gem 'omniauth-oauth2', '~> 1.7.1' gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem diff --git a/Gemfile.lock b/Gemfile.lock index 24b4da7..d84c396 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,56 +1,56 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.3.4) - actionpack (= 6.0.3.4) + actioncable (6.0.3.5) + actionpack (= 6.0.3.5) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.3.4) - actionpack (= 6.0.3.4) - activejob (= 6.0.3.4) - activerecord (= 6.0.3.4) - activestorage (= 6.0.3.4) - activesupport (= 6.0.3.4) + actionmailbox (6.0.3.5) + actionpack (= 6.0.3.5) + activejob (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) mail (>= 2.7.1) - actionmailer (6.0.3.4) - actionpack (= 6.0.3.4) - actionview (= 6.0.3.4) - activejob (= 6.0.3.4) + actionmailer (6.0.3.5) + actionpack (= 6.0.3.5) + actionview (= 6.0.3.5) + activejob (= 6.0.3.5) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.3.4) - actionview (= 6.0.3.4) - activesupport (= 6.0.3.4) + actionpack (6.0.3.5) + actionview (= 6.0.3.5) + activesupport (= 6.0.3.5) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.3.4) - actionpack (= 6.0.3.4) - activerecord (= 6.0.3.4) - activestorage (= 6.0.3.4) - activesupport (= 6.0.3.4) + actiontext (6.0.3.5) + actionpack (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) nokogiri (>= 1.8.5) - actionview (6.0.3.4) - activesupport (= 6.0.3.4) + actionview (6.0.3.5) + activesupport (= 6.0.3.5) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.3.4) - activesupport (= 6.0.3.4) + activejob (6.0.3.5) + activesupport (= 6.0.3.5) globalid (>= 0.3.6) - activemodel (6.0.3.4) - activesupport (= 6.0.3.4) - activerecord (6.0.3.4) - activemodel (= 6.0.3.4) - activesupport (= 6.0.3.4) - activestorage (6.0.3.4) - actionpack (= 6.0.3.4) - activejob (= 6.0.3.4) - activerecord (= 6.0.3.4) + activemodel (6.0.3.5) + activesupport (= 6.0.3.5) + activerecord (6.0.3.5) + activemodel (= 6.0.3.5) + activesupport (= 6.0.3.5) + activestorage (6.0.3.5) + actionpack (= 6.0.3.5) + activejob (= 6.0.3.5) + activerecord (= 6.0.3.5) marcel (~> 0.3.1) - activesupport (6.0.3.4) + activesupport (6.0.3.5) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -87,7 +87,8 @@ GEM coffee-script-source (1.12.2) concurrent-ruby (1.1.7) crass (1.0.6) - docusign_click (1.0.0.beta2) + docusign_click (1.0.0) + addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) @@ -103,10 +104,13 @@ GEM ethon (0.12.0) ffi (>= 1.3.0) execjs (2.7.0) - faraday (1.1.0) + faraday (1.3.0) + faraday-net_http (~> 1.0) multipart-post (>= 1.2, < 3) ruby2_keywords + faraday-net_http (1.0.1) ffi (1.13.1) + ffi (1.13.1-x64-mingw32) globalid (0.4.2) activesupport (>= 4.2.0) hashie (4.1.0) @@ -133,6 +137,7 @@ GEM mini_portile2 (2.5.0) minitest (5.14.2) msgpack (1.3.3) + msgpack (1.3.3-x64-mingw32) multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) @@ -140,6 +145,8 @@ GEM nokogiri (1.11.1) mini_portile2 (~> 2.5.0) racc (~> 1.4) + nokogiri (1.11.1-x64-mingw32) + racc (~> 1.4) oauth2 (1.4.4) faraday (>= 0.8, < 2.0) jwt (>= 1.0, < 3.0) @@ -149,9 +156,9 @@ GEM omniauth (1.9.1) hashie (>= 3.4.6) rack (>= 1.6.2, < 3) - omniauth-oauth2 (1.7.0) + omniauth-oauth2 (1.7.1) oauth2 (~> 1.4) - omniauth (~> 1.9) + omniauth (>= 1.9, < 3) omniauth-rails_csrf_protection (0.1.2) actionpack (>= 4.2) omniauth (>= 1.3.1) @@ -169,29 +176,29 @@ GEM rack (2.2.3) rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.0.3.4) - actioncable (= 6.0.3.4) - actionmailbox (= 6.0.3.4) - actionmailer (= 6.0.3.4) - actionpack (= 6.0.3.4) - actiontext (= 6.0.3.4) - actionview (= 6.0.3.4) - activejob (= 6.0.3.4) - activemodel (= 6.0.3.4) - activerecord (= 6.0.3.4) - activestorage (= 6.0.3.4) - activesupport (= 6.0.3.4) + rails (6.0.3.5) + actioncable (= 6.0.3.5) + actionmailbox (= 6.0.3.5) + actionmailer (= 6.0.3.5) + actionpack (= 6.0.3.5) + actiontext (= 6.0.3.5) + actionview (= 6.0.3.5) + activejob (= 6.0.3.5) + activemodel (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) bundler (>= 1.3.0) - railties (= 6.0.3.4) + railties (= 6.0.3.5) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) - railties (6.0.3.4) - actionpack (= 6.0.3.4) - activesupport (= 6.0.3.4) + railties (6.0.3.5) + actionpack (= 6.0.3.5) + activesupport (= 6.0.3.5) method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) @@ -200,12 +207,14 @@ GEM rb-inotify (0.10.1) ffi (~> 1.0) regexp_parser (1.8.2) - ruby2_keywords (0.0.2) + ruby2_keywords (0.0.4) rubyzip (2.3.0) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) sassc (2.4.0) ffi (~> 1.9) + sassc (2.4.0-x64-mingw32) + ffi (~> 1.9) sassc-rails (2.1.2) railties (>= 4.0.0) sassc (>= 2.0) @@ -237,8 +246,11 @@ GEM ethon (>= 0.9.0) tzinfo (1.2.7) thread_safe (~> 0.1) + tzinfo-data (1.2019.3) + tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) + wdm (0.1.1) web-console (4.0.4) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -253,6 +265,7 @@ GEM PLATFORMS ruby + x64-mingw32 DEPENDENCIES bootsnap (~> 1.4.5) @@ -260,17 +273,17 @@ DEPENDENCIES capybara (~> 3.31.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_click + docusign_click (~> 1.0.0) docusign_esign (~> 3.8.0.rc1) docusign_rooms (~> 1.1.0.rc1) jbuilder (~> 2.10.0) listen (~> 3.2.1) - omniauth-oauth2 (~> 1.6) + omniauth-oauth2 (~> 1.7.1) omniauth-rails_csrf_protection pry-nav (~> 0.3.0) pry-rails (~> 0.3.9) puma (~> 4.3.3) - rails (~> 6.0.3.3) + rails (~> 6.0.3.5) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) spring (~> 2.1.0) @@ -283,7 +296,7 @@ DEPENDENCIES web-console (~> 4.0.1) RUBY VERSION - ruby 2.7.1p83 + ruby 2.7.2p137 BUNDLED WITH 2.1.4 From cbcf4ae357e4d9a96708d1028e87960b7dd75baa Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 2 Mar 2021 16:50:49 -0800 Subject: [PATCH 008/363] Updating gem package versions --- Gemfile | 10 ++-- Gemfile.lock | 131 ++++++++++++++++++++++++++++----------------------- 2 files changed, 77 insertions(+), 64 deletions(-) diff --git a/Gemfile b/Gemfile index 2ef8df4..89d7d58 100644 --- a/Gemfile +++ b/Gemfile @@ -1,12 +1,12 @@ -# frozen_string_literal: true + # frozen_string_literal: true source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '2.7.1' +ruby '2.7.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 6.0.3.3' +gem 'rails', '~> 6.0.3.5' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4.2' # Use Puma as the app server @@ -64,8 +64,8 @@ end gem 'docusign_esign', '~> 3.8.0.rc1' gem 'docusign_rooms', '~> 1.1.0.rc1' -gem 'docusign_click' -gem 'omniauth-oauth2', '~> 1.6' +gem 'docusign_click', '~> 1.0.0' +gem 'omniauth-oauth2', '~> 1.7.1' gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem diff --git a/Gemfile.lock b/Gemfile.lock index 24b4da7..d84c396 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,56 +1,56 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.3.4) - actionpack (= 6.0.3.4) + actioncable (6.0.3.5) + actionpack (= 6.0.3.5) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.3.4) - actionpack (= 6.0.3.4) - activejob (= 6.0.3.4) - activerecord (= 6.0.3.4) - activestorage (= 6.0.3.4) - activesupport (= 6.0.3.4) + actionmailbox (6.0.3.5) + actionpack (= 6.0.3.5) + activejob (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) mail (>= 2.7.1) - actionmailer (6.0.3.4) - actionpack (= 6.0.3.4) - actionview (= 6.0.3.4) - activejob (= 6.0.3.4) + actionmailer (6.0.3.5) + actionpack (= 6.0.3.5) + actionview (= 6.0.3.5) + activejob (= 6.0.3.5) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.3.4) - actionview (= 6.0.3.4) - activesupport (= 6.0.3.4) + actionpack (6.0.3.5) + actionview (= 6.0.3.5) + activesupport (= 6.0.3.5) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.3.4) - actionpack (= 6.0.3.4) - activerecord (= 6.0.3.4) - activestorage (= 6.0.3.4) - activesupport (= 6.0.3.4) + actiontext (6.0.3.5) + actionpack (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) nokogiri (>= 1.8.5) - actionview (6.0.3.4) - activesupport (= 6.0.3.4) + actionview (6.0.3.5) + activesupport (= 6.0.3.5) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.3.4) - activesupport (= 6.0.3.4) + activejob (6.0.3.5) + activesupport (= 6.0.3.5) globalid (>= 0.3.6) - activemodel (6.0.3.4) - activesupport (= 6.0.3.4) - activerecord (6.0.3.4) - activemodel (= 6.0.3.4) - activesupport (= 6.0.3.4) - activestorage (6.0.3.4) - actionpack (= 6.0.3.4) - activejob (= 6.0.3.4) - activerecord (= 6.0.3.4) + activemodel (6.0.3.5) + activesupport (= 6.0.3.5) + activerecord (6.0.3.5) + activemodel (= 6.0.3.5) + activesupport (= 6.0.3.5) + activestorage (6.0.3.5) + actionpack (= 6.0.3.5) + activejob (= 6.0.3.5) + activerecord (= 6.0.3.5) marcel (~> 0.3.1) - activesupport (6.0.3.4) + activesupport (6.0.3.5) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -87,7 +87,8 @@ GEM coffee-script-source (1.12.2) concurrent-ruby (1.1.7) crass (1.0.6) - docusign_click (1.0.0.beta2) + docusign_click (1.0.0) + addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) @@ -103,10 +104,13 @@ GEM ethon (0.12.0) ffi (>= 1.3.0) execjs (2.7.0) - faraday (1.1.0) + faraday (1.3.0) + faraday-net_http (~> 1.0) multipart-post (>= 1.2, < 3) ruby2_keywords + faraday-net_http (1.0.1) ffi (1.13.1) + ffi (1.13.1-x64-mingw32) globalid (0.4.2) activesupport (>= 4.2.0) hashie (4.1.0) @@ -133,6 +137,7 @@ GEM mini_portile2 (2.5.0) minitest (5.14.2) msgpack (1.3.3) + msgpack (1.3.3-x64-mingw32) multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) @@ -140,6 +145,8 @@ GEM nokogiri (1.11.1) mini_portile2 (~> 2.5.0) racc (~> 1.4) + nokogiri (1.11.1-x64-mingw32) + racc (~> 1.4) oauth2 (1.4.4) faraday (>= 0.8, < 2.0) jwt (>= 1.0, < 3.0) @@ -149,9 +156,9 @@ GEM omniauth (1.9.1) hashie (>= 3.4.6) rack (>= 1.6.2, < 3) - omniauth-oauth2 (1.7.0) + omniauth-oauth2 (1.7.1) oauth2 (~> 1.4) - omniauth (~> 1.9) + omniauth (>= 1.9, < 3) omniauth-rails_csrf_protection (0.1.2) actionpack (>= 4.2) omniauth (>= 1.3.1) @@ -169,29 +176,29 @@ GEM rack (2.2.3) rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.0.3.4) - actioncable (= 6.0.3.4) - actionmailbox (= 6.0.3.4) - actionmailer (= 6.0.3.4) - actionpack (= 6.0.3.4) - actiontext (= 6.0.3.4) - actionview (= 6.0.3.4) - activejob (= 6.0.3.4) - activemodel (= 6.0.3.4) - activerecord (= 6.0.3.4) - activestorage (= 6.0.3.4) - activesupport (= 6.0.3.4) + rails (6.0.3.5) + actioncable (= 6.0.3.5) + actionmailbox (= 6.0.3.5) + actionmailer (= 6.0.3.5) + actionpack (= 6.0.3.5) + actiontext (= 6.0.3.5) + actionview (= 6.0.3.5) + activejob (= 6.0.3.5) + activemodel (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) bundler (>= 1.3.0) - railties (= 6.0.3.4) + railties (= 6.0.3.5) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) - railties (6.0.3.4) - actionpack (= 6.0.3.4) - activesupport (= 6.0.3.4) + railties (6.0.3.5) + actionpack (= 6.0.3.5) + activesupport (= 6.0.3.5) method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) @@ -200,12 +207,14 @@ GEM rb-inotify (0.10.1) ffi (~> 1.0) regexp_parser (1.8.2) - ruby2_keywords (0.0.2) + ruby2_keywords (0.0.4) rubyzip (2.3.0) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) sassc (2.4.0) ffi (~> 1.9) + sassc (2.4.0-x64-mingw32) + ffi (~> 1.9) sassc-rails (2.1.2) railties (>= 4.0.0) sassc (>= 2.0) @@ -237,8 +246,11 @@ GEM ethon (>= 0.9.0) tzinfo (1.2.7) thread_safe (~> 0.1) + tzinfo-data (1.2019.3) + tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) + wdm (0.1.1) web-console (4.0.4) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -253,6 +265,7 @@ GEM PLATFORMS ruby + x64-mingw32 DEPENDENCIES bootsnap (~> 1.4.5) @@ -260,17 +273,17 @@ DEPENDENCIES capybara (~> 3.31.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_click + docusign_click (~> 1.0.0) docusign_esign (~> 3.8.0.rc1) docusign_rooms (~> 1.1.0.rc1) jbuilder (~> 2.10.0) listen (~> 3.2.1) - omniauth-oauth2 (~> 1.6) + omniauth-oauth2 (~> 1.7.1) omniauth-rails_csrf_protection pry-nav (~> 0.3.0) pry-rails (~> 0.3.9) puma (~> 4.3.3) - rails (~> 6.0.3.3) + rails (~> 6.0.3.5) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) spring (~> 2.1.0) @@ -283,7 +296,7 @@ DEPENDENCIES web-console (~> 4.0.1) RUBY VERSION - ruby 2.7.1p83 + ruby 2.7.2p137 BUNDLED WITH 2.1.4 From f280faaecc6549a55714f5b8dd8b7b607abbe19f Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 4 Mar 2021 11:08:30 -0800 Subject: [PATCH 009/363] Update README.md --- README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/README.md b/README.md index ad77d74..14cd91e 100644 --- a/README.md +++ b/README.md @@ -275,6 +275,33 @@ When the token expires, it updates automatically. From there you should be able to run the launcher using `bundle exec rails server` then selecting **JSON Web Token** when authenticaing your account. +## Troubleshooting Windows SSL issue +When using the Ruby launcher on a Windows machine you may get the following error: + +SSL peer certificate or SSH remote key was not OK + +This error occurs because you’re attempting to use the Ruby launcher with a self-signed certificate or without SSL/HTTP security. The API calls from Ruby SDKs are using a built-in Curl tool that is enforcing the SSL requirement. You can disable this security check to run the launcher in an insecure manner on your developer machine. + +It is highly recommended that you don’t disable this security check in a production environment or in your integration. This method is offered here solely as a means to enable you to develop quickly by lowering the security bar on your local machine. + +Find the root folder for your Ruby gems (in this case, a 64-bit version of Ruby 2.7.0): + +C:\Ruby27-x64\lib\ruby\gems\2.7.0\gems\ + +Find the relevant DocuSign Ruby SDK you are using. The name always starts with “docusign”; for instance, DocuSign Click SDK version 1.0.0: + +C:\Ruby27-x64\lib\ruby\gems\2.7.0\gems\docusign_click-1.0.0\lib\docusign_click + +Find the configuration.rb file in that folder. +Modify the following two lines in the configuration.rb file, replacing “true” with “false”: + + @verify_ssl = true + @verify_ssl_host = true + + +Once this is complete, you can run your Ruby on Rails application again and you should be able to make API calls on your localhost. + + #### Payments code example To use the payments example, create a From 905fd23cee748ccd62baf0a9abec3b0acf428f21 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 4 Mar 2021 11:10:14 -0800 Subject: [PATCH 010/363] Update README.md --- README.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 14cd91e..944222c 100644 --- a/README.md +++ b/README.md @@ -275,14 +275,14 @@ When the token expires, it updates automatically. From there you should be able to run the launcher using `bundle exec rails server` then selecting **JSON Web Token** when authenticaing your account. -## Troubleshooting Windows SSL issue +### Troubleshooting Windows SSL issue When using the Ruby launcher on a Windows machine you may get the following error: -SSL peer certificate or SSH remote key was not OK +**SSL peer certificate or SSH remote key was not OK** This error occurs because you’re attempting to use the Ruby launcher with a self-signed certificate or without SSL/HTTP security. The API calls from Ruby SDKs are using a built-in Curl tool that is enforcing the SSL requirement. You can disable this security check to run the launcher in an insecure manner on your developer machine. -It is highly recommended that you don’t disable this security check in a production environment or in your integration. This method is offered here solely as a means to enable you to develop quickly by lowering the security bar on your local machine. +**It is highly recommended that you don’t disable this security check in a production environment or in your integration. This method is offered here solely as a means to enable you to develop quickly by lowering the security bar on your local machine. Find the root folder for your Ruby gems (in this case, a 64-bit version of Ruby 2.7.0): @@ -292,8 +292,8 @@ Find the relevant DocuSign Ruby SDK you are using. The name always starts with C:\Ruby27-x64\lib\ruby\gems\2.7.0\gems\docusign_click-1.0.0\lib\docusign_click -Find the configuration.rb file in that folder. -Modify the following two lines in the configuration.rb file, replacing “true” with “false”: +Find the **configuration.rb** file in that folder. +Modify the following two lines in the **configuration.rb** file, replacing “true” with “false”: @verify_ssl = true @verify_ssl_host = true @@ -302,8 +302,7 @@ Modify the following two lines in the configuration.rb file, replacing “true Once this is complete, you can run your Ruby on Rails application again and you should be able to make API calls on your localhost. - -#### Payments code example +### Payments code example To use the payments example, create a test payments gateway for your developer sandbox account. @@ -313,7 +312,7 @@ file for instructions. Then add the payment gateway account id to the **config/application.rb** file. -## Using the examples with other authentication flows +### Using the examples with other authentication flows The examples in this repository can also be used with the Implicit grant OAuth flow. From fc584bd53a7f6e7e075aafa6c795b8eb2557b867 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 4 Mar 2021 11:11:44 -0800 Subject: [PATCH 011/363] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 944222c..22a6010 100644 --- a/README.md +++ b/README.md @@ -282,7 +282,7 @@ When using the Ruby launcher on a Windows machine you may get the following erro This error occurs because you’re attempting to use the Ruby launcher with a self-signed certificate or without SSL/HTTP security. The API calls from Ruby SDKs are using a built-in Curl tool that is enforcing the SSL requirement. You can disable this security check to run the launcher in an insecure manner on your developer machine. -**It is highly recommended that you don’t disable this security check in a production environment or in your integration. This method is offered here solely as a means to enable you to develop quickly by lowering the security bar on your local machine. +**It is highly recommended that you don’t disable this security check in a production environment or in your integration. This method is offered here solely as a means to enable you to develop quickly by lowering the security bar on your local machine.** Find the root folder for your Ruby gems (in this case, a 64-bit version of Ruby 2.7.0): From 93e29e17bc6a238df46acc9ef167daf53b83cc92 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 4 Mar 2021 11:12:53 -0800 Subject: [PATCH 012/363] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 22a6010..2f67c53 100644 --- a/README.md +++ b/README.md @@ -282,7 +282,7 @@ When using the Ruby launcher on a Windows machine you may get the following erro This error occurs because you’re attempting to use the Ruby launcher with a self-signed certificate or without SSL/HTTP security. The API calls from Ruby SDKs are using a built-in Curl tool that is enforcing the SSL requirement. You can disable this security check to run the launcher in an insecure manner on your developer machine. -**It is highly recommended that you don’t disable this security check in a production environment or in your integration. This method is offered here solely as a means to enable you to develop quickly by lowering the security bar on your local machine.** +**It is highly recommended that you don’t disable this security check in a production environment or in your integration. This method is offered here solely as a means to enable you to develop quickly by lowering the security bar on your local machine.** Find the root folder for your Ruby gems (in this case, a 64-bit version of Ruby 2.7.0): From 485c8c2a74d44e131df64bf5dd4925b40f3073ab Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 4 Mar 2021 11:15:05 -0800 Subject: [PATCH 013/363] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2f67c53..c1aa97f 100644 --- a/README.md +++ b/README.md @@ -282,8 +282,9 @@ When using the Ruby launcher on a Windows machine you may get the following erro This error occurs because you’re attempting to use the Ruby launcher with a self-signed certificate or without SSL/HTTP security. The API calls from Ruby SDKs are using a built-in Curl tool that is enforcing the SSL requirement. You can disable this security check to run the launcher in an insecure manner on your developer machine. -**It is highly recommended that you don’t disable this security check in a production environment or in your integration. This method is offered here solely as a means to enable you to develop quickly by lowering the security bar on your local machine.** - +```diff +- It is highly recommended that you don’t disable this security check in a production environment or in your integration. This method is offered here solely as a means to enable you to develop quickly by lowering the security bar on your local machine. +``` Find the root folder for your Ruby gems (in this case, a 64-bit version of Ruby 2.7.0): C:\Ruby27-x64\lib\ruby\gems\2.7.0\gems\ From 810e3a01f01f60fd8be916bdbcefaadc6fa0e8cc Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 4 Mar 2021 11:15:42 -0800 Subject: [PATCH 014/363] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c1aa97f..c859bb7 100644 --- a/README.md +++ b/README.md @@ -283,7 +283,8 @@ When using the Ruby launcher on a Windows machine you may get the following erro This error occurs because you’re attempting to use the Ruby launcher with a self-signed certificate or without SSL/HTTP security. The API calls from Ruby SDKs are using a built-in Curl tool that is enforcing the SSL requirement. You can disable this security check to run the launcher in an insecure manner on your developer machine. ```diff -- It is highly recommended that you don’t disable this security check in a production environment or in your integration. This method is offered here solely as a means to enable you to develop quickly by lowering the security bar on your local machine. +- It is highly recommended that you don’t disable this security check in a production environment or in your integration. +- This method is offered here solely as a means to enable you to develop quickly by lowering the security bar on your local machine. ``` Find the root folder for your Ruby gems (in this case, a 64-bit version of Ruby 2.7.0): From 9239855accc394bbf270ee1050e577d45fd60a98 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 4 Mar 2021 11:35:06 -0800 Subject: [PATCH 015/363] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c859bb7..69a689b 100644 --- a/README.md +++ b/README.md @@ -283,8 +283,10 @@ When using the Ruby launcher on a Windows machine you may get the following erro This error occurs because you’re attempting to use the Ruby launcher with a self-signed certificate or without SSL/HTTP security. The API calls from Ruby SDKs are using a built-in Curl tool that is enforcing the SSL requirement. You can disable this security check to run the launcher in an insecure manner on your developer machine. ```diff -- It is highly recommended that you don’t disable this security check in a production environment or in your integration. -- This method is offered here solely as a means to enable you to develop quickly by lowering the security bar on your local machine. +- It is highly recommended that you don’t disable this security check +- in a production environment or in your integration. +- This method is offered here solely as a means to enable you to +- develop quickly by lowering the security bar on your local machine. ``` Find the root folder for your Ruby gems (in this case, a 64-bit version of Ruby 2.7.0): From e24e5847fbcddf42ea1d60a4a9eaf333f958bc44 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 4 Mar 2021 11:52:50 -0800 Subject: [PATCH 016/363] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 69a689b..09246a7 100644 --- a/README.md +++ b/README.md @@ -283,7 +283,7 @@ When using the Ruby launcher on a Windows machine you may get the following erro This error occurs because you’re attempting to use the Ruby launcher with a self-signed certificate or without SSL/HTTP security. The API calls from Ruby SDKs are using a built-in Curl tool that is enforcing the SSL requirement. You can disable this security check to run the launcher in an insecure manner on your developer machine. ```diff -- It is highly recommended that you don’t disable this security check +It is highly recommended that you don’t disable this security check - in a production environment or in your integration. - This method is offered here solely as a means to enable you to - develop quickly by lowering the security bar on your local machine. @@ -297,7 +297,7 @@ Find the relevant DocuSign Ruby SDK you are using. The name always starts with C:\Ruby27-x64\lib\ruby\gems\2.7.0\gems\docusign_click-1.0.0\lib\docusign_click Find the **configuration.rb** file in that folder. -Modify the following two lines in the **configuration.rb** file, replacing “true” with “false”: +Modify the following two lines in the **configuration.rb** file, replacing `“true”` with `“false”`: @verify_ssl = true @verify_ssl_host = true From 8bb8d561e163477b59b20a5399608e62154e3503 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 4 Mar 2021 11:53:39 -0800 Subject: [PATCH 017/363] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 09246a7..3385e56 100644 --- a/README.md +++ b/README.md @@ -283,7 +283,7 @@ When using the Ruby launcher on a Windows machine you may get the following erro This error occurs because you’re attempting to use the Ruby launcher with a self-signed certificate or without SSL/HTTP security. The API calls from Ruby SDKs are using a built-in Curl tool that is enforcing the SSL requirement. You can disable this security check to run the launcher in an insecure manner on your developer machine. ```diff -It is highly recommended that you don’t disable this security check +- It is highly recommended that you don’t disable this security check - in a production environment or in your integration. - This method is offered here solely as a means to enable you to - develop quickly by lowering the security bar on your local machine. From ae393ddc30e871814847d5136c861b4b7a5a6e45 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 4 Mar 2021 11:55:01 -0800 Subject: [PATCH 018/363] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3385e56..3ce2384 100644 --- a/README.md +++ b/README.md @@ -297,7 +297,7 @@ Find the relevant DocuSign Ruby SDK you are using. The name always starts with C:\Ruby27-x64\lib\ruby\gems\2.7.0\gems\docusign_click-1.0.0\lib\docusign_click Find the **configuration.rb** file in that folder. -Modify the following two lines in the **configuration.rb** file, replacing `“true”` with `“false”`: +Modify the following two lines in the **configuration.rb** file, replacing `true` with `false`: @verify_ssl = true @verify_ssl_host = true From 8f480673c4cc172f4cb8854f10a5a02c59bb3eb2 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 4 Mar 2021 14:23:25 -0800 Subject: [PATCH 019/363] Updating README.md --- README.md | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ad77d74..3ce2384 100644 --- a/README.md +++ b/README.md @@ -275,8 +275,38 @@ When the token expires, it updates automatically. From there you should be able to run the launcher using `bundle exec rails server` then selecting **JSON Web Token** when authenticaing your account. +### Troubleshooting Windows SSL issue +When using the Ruby launcher on a Windows machine you may get the following error: -#### Payments code example +**SSL peer certificate or SSH remote key was not OK** + +This error occurs because you’re attempting to use the Ruby launcher with a self-signed certificate or without SSL/HTTP security. The API calls from Ruby SDKs are using a built-in Curl tool that is enforcing the SSL requirement. You can disable this security check to run the launcher in an insecure manner on your developer machine. + +```diff +- It is highly recommended that you don’t disable this security check +- in a production environment or in your integration. +- This method is offered here solely as a means to enable you to +- develop quickly by lowering the security bar on your local machine. +``` +Find the root folder for your Ruby gems (in this case, a 64-bit version of Ruby 2.7.0): + +C:\Ruby27-x64\lib\ruby\gems\2.7.0\gems\ + +Find the relevant DocuSign Ruby SDK you are using. The name always starts with “docusign”; for instance, DocuSign Click SDK version 1.0.0: + +C:\Ruby27-x64\lib\ruby\gems\2.7.0\gems\docusign_click-1.0.0\lib\docusign_click + +Find the **configuration.rb** file in that folder. +Modify the following two lines in the **configuration.rb** file, replacing `true` with `false`: + + @verify_ssl = true + @verify_ssl_host = true + + +Once this is complete, you can run your Ruby on Rails application again and you should be able to make API calls on your localhost. + + +### Payments code example To use the payments example, create a test payments gateway for your developer sandbox account. @@ -286,7 +316,7 @@ file for instructions. Then add the payment gateway account id to the **config/application.rb** file. -## Using the examples with other authentication flows +### Using the examples with other authentication flows The examples in this repository can also be used with the Implicit grant OAuth flow. From 47f0a20a456b68478a500f49e2ca4e303772e706 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Tue, 30 Mar 2021 11:16:29 -0700 Subject: [PATCH 020/363] bundle install, Ruby 2.7.2 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3ce2384..4092901 100644 --- a/README.md +++ b/README.md @@ -229,7 +229,7 @@ When the token expires, it updates automatically. `http://localhost:3000/auth/docusign/callback` -1. Ruby version 2.7.1 or later. Or you can update the Gemfile to use other versions of Ruby. +1. Ruby version 2.7.2 or later. Or you can update the Gemfile to use other versions of Ruby. 1. A name and email for a signer, and a name and email for a cc recipient. ### Installation steps @@ -239,7 +239,7 @@ When the token expires, it updates automatically. 1. **cd code-examples-ruby** 1. Install the needed gems listed in the Gemfile: - Run **bundler install** + Run **bundle install** 1. Copy the file **config/appsettings.example.yml** into a new file named **config/appsettings.yml** 1. Update the file **config/appsettings.yml** with the Integration Key and other settings. Note: The terms "client_id" and "Integration key" are synonyms. They refer to the same thing. From ddcce26f551dd9b08ca5c8d9b189bad7275f60d3 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Fri, 9 Apr 2021 10:29:45 -0700 Subject: [PATCH 021/363] Update PAYMENTS_INSTALLATION.md --- PAYMENTS_INSTALLATION.md | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/PAYMENTS_INSTALLATION.md b/PAYMENTS_INSTALLATION.md index bfd85dc..d575c2c 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 Developer 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) From f284dddce50b8ef0b200e13351029a5cb48c729c Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Fri, 9 Apr 2021 10:30:19 -0700 Subject: [PATCH 022/363] Update PAYMENTS_INSTALLATION.md --- PAYMENTS_INSTALLATION.md | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/PAYMENTS_INSTALLATION.md b/PAYMENTS_INSTALLATION.md index bfd85dc..d575c2c 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 Developer 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) From 049f83a747341936513dbe4b169da102d25feab4 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 15:48:12 -0700 Subject: [PATCH 023/363] Update README.md --- README.md | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 3ce2384..bbeca5f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Ruby Launcher Code Examples -### Github repo: code-examples-ruby +### Github repo: https://github.com/docusign/code-examples-ruby + This GitHub repo includes code examples for DocuSign APIs. @@ -8,11 +9,13 @@ To switch between API code examples, modify the `examples_API` setting at the en If none of the API types are set to true, the DocuSign eSignature REST API code examples will be shown. If multiple API types are set to true, only the first will be shown. -**Note:** to use the Rooms API you must also [create your DocuSign Developer Account for Rooms](https://developers.docusign.com/docs/rooms-api/rooms101/create-account). +**Note:** To use the Rooms API you must also [create your Rooms developer account](https://developers.docusign.com/docs/rooms-api/rooms101/create-account). + ## Introduction This repo is a Ruby on Rails application that demonstrates: + ## eSignature API For more information about the scopes used for obtaining authorization to use the eSignature API, see the [Required Scopes section](https://developers.docusign.com/docs/esign-rest-api/esign101/auth). @@ -144,6 +147,7 @@ For more information about the scopes used for obtaining authorization to use th [Source.](app/services/e_sign/eg035_sms_delivery_service.rb) This code example demonstrates how to send a signature request via an SMS message using the [Envelopes: create](https://developers.docusign.com/esign-rest-api/reference/Envelopes/Envelopes/create) method. + ## Rooms API For more information about the scopes used for obtaining authorization to use the Rooms API, see the [Required Scopes section](https://developers.docusign.com/docs/rooms-api/rooms101/auth/). @@ -176,6 +180,7 @@ For more information about the scopes used for obtaining authorization to use th [Source.](./app/services/room_api/eg009_assign_form_to_form_group_service.rb) This example assigns a form to a form group for your DocuSign Rooms. + ## Click API For more information about the scopes used for obtaining authorization to use the Clickwrap API, see the [Required Scopes section](https://developers.docusign.com/docs/click-api/click101/auth). @@ -196,20 +201,18 @@ This example demonstrates how to use the Click API to get a list of clickwraps a [Source.](./app/services/clickwrap/eg005_clickwrap_responses_service.rb) This example demonstrates how to use the Click API to get a list of clickwraps associated with a specific DocuSign user. -## 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. +## Included OAuth grant types + +* Authentication with Docusign via [Authorization Code Grant](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](https://developers.docusign.com/platform/auth/authcode/authcode-get-token#using-refresh-tokens) 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). -When the token expires, it updates automatically. +* Authentication with DocuSign via [JSON Web Token (JWT) Grant](https://developers.docusign.com/esign-rest-api/guides/authentication/oauth2-jsonwebtoken). When the token expires, it updates automatically. ## Installation ### Prerequisites -**Note: If you downloaded this code using Quickstart from the DocuSign Developer Center, skip steps 1 and 2 below as they're automatically performed for you.** +**Note:** If you downloaded this code using Quickstart from the DocuSign Developer Center, skip items 1 and 2 below as they were automatically performed for you. 1. A DocuSign Developer account (email and password) on [demo.docusign.net](https://demo.docusign.net). Create a [free account](https://go.docusign.com/sandbox/productshot/?elqCampaignId=16536). @@ -232,6 +235,7 @@ When the token expires, it updates automatically. 1. Ruby version 2.7.1 or later. Or you can update the Gemfile to use other versions of Ruby. 1. A name and email for a signer, and a name and email for a cc recipient. + ### Installation steps **Note: If you downloaded this code using Quickstart from the DocuSign Developer Center, skip steps 4, 5, and 6 below as they're automatically performed for you.** @@ -247,6 +251,7 @@ When the token expires, it updates automatically. 1. Update your Integration Key's settings to include a **Redirect URI** for your installation of the example. See Prerequisites item #2, above for more information. + #### Run the application 1. To start the development web server and application: @@ -259,6 +264,7 @@ When the token expires, it updates automatically. - *Place libcurl.dll into Ruby `C:\\\bin`* 1. Open a browser to the example's base url to view the index page. + ### Configuring JWT **Note:** Before you can make any API calls using JWT Grant, you must get your user’s consent for your app to impersonate them. To do this, the `impersonation` scope is added when requesting a JSON Web Token. @@ -275,6 +281,7 @@ When the token expires, it updates automatically. From there you should be able to run the launcher using `bundle exec rails server` then selecting **JSON Web Token** when authenticaing your account. + ### Troubleshooting Windows SSL issue When using the Ruby launcher on a Windows machine you may get the following error: @@ -306,7 +313,7 @@ Modify the following two lines in the **configuration.rb** file, replacing `true Once this is complete, you can run your Ruby on Rails application again and you should be able to make API calls on your localhost. -### Payments code example +## Payments code example To use the payments example, create a test payments gateway for your developer sandbox account. @@ -316,6 +323,7 @@ file for instructions. Then add the payment gateway account id to the **config/application.rb** file. + ### Using the examples with other authentication flows The examples in this repository can also be used with the @@ -323,17 +331,14 @@ Implicit grant 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. + ## License and additional information + ### License This repository uses the MIT License. See the LICENSE file for more information. + ### Pull Requests Pull requests are welcomed. Pull requests will only be considered if their content uses the MIT License. - -### Additional Resources -* [DocuSign Developer Center](https://developers.docusign.com) -* [DocuSign API on Twitter](https://twitter.com/docusignapi) -* [DocuSign For Developers on LinkedIn](https://www.linkedin.com/showcase/docusign-for-developers/) -* [DocuSign For Developers on YouTube](https://www.youtube.com/channel/UCJSJ2kMs_qeQotmw4-lX2NQ) From 914070368e434bb2cb0d3b4a7924e9a12dc695c0 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 15:56:48 -0700 Subject: [PATCH 024/363] Update README.md --- README.md | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index bbeca5f..53ec758 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ If none of the API types are set to true, the DocuSign eSignature REST API code ## Introduction -This repo is a Ruby on Rails application that demonstrates: +This repo is a Ruby on Rails application. ## eSignature API @@ -214,26 +214,34 @@ This example demonstrates how to use the Click API to get a list of clickwraps a ### Prerequisites **Note:** If you downloaded this code using Quickstart from the DocuSign Developer Center, skip items 1 and 2 below as they were automatically performed for you. -1. A DocuSign Developer account (email and password) on [demo.docusign.net](https://demo.docusign.net). - Create a [free account](https://go.docusign.com/sandbox/productshot/?elqCampaignId=16536). -1. A DocuSign Integration Key and secret key (a client ID). 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. - - You will need the **Integration Key** itself, and its **secret**. +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 for authentication to use either [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) or [JWT Grant](https://developers.docusign.com/platform/auth/jwt/). - The Integration key must include a **Redirect URI** of + This [video](https://www.youtube.com/watch?v=eiRI4fe5HgM) demonstrates how to obtain an integration key. - `{base_url}/auth/docusign/callback` + 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. - Where `{base_url}` is the url for the web app. + To use [JWT Grant](https://developers.docusign.com/platform/auth/jwt/), you will need an integration key, an RSA key pair, and the API Username GUID of the impersonated user. See [Installation steps for JWT Grant authentication](#installation-steps-for-jwt-grant-authentication) for details. - By default, the rails app starts on url `http://localhost:3000` + For both authentication flows: - So the default Redirect URI for your Integration Key is + If you use this launcher on your own workstation, the integration key must include a redirect URI of - `http://localhost:3000/auth/docusign/callback` + http://localhost:3000/auth/docusign/callback -1. Ruby version 2.7.1 or later. Or you can update the Gemfile to use other versions of Ruby. -1. A name and email for a signer, and a name and email for a cc recipient. + If you host this launcher on a remote web server, set your redirect URI as + + {base_url}/auth/docusign/callback + + where {base_url} is the URL for the web app. + +1. [Ruby version 2.7.2](https://www.ruby-lang.org/en/downloads/) or later. + 1. Update the Gemfile to use later versions of Ruby. + 1. Windows x64 only: + 1. Ensure that your Ruby folder is appended with -x64, e.g. Ruby27-x64. + 2. Install Curl for Ruby: Download libcurl.dll + Save libcurl-x64.dll as libcurl.dll + Place libcurl.dll in your Ruby folder: C:\-x64\bin ### Installation steps From 3ad307c7570067117e5793b4b94579c44a84d321 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 15:58:06 -0700 Subject: [PATCH 025/363] add line breaks --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 53ec758..17693e5 100644 --- a/README.md +++ b/README.md @@ -239,9 +239,9 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. Update the Gemfile to use later versions of Ruby. 1. Windows x64 only: 1. Ensure that your Ruby folder is appended with -x64, e.g. Ruby27-x64. - 2. Install Curl for Ruby: Download libcurl.dll - Save libcurl-x64.dll as libcurl.dll - Place libcurl.dll in your Ruby folder: C:\-x64\bin + 2. Install Curl for Ruby: Download libcurl.dll + Save libcurl-x64.dll as libcurl.dll + Place libcurl.dll in your Ruby folder: C:\-x64\bin ### Installation steps From 09a3513a09d666f5b31aa903ef634940acf65b19 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 16:24:07 -0700 Subject: [PATCH 026/363] Update README.md --- README.md | 109 +++++++++++++++++++++++------------------------------- 1 file changed, 46 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 17693e5..e992b43 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ To switch between API code examples, modify the `examples_API` setting at the en If none of the API types are set to true, the DocuSign eSignature REST API code examples will be shown. If multiple API types are set to true, only the first will be shown. -**Note:** To use the Rooms API you must also [create your Rooms developer account](https://developers.docusign.com/docs/rooms-api/rooms101/create-account). +**Note:** Before you can make any API calls using JWT Grant, you must get your user’s consent for your app to impersonate them. To do this, the `impersonation` scope is added when requesting a JSON Web Token. ## Introduction @@ -150,6 +150,8 @@ For more information about the scopes used for obtaining authorization to use th ## Rooms API +**Note:** To use the Rooms API you must also [create your Rooms developer account](https://developers.docusign.com/docs/rooms-api/rooms101/create-account). + For more information about the scopes used for obtaining authorization to use the Rooms API, see the [Required Scopes section](https://developers.docusign.com/docs/rooms-api/rooms101/auth/). 1. **Create a room with data.** @@ -212,7 +214,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a ## Installation ### Prerequisites -**Note:** If you downloaded this code using Quickstart from the DocuSign Developer Center, skip items 1 and 2 below as they were automatically performed for you. +**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 below 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 for authentication to use either [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) or [JWT Grant](https://developers.docusign.com/platform/auth/jwt/). @@ -239,55 +241,50 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. Update the Gemfile to use later versions of Ruby. 1. Windows x64 only: 1. Ensure that your Ruby folder is appended with -x64, e.g. Ruby27-x64. - 2. Install Curl for Ruby: Download libcurl.dll + 2. Install Curl for Ruby: [Download libcurl.dll](https://curl.haxx.se/windows/) Save libcurl-x64.dll as libcurl.dll Place libcurl.dll in your Ruby folder: C:\-x64\bin ### Installation steps -**Note: If you downloaded this code using Quickstart from the DocuSign Developer Center, skip steps 4, 5, and 6 below as they're automatically performed for you.** - -1. Download or clone this repository to your workstation to directory **code-examples-ruby** -1. **cd code-examples-ruby** -1. Install the needed gems listed in the Gemfile: - - Run **bundler install** -1. Copy the file **config/appsettings.example.yml** into a new file named **config/appsettings.yml** -1. Update the file **config/appsettings.yml** with the Integration Key and other settings. - Note: The terms "client_id" and "Integration key" are synonyms. They refer to the same thing. - -1. Update your Integration Key's settings to include a **Redirect URI** for - your installation of the example. See Prerequisites item #2, above for more information. - - -#### Run the application -1. To start the development web server and application: - - Run **rails s** - - *Note that on Windows additional actions might be necessary:* - - *Install sqlite3: **gem install sqlite3 --platform=ruby*** - - *Download curllib.dll (https://curl.haxx.se/windows/)* - - *libcurl-x64.dll should be copied as libcurl.dll* - - *Place libcurl.dll into Ruby `C:\\\bin`* -1. Open a browser to the example's base url to view the index page. - - -### Configuring JWT - -**Note:** Before you can make any API calls using JWT Grant, you must get your user’s consent for your app to impersonate them. To do this, the `impersonation` scope is added when requesting a JSON Web Token. - -1. Create a developer sandbox account on developers.docusign.com if you don't already have one. -2. Create a new API key in the Admin panel: https://admindemo.docusign.com/api-integrator-key - - Take note of the _Integration Key_. - - Generate a _RSA Keypair_ and copy the private key to a secure location. - - Set a _Redirect URI_ of `http://localhost:3000/auth/docusign/callback` as mentioned in the installation steps above. -3. Create a new file in the config folder named **docusign_private_key.txt**, and paste in that copied RSA private key, then save it. -4. Update the file **config/appsettings.yml** and include the settings from step 2. - -[Obtaining consent](https://developers.docusign.com/esign-rest-api/guides/authentication/obtaining-consent#individual-consent) does not need to be configured, as it is already being done in the code at [JwtAuth::JwtCreator#update_token](./app/services/jwt_auth/jwt_creator.rb#L35) - -From there you should be able to run the launcher using `bundle exec rails server` then selecting **JSON Web Token** when authenticaing your account. +**Note:** If you downloaded this code using [Quickstart](https://developers.docusign.com/docs/esign-rest-api/quickstart/) from the DocuSign Developer Center, skip steps 4 as it was automatically performed for you. + +1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. +1. In your command-line environment, switch the the folder: + `cd ` or `cd code-examples-ruby` +1. Install the dependencies: `bundle install` +1. To configure the launcher for [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. + 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 appsettings.yml as your `integration_key`. + 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 appsettings.yml as your `integration_secret`. + 1. Add the launcher’s redirect URI. Under **Additional settings**, select **+ ADD URI**, and set a redirect URI of http://localhost:3000/auth/docusign/callback. Select **SAVE**. + 1. Set a name and email address for the signer. In appsettings.yml, save an email address as `signer_email` and a name as `signer_name`. +**Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. +1. Run the launcher: `rails s` +1. Open a browser to http://localhost:3000/auth/docusign + + +### 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 config/appsettings.yml, change `quickstart` to `false`. + +1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. +1. In your command-line environment, switch the the folder: + `cd ` or `cd code-examples-ruby` +1. Install the dependencies: `bundle install` +1. To configure the launcher for [JWT Grant](https://developers.docusign.com/platform/auth/jwt/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. + 1. Add your API Username. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **My Account Information**, copy the **API Username** GUID and save it in appsettings.yml as your `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 appsettings.yml as your `jwt_integration_key`. + 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 config/docusign_private_key.txt. + 1. Add the launcher’s redirect URI. Under **Additional settings**, select **+ ADD URI**, and set a redirect URI of http://localhost:3000/auth/docusign/callback. Select **SAVE**. + 1. Set a name and email address for the signer. In appsettings.yml, save an email address as `signer_email` and a name as `signer_name`. +**Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. +1. Run the launcher: `rails s` +1. Open a browser to http://localhost:3000/auth/docusign +**Note:** This step is currently broken in Windows. We will remove this note when it has been fixed. + +1. If it is your first time using the app, grant consent by selecting **Accept**. On the black navigation bar, select **Logout**, then **Login**. +1. From the picklist, select **JSON Web Token (JWT) grant** > **Authenticate with DocuSign**. +1. Select your desired code example. ### Troubleshooting Windows SSL issue @@ -322,29 +319,15 @@ Once this is complete, you can run your Ruby on Rails application again and you ## Payments code example -To use the payments example, create a -test payments gateway for your developer sandbox account. +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. -See the -[PAYMENTS_INSTALLATION.md](./PAYMENTS_INSTALLATION.md) -file for instructions. - -Then add the payment gateway account id to the **config/application.rb** file. - - -### Using the examples with other authentication flows - -The examples in this repository can also be used with the -Implicit grant 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. +Once you've created a payment gateway, save the **Gateway Account ID** GUID to appsettings.yml. ## License and additional information - ### License -This repository uses the MIT License. See the LICENSE file for more information. +This repository uses the MIT License. See [LICENSE](./LICENSE) for details. ### Pull Requests From feb192885dd1b8d48337ec6071923e3392ceeacf Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 16:26:16 -0700 Subject: [PATCH 027/363] edit Rooms line --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e992b43..db6ff22 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ For more information about the scopes used for obtaining authorization to use th ## Rooms API -**Note:** To use the Rooms API you must also [create your Rooms developer account](https://developers.docusign.com/docs/rooms-api/rooms101/create-account). +**Note:** To use the Rooms API, you must also [create a Rooms developer account](https://developers.docusign.com/docs/rooms-api/rooms101/create-account). For more information about the scopes used for obtaining authorization to use the Rooms API, see the [Required Scopes section](https://developers.docusign.com/docs/rooms-api/rooms101/auth/). From abc125e26dbfe2180f8ab0989c44a013601d6bb4 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 16:27:59 -0700 Subject: [PATCH 028/363] deleted a section --- README.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/README.md b/README.md index db6ff22..53cd486 100644 --- a/README.md +++ b/README.md @@ -204,13 +204,6 @@ This example demonstrates how to use the Click API to get a list of clickwraps a This example demonstrates how to use the Click API to get a list of clickwraps associated with a specific DocuSign user. -## Included OAuth grant types - -* Authentication with Docusign via [Authorization Code Grant](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](https://developers.docusign.com/platform/auth/authcode/authcode-get-token#using-refresh-tokens) is not used in this example. - -* Authentication with DocuSign via [JSON Web Token (JWT) Grant](https://developers.docusign.com/esign-rest-api/guides/authentication/oauth2-jsonwebtoken). When the token expires, it updates automatically. - - ## Installation ### Prerequisites From 3ff507fc670359c4aa139da1d09c36cb6a22b920 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 16:31:44 -0700 Subject: [PATCH 029/363] bold UI items --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 53cd486..d03f8ef 100644 --- a/README.md +++ b/README.md @@ -233,10 +233,10 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. [Ruby version 2.7.2](https://www.ruby-lang.org/en/downloads/) or later. 1. Update the Gemfile to use later versions of Ruby. 1. Windows x64 only: - 1. Ensure that your Ruby folder is appended with -x64, e.g. Ruby27-x64. + 1. Ensure that your Ruby folder is appended with -x64, e.g. **Ruby27-x64**. 2. Install Curl for Ruby: [Download libcurl.dll](https://curl.haxx.se/windows/) - Save libcurl-x64.dll as libcurl.dll - Place libcurl.dll in your Ruby folder: C:\-x64\bin + Save **libcurl-x64.dll** as **libcurl.dll** + Place **libcurl.dll** in your Ruby folder: **C:\-x64\bin** ### Installation steps From 6f4a414337dc4c4ebfd2c292afc6a97f10b856c2 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 16:32:30 -0700 Subject: [PATCH 030/363] add line breaks --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d03f8ef..7aefc3b 100644 --- a/README.md +++ b/README.md @@ -234,9 +234,9 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. Update the Gemfile to use later versions of Ruby. 1. Windows x64 only: 1. Ensure that your Ruby folder is appended with -x64, e.g. **Ruby27-x64**. - 2. Install Curl for Ruby: [Download libcurl.dll](https://curl.haxx.se/windows/) - Save **libcurl-x64.dll** as **libcurl.dll** - Place **libcurl.dll** in your Ruby folder: **C:\-x64\bin** + 2. Install Curl for Ruby: [Download libcurl.dll](https://curl.haxx.se/windows/) + Save **libcurl-x64.dll** as **libcurl.dll** + Place **libcurl.dll** in your Ruby folder: **C:\-x64\bin** ### Installation steps From d7bf3efe4a3ef1ce6c76a0844e56c9c58943b5be Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 16:33:43 -0700 Subject: [PATCH 031/363] remove period --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7aefc3b..ae57ec4 100644 --- a/README.md +++ b/README.md @@ -233,7 +233,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. [Ruby version 2.7.2](https://www.ruby-lang.org/en/downloads/) or later. 1. Update the Gemfile to use later versions of Ruby. 1. Windows x64 only: - 1. Ensure that your Ruby folder is appended with -x64, e.g. **Ruby27-x64**. + 1. Ensure that your Ruby folder is appended with -x64, e.g. **Ruby27-x64** 2. Install Curl for Ruby: [Download libcurl.dll](https://curl.haxx.se/windows/) Save **libcurl-x64.dll** as **libcurl.dll** Place **libcurl.dll** in your Ruby folder: **C:\-x64\bin** From 0fd6822992ed346f77d26e4d213bba8a6cdcb53b Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 16:34:41 -0700 Subject: [PATCH 032/363] remove line break --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ae57ec4..6f5773e 100644 --- a/README.md +++ b/README.md @@ -230,7 +230,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a where {base_url} is the URL for the web app. -1. [Ruby version 2.7.2](https://www.ruby-lang.org/en/downloads/) or later. +1. [Ruby version 2.7.2](https://www.ruby-lang.org/en/downloads/) or later 1. Update the Gemfile to use later versions of Ruby. 1. Windows x64 only: 1. Ensure that your Ruby folder is appended with -x64, e.g. **Ruby27-x64** From a2142d8a371ac20d7d8c4c2b8bfa5428dd007f18 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 16:36:49 -0700 Subject: [PATCH 033/363] sample Ruby folder --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6f5773e..935d45a 100644 --- a/README.md +++ b/README.md @@ -236,7 +236,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. Ensure that your Ruby folder is appended with -x64, e.g. **Ruby27-x64** 2. Install Curl for Ruby: [Download libcurl.dll](https://curl.haxx.se/windows/) Save **libcurl-x64.dll** as **libcurl.dll** - Place **libcurl.dll** in your Ruby folder: **C:\-x64\bin** + Place **libcurl.dll** in your Ruby folder, e.g. **Ruby27-x64** ### Installation steps From 880a4a762fd50c1b7e0a985fc8f9e0cbd17d3d1a Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 16:39:06 -0700 Subject: [PATCH 034/363] add backslash --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 935d45a..c7ca59e 100644 --- a/README.md +++ b/README.md @@ -236,7 +236,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. Ensure that your Ruby folder is appended with -x64, e.g. **Ruby27-x64** 2. Install Curl for Ruby: [Download libcurl.dll](https://curl.haxx.se/windows/) Save **libcurl-x64.dll** as **libcurl.dll** - Place **libcurl.dll** in your Ruby folder, e.g. **Ruby27-x64** + Place **libcurl.dll** in your Ruby folder, e.g. **C:"\Ruby27-x64** ### Installation steps From 57269ff086aaa079f8891716988e5065542d7d66 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 16:40:07 -0700 Subject: [PATCH 035/363] add bin --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c7ca59e..12950ac 100644 --- a/README.md +++ b/README.md @@ -236,7 +236,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. Ensure that your Ruby folder is appended with -x64, e.g. **Ruby27-x64** 2. Install Curl for Ruby: [Download libcurl.dll](https://curl.haxx.se/windows/) Save **libcurl-x64.dll** as **libcurl.dll** - Place **libcurl.dll** in your Ruby folder, e.g. **C:"\Ruby27-x64** + Place **libcurl.dll** in your Ruby folder, e.g. **C:\Ruby27-x64\bin** ### Installation steps From 29086f15358aaccf52ef63e208ba22cc001c040a Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 16:41:22 -0700 Subject: [PATCH 036/363] step --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 12950ac..7d761f8 100644 --- a/README.md +++ b/README.md @@ -240,7 +240,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a ### 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 steps 4 as it was automatically performed for you. +**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-ruby repository. 1. In your command-line environment, switch the the folder: From f6e479abadb0247df99c39df53c5757dc1350b6e Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 16:43:06 -0700 Subject: [PATCH 037/363] to --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7d761f8..e82d232 100644 --- a/README.md +++ b/README.md @@ -243,7 +243,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a **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-ruby repository. -1. In your command-line environment, switch the the folder: +1. In your command-line environment, switch to the folder: `cd ` or `cd code-examples-ruby` 1. Install the dependencies: `bundle install` 1. To configure the launcher for [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. @@ -261,7 +261,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a Also, in order to select JSON Web Token authentication in the launcher, in config/appsettings.yml, change `quickstart` to `false`. 1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. -1. In your command-line environment, switch the the folder: +1. In your command-line environment, switch to the folder: `cd ` or `cd code-examples-ruby` 1. Install the dependencies: `bundle install` 1. To configure the launcher for [JWT Grant](https://developers.docusign.com/platform/auth/jwt/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. From d096689608d0a75fcde42ca4e41e3f06ee567af8 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 16:56:35 -0700 Subject: [PATCH 038/363] small updates --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e82d232..53f80fb 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,11 @@ This GitHub repo includes code examples for DocuSign APIs. -To switch between API code examples, modify the `examples_API` setting at the end of the configuration file. Set only one API type to true and set the remaining to false. +To switch between API code examples, modify the `examples_API` setting at the end of the configuration file. Set only one API type to `true` and set the remaining to `false`. -If none of the API types are set to true, the DocuSign eSignature REST API code examples will be shown. If multiple API types are set to true, only the first will be shown. +If none of the API types are set to `true`, the DocuSign eSignature REST API code examples will be shown. If multiple API types are set to `true`, only the first will be shown. -**Note:** Before you can make any API calls using JWT Grant, you must get your user’s consent for your app to impersonate them. To do this, the `impersonation` scope is added when requesting a JSON Web Token. +Before you can make any API calls using JWT Grant, you must get your user’s consent for your app to impersonate them. To do this, the `impersonation` scope is added when requesting a JSON Web Token. ## Introduction From 339fa3f181bff25e566651054e7af27814018827 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 16:58:02 -0700 Subject: [PATCH 039/363] added JWT link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 53f80fb..698aaa2 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ To switch between API code examples, modify the `examples_API` setting at the en If none of the API types are set to `true`, the DocuSign eSignature REST API code examples will be shown. If multiple API types are set to `true`, only the first will be shown. -Before you can make any API calls using JWT Grant, you must get your user’s consent for your app to impersonate them. To do this, the `impersonation` scope is added when requesting a JSON Web Token. +Before you can make any API calls using [JWT Grant](https://developers.docusign.com/platform/auth/jwt/), you must get your user’s consent for your app to impersonate them. To do this, the `impersonation` scope is added when requesting a JSON Web Token. ## Introduction From 46ff4068e7d509dc4ae453dfa3a6ce0fca483fe6 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 16:59:05 -0700 Subject: [PATCH 040/363] remove line break --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 698aaa2..9cc9ab3 100644 --- a/README.md +++ b/README.md @@ -150,8 +150,7 @@ For more information about the scopes used for obtaining authorization to use th ## Rooms API -**Note:** To use the Rooms API, you must also [create a Rooms developer account](https://developers.docusign.com/docs/rooms-api/rooms101/create-account). - +**Note:** To use the Rooms API, you must also [create a Rooms developer account](https://developers.docusign.com/docs/rooms-api/rooms101/create-account). For more information about the scopes used for obtaining authorization to use the Rooms API, see the [Required Scopes section](https://developers.docusign.com/docs/rooms-api/rooms101/auth/). 1. **Create a room with data.** From a42956a42dd2d86823487d4ff6788b82e1964713 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 17:05:46 -0700 Subject: [PATCH 041/363] synced with private --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4092901..3ce2384 100644 --- a/README.md +++ b/README.md @@ -229,7 +229,7 @@ When the token expires, it updates automatically. `http://localhost:3000/auth/docusign/callback` -1. Ruby version 2.7.2 or later. Or you can update the Gemfile to use other versions of Ruby. +1. Ruby version 2.7.1 or later. Or you can update the Gemfile to use other versions of Ruby. 1. A name and email for a signer, and a name and email for a cc recipient. ### Installation steps @@ -239,7 +239,7 @@ When the token expires, it updates automatically. 1. **cd code-examples-ruby** 1. Install the needed gems listed in the Gemfile: - Run **bundle install** + Run **bundler install** 1. Copy the file **config/appsettings.example.yml** into a new file named **config/appsettings.yml** 1. Update the file **config/appsettings.yml** with the Integration Key and other settings. Note: The terms "client_id" and "Integration key" are synonyms. They refer to the same thing. From 55d22d57e2448d50ed38e0e3e4adcdf520aca5be Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 17:07:55 -0700 Subject: [PATCH 042/363] synced with private --- README.md | 166 +++++++++++++++++++++++++----------------------------- 1 file changed, 77 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index 3ce2384..9cc9ab3 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,20 @@ # Ruby Launcher Code Examples -### Github repo: code-examples-ruby +### Github repo: https://github.com/docusign/code-examples-ruby + This GitHub repo includes code examples for DocuSign APIs. -To switch between API code examples, modify the `examples_API` setting at the end of the configuration file. Set only one API type to true and set the remaining to false. +To switch between API code examples, modify the `examples_API` setting at the end of the configuration file. Set only one API type to `true` and set the remaining to `false`. + +If none of the API types are set to `true`, the DocuSign eSignature REST API code examples will be shown. If multiple API types are set to `true`, only the first will be shown. -If none of the API types are set to true, the DocuSign eSignature REST API code examples will be shown. If multiple API types are set to true, only the first will be shown. +Before you can make any API calls using [JWT Grant](https://developers.docusign.com/platform/auth/jwt/), you must get your user’s consent for your app to impersonate them. To do this, the `impersonation` scope is added when requesting a JSON Web Token. -**Note:** to use the Rooms API you must also [create your DocuSign Developer Account for Rooms](https://developers.docusign.com/docs/rooms-api/rooms101/create-account). ## Introduction -This repo is a Ruby on Rails application that demonstrates: +This repo is a Ruby on Rails application. + ## eSignature API @@ -144,8 +147,10 @@ For more information about the scopes used for obtaining authorization to use th [Source.](app/services/e_sign/eg035_sms_delivery_service.rb) This code example demonstrates how to send a signature request via an SMS message using the [Envelopes: create](https://developers.docusign.com/esign-rest-api/reference/Envelopes/Envelopes/create) method. + ## Rooms API +**Note:** To use the Rooms API, you must also [create a Rooms developer account](https://developers.docusign.com/docs/rooms-api/rooms101/create-account). For more information about the scopes used for obtaining authorization to use the Rooms API, see the [Required Scopes section](https://developers.docusign.com/docs/rooms-api/rooms101/auth/). 1. **Create a room with data.** @@ -176,6 +181,7 @@ For more information about the scopes used for obtaining authorization to use th [Source.](./app/services/room_api/eg009_assign_form_to_form_group_service.rb) This example assigns a form to a form group for your DocuSign Rooms. + ## Click API For more information about the scopes used for obtaining authorization to use the Clickwrap API, see the [Required Scopes section](https://developers.docusign.com/docs/click-api/click101/auth). @@ -196,84 +202,82 @@ This example demonstrates how to use the Click API to get a list of clickwraps a [Source.](./app/services/clickwrap/eg005_clickwrap_responses_service.rb) This example demonstrates how to use the Click API to get a list of clickwraps associated with a specific DocuSign user. -## 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). -When the token expires, it updates automatically. - ## Installation ### Prerequisites -**Note: If you downloaded this code using Quickstart from the DocuSign Developer Center, skip steps 1 and 2 below as they're automatically performed for you.** +**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 below as they were automatically performed for you. -1. A DocuSign Developer account (email and password) on [demo.docusign.net](https://demo.docusign.net). - Create a [free account](https://go.docusign.com/sandbox/productshot/?elqCampaignId=16536). -1. A DocuSign Integration Key and secret key (a client ID). 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. - - You will need the **Integration Key** itself, and its **secret**. +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 for authentication to use either [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) or [JWT Grant](https://developers.docusign.com/platform/auth/jwt/). - The Integration key must include a **Redirect URI** of + This [video](https://www.youtube.com/watch?v=eiRI4fe5HgM) demonstrates how to obtain an integration key. - `{base_url}/auth/docusign/callback` + 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. - Where `{base_url}` is the url for the web app. + To use [JWT Grant](https://developers.docusign.com/platform/auth/jwt/), you will need an integration key, an RSA key pair, and the API Username GUID of the impersonated user. See [Installation steps for JWT Grant authentication](#installation-steps-for-jwt-grant-authentication) for details. - By default, the rails app starts on url `http://localhost:3000` + For both authentication flows: - So the default Redirect URI for your Integration Key is - - `http://localhost:3000/auth/docusign/callback` - -1. Ruby version 2.7.1 or later. Or you can update the Gemfile to use other versions of Ruby. -1. A name and email for a signer, and a name and email for a cc recipient. - -### Installation steps -**Note: If you downloaded this code using Quickstart from the DocuSign Developer Center, skip steps 4, 5, and 6 below as they're automatically performed for you.** - -1. Download or clone this repository to your workstation to directory **code-examples-ruby** -1. **cd code-examples-ruby** -1. Install the needed gems listed in the Gemfile: + If you use this launcher on your own workstation, the integration key must include a redirect URI of - Run **bundler install** -1. Copy the file **config/appsettings.example.yml** into a new file named **config/appsettings.yml** -1. Update the file **config/appsettings.yml** with the Integration Key and other settings. - Note: The terms "client_id" and "Integration key" are synonyms. They refer to the same thing. + http://localhost:3000/auth/docusign/callback -1. Update your Integration Key's settings to include a **Redirect URI** for - your installation of the example. See Prerequisites item #2, above for more information. - -#### Run the application -1. To start the development web server and application: - - Run **rails s** - - *Note that on Windows additional actions might be necessary:* - - *Install sqlite3: **gem install sqlite3 --platform=ruby*** - - *Download curllib.dll (https://curl.haxx.se/windows/)* - - *libcurl-x64.dll should be copied as libcurl.dll* - - *Place libcurl.dll into Ruby `C:\\\bin`* -1. Open a browser to the example's base url to view the index page. - -### Configuring JWT - -**Note:** Before you can make any API calls using JWT Grant, you must get your user’s consent for your app to impersonate them. To do this, the `impersonation` scope is added when requesting a JSON Web Token. + If you host this launcher on a remote web server, set your redirect URI as + + {base_url}/auth/docusign/callback + + where {base_url} is the URL for the web app. + +1. [Ruby version 2.7.2](https://www.ruby-lang.org/en/downloads/) or later + 1. Update the Gemfile to use later versions of Ruby. + 1. Windows x64 only: + 1. Ensure that your Ruby folder is appended with -x64, e.g. **Ruby27-x64** + 2. Install Curl for Ruby: [Download libcurl.dll](https://curl.haxx.se/windows/) + Save **libcurl-x64.dll** as **libcurl.dll** + Place **libcurl.dll** in your Ruby folder, e.g. **C:\Ruby27-x64\bin** -1. Create a developer sandbox account on developers.docusign.com if you don't already have one. -2. Create a new API key in the Admin panel: https://admindemo.docusign.com/api-integrator-key - - Take note of the _Integration Key_. - - Generate a _RSA Keypair_ and copy the private key to a secure location. - - Set a _Redirect URI_ of `http://localhost:3000/auth/docusign/callback` as mentioned in the installation steps above. -3. Create a new file in the config folder named **docusign_private_key.txt**, and paste in that copied RSA private key, then save it. -4. Update the file **config/appsettings.yml** and include the settings from step 2. -[Obtaining consent](https://developers.docusign.com/esign-rest-api/guides/authentication/obtaining-consent#individual-consent) does not need to be configured, as it is already being done in the code at [JwtAuth::JwtCreator#update_token](./app/services/jwt_auth/jwt_creator.rb#L35) +### 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-ruby repository. +1. In your command-line environment, switch to the folder: + `cd ` or `cd code-examples-ruby` +1. Install the dependencies: `bundle install` +1. To configure the launcher for [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. + 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 appsettings.yml as your `integration_key`. + 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 appsettings.yml as your `integration_secret`. + 1. Add the launcher’s redirect URI. Under **Additional settings**, select **+ ADD URI**, and set a redirect URI of http://localhost:3000/auth/docusign/callback. Select **SAVE**. + 1. Set a name and email address for the signer. In appsettings.yml, save an email address as `signer_email` and a name as `signer_name`. +**Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. +1. Run the launcher: `rails s` +1. Open a browser to http://localhost:3000/auth/docusign + + +### 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 config/appsettings.yml, change `quickstart` to `false`. + +1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. +1. In your command-line environment, switch to the folder: + `cd ` or `cd code-examples-ruby` +1. Install the dependencies: `bundle install` +1. To configure the launcher for [JWT Grant](https://developers.docusign.com/platform/auth/jwt/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. + 1. Add your API Username. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **My Account Information**, copy the **API Username** GUID and save it in appsettings.yml as your `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 appsettings.yml as your `jwt_integration_key`. + 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 config/docusign_private_key.txt. + 1. Add the launcher’s redirect URI. Under **Additional settings**, select **+ ADD URI**, and set a redirect URI of http://localhost:3000/auth/docusign/callback. Select **SAVE**. + 1. Set a name and email address for the signer. In appsettings.yml, save an email address as `signer_email` and a name as `signer_name`. +**Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. +1. Run the launcher: `rails s` +1. Open a browser to http://localhost:3000/auth/docusign +**Note:** This step is currently broken in Windows. We will remove this note when it has been fixed. + +1. If it is your first time using the app, grant consent by selecting **Accept**. On the black navigation bar, select **Logout**, then **Login**. +1. From the picklist, select **JSON Web Token (JWT) grant** > **Authenticate with DocuSign**. +1. Select your desired code example. -From there you should be able to run the launcher using `bundle exec rails server` then selecting **JSON Web Token** when authenticaing your account. ### Troubleshooting Windows SSL issue When using the Ruby launcher on a Windows machine you may get the following error: @@ -306,34 +310,18 @@ Modify the following two lines in the **configuration.rb** file, replacing `true Once this is complete, you can run your Ruby on Rails application again and you should be able to make API calls on your localhost. -### Payments code example -To use the payments example, create a -test payments gateway for your developer sandbox account. - -See the -[PAYMENTS_INSTALLATION.md](./PAYMENTS_INSTALLATION.md) -file for instructions. +## 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. -Then add the payment gateway account id to the **config/application.rb** file. +Once you've created a payment gateway, save the **Gateway Account ID** GUID to appsettings.yml. -### Using the examples with other authentication flows - -The examples in this repository can also be used with the -Implicit grant 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. ## License and additional information ### License -This repository uses the MIT License. See the LICENSE file for more information. +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 uses the MIT License. - -### Additional Resources -* [DocuSign Developer Center](https://developers.docusign.com) -* [DocuSign API on Twitter](https://twitter.com/docusignapi) -* [DocuSign For Developers on LinkedIn](https://www.linkedin.com/showcase/docusign-for-developers/) -* [DocuSign For Developers on YouTube](https://www.youtube.com/channel/UCJSJ2kMs_qeQotmw4-lX2NQ) From 4f68c84ea91b8b5b7d950dd8899b85fa4febc2a3 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 12 Apr 2021 17:10:07 -0700 Subject: [PATCH 043/363] sync with private --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 9cc9ab3..a199fea 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,6 @@ ### Github repo: https://github.com/docusign/code-examples-ruby - -This GitHub repo includes code examples for DocuSign APIs. - To switch between API code examples, modify the `examples_API` setting at the end of the configuration file. Set only one API type to `true` and set the remaining to `false`. If none of the API types are set to `true`, the DocuSign eSignature REST API code examples will be shown. If multiple API types are set to `true`, only the first will be shown. From 1992a3ab396cf60931837c159b6251a5445ada4b Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Wed, 14 Apr 2021 12:08:29 -0700 Subject: [PATCH 044/363] fix JWT redirect_uri and add state (#21) --- Gemfile | 12 +- Gemfile.lock | 139 +++++++++++------------- app/controllers/ds_common_controller.rb | 3 +- app/services/jwt_auth/jwt_creator.rb | 8 +- 4 files changed, 74 insertions(+), 88 deletions(-) diff --git a/Gemfile b/Gemfile index 89d7d58..4ed9224 100644 --- a/Gemfile +++ b/Gemfile @@ -1,12 +1,12 @@ - # frozen_string_literal: true +# frozen_string_literal: true source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '2.7.2' +ruby '2.7.1' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 6.0.3.5' +gem 'rails', '~> 6.0.3.3' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4.2' # Use Puma as the app server @@ -64,10 +64,10 @@ end gem 'docusign_esign', '~> 3.8.0.rc1' gem 'docusign_rooms', '~> 1.1.0.rc1' -gem 'docusign_click', '~> 1.0.0' -gem 'omniauth-oauth2', '~> 1.7.1' +gem 'docusign_click' +gem 'omniauth-oauth2', '~> 1.6' gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', '~> 1.2019.3', platforms: %i[mingw mswin x64_mingw jruby] -gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] +gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index d84c396..0dac2dc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,56 +1,56 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.3.5) - actionpack (= 6.0.3.5) + actioncable (6.0.3.4) + actionpack (= 6.0.3.4) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.3.5) - actionpack (= 6.0.3.5) - activejob (= 6.0.3.5) - activerecord (= 6.0.3.5) - activestorage (= 6.0.3.5) - activesupport (= 6.0.3.5) + actionmailbox (6.0.3.4) + actionpack (= 6.0.3.4) + activejob (= 6.0.3.4) + activerecord (= 6.0.3.4) + activestorage (= 6.0.3.4) + activesupport (= 6.0.3.4) mail (>= 2.7.1) - actionmailer (6.0.3.5) - actionpack (= 6.0.3.5) - actionview (= 6.0.3.5) - activejob (= 6.0.3.5) + actionmailer (6.0.3.4) + actionpack (= 6.0.3.4) + actionview (= 6.0.3.4) + activejob (= 6.0.3.4) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.3.5) - actionview (= 6.0.3.5) - activesupport (= 6.0.3.5) + actionpack (6.0.3.4) + actionview (= 6.0.3.4) + activesupport (= 6.0.3.4) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.3.5) - actionpack (= 6.0.3.5) - activerecord (= 6.0.3.5) - activestorage (= 6.0.3.5) - activesupport (= 6.0.3.5) + actiontext (6.0.3.4) + actionpack (= 6.0.3.4) + activerecord (= 6.0.3.4) + activestorage (= 6.0.3.4) + activesupport (= 6.0.3.4) nokogiri (>= 1.8.5) - actionview (6.0.3.5) - activesupport (= 6.0.3.5) + actionview (6.0.3.4) + activesupport (= 6.0.3.4) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.3.5) - activesupport (= 6.0.3.5) + activejob (6.0.3.4) + activesupport (= 6.0.3.4) globalid (>= 0.3.6) - activemodel (6.0.3.5) - activesupport (= 6.0.3.5) - activerecord (6.0.3.5) - activemodel (= 6.0.3.5) - activesupport (= 6.0.3.5) - activestorage (6.0.3.5) - actionpack (= 6.0.3.5) - activejob (= 6.0.3.5) - activerecord (= 6.0.3.5) + activemodel (6.0.3.4) + activesupport (= 6.0.3.4) + activerecord (6.0.3.4) + activemodel (= 6.0.3.4) + activesupport (= 6.0.3.4) + activestorage (6.0.3.4) + actionpack (= 6.0.3.4) + activejob (= 6.0.3.4) + activerecord (= 6.0.3.4) marcel (~> 0.3.1) - activesupport (6.0.3.5) + activesupport (6.0.3.4) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -87,8 +87,7 @@ GEM coffee-script-source (1.12.2) concurrent-ruby (1.1.7) crass (1.0.6) - docusign_click (1.0.0) - addressable (~> 2.7, >= 2.7.0) + docusign_click (1.0.0.beta2) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) @@ -104,13 +103,10 @@ GEM ethon (0.12.0) ffi (>= 1.3.0) execjs (2.7.0) - faraday (1.3.0) - faraday-net_http (~> 1.0) + faraday (1.1.0) multipart-post (>= 1.2, < 3) ruby2_keywords - faraday-net_http (1.0.1) ffi (1.13.1) - ffi (1.13.1-x64-mingw32) globalid (0.4.2) activesupport (>= 4.2.0) hashie (4.1.0) @@ -134,19 +130,15 @@ GEM method_source (0.9.2) mimemagic (0.3.5) mini_mime (1.0.2) - mini_portile2 (2.5.0) + mini_portile2 (2.4.0) minitest (5.14.2) msgpack (1.3.3) - msgpack (1.3.3-x64-mingw32) multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) nio4r (2.5.4) - nokogiri (1.11.1) - mini_portile2 (~> 2.5.0) - racc (~> 1.4) - nokogiri (1.11.1-x64-mingw32) - racc (~> 1.4) + nokogiri (1.10.10) + mini_portile2 (~> 2.4.0) oauth2 (1.4.4) faraday (>= 0.8, < 2.0) jwt (>= 1.0, < 3.0) @@ -156,9 +148,9 @@ GEM omniauth (1.9.1) hashie (>= 3.4.6) rack (>= 1.6.2, < 3) - omniauth-oauth2 (1.7.1) + omniauth-oauth2 (1.7.0) oauth2 (~> 1.4) - omniauth (>= 1.9, < 3) + omniauth (~> 1.9) omniauth-rails_csrf_protection (0.1.2) actionpack (>= 4.2) omniauth (>= 1.3.1) @@ -172,33 +164,32 @@ GEM public_suffix (4.0.6) puma (4.3.6) nio4r (~> 2.0) - racc (1.5.2) rack (2.2.3) rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.0.3.5) - actioncable (= 6.0.3.5) - actionmailbox (= 6.0.3.5) - actionmailer (= 6.0.3.5) - actionpack (= 6.0.3.5) - actiontext (= 6.0.3.5) - actionview (= 6.0.3.5) - activejob (= 6.0.3.5) - activemodel (= 6.0.3.5) - activerecord (= 6.0.3.5) - activestorage (= 6.0.3.5) - activesupport (= 6.0.3.5) + rails (6.0.3.4) + actioncable (= 6.0.3.4) + actionmailbox (= 6.0.3.4) + actionmailer (= 6.0.3.4) + actionpack (= 6.0.3.4) + actiontext (= 6.0.3.4) + actionview (= 6.0.3.4) + activejob (= 6.0.3.4) + activemodel (= 6.0.3.4) + activerecord (= 6.0.3.4) + activestorage (= 6.0.3.4) + activesupport (= 6.0.3.4) bundler (>= 1.3.0) - railties (= 6.0.3.5) + railties (= 6.0.3.4) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) - railties (6.0.3.5) - actionpack (= 6.0.3.5) - activesupport (= 6.0.3.5) + railties (6.0.3.4) + actionpack (= 6.0.3.4) + activesupport (= 6.0.3.4) method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) @@ -207,14 +198,12 @@ GEM rb-inotify (0.10.1) ffi (~> 1.0) regexp_parser (1.8.2) - ruby2_keywords (0.0.4) + ruby2_keywords (0.0.2) rubyzip (2.3.0) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) sassc (2.4.0) ffi (~> 1.9) - sassc (2.4.0-x64-mingw32) - ffi (~> 1.9) sassc-rails (2.1.2) railties (>= 4.0.0) sassc (>= 2.0) @@ -246,11 +235,8 @@ GEM ethon (>= 0.9.0) tzinfo (1.2.7) thread_safe (~> 0.1) - tzinfo-data (1.2019.3) - tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) - wdm (0.1.1) web-console (4.0.4) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -265,7 +251,6 @@ GEM PLATFORMS ruby - x64-mingw32 DEPENDENCIES bootsnap (~> 1.4.5) @@ -273,17 +258,17 @@ DEPENDENCIES capybara (~> 3.31.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_click (~> 1.0.0) + docusign_click docusign_esign (~> 3.8.0.rc1) docusign_rooms (~> 1.1.0.rc1) jbuilder (~> 2.10.0) listen (~> 3.2.1) - omniauth-oauth2 (~> 1.7.1) + omniauth-oauth2 (~> 1.6) omniauth-rails_csrf_protection pry-nav (~> 0.3.0) pry-rails (~> 0.3.9) puma (~> 4.3.3) - rails (~> 6.0.3.5) + rails (~> 6.0.3.3) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) spring (~> 2.1.0) @@ -296,7 +281,7 @@ DEPENDENCIES web-console (~> 4.0.1) RUBY VERSION - ruby 2.7.2p137 + ruby 2.7.1p83 BUNDLED WITH 2.1.4 diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index 9d366c4..26e4e7b 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -44,7 +44,8 @@ def ds_must_authenticate url = root_path end else - url = JwtAuth::JwtCreator.consent_url + session['omniauth.state'] = SecureRandom.hex + url = JwtAuth::JwtCreator.consent_url(session['omniauth.state']) redirect_to root_path if session[:token].present? end if Rails.configuration.examples_API['Rooms'] == true diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index dae03df..e3e6bb7 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -4,12 +4,12 @@ module JwtAuth class JwtCreator include ApiCreator - attr_reader :session, :api_client + attr_reader :session, :api_client, :state # DocuSign authorization URI to obtain individual consent # https://developers.docusign.com/platform/auth/jwt/jwt-get-token # https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/ - def self.consent_url + def self.consent_url(state) # GET /oauth/auth # This endpoint is used to obtain consent and is the first step in several authentication flows. # https://developers.docusign.com/platform/auth/reference/obtain-consent @@ -24,8 +24,8 @@ def self.consent_url response_type = "code" scopes = ERB::Util.url_encode(scope) # https://developers.docusign.com/platform/auth/reference/scopes/ client_id = Rails.configuration.jwt_integration_key - redirect_uri = Rails.configuration.app_url - consent_url = "#{base_uri}?response_type=#{response_type}&scope=#{scopes}&client_id=#{client_id}&redirect_uri=#{redirect_uri}" + redirect_uri = "#{Rails.configuration.app_url}/auth/docusign/callback" + consent_url = "#{base_uri}?response_type=#{response_type}&scope=#{scopes}&client_id=#{client_id}&state=#{state}&redirect_uri=#{redirect_uri}" Rails.logger.info "==> Obtain Consent Grant required: #{consent_url}" consent_url end From f3d7d9f25ac4a0aa295952290ff45caede6eb957 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Apr 2021 19:10:02 +0000 Subject: [PATCH 045/363] Bump nokogiri from 1.10.10 to 1.11.3 Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.10.10 to 1.11.3. - [Release notes](https://github.com/sparklemotion/nokogiri/releases) - [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md) - [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.10.10...v1.11.3) Signed-off-by: dependabot[bot] --- Gemfile.lock | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 0dac2dc..3f16e3f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -128,17 +128,20 @@ GEM marcel (0.3.3) mimemagic (~> 0.3.2) method_source (0.9.2) - mimemagic (0.3.5) + mimemagic (0.3.10) + nokogiri (~> 1) + rake mini_mime (1.0.2) - mini_portile2 (2.4.0) + mini_portile2 (2.5.0) minitest (5.14.2) msgpack (1.3.3) multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) nio4r (2.5.4) - nokogiri (1.10.10) - mini_portile2 (~> 2.4.0) + nokogiri (1.11.3) + mini_portile2 (~> 2.5.0) + racc (~> 1.4) oauth2 (1.4.4) faraday (>= 0.8, < 2.0) jwt (>= 1.0, < 3.0) @@ -164,6 +167,7 @@ GEM public_suffix (4.0.6) puma (4.3.6) nio4r (~> 2.0) + racc (1.5.2) rack (2.2.3) rack-test (1.1.0) rack (>= 1.0, < 3) From 4bedbb28d0071b467ec5224898805ddd3fcfd8c0 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Wed, 14 Apr 2021 12:23:50 -0700 Subject: [PATCH 046/363] removed note about broken jwt --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index a199fea..7930541 100644 --- a/README.md +++ b/README.md @@ -269,8 +269,6 @@ Also, in order to select JSON Web Token authentication in the launcher, in confi **Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. 1. Run the launcher: `rails s` 1. Open a browser to http://localhost:3000/auth/docusign -**Note:** This step is currently broken in Windows. We will remove this note when it has been fixed. - 1. If it is your first time using the app, grant consent by selecting **Accept**. On the black navigation bar, select **Logout**, then **Login**. 1. From the picklist, select **JSON Web Token (JWT) grant** > **Authenticate with DocuSign**. 1. Select your desired code example. From 2e617059ace5a024d2041a1def82415d61ce2fd5 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Thu, 15 Apr 2021 11:33:32 -0700 Subject: [PATCH 047/363] small edit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9cc9ab3..bad8eb9 100644 --- a/README.md +++ b/README.md @@ -209,7 +209,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a **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 below 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 for authentication to use either [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) or [JWT Grant](https://developers.docusign.com/platform/auth/jwt/). +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. @@ -232,7 +232,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. [Ruby version 2.7.2](https://www.ruby-lang.org/en/downloads/) or later 1. Update the Gemfile to use later versions of Ruby. 1. Windows x64 only: - 1. Ensure that your Ruby folder is appended with -x64, e.g. **Ruby27-x64** + 1. Ensure that your Ruby folder is appended with **-x64**, e.g. **Ruby27-x64** 2. Install Curl for Ruby: [Download libcurl.dll](https://curl.haxx.se/windows/) Save **libcurl-x64.dll** as **libcurl.dll** Place **libcurl.dll** in your Ruby folder, e.g. **C:\Ruby27-x64\bin** From 1abef8c6cb37b295de973b533a402e7729592573 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Thu, 15 Apr 2021 11:35:16 -0700 Subject: [PATCH 048/363] sync with private --- README.md | 166 +++++++++++++++++++++++++----------------------------- 1 file changed, 77 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index 3ce2384..bad8eb9 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,20 @@ # Ruby Launcher Code Examples -### Github repo: code-examples-ruby +### Github repo: https://github.com/docusign/code-examples-ruby + This GitHub repo includes code examples for DocuSign APIs. -To switch between API code examples, modify the `examples_API` setting at the end of the configuration file. Set only one API type to true and set the remaining to false. +To switch between API code examples, modify the `examples_API` setting at the end of the configuration file. Set only one API type to `true` and set the remaining to `false`. + +If none of the API types are set to `true`, the DocuSign eSignature REST API code examples will be shown. If multiple API types are set to `true`, only the first will be shown. -If none of the API types are set to true, the DocuSign eSignature REST API code examples will be shown. If multiple API types are set to true, only the first will be shown. +Before you can make any API calls using [JWT Grant](https://developers.docusign.com/platform/auth/jwt/), you must get your user’s consent for your app to impersonate them. To do this, the `impersonation` scope is added when requesting a JSON Web Token. -**Note:** to use the Rooms API you must also [create your DocuSign Developer Account for Rooms](https://developers.docusign.com/docs/rooms-api/rooms101/create-account). ## Introduction -This repo is a Ruby on Rails application that demonstrates: +This repo is a Ruby on Rails application. + ## eSignature API @@ -144,8 +147,10 @@ For more information about the scopes used for obtaining authorization to use th [Source.](app/services/e_sign/eg035_sms_delivery_service.rb) This code example demonstrates how to send a signature request via an SMS message using the [Envelopes: create](https://developers.docusign.com/esign-rest-api/reference/Envelopes/Envelopes/create) method. + ## Rooms API +**Note:** To use the Rooms API, you must also [create a Rooms developer account](https://developers.docusign.com/docs/rooms-api/rooms101/create-account). For more information about the scopes used for obtaining authorization to use the Rooms API, see the [Required Scopes section](https://developers.docusign.com/docs/rooms-api/rooms101/auth/). 1. **Create a room with data.** @@ -176,6 +181,7 @@ For more information about the scopes used for obtaining authorization to use th [Source.](./app/services/room_api/eg009_assign_form_to_form_group_service.rb) This example assigns a form to a form group for your DocuSign Rooms. + ## Click API For more information about the scopes used for obtaining authorization to use the Clickwrap API, see the [Required Scopes section](https://developers.docusign.com/docs/click-api/click101/auth). @@ -196,84 +202,82 @@ This example demonstrates how to use the Click API to get a list of clickwraps a [Source.](./app/services/clickwrap/eg005_clickwrap_responses_service.rb) This example demonstrates how to use the Click API to get a list of clickwraps associated with a specific DocuSign user. -## 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). -When the token expires, it updates automatically. - ## Installation ### Prerequisites -**Note: If you downloaded this code using Quickstart from the DocuSign Developer Center, skip steps 1 and 2 below as they're automatically performed for you.** +**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 below as they were automatically performed for you. -1. A DocuSign Developer account (email and password) on [demo.docusign.net](https://demo.docusign.net). - Create a [free account](https://go.docusign.com/sandbox/productshot/?elqCampaignId=16536). -1. A DocuSign Integration Key and secret key (a client ID). 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. - - You will need the **Integration Key** itself, and its **secret**. +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. - The Integration key must include a **Redirect URI** of + This [video](https://www.youtube.com/watch?v=eiRI4fe5HgM) demonstrates how to obtain an integration key. - `{base_url}/auth/docusign/callback` + 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. - Where `{base_url}` is the url for the web app. + To use [JWT Grant](https://developers.docusign.com/platform/auth/jwt/), you will need an integration key, an RSA key pair, and the API Username GUID of the impersonated user. See [Installation steps for JWT Grant authentication](#installation-steps-for-jwt-grant-authentication) for details. - By default, the rails app starts on url `http://localhost:3000` + For both authentication flows: - So the default Redirect URI for your Integration Key is - - `http://localhost:3000/auth/docusign/callback` - -1. Ruby version 2.7.1 or later. Or you can update the Gemfile to use other versions of Ruby. -1. A name and email for a signer, and a name and email for a cc recipient. - -### Installation steps -**Note: If you downloaded this code using Quickstart from the DocuSign Developer Center, skip steps 4, 5, and 6 below as they're automatically performed for you.** - -1. Download or clone this repository to your workstation to directory **code-examples-ruby** -1. **cd code-examples-ruby** -1. Install the needed gems listed in the Gemfile: + If you use this launcher on your own workstation, the integration key must include a redirect URI of - Run **bundler install** -1. Copy the file **config/appsettings.example.yml** into a new file named **config/appsettings.yml** -1. Update the file **config/appsettings.yml** with the Integration Key and other settings. - Note: The terms "client_id" and "Integration key" are synonyms. They refer to the same thing. + http://localhost:3000/auth/docusign/callback -1. Update your Integration Key's settings to include a **Redirect URI** for - your installation of the example. See Prerequisites item #2, above for more information. - -#### Run the application -1. To start the development web server and application: - - Run **rails s** - - *Note that on Windows additional actions might be necessary:* - - *Install sqlite3: **gem install sqlite3 --platform=ruby*** - - *Download curllib.dll (https://curl.haxx.se/windows/)* - - *libcurl-x64.dll should be copied as libcurl.dll* - - *Place libcurl.dll into Ruby `C:\\\bin`* -1. Open a browser to the example's base url to view the index page. - -### Configuring JWT - -**Note:** Before you can make any API calls using JWT Grant, you must get your user’s consent for your app to impersonate them. To do this, the `impersonation` scope is added when requesting a JSON Web Token. + If you host this launcher on a remote web server, set your redirect URI as + + {base_url}/auth/docusign/callback + + where {base_url} is the URL for the web app. + +1. [Ruby version 2.7.2](https://www.ruby-lang.org/en/downloads/) or later + 1. Update the Gemfile to use later versions of Ruby. + 1. Windows x64 only: + 1. Ensure that your Ruby folder is appended with **-x64**, e.g. **Ruby27-x64** + 2. Install Curl for Ruby: [Download libcurl.dll](https://curl.haxx.se/windows/) + Save **libcurl-x64.dll** as **libcurl.dll** + Place **libcurl.dll** in your Ruby folder, e.g. **C:\Ruby27-x64\bin** -1. Create a developer sandbox account on developers.docusign.com if you don't already have one. -2. Create a new API key in the Admin panel: https://admindemo.docusign.com/api-integrator-key - - Take note of the _Integration Key_. - - Generate a _RSA Keypair_ and copy the private key to a secure location. - - Set a _Redirect URI_ of `http://localhost:3000/auth/docusign/callback` as mentioned in the installation steps above. -3. Create a new file in the config folder named **docusign_private_key.txt**, and paste in that copied RSA private key, then save it. -4. Update the file **config/appsettings.yml** and include the settings from step 2. -[Obtaining consent](https://developers.docusign.com/esign-rest-api/guides/authentication/obtaining-consent#individual-consent) does not need to be configured, as it is already being done in the code at [JwtAuth::JwtCreator#update_token](./app/services/jwt_auth/jwt_creator.rb#L35) +### 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-ruby repository. +1. In your command-line environment, switch to the folder: + `cd ` or `cd code-examples-ruby` +1. Install the dependencies: `bundle install` +1. To configure the launcher for [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. + 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 appsettings.yml as your `integration_key`. + 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 appsettings.yml as your `integration_secret`. + 1. Add the launcher’s redirect URI. Under **Additional settings**, select **+ ADD URI**, and set a redirect URI of http://localhost:3000/auth/docusign/callback. Select **SAVE**. + 1. Set a name and email address for the signer. In appsettings.yml, save an email address as `signer_email` and a name as `signer_name`. +**Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. +1. Run the launcher: `rails s` +1. Open a browser to http://localhost:3000/auth/docusign + + +### 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 config/appsettings.yml, change `quickstart` to `false`. + +1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. +1. In your command-line environment, switch to the folder: + `cd ` or `cd code-examples-ruby` +1. Install the dependencies: `bundle install` +1. To configure the launcher for [JWT Grant](https://developers.docusign.com/platform/auth/jwt/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. + 1. Add your API Username. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **My Account Information**, copy the **API Username** GUID and save it in appsettings.yml as your `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 appsettings.yml as your `jwt_integration_key`. + 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 config/docusign_private_key.txt. + 1. Add the launcher’s redirect URI. Under **Additional settings**, select **+ ADD URI**, and set a redirect URI of http://localhost:3000/auth/docusign/callback. Select **SAVE**. + 1. Set a name and email address for the signer. In appsettings.yml, save an email address as `signer_email` and a name as `signer_name`. +**Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. +1. Run the launcher: `rails s` +1. Open a browser to http://localhost:3000/auth/docusign +**Note:** This step is currently broken in Windows. We will remove this note when it has been fixed. + +1. If it is your first time using the app, grant consent by selecting **Accept**. On the black navigation bar, select **Logout**, then **Login**. +1. From the picklist, select **JSON Web Token (JWT) grant** > **Authenticate with DocuSign**. +1. Select your desired code example. -From there you should be able to run the launcher using `bundle exec rails server` then selecting **JSON Web Token** when authenticaing your account. ### Troubleshooting Windows SSL issue When using the Ruby launcher on a Windows machine you may get the following error: @@ -306,34 +310,18 @@ Modify the following two lines in the **configuration.rb** file, replacing `true Once this is complete, you can run your Ruby on Rails application again and you should be able to make API calls on your localhost. -### Payments code example -To use the payments example, create a -test payments gateway for your developer sandbox account. - -See the -[PAYMENTS_INSTALLATION.md](./PAYMENTS_INSTALLATION.md) -file for instructions. +## 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. -Then add the payment gateway account id to the **config/application.rb** file. +Once you've created a payment gateway, save the **Gateway Account ID** GUID to appsettings.yml. -### Using the examples with other authentication flows - -The examples in this repository can also be used with the -Implicit grant 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. ## License and additional information ### License -This repository uses the MIT License. See the LICENSE file for more information. +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 uses the MIT License. - -### Additional Resources -* [DocuSign Developer Center](https://developers.docusign.com) -* [DocuSign API on Twitter](https://twitter.com/docusignapi) -* [DocuSign For Developers on LinkedIn](https://www.linkedin.com/showcase/docusign-for-developers/) -* [DocuSign For Developers on YouTube](https://www.youtube.com/channel/UCJSJ2kMs_qeQotmw4-lX2NQ) From ac4071cb6c8c94e16994b7b999cb310086b2ae82 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Thu, 15 Apr 2021 11:37:18 -0700 Subject: [PATCH 049/363] remove note about broken jwt --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index bad8eb9..3e3358b 100644 --- a/README.md +++ b/README.md @@ -272,8 +272,6 @@ Also, in order to select JSON Web Token authentication in the launcher, in confi **Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. 1. Run the launcher: `rails s` 1. Open a browser to http://localhost:3000/auth/docusign -**Note:** This step is currently broken in Windows. We will remove this note when it has been fixed. - 1. If it is your first time using the app, grant consent by selecting **Accept**. On the black navigation bar, select **Logout**, then **Login**. 1. From the picklist, select **JSON Web Token (JWT) grant** > **Authenticate with DocuSign**. 1. Select your desired code example. From f1459d40759ecfe519fc11d3f07cf57968ecd7c9 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Thu, 15 Apr 2021 11:37:59 -0700 Subject: [PATCH 050/363] sync with private --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index bad8eb9..3e3358b 100644 --- a/README.md +++ b/README.md @@ -272,8 +272,6 @@ Also, in order to select JSON Web Token authentication in the launcher, in confi **Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. 1. Run the launcher: `rails s` 1. Open a browser to http://localhost:3000/auth/docusign -**Note:** This step is currently broken in Windows. We will remove this note when it has been fixed. - 1. If it is your first time using the app, grant consent by selecting **Accept**. On the black navigation bar, select **Logout**, then **Login**. 1. From the picklist, select **JSON Web Token (JWT) grant** > **Authenticate with DocuSign**. 1. Select your desired code example. From c7a10b940c45cb131396db9b9a9a11745fc89fca Mon Sep 17 00:00:00 2001 From: Jack Lin Date: Fri, 16 Apr 2021 06:00:47 -0700 Subject: [PATCH 051/363] add steps for updating local SSL certificates to run the quick starter --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 7930541..b34044e 100644 --- a/README.md +++ b/README.md @@ -304,6 +304,17 @@ Modify the following two lines in the **configuration.rb** file, replacing `true Once this is complete, you can run your Ruby on Rails application again and you should be able to make API calls on your localhost. +### Troubleshooting macOS SSL issue +When using the Ruby launcher on OSX you may get the following error: + +``` +Faraday::SSLError (SSL_connect returned=1 errno=0 state=error: certificate verify failed (self signed certificate in certificate chain)) +``` +Please update SSL certificates if brew is your package manager. Or check [other steps for other package manager](https://gemfury.com/help/could-not-verify-ssl-certificate/#updating-ssl-certificates) +``` +$ rvm osx-ssl-certs status all +$ rvm osx-ssl-certs update all +``` ## 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. From 24d577efca310b852c4112f6bcfc38c5ecf73a41 Mon Sep 17 00:00:00 2001 From: Jack Lin Date: Fri, 16 Apr 2021 06:08:36 -0700 Subject: [PATCH 052/363] change language to make the rvm more clear --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b34044e..95ce724 100644 --- a/README.md +++ b/README.md @@ -310,7 +310,7 @@ When using the Ruby launcher on OSX you may get the following error: ``` Faraday::SSLError (SSL_connect returned=1 errno=0 state=error: certificate verify failed (self signed certificate in certificate chain)) ``` -Please update SSL certificates if brew is your package manager. Or check [other steps for other package manager](https://gemfury.com/help/could-not-verify-ssl-certificate/#updating-ssl-certificates) +Please update SSL certificates if rvm is your version manager. Or check [other steps for different scenarios](https://gemfury.com/help/could-not-verify-ssl-certificate/#updating-ssl-certificates). ``` $ rvm osx-ssl-certs status all $ rvm osx-ssl-certs update all From 5b79af0a8d09ace4cffb8918ee20e614beabedca Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Tue, 20 Apr 2021 22:48:18 -0700 Subject: [PATCH 053/363] fix JWT error in eSignature examples --- Gemfile | 12 +- Gemfile.lock | 183 ++++++++++++++------------- app/services/jwt_auth/jwt_creator.rb | 2 +- 3 files changed, 105 insertions(+), 92 deletions(-) diff --git a/Gemfile b/Gemfile index 4ed9224..72fb506 100644 --- a/Gemfile +++ b/Gemfile @@ -1,12 +1,12 @@ -# frozen_string_literal: true + # frozen_string_literal: true source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '2.7.1' +ruby '2.7.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 6.0.3.3' +gem 'rails', '~> 6.0.3.5' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4.2' # Use Puma as the app server @@ -36,7 +36,7 @@ gem 'jbuilder', '~> 2.10.0' # gem 'capistrano-rails', group: :development # Reduces boot times through caching; required in config/boot.rb -gem 'bootsnap', '~> 1.4.5', require: false +gem 'bootsnap', '~> 1.7.3', require: false group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console @@ -64,8 +64,8 @@ end gem 'docusign_esign', '~> 3.8.0.rc1' gem 'docusign_rooms', '~> 1.1.0.rc1' -gem 'docusign_click' -gem 'omniauth-oauth2', '~> 1.6' +gem 'docusign_click', '~> 1.0.0' +gem 'omniauth-oauth2', '~> 1.7.1' gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem diff --git a/Gemfile.lock b/Gemfile.lock index 3f16e3f..76798cd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,56 +1,56 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.3.4) - actionpack (= 6.0.3.4) + actioncable (6.0.3.5) + actionpack (= 6.0.3.5) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.3.4) - actionpack (= 6.0.3.4) - activejob (= 6.0.3.4) - activerecord (= 6.0.3.4) - activestorage (= 6.0.3.4) - activesupport (= 6.0.3.4) + actionmailbox (6.0.3.5) + actionpack (= 6.0.3.5) + activejob (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) mail (>= 2.7.1) - actionmailer (6.0.3.4) - actionpack (= 6.0.3.4) - actionview (= 6.0.3.4) - activejob (= 6.0.3.4) + actionmailer (6.0.3.5) + actionpack (= 6.0.3.5) + actionview (= 6.0.3.5) + activejob (= 6.0.3.5) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.3.4) - actionview (= 6.0.3.4) - activesupport (= 6.0.3.4) + actionpack (6.0.3.5) + actionview (= 6.0.3.5) + activesupport (= 6.0.3.5) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.3.4) - actionpack (= 6.0.3.4) - activerecord (= 6.0.3.4) - activestorage (= 6.0.3.4) - activesupport (= 6.0.3.4) + actiontext (6.0.3.5) + actionpack (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) nokogiri (>= 1.8.5) - actionview (6.0.3.4) - activesupport (= 6.0.3.4) + actionview (6.0.3.5) + activesupport (= 6.0.3.5) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.3.4) - activesupport (= 6.0.3.4) + activejob (6.0.3.5) + activesupport (= 6.0.3.5) globalid (>= 0.3.6) - activemodel (6.0.3.4) - activesupport (= 6.0.3.4) - activerecord (6.0.3.4) - activemodel (= 6.0.3.4) - activesupport (= 6.0.3.4) - activestorage (6.0.3.4) - actionpack (= 6.0.3.4) - activejob (= 6.0.3.4) - activerecord (= 6.0.3.4) + activemodel (6.0.3.5) + activesupport (= 6.0.3.5) + activerecord (6.0.3.5) + activemodel (= 6.0.3.5) + activesupport (= 6.0.3.5) + activestorage (6.0.3.5) + actionpack (= 6.0.3.5) + activejob (= 6.0.3.5) + activerecord (= 6.0.3.5) marcel (~> 0.3.1) - activesupport (6.0.3.4) + activesupport (6.0.3.5) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -61,7 +61,7 @@ GEM archive-zip (0.12.0) io-like (~> 0.3.0) bindex (0.8.1) - bootsnap (1.4.8) + bootsnap (1.4.1) msgpack (~> 1.0) builder (3.2.4) byebug (11.1.3) @@ -85,9 +85,10 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.1.7) + concurrent-ruby (1.1.8) crass (1.0.6) - docusign_click (1.0.0.beta2) + docusign_click (1.0.0) + addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) @@ -99,28 +100,31 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - erubi (1.9.0) + erubi (1.10.0) ethon (0.12.0) ffi (>= 1.3.0) execjs (2.7.0) - faraday (1.1.0) + faraday (1.3.0) + faraday-net_http (~> 1.0) multipart-post (>= 1.2, < 3) ruby2_keywords - ffi (1.13.1) + faraday-net_http (1.0.1) + ffi (1.15.0) + ffi (1.15.0-x64-mingw32) globalid (0.4.2) activesupport (>= 4.2.0) hashie (4.1.0) - i18n (1.8.5) + i18n (1.8.9) concurrent-ruby (~> 1.0) io-like (0.3.1) - jbuilder (2.10.1) + jbuilder (2.10.2) activesupport (>= 5.0.0) - json (2.3.1) + json (2.5.1) jwt (2.2.2) listen (3.2.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.7.0) + loofah (2.9.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -128,35 +132,36 @@ GEM marcel (0.3.3) mimemagic (~> 0.3.2) method_source (0.9.2) - mimemagic (0.3.10) - nokogiri (~> 1) - rake + mimemagic (0.3.5) mini_mime (1.0.2) mini_portile2 (2.5.0) - minitest (5.14.2) - msgpack (1.3.3) + minitest (5.14.4) + msgpack (1.4.2) multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) - nio4r (2.5.4) - nokogiri (1.11.3) + nio4r (2.5.7) + nokogiri (1.11.2) mini_portile2 (~> 2.5.0) racc (~> 1.4) - oauth2 (1.4.4) + nokogiri (1.11.2-x64-mingw32) + racc (~> 1.4) + oauth2 (1.4.7) faraday (>= 0.8, < 2.0) jwt (>= 1.0, < 3.0) multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - omniauth (1.9.1) + omniauth (2.0.3) hashie (>= 3.4.6) rack (>= 1.6.2, < 3) - omniauth-oauth2 (1.7.0) + rack-protection + omniauth-oauth2 (1.7.1) oauth2 (~> 1.4) - omniauth (~> 1.9) - omniauth-rails_csrf_protection (0.1.2) + omniauth (>= 1.9, < 3) + omniauth-rails_csrf_protection (1.0.0) actionpack (>= 4.2) - omniauth (>= 1.3.1) + omniauth (~> 2.0) pry (0.12.2) coderay (~> 1.1.0) method_source (~> 0.9.0) @@ -165,49 +170,53 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.6) - puma (4.3.6) + puma (4.3.7) nio4r (~> 2.0) racc (1.5.2) rack (2.2.3) + rack-protection (2.1.0) + rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.0.3.4) - actioncable (= 6.0.3.4) - actionmailbox (= 6.0.3.4) - actionmailer (= 6.0.3.4) - actionpack (= 6.0.3.4) - actiontext (= 6.0.3.4) - actionview (= 6.0.3.4) - activejob (= 6.0.3.4) - activemodel (= 6.0.3.4) - activerecord (= 6.0.3.4) - activestorage (= 6.0.3.4) - activesupport (= 6.0.3.4) + rails (6.0.3.5) + actioncable (= 6.0.3.5) + actionmailbox (= 6.0.3.5) + actionmailer (= 6.0.3.5) + actionpack (= 6.0.3.5) + actiontext (= 6.0.3.5) + actionview (= 6.0.3.5) + activejob (= 6.0.3.5) + activemodel (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) bundler (>= 1.3.0) - railties (= 6.0.3.4) + railties (= 6.0.3.5) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) - railties (6.0.3.4) - actionpack (= 6.0.3.4) - activesupport (= 6.0.3.4) + railties (6.0.3.5) + actionpack (= 6.0.3.5) + activesupport (= 6.0.3.5) method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) - rake (13.0.1) + rake (13.0.3) rb-fsevent (0.10.4) rb-inotify (0.10.1) ffi (~> 1.0) regexp_parser (1.8.2) - ruby2_keywords (0.0.2) + ruby2_keywords (0.0.4) rubyzip (2.3.0) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) sassc (2.4.0) ffi (~> 1.9) + sassc (2.4.0-x64-mingw32) + ffi (~> 1.9) sassc-rails (2.1.2) railties (>= 4.0.0) sassc (>= 2.0) @@ -229,7 +238,7 @@ GEM activesupport (>= 4.0) sprockets (>= 3.0.0) sqlite3 (1.4.2) - thor (1.0.1) + thor (1.1.0) thread_safe (0.3.6) tilt (2.0.10) turbolinks (5.2.1) @@ -237,10 +246,13 @@ GEM turbolinks-source (5.2.0) typhoeus (1.4.0) ethon (>= 0.9.0) - tzinfo (1.2.7) + tzinfo (1.2.9) thread_safe (~> 0.1) + tzinfo-data (1.2019.3) + tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) + wdm (0.1.1) web-console (4.0.4) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -251,28 +263,29 @@ GEM websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.4.0) + zeitwerk (2.4.2) PLATFORMS ruby + x64-mingw32 DEPENDENCIES - bootsnap (~> 1.4.5) + bootsnap (>= 1.1.0, < 1.4.2) byebug (~> 11.1.1) capybara (~> 3.31.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_click + docusign_click (~> 1.0.0) docusign_esign (~> 3.8.0.rc1) docusign_rooms (~> 1.1.0.rc1) jbuilder (~> 2.10.0) listen (~> 3.2.1) - omniauth-oauth2 (~> 1.6) + omniauth-oauth2 (~> 1.7.1) omniauth-rails_csrf_protection pry-nav (~> 0.3.0) pry-rails (~> 0.3.9) puma (~> 4.3.3) - rails (~> 6.0.3.3) + rails (~> 6.0.3.5) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) spring (~> 2.1.0) @@ -285,7 +298,7 @@ DEPENDENCIES web-console (~> 4.0.1) RUBY VERSION - ruby 2.7.1p83 + ruby 2.7.2p137 BUNDLED WITH - 2.1.4 + 2.1.4 \ No newline at end of file diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index e3e6bb7..462409f 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -33,7 +33,7 @@ def self.consent_url(state) def initialize(session) @session = session @api_client = create_initial_api_client(host: Rails.configuration.aud, debugging: false) - @scope = "signature" + scope = "signature" if Rails.configuration.examples_API['Rooms'] == true scope = "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" elsif Rails.configuration.examples_API['Click'] == true From 9f912d9716ba415a367498daf99b4fea61fcf984 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Wed, 21 Apr 2021 08:23:30 -0700 Subject: [PATCH 054/363] Devdocs 4539 (#23) * fix JWT error in eSignature examples --- Gemfile | 10 +- Gemfile.lock | 183 ++++++++++++++------------- app/services/jwt_auth/jwt_creator.rb | 2 +- 3 files changed, 104 insertions(+), 91 deletions(-) diff --git a/Gemfile b/Gemfile index 4ed9224..cf0c79a 100644 --- a/Gemfile +++ b/Gemfile @@ -3,10 +3,10 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '2.7.1' +ruby '2.7.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 6.0.3.3' +gem 'rails', '~> 6.0.3.5' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4.2' # Use Puma as the app server @@ -36,7 +36,7 @@ gem 'jbuilder', '~> 2.10.0' # gem 'capistrano-rails', group: :development # Reduces boot times through caching; required in config/boot.rb -gem 'bootsnap', '~> 1.4.5', require: false +gem 'bootsnap', '~> 1.7.3', require: false group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console @@ -64,8 +64,8 @@ end gem 'docusign_esign', '~> 3.8.0.rc1' gem 'docusign_rooms', '~> 1.1.0.rc1' -gem 'docusign_click' -gem 'omniauth-oauth2', '~> 1.6' +gem 'docusign_click', '~> 1.0.0' +gem 'omniauth-oauth2', '~> 1.7.1' gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem diff --git a/Gemfile.lock b/Gemfile.lock index 3f16e3f..76798cd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,56 +1,56 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.3.4) - actionpack (= 6.0.3.4) + actioncable (6.0.3.5) + actionpack (= 6.0.3.5) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.3.4) - actionpack (= 6.0.3.4) - activejob (= 6.0.3.4) - activerecord (= 6.0.3.4) - activestorage (= 6.0.3.4) - activesupport (= 6.0.3.4) + actionmailbox (6.0.3.5) + actionpack (= 6.0.3.5) + activejob (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) mail (>= 2.7.1) - actionmailer (6.0.3.4) - actionpack (= 6.0.3.4) - actionview (= 6.0.3.4) - activejob (= 6.0.3.4) + actionmailer (6.0.3.5) + actionpack (= 6.0.3.5) + actionview (= 6.0.3.5) + activejob (= 6.0.3.5) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.3.4) - actionview (= 6.0.3.4) - activesupport (= 6.0.3.4) + actionpack (6.0.3.5) + actionview (= 6.0.3.5) + activesupport (= 6.0.3.5) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.3.4) - actionpack (= 6.0.3.4) - activerecord (= 6.0.3.4) - activestorage (= 6.0.3.4) - activesupport (= 6.0.3.4) + actiontext (6.0.3.5) + actionpack (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) nokogiri (>= 1.8.5) - actionview (6.0.3.4) - activesupport (= 6.0.3.4) + actionview (6.0.3.5) + activesupport (= 6.0.3.5) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.3.4) - activesupport (= 6.0.3.4) + activejob (6.0.3.5) + activesupport (= 6.0.3.5) globalid (>= 0.3.6) - activemodel (6.0.3.4) - activesupport (= 6.0.3.4) - activerecord (6.0.3.4) - activemodel (= 6.0.3.4) - activesupport (= 6.0.3.4) - activestorage (6.0.3.4) - actionpack (= 6.0.3.4) - activejob (= 6.0.3.4) - activerecord (= 6.0.3.4) + activemodel (6.0.3.5) + activesupport (= 6.0.3.5) + activerecord (6.0.3.5) + activemodel (= 6.0.3.5) + activesupport (= 6.0.3.5) + activestorage (6.0.3.5) + actionpack (= 6.0.3.5) + activejob (= 6.0.3.5) + activerecord (= 6.0.3.5) marcel (~> 0.3.1) - activesupport (6.0.3.4) + activesupport (6.0.3.5) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -61,7 +61,7 @@ GEM archive-zip (0.12.0) io-like (~> 0.3.0) bindex (0.8.1) - bootsnap (1.4.8) + bootsnap (1.4.1) msgpack (~> 1.0) builder (3.2.4) byebug (11.1.3) @@ -85,9 +85,10 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.1.7) + concurrent-ruby (1.1.8) crass (1.0.6) - docusign_click (1.0.0.beta2) + docusign_click (1.0.0) + addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) @@ -99,28 +100,31 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - erubi (1.9.0) + erubi (1.10.0) ethon (0.12.0) ffi (>= 1.3.0) execjs (2.7.0) - faraday (1.1.0) + faraday (1.3.0) + faraday-net_http (~> 1.0) multipart-post (>= 1.2, < 3) ruby2_keywords - ffi (1.13.1) + faraday-net_http (1.0.1) + ffi (1.15.0) + ffi (1.15.0-x64-mingw32) globalid (0.4.2) activesupport (>= 4.2.0) hashie (4.1.0) - i18n (1.8.5) + i18n (1.8.9) concurrent-ruby (~> 1.0) io-like (0.3.1) - jbuilder (2.10.1) + jbuilder (2.10.2) activesupport (>= 5.0.0) - json (2.3.1) + json (2.5.1) jwt (2.2.2) listen (3.2.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.7.0) + loofah (2.9.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -128,35 +132,36 @@ GEM marcel (0.3.3) mimemagic (~> 0.3.2) method_source (0.9.2) - mimemagic (0.3.10) - nokogiri (~> 1) - rake + mimemagic (0.3.5) mini_mime (1.0.2) mini_portile2 (2.5.0) - minitest (5.14.2) - msgpack (1.3.3) + minitest (5.14.4) + msgpack (1.4.2) multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) - nio4r (2.5.4) - nokogiri (1.11.3) + nio4r (2.5.7) + nokogiri (1.11.2) mini_portile2 (~> 2.5.0) racc (~> 1.4) - oauth2 (1.4.4) + nokogiri (1.11.2-x64-mingw32) + racc (~> 1.4) + oauth2 (1.4.7) faraday (>= 0.8, < 2.0) jwt (>= 1.0, < 3.0) multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - omniauth (1.9.1) + omniauth (2.0.3) hashie (>= 3.4.6) rack (>= 1.6.2, < 3) - omniauth-oauth2 (1.7.0) + rack-protection + omniauth-oauth2 (1.7.1) oauth2 (~> 1.4) - omniauth (~> 1.9) - omniauth-rails_csrf_protection (0.1.2) + omniauth (>= 1.9, < 3) + omniauth-rails_csrf_protection (1.0.0) actionpack (>= 4.2) - omniauth (>= 1.3.1) + omniauth (~> 2.0) pry (0.12.2) coderay (~> 1.1.0) method_source (~> 0.9.0) @@ -165,49 +170,53 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.6) - puma (4.3.6) + puma (4.3.7) nio4r (~> 2.0) racc (1.5.2) rack (2.2.3) + rack-protection (2.1.0) + rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.0.3.4) - actioncable (= 6.0.3.4) - actionmailbox (= 6.0.3.4) - actionmailer (= 6.0.3.4) - actionpack (= 6.0.3.4) - actiontext (= 6.0.3.4) - actionview (= 6.0.3.4) - activejob (= 6.0.3.4) - activemodel (= 6.0.3.4) - activerecord (= 6.0.3.4) - activestorage (= 6.0.3.4) - activesupport (= 6.0.3.4) + rails (6.0.3.5) + actioncable (= 6.0.3.5) + actionmailbox (= 6.0.3.5) + actionmailer (= 6.0.3.5) + actionpack (= 6.0.3.5) + actiontext (= 6.0.3.5) + actionview (= 6.0.3.5) + activejob (= 6.0.3.5) + activemodel (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) bundler (>= 1.3.0) - railties (= 6.0.3.4) + railties (= 6.0.3.5) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) - railties (6.0.3.4) - actionpack (= 6.0.3.4) - activesupport (= 6.0.3.4) + railties (6.0.3.5) + actionpack (= 6.0.3.5) + activesupport (= 6.0.3.5) method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) - rake (13.0.1) + rake (13.0.3) rb-fsevent (0.10.4) rb-inotify (0.10.1) ffi (~> 1.0) regexp_parser (1.8.2) - ruby2_keywords (0.0.2) + ruby2_keywords (0.0.4) rubyzip (2.3.0) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) sassc (2.4.0) ffi (~> 1.9) + sassc (2.4.0-x64-mingw32) + ffi (~> 1.9) sassc-rails (2.1.2) railties (>= 4.0.0) sassc (>= 2.0) @@ -229,7 +238,7 @@ GEM activesupport (>= 4.0) sprockets (>= 3.0.0) sqlite3 (1.4.2) - thor (1.0.1) + thor (1.1.0) thread_safe (0.3.6) tilt (2.0.10) turbolinks (5.2.1) @@ -237,10 +246,13 @@ GEM turbolinks-source (5.2.0) typhoeus (1.4.0) ethon (>= 0.9.0) - tzinfo (1.2.7) + tzinfo (1.2.9) thread_safe (~> 0.1) + tzinfo-data (1.2019.3) + tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) + wdm (0.1.1) web-console (4.0.4) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -251,28 +263,29 @@ GEM websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.4.0) + zeitwerk (2.4.2) PLATFORMS ruby + x64-mingw32 DEPENDENCIES - bootsnap (~> 1.4.5) + bootsnap (>= 1.1.0, < 1.4.2) byebug (~> 11.1.1) capybara (~> 3.31.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_click + docusign_click (~> 1.0.0) docusign_esign (~> 3.8.0.rc1) docusign_rooms (~> 1.1.0.rc1) jbuilder (~> 2.10.0) listen (~> 3.2.1) - omniauth-oauth2 (~> 1.6) + omniauth-oauth2 (~> 1.7.1) omniauth-rails_csrf_protection pry-nav (~> 0.3.0) pry-rails (~> 0.3.9) puma (~> 4.3.3) - rails (~> 6.0.3.3) + rails (~> 6.0.3.5) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) spring (~> 2.1.0) @@ -285,7 +298,7 @@ DEPENDENCIES web-console (~> 4.0.1) RUBY VERSION - ruby 2.7.1p83 + ruby 2.7.2p137 BUNDLED WITH - 2.1.4 + 2.1.4 \ No newline at end of file diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index e3e6bb7..462409f 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -33,7 +33,7 @@ def self.consent_url(state) def initialize(session) @session = session @api_client = create_initial_api_client(host: Rails.configuration.aud, debugging: false) - @scope = "signature" + scope = "signature" if Rails.configuration.examples_API['Rooms'] == true scope = "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" elsif Rails.configuration.examples_API['Click'] == true From 97a8d5a3fc477b1c863992b595c194a25169986b Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Wed, 21 Apr 2021 08:39:34 -0700 Subject: [PATCH 055/363] Update from main (#32) Update from Main --- Gemfile | 4 +- Gemfile.lock | 52 ++++++++++--------- README.md | 4 -- app/controllers/ds_common_controller.rb | 3 +- app/services/api_creator.rb | 11 ++-- .../e_sign/eg007_envelope_get_doc_service.rb | 5 +- app/services/jwt_auth/jwt_creator.rb | 10 ++-- 7 files changed, 45 insertions(+), 44 deletions(-) diff --git a/Gemfile b/Gemfile index 89d7d58..72fb506 100644 --- a/Gemfile +++ b/Gemfile @@ -36,7 +36,7 @@ gem 'jbuilder', '~> 2.10.0' # gem 'capistrano-rails', group: :development # Reduces boot times through caching; required in config/boot.rb -gem 'bootsnap', '~> 1.4.5', require: false +gem 'bootsnap', '~> 1.7.3', require: false group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console @@ -70,4 +70,4 @@ gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', '~> 1.2019.3', platforms: %i[mingw mswin x64_mingw jruby] -gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] +gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index d84c396..a9a9ab2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -61,7 +61,7 @@ GEM archive-zip (0.12.0) io-like (~> 0.3.0) bindex (0.8.1) - bootsnap (1.4.8) + bootsnap (1.4.1) msgpack (~> 1.0) builder (3.2.4) byebug (11.1.3) @@ -85,7 +85,7 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.1.7) + concurrent-ruby (1.1.8) crass (1.0.6) docusign_click (1.0.0) addressable (~> 2.7, >= 2.7.0) @@ -100,7 +100,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - erubi (1.9.0) + erubi (1.10.0) ethon (0.12.0) ffi (>= 1.3.0) execjs (2.7.0) @@ -109,22 +109,22 @@ GEM multipart-post (>= 1.2, < 3) ruby2_keywords faraday-net_http (1.0.1) - ffi (1.13.1) - ffi (1.13.1-x64-mingw32) + ffi (1.15.0) + ffi (1.15.0-x64-mingw32) globalid (0.4.2) activesupport (>= 4.2.0) hashie (4.1.0) - i18n (1.8.5) + i18n (1.8.9) concurrent-ruby (~> 1.0) io-like (0.3.1) - jbuilder (2.10.1) + jbuilder (2.10.2) activesupport (>= 5.0.0) - json (2.3.1) + json (2.5.1) jwt (2.2.2) listen (3.2.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.7.0) + loofah (2.9.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -135,33 +135,33 @@ GEM mimemagic (0.3.5) mini_mime (1.0.2) mini_portile2 (2.5.0) - minitest (5.14.2) - msgpack (1.3.3) - msgpack (1.3.3-x64-mingw32) + minitest (5.14.4) + msgpack (1.4.2) multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) - nio4r (2.5.4) - nokogiri (1.11.1) + nio4r (2.5.7) + nokogiri (1.11.2) mini_portile2 (~> 2.5.0) racc (~> 1.4) - nokogiri (1.11.1-x64-mingw32) + nokogiri (1.11.2-x64-mingw32) racc (~> 1.4) - oauth2 (1.4.4) + oauth2 (1.4.7) faraday (>= 0.8, < 2.0) jwt (>= 1.0, < 3.0) multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - omniauth (1.9.1) + omniauth (2.0.3) hashie (>= 3.4.6) rack (>= 1.6.2, < 3) + rack-protection omniauth-oauth2 (1.7.1) oauth2 (~> 1.4) omniauth (>= 1.9, < 3) - omniauth-rails_csrf_protection (0.1.2) + omniauth-rails_csrf_protection (1.0.0) actionpack (>= 4.2) - omniauth (>= 1.3.1) + omniauth (~> 2.0) pry (0.12.2) coderay (~> 1.1.0) method_source (~> 0.9.0) @@ -170,10 +170,12 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.6) - puma (4.3.6) + puma (4.3.7) nio4r (~> 2.0) racc (1.5.2) rack (2.2.3) + rack-protection (2.1.0) + rack rack-test (1.1.0) rack (>= 1.0, < 3) rails (6.0.3.5) @@ -202,7 +204,7 @@ GEM method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) - rake (13.0.1) + rake (13.0.3) rb-fsevent (0.10.4) rb-inotify (0.10.1) ffi (~> 1.0) @@ -236,7 +238,7 @@ GEM activesupport (>= 4.0) sprockets (>= 3.0.0) sqlite3 (1.4.2) - thor (1.0.1) + thor (1.1.0) thread_safe (0.3.6) tilt (2.0.10) turbolinks (5.2.1) @@ -244,7 +246,7 @@ GEM turbolinks-source (5.2.0) typhoeus (1.4.0) ethon (>= 0.9.0) - tzinfo (1.2.7) + tzinfo (1.2.9) thread_safe (~> 0.1) tzinfo-data (1.2019.3) tzinfo (>= 1.0.0) @@ -261,14 +263,14 @@ GEM websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.4.0) + zeitwerk (2.4.2) PLATFORMS ruby x64-mingw32 DEPENDENCIES - bootsnap (~> 1.4.5) + bootsnap (>= 1.1.0, < 1.4.2) byebug (~> 11.1.1) capybara (~> 3.31.0) chromedriver-helper (~> 2.1.1) diff --git a/README.md b/README.md index 3e3358b..6d05d5b 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,6 @@ ### Github repo: https://github.com/docusign/code-examples-ruby - -This GitHub repo includes code examples for DocuSign APIs. - To switch between API code examples, modify the `examples_API` setting at the end of the configuration file. Set only one API type to `true` and set the remaining to `false`. If none of the API types are set to `true`, the DocuSign eSignature REST API code examples will be shown. If multiple API types are set to `true`, only the first will be shown. @@ -313,7 +310,6 @@ To use the payments code example, create a test payment gateway on the [**Paymen Once you've created a payment gateway, save the **Gateway Account ID** GUID to appsettings.yml. - ## License and additional information ### License diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index 9d366c4..26e4e7b 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -44,7 +44,8 @@ def ds_must_authenticate url = root_path end else - url = JwtAuth::JwtCreator.consent_url + session['omniauth.state'] = SecureRandom.hex + url = JwtAuth::JwtCreator.consent_url(session['omniauth.state']) redirect_to root_path if session[:token].present? end if Rails.configuration.examples_API['Rooms'] == true diff --git a/app/services/api_creator.rb b/app/services/api_creator.rb index 6e3d04c..3cc5b29 100644 --- a/app/services/api_creator.rb +++ b/app/services/api_creator.rb @@ -13,15 +13,15 @@ def create_initial_api_client(host: nil, debugging: false) end def create_account_api(args) - # Step 1. Obtain your OAuth token + # Obtain your OAuth token configuration = DocuSign_eSign::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_eSign::ApiClient.new configuration - # Step 2. Construct your API headers + # Construct your API headers api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" - # Step 3: Construct your request body + # Construct your request body accounts_api = DocuSign_eSign::AccountsApi.new api_client end @@ -34,13 +34,14 @@ def create_template_api(args) end def create_envelope_api(args) - # Step 1. Obtain your OAuth token + # Obtain your OAuth token + # Step 2 start configuration = DocuSign_eSign::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_eSign::ApiClient.new configuration - # Step 2. Construct your API headers api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" + # Step 2 end DocuSign_eSign::EnvelopesApi.new api_client end diff --git a/app/services/e_sign/eg007_envelope_get_doc_service.rb b/app/services/e_sign/eg007_envelope_get_doc_service.rb index 9baace9..441470c 100644 --- a/app/services/e_sign/eg007_envelope_get_doc_service.rb +++ b/app/services/e_sign/eg007_envelope_get_doc_service.rb @@ -22,13 +22,14 @@ def call private - # ***DS.snippet.0.start def worker + # Step 3 start envelope_api = create_envelope_api(args) document_id = args['document_id'] temp_file = envelope_api.get_document args[:account_id], document_id, args[:envelope_id] + # Step 3 end # Find the matching document information item doc_item = args['envelope_documents']['documents'].find { |item| item['document_id'] == document_id } @@ -53,4 +54,4 @@ def worker end { 'mime_type' => mime_type, 'doc_name' => doc_name, 'data' => File.binread(temp_file.path) } end -end \ No newline at end of file +end diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index dae03df..462409f 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -4,12 +4,12 @@ module JwtAuth class JwtCreator include ApiCreator - attr_reader :session, :api_client + attr_reader :session, :api_client, :state # DocuSign authorization URI to obtain individual consent # https://developers.docusign.com/platform/auth/jwt/jwt-get-token # https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/ - def self.consent_url + def self.consent_url(state) # GET /oauth/auth # This endpoint is used to obtain consent and is the first step in several authentication flows. # https://developers.docusign.com/platform/auth/reference/obtain-consent @@ -24,8 +24,8 @@ def self.consent_url response_type = "code" scopes = ERB::Util.url_encode(scope) # https://developers.docusign.com/platform/auth/reference/scopes/ client_id = Rails.configuration.jwt_integration_key - redirect_uri = Rails.configuration.app_url - consent_url = "#{base_uri}?response_type=#{response_type}&scope=#{scopes}&client_id=#{client_id}&redirect_uri=#{redirect_uri}" + redirect_uri = "#{Rails.configuration.app_url}/auth/docusign/callback" + consent_url = "#{base_uri}?response_type=#{response_type}&scope=#{scopes}&client_id=#{client_id}&state=#{state}&redirect_uri=#{redirect_uri}" Rails.logger.info "==> Obtain Consent Grant required: #{consent_url}" consent_url end @@ -33,7 +33,7 @@ def self.consent_url def initialize(session) @session = session @api_client = create_initial_api_client(host: Rails.configuration.aud, debugging: false) - @scope = "signature" + scope = "signature" if Rails.configuration.examples_API['Rooms'] == true scope = "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" elsif Rails.configuration.examples_API['Click'] == true From 5da736564ee015e9d401a42d505839d7acdbc086 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Wed, 21 Apr 2021 11:29:49 -0700 Subject: [PATCH 056/363] update gemfile --- .ruby-version | 2 +- Gemfile | 142 +++++++++++++++++++++++++------------------------- Gemfile.lock | 140 +++++++++++++++++++++++++------------------------ 3 files changed, 143 insertions(+), 141 deletions(-) diff --git a/.ruby-version b/.ruby-version index 5588ae8..fbafd6b 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.7.1 \ No newline at end of file +2.7.2 \ No newline at end of file diff --git a/Gemfile b/Gemfile index 72fb506..3919792 100644 --- a/Gemfile +++ b/Gemfile @@ -1,73 +1,73 @@ # frozen_string_literal: true -source 'https://rubygems.org' -git_source(:github) { |repo| "https://github.com/#{repo}.git" } - -ruby '2.7.2' - -# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 6.0.3.5' -# Use sqlite3 as the database for Active Record -gem 'sqlite3', '~> 1.4.2' -# Use Puma as the app server -gem 'puma', '~> 4.3.3' -# Use SCSS for stylesheets -gem 'sass-rails', '~> 6.0.0' -# Use Uglifier as compressor for JavaScript assets -gem 'uglifier', '~> 4.2.0' -# See https://github.com/rails/execjs#readme for more supported runtimes -# gem 'mini_racer', platforms: :ruby - -# Use CoffeeScript for .coffee assets and views -gem 'coffee-rails', '~> 5.0.0' -# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks -gem 'turbolinks', '~> 5.2.1' -# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder -gem 'jbuilder', '~> 2.10.0' -# Use Redis adapter to run Action Cable in production -# gem 'redis', '~> 4.0' -# Use ActiveModel has_secure_password -# gem 'bcrypt', '~> 3.1.7' - -# Use ActiveStorage variant -# gem 'mini_magick', '~> 4.8' - -# Use Capistrano for deployment -# gem 'capistrano-rails', group: :development - -# Reduces boot times through caching; required in config/boot.rb -gem 'bootsnap', '~> 1.7.3', require: false - -group :development, :test do - # Call 'byebug' anywhere in the code to stop execution and get a debugger console - gem 'byebug', '~> 11.1.1', platforms: %i[mri mingw x64_mingw] -end - -group :development do - # Access an interactive console on exception pages or by calling 'console' anywhere in the code. - gem 'listen', '~> 3.2.1' - gem 'web-console', '~> 4.0.1' - # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring - gem 'pry-nav', '~> 0.3.0' - gem 'pry-rails', '~> 0.3.9' - gem 'spring', '~> 2.1.0' - gem 'spring-watcher-listen', '~> 2.0.1' -end - -group :test do - # Adds support for Capybara system testing and selenium driver - gem 'capybara', '~> 3.31.0' - gem 'selenium-webdriver', '~> 3.142.7' - # Easy installation and use of chromedriver to run system tests with Chrome - gem 'chromedriver-helper', '~> 2.1.1' -end - -gem 'docusign_esign', '~> 3.8.0.rc1' -gem 'docusign_rooms', '~> 1.1.0.rc1' -gem 'docusign_click', '~> 1.0.0' -gem 'omniauth-oauth2', '~> 1.7.1' -gem 'omniauth-rails_csrf_protection' - -# Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem 'tzinfo-data', '~> 1.2019.3', platforms: %i[mingw mswin x64_mingw jruby] -gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] \ No newline at end of file + source 'https://rubygems.org' + git_source(:github) { |repo| "https://github.com/#{repo}.git" } + + ruby '2.7.2' + + # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' + gem 'rails', '~> 6.0.3.5' + # Use sqlite3 as the database for Active Record + gem 'sqlite3', '~> 1.4.2' + # Use Puma as the app server + gem 'puma', '~> 4.3.3' + # Use SCSS for stylesheets + gem 'sass-rails', '~> 6.0.0' + # Use Uglifier as compressor for JavaScript assets + gem 'uglifier', '~> 4.2.0' + # See https://github.com/rails/execjs#readme for more supported runtimes + # gem 'mini_racer', platforms: :ruby + + # Use CoffeeScript for .coffee assets and views + gem 'coffee-rails', '~> 5.0.0' + # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks + gem 'turbolinks', '~> 5.2.1' + # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder + gem 'jbuilder', '~> 2.10.0' + # Use Redis adapter to run Action Cable in production + # gem 'redis', '~> 4.0' + # Use ActiveModel has_secure_password + # gem 'bcrypt', '~> 3.1.7' + + # Use ActiveStorage variant + # gem 'mini_magick', '~> 4.8' + + # Use Capistrano for deployment + # gem 'capistrano-rails', group: :development + + # Reduces boot times through caching; required in config/boot.rb + gem 'bootsnap', '~> 1.7.3', require: false + + group :development, :test do + # Call 'byebug' anywhere in the code to stop execution and get a debugger console + gem 'byebug', '~> 11.1.1', platforms: %i[mri mingw x64_mingw] + end + + group :development do + # Access an interactive console on exception pages or by calling 'console' anywhere in the code. + gem 'listen', '~> 3.2.1' + gem 'web-console', '~> 4.0.1' + # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring + gem 'pry-nav', '~> 0.3.0' + gem 'pry-rails', '~> 0.3.9' + gem 'spring', '~> 2.1.0' + gem 'spring-watcher-listen', '~> 2.0.1' + end + + group :test do + # Adds support for Capybara system testing and selenium driver + gem 'capybara', '~> 3.31.0' + gem 'selenium-webdriver', '~> 3.142.7' + # Easy installation and use of chromedriver to run system tests with Chrome + gem 'chromedriver-helper', '~> 2.1.1' + end + + gem 'docusign_esign', '~> 3.8.0.rc1' + gem 'docusign_rooms', '~> 1.1.0.rc1' + gem 'docusign_click', '~> 1.0.0' + gem 'omniauth-oauth2', '~> 1.7.1' + gem 'omniauth-rails_csrf_protection' + + # Windows does not include zoneinfo files, so bundle the tzinfo-data gem + gem 'tzinfo-data', '~> 1.2019.3', platforms: %i[mingw mswin x64_mingw jruby] + gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index a9a9ab2..594b67d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,56 +1,56 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.3.5) - actionpack (= 6.0.3.5) + actioncable (6.0.3.6) + actionpack (= 6.0.3.6) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.3.5) - actionpack (= 6.0.3.5) - activejob (= 6.0.3.5) - activerecord (= 6.0.3.5) - activestorage (= 6.0.3.5) - activesupport (= 6.0.3.5) + actionmailbox (6.0.3.6) + actionpack (= 6.0.3.6) + activejob (= 6.0.3.6) + activerecord (= 6.0.3.6) + activestorage (= 6.0.3.6) + activesupport (= 6.0.3.6) mail (>= 2.7.1) - actionmailer (6.0.3.5) - actionpack (= 6.0.3.5) - actionview (= 6.0.3.5) - activejob (= 6.0.3.5) + actionmailer (6.0.3.6) + actionpack (= 6.0.3.6) + actionview (= 6.0.3.6) + activejob (= 6.0.3.6) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.3.5) - actionview (= 6.0.3.5) - activesupport (= 6.0.3.5) + actionpack (6.0.3.6) + actionview (= 6.0.3.6) + activesupport (= 6.0.3.6) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.3.5) - actionpack (= 6.0.3.5) - activerecord (= 6.0.3.5) - activestorage (= 6.0.3.5) - activesupport (= 6.0.3.5) + actiontext (6.0.3.6) + actionpack (= 6.0.3.6) + activerecord (= 6.0.3.6) + activestorage (= 6.0.3.6) + activesupport (= 6.0.3.6) nokogiri (>= 1.8.5) - actionview (6.0.3.5) - activesupport (= 6.0.3.5) + actionview (6.0.3.6) + activesupport (= 6.0.3.6) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.3.5) - activesupport (= 6.0.3.5) + activejob (6.0.3.6) + activesupport (= 6.0.3.6) globalid (>= 0.3.6) - activemodel (6.0.3.5) - activesupport (= 6.0.3.5) - activerecord (6.0.3.5) - activemodel (= 6.0.3.5) - activesupport (= 6.0.3.5) - activestorage (6.0.3.5) - actionpack (= 6.0.3.5) - activejob (= 6.0.3.5) - activerecord (= 6.0.3.5) - marcel (~> 0.3.1) - activesupport (6.0.3.5) + activemodel (6.0.3.6) + activesupport (= 6.0.3.6) + activerecord (6.0.3.6) + activemodel (= 6.0.3.6) + activesupport (= 6.0.3.6) + activestorage (6.0.3.6) + actionpack (= 6.0.3.6) + activejob (= 6.0.3.6) + activerecord (= 6.0.3.6) + marcel (~> 1.0.0) + activesupport (6.0.3.6) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -61,7 +61,7 @@ GEM archive-zip (0.12.0) io-like (~> 0.3.0) bindex (0.8.1) - bootsnap (1.4.1) + bootsnap (1.7.4) msgpack (~> 1.0) builder (3.2.4) byebug (11.1.3) @@ -96,44 +96,46 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_rooms (1.1.0.rc1) + docusign_rooms (1.1.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) erubi (1.10.0) - ethon (0.12.0) - ffi (>= 1.3.0) + ethon (0.13.0) + ffi (>= 1.15.0) execjs (2.7.0) - faraday (1.3.0) + faraday (1.4.1) + faraday-excon (~> 1.1) faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.1) multipart-post (>= 1.2, < 3) - ruby2_keywords + ruby2_keywords (>= 0.0.4) + faraday-excon (1.1.0) faraday-net_http (1.0.1) + faraday-net_http_persistent (1.1.0) ffi (1.15.0) ffi (1.15.0-x64-mingw32) globalid (0.4.2) activesupport (>= 4.2.0) hashie (4.1.0) - i18n (1.8.9) + i18n (1.8.10) concurrent-ruby (~> 1.0) io-like (0.3.1) jbuilder (2.10.2) activesupport (>= 5.0.0) json (2.5.1) - jwt (2.2.2) + jwt (2.2.3) listen (3.2.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.9.0) + loofah (2.9.1) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) - marcel (0.3.3) - mimemagic (~> 0.3.2) + marcel (1.0.1) method_source (0.9.2) - mimemagic (0.3.5) - mini_mime (1.0.2) + mini_mime (1.1.0) mini_portile2 (2.5.0) minitest (5.14.4) msgpack (1.4.2) @@ -141,10 +143,10 @@ GEM multi_xml (0.6.0) multipart-post (2.1.1) nio4r (2.5.7) - nokogiri (1.11.2) + nokogiri (1.11.3) mini_portile2 (~> 2.5.0) racc (~> 1.4) - nokogiri (1.11.2-x64-mingw32) + nokogiri (1.11.3-x64-mingw32) racc (~> 1.4) oauth2 (1.4.7) faraday (>= 0.8, < 2.0) @@ -152,7 +154,7 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - omniauth (2.0.3) + omniauth (2.0.4) hashie (>= 3.4.6) rack (>= 1.6.2, < 3) rack-protection @@ -178,29 +180,29 @@ GEM rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.0.3.5) - actioncable (= 6.0.3.5) - actionmailbox (= 6.0.3.5) - actionmailer (= 6.0.3.5) - actionpack (= 6.0.3.5) - actiontext (= 6.0.3.5) - actionview (= 6.0.3.5) - activejob (= 6.0.3.5) - activemodel (= 6.0.3.5) - activerecord (= 6.0.3.5) - activestorage (= 6.0.3.5) - activesupport (= 6.0.3.5) + rails (6.0.3.6) + actioncable (= 6.0.3.6) + actionmailbox (= 6.0.3.6) + actionmailer (= 6.0.3.6) + actionpack (= 6.0.3.6) + actiontext (= 6.0.3.6) + actionview (= 6.0.3.6) + activejob (= 6.0.3.6) + activemodel (= 6.0.3.6) + activerecord (= 6.0.3.6) + activestorage (= 6.0.3.6) + activesupport (= 6.0.3.6) bundler (>= 1.3.0) - railties (= 6.0.3.5) + railties (= 6.0.3.6) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) - railties (6.0.3.5) - actionpack (= 6.0.3.5) - activesupport (= 6.0.3.5) + railties (6.0.3.6) + actionpack (= 6.0.3.6) + activesupport (= 6.0.3.6) method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) @@ -270,7 +272,7 @@ PLATFORMS x64-mingw32 DEPENDENCIES - bootsnap (>= 1.1.0, < 1.4.2) + bootsnap (~> 1.7.3) byebug (~> 11.1.1) capybara (~> 3.31.0) chromedriver-helper (~> 2.1.1) @@ -301,4 +303,4 @@ RUBY VERSION ruby 2.7.2p137 BUNDLED WITH - 2.1.4 + 2.2.16 From e20a822b6aafe343e0d5fea7196ca6d480d49f23 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Wed, 21 Apr 2021 13:00:51 -0700 Subject: [PATCH 057/363] Devdocs 4539 (#33) Update Gemfiles --- .ruby-version | 2 +- Gemfile | 2 +- Gemfile.lock | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.ruby-version b/.ruby-version index 5588ae8..fbafd6b 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.7.1 \ No newline at end of file +2.7.2 \ No newline at end of file diff --git a/Gemfile b/Gemfile index 72fb506..52abc2b 100644 --- a/Gemfile +++ b/Gemfile @@ -36,7 +36,7 @@ gem 'jbuilder', '~> 2.10.0' # gem 'capistrano-rails', group: :development # Reduces boot times through caching; required in config/boot.rb -gem 'bootsnap', '~> 1.7.3', require: false +gem 'bootsnap', '>= 1.1.0', '< 1.4.2', require: false group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console diff --git a/Gemfile.lock b/Gemfile.lock index a9a9ab2..76798cd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -301,4 +301,4 @@ RUBY VERSION ruby 2.7.2p137 BUNDLED WITH - 2.1.4 + 2.1.4 \ No newline at end of file From 920c7c0b60dc9d4dc4cbe146335518650bacd47b Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Wed, 21 Apr 2021 13:02:00 -0700 Subject: [PATCH 058/363] Devdocs 4539 (#34) * update Gemfiles --- Gemfile | 142 +++++++++++++++++++++++++-------------------------- Gemfile.lock | 140 +++++++++++++++++++++++++------------------------- 2 files changed, 140 insertions(+), 142 deletions(-) diff --git a/Gemfile b/Gemfile index 3919792..52abc2b 100644 --- a/Gemfile +++ b/Gemfile @@ -1,73 +1,73 @@ # frozen_string_literal: true - source 'https://rubygems.org' - git_source(:github) { |repo| "https://github.com/#{repo}.git" } - - ruby '2.7.2' - - # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' - gem 'rails', '~> 6.0.3.5' - # Use sqlite3 as the database for Active Record - gem 'sqlite3', '~> 1.4.2' - # Use Puma as the app server - gem 'puma', '~> 4.3.3' - # Use SCSS for stylesheets - gem 'sass-rails', '~> 6.0.0' - # Use Uglifier as compressor for JavaScript assets - gem 'uglifier', '~> 4.2.0' - # See https://github.com/rails/execjs#readme for more supported runtimes - # gem 'mini_racer', platforms: :ruby - - # Use CoffeeScript for .coffee assets and views - gem 'coffee-rails', '~> 5.0.0' - # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks - gem 'turbolinks', '~> 5.2.1' - # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder - gem 'jbuilder', '~> 2.10.0' - # Use Redis adapter to run Action Cable in production - # gem 'redis', '~> 4.0' - # Use ActiveModel has_secure_password - # gem 'bcrypt', '~> 3.1.7' - - # Use ActiveStorage variant - # gem 'mini_magick', '~> 4.8' - - # Use Capistrano for deployment - # gem 'capistrano-rails', group: :development - - # Reduces boot times through caching; required in config/boot.rb - gem 'bootsnap', '~> 1.7.3', require: false - - group :development, :test do - # Call 'byebug' anywhere in the code to stop execution and get a debugger console - gem 'byebug', '~> 11.1.1', platforms: %i[mri mingw x64_mingw] - end - - group :development do - # Access an interactive console on exception pages or by calling 'console' anywhere in the code. - gem 'listen', '~> 3.2.1' - gem 'web-console', '~> 4.0.1' - # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring - gem 'pry-nav', '~> 0.3.0' - gem 'pry-rails', '~> 0.3.9' - gem 'spring', '~> 2.1.0' - gem 'spring-watcher-listen', '~> 2.0.1' - end - - group :test do - # Adds support for Capybara system testing and selenium driver - gem 'capybara', '~> 3.31.0' - gem 'selenium-webdriver', '~> 3.142.7' - # Easy installation and use of chromedriver to run system tests with Chrome - gem 'chromedriver-helper', '~> 2.1.1' - end - - gem 'docusign_esign', '~> 3.8.0.rc1' - gem 'docusign_rooms', '~> 1.1.0.rc1' - gem 'docusign_click', '~> 1.0.0' - gem 'omniauth-oauth2', '~> 1.7.1' - gem 'omniauth-rails_csrf_protection' - - # Windows does not include zoneinfo files, so bundle the tzinfo-data gem - gem 'tzinfo-data', '~> 1.2019.3', platforms: %i[mingw mswin x64_mingw jruby] - gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] \ No newline at end of file +source 'https://rubygems.org' +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby '2.7.2' + +# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' +gem 'rails', '~> 6.0.3.5' +# Use sqlite3 as the database for Active Record +gem 'sqlite3', '~> 1.4.2' +# Use Puma as the app server +gem 'puma', '~> 4.3.3' +# Use SCSS for stylesheets +gem 'sass-rails', '~> 6.0.0' +# Use Uglifier as compressor for JavaScript assets +gem 'uglifier', '~> 4.2.0' +# See https://github.com/rails/execjs#readme for more supported runtimes +# gem 'mini_racer', platforms: :ruby + +# Use CoffeeScript for .coffee assets and views +gem 'coffee-rails', '~> 5.0.0' +# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks +gem 'turbolinks', '~> 5.2.1' +# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder +gem 'jbuilder', '~> 2.10.0' +# Use Redis adapter to run Action Cable in production +# gem 'redis', '~> 4.0' +# Use ActiveModel has_secure_password +# gem 'bcrypt', '~> 3.1.7' + +# Use ActiveStorage variant +# gem 'mini_magick', '~> 4.8' + +# Use Capistrano for deployment +# gem 'capistrano-rails', group: :development + +# Reduces boot times through caching; required in config/boot.rb +gem 'bootsnap', '>= 1.1.0', '< 1.4.2', require: false + +group :development, :test do + # Call 'byebug' anywhere in the code to stop execution and get a debugger console + gem 'byebug', '~> 11.1.1', platforms: %i[mri mingw x64_mingw] +end + +group :development do + # Access an interactive console on exception pages or by calling 'console' anywhere in the code. + gem 'listen', '~> 3.2.1' + gem 'web-console', '~> 4.0.1' + # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring + gem 'pry-nav', '~> 0.3.0' + gem 'pry-rails', '~> 0.3.9' + gem 'spring', '~> 2.1.0' + gem 'spring-watcher-listen', '~> 2.0.1' +end + +group :test do + # Adds support for Capybara system testing and selenium driver + gem 'capybara', '~> 3.31.0' + gem 'selenium-webdriver', '~> 3.142.7' + # Easy installation and use of chromedriver to run system tests with Chrome + gem 'chromedriver-helper', '~> 2.1.1' +end + +gem 'docusign_esign', '~> 3.8.0.rc1' +gem 'docusign_rooms', '~> 1.1.0.rc1' +gem 'docusign_click', '~> 1.0.0' +gem 'omniauth-oauth2', '~> 1.7.1' +gem 'omniauth-rails_csrf_protection' + +# Windows does not include zoneinfo files, so bundle the tzinfo-data gem +gem 'tzinfo-data', '~> 1.2019.3', platforms: %i[mingw mswin x64_mingw jruby] +gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 594b67d..76798cd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,56 +1,56 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.3.6) - actionpack (= 6.0.3.6) + actioncable (6.0.3.5) + actionpack (= 6.0.3.5) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.3.6) - actionpack (= 6.0.3.6) - activejob (= 6.0.3.6) - activerecord (= 6.0.3.6) - activestorage (= 6.0.3.6) - activesupport (= 6.0.3.6) + actionmailbox (6.0.3.5) + actionpack (= 6.0.3.5) + activejob (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) mail (>= 2.7.1) - actionmailer (6.0.3.6) - actionpack (= 6.0.3.6) - actionview (= 6.0.3.6) - activejob (= 6.0.3.6) + actionmailer (6.0.3.5) + actionpack (= 6.0.3.5) + actionview (= 6.0.3.5) + activejob (= 6.0.3.5) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.3.6) - actionview (= 6.0.3.6) - activesupport (= 6.0.3.6) + actionpack (6.0.3.5) + actionview (= 6.0.3.5) + activesupport (= 6.0.3.5) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.3.6) - actionpack (= 6.0.3.6) - activerecord (= 6.0.3.6) - activestorage (= 6.0.3.6) - activesupport (= 6.0.3.6) + actiontext (6.0.3.5) + actionpack (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) nokogiri (>= 1.8.5) - actionview (6.0.3.6) - activesupport (= 6.0.3.6) + actionview (6.0.3.5) + activesupport (= 6.0.3.5) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.3.6) - activesupport (= 6.0.3.6) + activejob (6.0.3.5) + activesupport (= 6.0.3.5) globalid (>= 0.3.6) - activemodel (6.0.3.6) - activesupport (= 6.0.3.6) - activerecord (6.0.3.6) - activemodel (= 6.0.3.6) - activesupport (= 6.0.3.6) - activestorage (6.0.3.6) - actionpack (= 6.0.3.6) - activejob (= 6.0.3.6) - activerecord (= 6.0.3.6) - marcel (~> 1.0.0) - activesupport (6.0.3.6) + activemodel (6.0.3.5) + activesupport (= 6.0.3.5) + activerecord (6.0.3.5) + activemodel (= 6.0.3.5) + activesupport (= 6.0.3.5) + activestorage (6.0.3.5) + actionpack (= 6.0.3.5) + activejob (= 6.0.3.5) + activerecord (= 6.0.3.5) + marcel (~> 0.3.1) + activesupport (6.0.3.5) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -61,7 +61,7 @@ GEM archive-zip (0.12.0) io-like (~> 0.3.0) bindex (0.8.1) - bootsnap (1.7.4) + bootsnap (1.4.1) msgpack (~> 1.0) builder (3.2.4) byebug (11.1.3) @@ -96,46 +96,44 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_rooms (1.1.0) + docusign_rooms (1.1.0.rc1) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) erubi (1.10.0) - ethon (0.13.0) - ffi (>= 1.15.0) + ethon (0.12.0) + ffi (>= 1.3.0) execjs (2.7.0) - faraday (1.4.1) - faraday-excon (~> 1.1) + faraday (1.3.0) faraday-net_http (~> 1.0) - faraday-net_http_persistent (~> 1.1) multipart-post (>= 1.2, < 3) - ruby2_keywords (>= 0.0.4) - faraday-excon (1.1.0) + ruby2_keywords faraday-net_http (1.0.1) - faraday-net_http_persistent (1.1.0) ffi (1.15.0) ffi (1.15.0-x64-mingw32) globalid (0.4.2) activesupport (>= 4.2.0) hashie (4.1.0) - i18n (1.8.10) + i18n (1.8.9) concurrent-ruby (~> 1.0) io-like (0.3.1) jbuilder (2.10.2) activesupport (>= 5.0.0) json (2.5.1) - jwt (2.2.3) + jwt (2.2.2) listen (3.2.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.9.1) + loofah (2.9.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) - marcel (1.0.1) + marcel (0.3.3) + mimemagic (~> 0.3.2) method_source (0.9.2) - mini_mime (1.1.0) + mimemagic (0.3.5) + mini_mime (1.0.2) mini_portile2 (2.5.0) minitest (5.14.4) msgpack (1.4.2) @@ -143,10 +141,10 @@ GEM multi_xml (0.6.0) multipart-post (2.1.1) nio4r (2.5.7) - nokogiri (1.11.3) + nokogiri (1.11.2) mini_portile2 (~> 2.5.0) racc (~> 1.4) - nokogiri (1.11.3-x64-mingw32) + nokogiri (1.11.2-x64-mingw32) racc (~> 1.4) oauth2 (1.4.7) faraday (>= 0.8, < 2.0) @@ -154,7 +152,7 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - omniauth (2.0.4) + omniauth (2.0.3) hashie (>= 3.4.6) rack (>= 1.6.2, < 3) rack-protection @@ -180,29 +178,29 @@ GEM rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.0.3.6) - actioncable (= 6.0.3.6) - actionmailbox (= 6.0.3.6) - actionmailer (= 6.0.3.6) - actionpack (= 6.0.3.6) - actiontext (= 6.0.3.6) - actionview (= 6.0.3.6) - activejob (= 6.0.3.6) - activemodel (= 6.0.3.6) - activerecord (= 6.0.3.6) - activestorage (= 6.0.3.6) - activesupport (= 6.0.3.6) + rails (6.0.3.5) + actioncable (= 6.0.3.5) + actionmailbox (= 6.0.3.5) + actionmailer (= 6.0.3.5) + actionpack (= 6.0.3.5) + actiontext (= 6.0.3.5) + actionview (= 6.0.3.5) + activejob (= 6.0.3.5) + activemodel (= 6.0.3.5) + activerecord (= 6.0.3.5) + activestorage (= 6.0.3.5) + activesupport (= 6.0.3.5) bundler (>= 1.3.0) - railties (= 6.0.3.6) + railties (= 6.0.3.5) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) - railties (6.0.3.6) - actionpack (= 6.0.3.6) - activesupport (= 6.0.3.6) + railties (6.0.3.5) + actionpack (= 6.0.3.5) + activesupport (= 6.0.3.5) method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) @@ -272,7 +270,7 @@ PLATFORMS x64-mingw32 DEPENDENCIES - bootsnap (~> 1.7.3) + bootsnap (>= 1.1.0, < 1.4.2) byebug (~> 11.1.1) capybara (~> 3.31.0) chromedriver-helper (~> 2.1.1) @@ -303,4 +301,4 @@ RUBY VERSION ruby 2.7.2p137 BUNDLED WITH - 2.2.16 + 2.1.4 \ No newline at end of file From 02ac846c63840468f1810b8038dd9cbf507db275 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Thu, 22 Apr 2021 11:43:02 -0700 Subject: [PATCH 059/363] updated URL --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3e3358b..8e7a21a 100644 --- a/README.md +++ b/README.md @@ -252,7 +252,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. Set a name and email address for the signer. In appsettings.yml, save an email address as `signer_email` and a name as `signer_name`. **Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. 1. Run the launcher: `rails s` -1. Open a browser to http://localhost:3000/auth/docusign +1. Open a browser to http://localhost:3000 ### Installation steps for JWT Grant authentication @@ -271,7 +271,7 @@ Also, in order to select JSON Web Token authentication in the launcher, in confi 1. Set a name and email address for the signer. In appsettings.yml, save an email address as `signer_email` and a name as `signer_name`. **Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. 1. Run the launcher: `rails s` -1. Open a browser to http://localhost:3000/auth/docusign +1. Open a browser to http://localhost:3000 1. If it is your first time using the app, grant consent by selecting **Accept**. On the black navigation bar, select **Logout**, then **Login**. 1. From the picklist, select **JSON Web Token (JWT) grant** > **Authenticate with DocuSign**. 1. Select your desired code example. From 9739cc505bad31608fc4cddaf986396f235e23f5 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Thu, 22 Apr 2021 11:43:47 -0700 Subject: [PATCH 060/363] updated URL --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6d05d5b..393df18 100644 --- a/README.md +++ b/README.md @@ -249,7 +249,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. Set a name and email address for the signer. In appsettings.yml, save an email address as `signer_email` and a name as `signer_name`. **Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. 1. Run the launcher: `rails s` -1. Open a browser to http://localhost:3000/auth/docusign +1. Open a browser to http://localhost:3000 ### Installation steps for JWT Grant authentication @@ -268,7 +268,7 @@ Also, in order to select JSON Web Token authentication in the launcher, in confi 1. Set a name and email address for the signer. In appsettings.yml, save an email address as `signer_email` and a name as `signer_name`. **Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. 1. Run the launcher: `rails s` -1. Open a browser to http://localhost:3000/auth/docusign +1. Open a browser to http://localhost:3000 1. If it is your first time using the app, grant consent by selecting **Accept**. On the black navigation bar, select **Logout**, then **Login**. 1. From the picklist, select **JSON Web Token (JWT) grant** > **Authenticate with DocuSign**. 1. Select your desired code example. From 3b016ab7fcc98fae396fc262c6c86cb76fd3d393 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Thu, 22 Apr 2021 12:23:25 -0700 Subject: [PATCH 061/363] removed below --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 393df18..20533e9 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a ## 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 below as they were automatically performed for you. +**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. From 18be9836642dbdb55219422628d98d94e969ef4d Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Thu, 22 Apr 2021 12:24:04 -0700 Subject: [PATCH 062/363] removed below --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7930541..25b2a79 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a ## 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 below as they were automatically performed for you. +**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 for authentication to use either [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) or [JWT Grant](https://developers.docusign.com/platform/auth/jwt/). From 215eb309097a8487c4145a52e8e700234abd190e Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Thu, 22 Apr 2021 13:03:11 -0700 Subject: [PATCH 063/363] bundler --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 20533e9..1bbcb92 100644 --- a/README.md +++ b/README.md @@ -241,7 +241,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. 1. In your command-line environment, switch to the folder: `cd ` or `cd code-examples-ruby` -1. Install the dependencies: `bundle install` +1. Install the dependencies: `bundler install` 1. To configure the launcher for [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. 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 appsettings.yml as your `integration_key`. 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 appsettings.yml as your `integration_secret`. @@ -259,7 +259,7 @@ Also, in order to select JSON Web Token authentication in the launcher, in confi 1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. 1. In your command-line environment, switch to the folder: `cd ` or `cd code-examples-ruby` -1. Install the dependencies: `bundle install` +1. Install the dependencies: `bundler install` 1. To configure the launcher for [JWT Grant](https://developers.docusign.com/platform/auth/jwt/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. 1. Add your API Username. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **My Account Information**, copy the **API Username** GUID and save it in appsettings.yml as your `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 appsettings.yml as your `jwt_integration_key`. From 5bb4d36dbf1f087c0368f23a827c094f8c855110 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Thu, 22 Apr 2021 13:03:47 -0700 Subject: [PATCH 064/363] bundler --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8e7a21a..00ea2c2 100644 --- a/README.md +++ b/README.md @@ -244,7 +244,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. 1. In your command-line environment, switch to the folder: `cd ` or `cd code-examples-ruby` -1. Install the dependencies: `bundle install` +1. Install the dependencies: `bundler install` 1. To configure the launcher for [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. 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 appsettings.yml as your `integration_key`. 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 appsettings.yml as your `integration_secret`. @@ -262,7 +262,7 @@ Also, in order to select JSON Web Token authentication in the launcher, in confi 1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. 1. In your command-line environment, switch to the folder: `cd ` or `cd code-examples-ruby` -1. Install the dependencies: `bundle install` +1. Install the dependencies: `bundler install` 1. To configure the launcher for [JWT Grant](https://developers.docusign.com/platform/auth/jwt/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. 1. Add your API Username. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **My Account Information**, copy the **API Username** GUID and save it in appsettings.yml as your `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 appsettings.yml as your `jwt_integration_key`. From 837f502596b1fffc5813d6d5094e702890e56a8b Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Thu, 22 Apr 2021 14:05:20 -0700 Subject: [PATCH 065/363] Devdocs 4634 (#24) fix quickstart auth issue --- Gemfile | 2 +- app/controllers/ds_common_controller.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index cf0c79a..72fb506 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,4 @@ -# frozen_string_literal: true + # frozen_string_literal: true source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index 26e4e7b..f37fb5e 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -28,7 +28,7 @@ def ds_return end def ds_must_authenticate - if Rails.configuration.quickstart == "true" + if Rails.configuration.quickstart == true redirect_to('auth/docusign') end @title = 'Authenticate with DocuSign' From 9a8a0813060741a88518eb81f15780a4ba312594 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Thu, 22 Apr 2021 14:08:10 -0700 Subject: [PATCH 066/363] Quickstart auth (#35) * update Gemfile * set quickstart to automatically use auth code grant --- app/controllers/ds_common_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index 26e4e7b..f37fb5e 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -28,7 +28,7 @@ def ds_return end def ds_must_authenticate - if Rails.configuration.quickstart == "true" + if Rails.configuration.quickstart == true redirect_to('auth/docusign') end @title = 'Authenticate with DocuSign' From 3f8a14dd3bfd2d74909460a925985515c2dfab7a Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Thu, 22 Apr 2021 14:09:31 -0700 Subject: [PATCH 067/363] Quickstart auth (#36) * Master (#29) * add info about scopes to README and update JWT scopes (#9) * update README * Master (#30) * update readme * SMS update * Updating the name of the signHere tab to match all other langs. * Renaming one variable to match other code examples * docusign_esign gem version update * Updated eSign31 example: added confirm successful batch send step * Updated quickstart logic * Clean up eg031 * Bump nokogiri from 1.10.10 to 1.11.1 Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.10.10 to 1.11.1. - [Release notes](https://github.com/sparklemotion/nokogiri/releases) - [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md) - [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.10.10...v1.11.1) Signed-off-by: dependabot[bot] * update gist steps comments (#18) * update gist steps comments * Various updates including step 8 of bulk send * Updating various packages to move forward with new versions * Updating gem package versions * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * updating README.md * Added Step 3 comments * Added Step 2 comments; removed other numbers in comments * bundler update omniauth to address CVE-2015-9284 * bundle install, Ruby 2.7.2 * Update PAYMENTS_INSTALLATION.md * Update README.md * Update README.md * add line breaks * Update README.md * edit Rooms line * deleted a section * bold UI items * add line breaks * remove period * remove line break * sample Ruby folder * add backslash * add bin * step * to * small updates * added JWT link * remove line break * synced with private * synced with private * sync with private * fix JWT redirect_uri and add state (#21) * Bump nokogiri from 1.10.10 to 1.11.3 Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.10.10 to 1.11.3. - [Release notes](https://github.com/sparklemotion/nokogiri/releases) - [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md) - [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.10.10...v1.11.3) Signed-off-by: dependabot[bot] * removed note about broken jwt * small edit * remove note about broken jwt * Devdocs 4539 (#23) * fix JWT error in eSignature examples * update gemfile * update Gemfile * Devdocs 4539 (#34) * update Gemfiles * updated URL * removed below * bundler * set quickstart to automatically use auth code grant Co-authored-by: Matthew Lusher Co-authored-by: Inbar Gazit Co-authored-by: an-tk Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: meihDS <70775251+meihDS@users.noreply.github.com> Co-authored-by: Aaron JacksonWilde --- README.md | 10 +++++----- app/controllers/ds_common_controller.rb | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 6d05d5b..1bbcb92 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a ## 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 below as they were automatically performed for you. +**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. @@ -241,7 +241,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. 1. In your command-line environment, switch to the folder: `cd ` or `cd code-examples-ruby` -1. Install the dependencies: `bundle install` +1. Install the dependencies: `bundler install` 1. To configure the launcher for [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. 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 appsettings.yml as your `integration_key`. 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 appsettings.yml as your `integration_secret`. @@ -249,7 +249,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. Set a name and email address for the signer. In appsettings.yml, save an email address as `signer_email` and a name as `signer_name`. **Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. 1. Run the launcher: `rails s` -1. Open a browser to http://localhost:3000/auth/docusign +1. Open a browser to http://localhost:3000 ### Installation steps for JWT Grant authentication @@ -259,7 +259,7 @@ Also, in order to select JSON Web Token authentication in the launcher, in confi 1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. 1. In your command-line environment, switch to the folder: `cd ` or `cd code-examples-ruby` -1. Install the dependencies: `bundle install` +1. Install the dependencies: `bundler install` 1. To configure the launcher for [JWT Grant](https://developers.docusign.com/platform/auth/jwt/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. 1. Add your API Username. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **My Account Information**, copy the **API Username** GUID and save it in appsettings.yml as your `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 appsettings.yml as your `jwt_integration_key`. @@ -268,7 +268,7 @@ Also, in order to select JSON Web Token authentication in the launcher, in confi 1. Set a name and email address for the signer. In appsettings.yml, save an email address as `signer_email` and a name as `signer_name`. **Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. 1. Run the launcher: `rails s` -1. Open a browser to http://localhost:3000/auth/docusign +1. Open a browser to http://localhost:3000 1. If it is your first time using the app, grant consent by selecting **Accept**. On the black navigation bar, select **Logout**, then **Login**. 1. From the picklist, select **JSON Web Token (JWT) grant** > **Authenticate with DocuSign**. 1. Select your desired code example. diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index 26e4e7b..f37fb5e 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -28,7 +28,7 @@ def ds_return end def ds_must_authenticate - if Rails.configuration.quickstart == "true" + if Rails.configuration.quickstart == true redirect_to('auth/docusign') end @title = 'Authenticate with DocuSign' From e5e99aee2e79142d23dd4f5e387eaa6dda91f942 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Thu, 22 Apr 2021 14:25:51 -0700 Subject: [PATCH 068/363] Auth (#37) * update Gemfile * set quickstart to automatically use auth code grant * update route for quickstart auth --- app/controllers/ds_common_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index f37fb5e..26d187f 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -29,7 +29,7 @@ def ds_return def ds_must_authenticate if Rails.configuration.quickstart == true - redirect_to('auth/docusign') + redirect_to('/auth/docusign') end @title = 'Authenticate with DocuSign' @show_doc = Rails.application.config.documentation From 50f3c32aef220952b0a3411fd1c51b03a1ffbdb4 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Thu, 22 Apr 2021 14:29:21 -0700 Subject: [PATCH 069/363] Auth (#38) update route for quickstart auth --- app/controllers/ds_common_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index f37fb5e..26d187f 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -29,7 +29,7 @@ def ds_return def ds_must_authenticate if Rails.configuration.quickstart == true - redirect_to('auth/docusign') + redirect_to('/auth/docusign') end @title = 'Authenticate with DocuSign' @show_doc = Rails.application.config.documentation From b409e8dbaf3b52f78a03aa2be637cd7caaf805a7 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Thu, 22 Apr 2021 14:30:47 -0700 Subject: [PATCH 070/363] update quickstart auth --- app/controllers/ds_common_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index f37fb5e..26d187f 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -29,7 +29,7 @@ def ds_return def ds_must_authenticate if Rails.configuration.quickstart == true - redirect_to('auth/docusign') + redirect_to('/auth/docusign') end @title = 'Authenticate with DocuSign' @show_doc = Rails.application.config.documentation From bc2fffa1a6f0e0f05083eb2792e225ca6678972a Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Thu, 22 Apr 2021 14:44:04 -0700 Subject: [PATCH 071/363] removed "name" --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1bbcb92..2ca7493 100644 --- a/README.md +++ b/README.md @@ -240,7 +240,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. 1. In your command-line environment, switch to the folder: - `cd ` or `cd code-examples-ruby` + `cd ` or `cd code-examples-ruby` 1. Install the dependencies: `bundler install` 1. To configure the launcher for [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. 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 appsettings.yml as your `integration_key`. @@ -258,7 +258,7 @@ Also, in order to select JSON Web Token authentication in the launcher, in confi 1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. 1. In your command-line environment, switch to the folder: - `cd ` or `cd code-examples-ruby` + `cd ` or `cd code-examples-ruby` 1. Install the dependencies: `bundler install` 1. To configure the launcher for [JWT Grant](https://developers.docusign.com/platform/auth/jwt/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. 1. Add your API Username. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **My Account Information**, copy the **API Username** GUID and save it in appsettings.yml as your `impersonated_user_guid`. From 1016fcc0ae585b908e0d13f8c31a35f87dbf5918 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Thu, 22 Apr 2021 14:44:37 -0700 Subject: [PATCH 072/363] removed "name" --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 00ea2c2..90c61c6 100644 --- a/README.md +++ b/README.md @@ -243,7 +243,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. 1. In your command-line environment, switch to the folder: - `cd ` or `cd code-examples-ruby` + `cd ` or `cd code-examples-ruby` 1. Install the dependencies: `bundler install` 1. To configure the launcher for [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. 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 appsettings.yml as your `integration_key`. @@ -261,7 +261,7 @@ Also, in order to select JSON Web Token authentication in the launcher, in confi 1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. 1. In your command-line environment, switch to the folder: - `cd ` or `cd code-examples-ruby` + `cd ` or `cd code-examples-ruby` 1. Install the dependencies: `bundler install` 1. To configure the launcher for [JWT Grant](https://developers.docusign.com/platform/auth/jwt/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. 1. Add your API Username. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **My Account Information**, copy the **API Username** GUID and save it in appsettings.yml as your `impersonated_user_guid`. From 26a65cfd51696ab42c6cbf3f3c0baa42784b891a Mon Sep 17 00:00:00 2001 From: robert-knight Date: Mon, 26 Apr 2021 07:59:18 -0700 Subject: [PATCH 073/363] Updated sequence values for eg013. --- Gemfile | 2 +- Gemfile.lock | 144 +++++++++--------- .../eg013_add_doc_to_template_service.rb | 4 +- 3 files changed, 72 insertions(+), 78 deletions(-) diff --git a/Gemfile b/Gemfile index 52abc2b..6e57591 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '2.7.2' +ruby '~>2.7.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '~> 6.0.3.5' diff --git a/Gemfile.lock b/Gemfile.lock index 76798cd..a694ac7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,56 +1,56 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.3.5) - actionpack (= 6.0.3.5) + actioncable (6.0.3.6) + actionpack (= 6.0.3.6) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.3.5) - actionpack (= 6.0.3.5) - activejob (= 6.0.3.5) - activerecord (= 6.0.3.5) - activestorage (= 6.0.3.5) - activesupport (= 6.0.3.5) + actionmailbox (6.0.3.6) + actionpack (= 6.0.3.6) + activejob (= 6.0.3.6) + activerecord (= 6.0.3.6) + activestorage (= 6.0.3.6) + activesupport (= 6.0.3.6) mail (>= 2.7.1) - actionmailer (6.0.3.5) - actionpack (= 6.0.3.5) - actionview (= 6.0.3.5) - activejob (= 6.0.3.5) + actionmailer (6.0.3.6) + actionpack (= 6.0.3.6) + actionview (= 6.0.3.6) + activejob (= 6.0.3.6) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.3.5) - actionview (= 6.0.3.5) - activesupport (= 6.0.3.5) + actionpack (6.0.3.6) + actionview (= 6.0.3.6) + activesupport (= 6.0.3.6) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.3.5) - actionpack (= 6.0.3.5) - activerecord (= 6.0.3.5) - activestorage (= 6.0.3.5) - activesupport (= 6.0.3.5) + actiontext (6.0.3.6) + actionpack (= 6.0.3.6) + activerecord (= 6.0.3.6) + activestorage (= 6.0.3.6) + activesupport (= 6.0.3.6) nokogiri (>= 1.8.5) - actionview (6.0.3.5) - activesupport (= 6.0.3.5) + actionview (6.0.3.6) + activesupport (= 6.0.3.6) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.3.5) - activesupport (= 6.0.3.5) + activejob (6.0.3.6) + activesupport (= 6.0.3.6) globalid (>= 0.3.6) - activemodel (6.0.3.5) - activesupport (= 6.0.3.5) - activerecord (6.0.3.5) - activemodel (= 6.0.3.5) - activesupport (= 6.0.3.5) - activestorage (6.0.3.5) - actionpack (= 6.0.3.5) - activejob (= 6.0.3.5) - activerecord (= 6.0.3.5) - marcel (~> 0.3.1) - activesupport (6.0.3.5) + activemodel (6.0.3.6) + activesupport (= 6.0.3.6) + activerecord (6.0.3.6) + activemodel (= 6.0.3.6) + activesupport (= 6.0.3.6) + activestorage (6.0.3.6) + actionpack (= 6.0.3.6) + activejob (= 6.0.3.6) + activerecord (= 6.0.3.6) + marcel (~> 1.0.0) + activesupport (6.0.3.6) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -96,55 +96,52 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_rooms (1.1.0.rc1) + docusign_rooms (1.1.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) erubi (1.10.0) - ethon (0.12.0) - ffi (>= 1.3.0) + ethon (0.13.0) + ffi (>= 1.15.0) execjs (2.7.0) - faraday (1.3.0) + faraday (1.4.1) + faraday-excon (~> 1.1) faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.1) multipart-post (>= 1.2, < 3) - ruby2_keywords + ruby2_keywords (>= 0.0.4) + faraday-excon (1.1.0) faraday-net_http (1.0.1) - ffi (1.15.0) + faraday-net_http_persistent (1.1.0) ffi (1.15.0-x64-mingw32) globalid (0.4.2) activesupport (>= 4.2.0) hashie (4.1.0) - i18n (1.8.9) + i18n (1.8.10) concurrent-ruby (~> 1.0) io-like (0.3.1) jbuilder (2.10.2) activesupport (>= 5.0.0) json (2.5.1) - jwt (2.2.2) + jwt (2.2.3) listen (3.2.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.9.0) + loofah (2.9.1) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) - marcel (0.3.3) - mimemagic (~> 0.3.2) + marcel (1.0.1) method_source (0.9.2) - mimemagic (0.3.5) - mini_mime (1.0.2) - mini_portile2 (2.5.0) + mini_mime (1.1.0) minitest (5.14.4) msgpack (1.4.2) multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) nio4r (2.5.7) - nokogiri (1.11.2) - mini_portile2 (~> 2.5.0) - racc (~> 1.4) - nokogiri (1.11.2-x64-mingw32) + nokogiri (1.11.3-x64-mingw32) racc (~> 1.4) oauth2 (1.4.7) faraday (>= 0.8, < 2.0) @@ -152,7 +149,7 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - omniauth (2.0.3) + omniauth (2.0.4) hashie (>= 3.4.6) rack (>= 1.6.2, < 3) rack-protection @@ -178,29 +175,29 @@ GEM rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.0.3.5) - actioncable (= 6.0.3.5) - actionmailbox (= 6.0.3.5) - actionmailer (= 6.0.3.5) - actionpack (= 6.0.3.5) - actiontext (= 6.0.3.5) - actionview (= 6.0.3.5) - activejob (= 6.0.3.5) - activemodel (= 6.0.3.5) - activerecord (= 6.0.3.5) - activestorage (= 6.0.3.5) - activesupport (= 6.0.3.5) + rails (6.0.3.6) + actioncable (= 6.0.3.6) + actionmailbox (= 6.0.3.6) + actionmailer (= 6.0.3.6) + actionpack (= 6.0.3.6) + actiontext (= 6.0.3.6) + actionview (= 6.0.3.6) + activejob (= 6.0.3.6) + activemodel (= 6.0.3.6) + activerecord (= 6.0.3.6) + activestorage (= 6.0.3.6) + activesupport (= 6.0.3.6) bundler (>= 1.3.0) - railties (= 6.0.3.5) + railties (= 6.0.3.6) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) - railties (6.0.3.5) - actionpack (= 6.0.3.5) - activesupport (= 6.0.3.5) + railties (6.0.3.6) + actionpack (= 6.0.3.6) + activesupport (= 6.0.3.6) method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) @@ -213,8 +210,6 @@ GEM rubyzip (2.3.0) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) - sassc (2.4.0) - ffi (~> 1.9) sassc (2.4.0-x64-mingw32) ffi (~> 1.9) sassc-rails (2.1.2) @@ -266,7 +261,6 @@ GEM zeitwerk (2.4.2) PLATFORMS - ruby x64-mingw32 DEPENDENCIES @@ -298,7 +292,7 @@ DEPENDENCIES web-console (~> 4.0.1) RUBY VERSION - ruby 2.7.2p137 + ruby 2.7.3p183 BUNDLED WITH - 2.1.4 \ No newline at end of file + 2.2.16 diff --git a/app/services/e_sign/eg013_add_doc_to_template_service.rb b/app/services/e_sign/eg013_add_doc_to_template_service.rb index 85d1dbe..130381c 100644 --- a/app/services/e_sign/eg013_add_doc_to_template_service.rb +++ b/app/services/e_sign/eg013_add_doc_to_template_service.rb @@ -91,7 +91,7 @@ def make_envelope(args) # Add the roles via an inlineTemplate inlineTemplates: [ DocuSign_eSign::InlineTemplate.new( - 'sequence' => '1', + 'sequence' => '2', 'recipients' => recipients_server_template ) ] @@ -136,7 +136,7 @@ def make_envelope(args) # Add the recipients via an inlineTemplate inlineTemplates: [ DocuSign_eSign::InlineTemplate.new( - sequence: '2', recipients: recipients_added_doc + sequence: '1', recipients: recipients_added_doc ) ], document: doc1 From f4c841cee4ad372574fec28e2c9fa6229ce3a27a Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 26 Apr 2021 14:42:49 -0700 Subject: [PATCH 074/363] Deleted strange line --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 84e9489..d68bf27 100644 --- a/README.md +++ b/README.md @@ -210,7 +210,6 @@ This example demonstrates how to use the Click API to get a list of clickwraps a 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. ======= 1. A DocuSign app and integration key that is configured for authentication to use either [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) or [JWT Grant](https://developers.docusign.com/platform/auth/jwt/). ->>>>>>> 18be9836642dbdb55219422628d98d94e969ef4d This [video](https://www.youtube.com/watch?v=eiRI4fe5HgM) demonstrates how to obtain an integration key. From f7be46b882868831aa095e318ae6f773e1c5b17c Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 26 Apr 2021 14:43:38 -0700 Subject: [PATCH 075/363] Deleted more strange lines --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index d68bf27..7990fbf 100644 --- a/README.md +++ b/README.md @@ -206,9 +206,7 @@ This example demonstrates how to use the Click API to get a list of clickwraps a **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. -<<<<<<< HEAD 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. -======= 1. A DocuSign app and integration key that is configured for authentication to use either [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) or [JWT Grant](https://developers.docusign.com/platform/auth/jwt/). This [video](https://www.youtube.com/watch?v=eiRI4fe5HgM) demonstrates how to obtain an integration key. From 6444069e1db89303b9280c754fc433a590797394 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Mon, 26 Apr 2021 15:14:12 -0700 Subject: [PATCH 076/363] update README --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 7990fbf..a9e3d51 100644 --- a/README.md +++ b/README.md @@ -206,7 +206,6 @@ This example demonstrates how to use the Click API to get a list of clickwraps a **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. 1. A DocuSign app and integration key that is configured for authentication to use either [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) or [JWT Grant](https://developers.docusign.com/platform/auth/jwt/). This [video](https://www.youtube.com/watch?v=eiRI4fe5HgM) demonstrates how to obtain an integration key. From 0d484314397cb46061b0631aa8a35990d892b5e9 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Wed, 28 Apr 2021 08:59:38 -0700 Subject: [PATCH 077/363] Update gemfile (#25) * Master (#25) * add info about scopes to README and update JWT scopes (#9) * Arr workflow (#11) * Added ARR workflow * Changed text and update readme * Changed default input value * Resolved comments * Resolved comments * add steps comments and catch ARR error * add save page to session and remove incorrect files * fix comments Co-authored-by: Karissa.Jacobsen Co-authored-by: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Co-authored-by: Aaron Wilde Co-authored-by: RustamAbdul <63346609+RustamAbdul@users.noreply.github.com> * Update README.md * Update README.md * Master (#26) * Added 5 clickwrap examples * Master (#28) * Add Rooms Q4 updates Co-authored-by: Aaron Wilde Co-authored-by: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Co-authored-by: RustamAbdul <63346609+RustamAbdul@users.noreply.github.com> Co-authored-by: Inbar Gazit Co-authored-by: Karissa.Jacobsen Co-authored-by: Aaron Wilde Co-authored-by: RustamAbdul <63346609+RustamAbdul@users.noreply.github.com> Co-authored-by: Inbar Gazit Co-authored-by: Anatoly Tkachenko * Bump nokogiri from 1.10.10 to 1.11.1 (#27) Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.10.10 to 1.11.1. - [Release notes](https://github.com/sparklemotion/nokogiri/releases) - [Changelog](https://github.com/sparklemotion/nokogiri/blob/master/CHANGELOG.md) - [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.10.10...v1.11.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Master (#29) * add info about scopes to README and update JWT scopes (#9) * update readme * Master (#30) * update readme * renaming variable to match other code example languages. * Renaming one variable to match other code examples * Various updates including adding step 8 of bulk send * Various updates including step 8 of bulk send * Updating gem package versions * Updating gem package versions * Updating README.md * updating README.md * Added Step 3 comments * Added Step 2 comments; removed other numbers in comments * bundler update omniauth to address CVE-2015-9284 * bundle install, Ruby 2.7.2 * Update PAYMENTS_INSTALLATION.md * synced with private * Update README.md * synced with private * delete first sentence * sync with private * removed note about broken jwt * removed broken jwt note * sync with private * sync with private * update gemfile * Devdocs 4539 (#34) * update Gemfiles * updated URL * removed below * removed below * bundler * Quickstart auth (#35) * update Gemfile * set quickstart to automatically use auth code grant * Auth (#37) * update Gemfile * set quickstart to automatically use auth code grant * update route for quickstart auth * removed "name" * Updated sequence values for eg013. * Deleted strange line * Deleted more strange lines * update README * sync public readme and update gemfile Co-authored-by: Aaron Wilde Co-authored-by: RustamAbdul <63346609+RustamAbdul@users.noreply.github.com> Co-authored-by: Inbar Gazit Co-authored-by: Anatoly Tkachenko Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: meihDS <70775251+meihDS@users.noreply.github.com> Co-authored-by: robert-knight --- .ruby-version | 2 +- Gemfile | 8 +- Gemfile.lock | 144 +++++++++--------- README.md | 8 +- app/services/api_creator.rb | 11 +- .../e_sign/eg007_envelope_get_doc_service.rb | 5 +- .../eg013_add_doc_to_template_service.rb | 4 +- 7 files changed, 89 insertions(+), 93 deletions(-) diff --git a/.ruby-version b/.ruby-version index 5588ae8..fbafd6b 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.7.1 \ No newline at end of file +2.7.2 \ No newline at end of file diff --git a/Gemfile b/Gemfile index 72fb506..0064ce8 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '2.7.2' +ruby '~>2.7.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '~> 6.0.3.5' @@ -36,7 +36,11 @@ gem 'jbuilder', '~> 2.10.0' # gem 'capistrano-rails', group: :development # Reduces boot times through caching; required in config/boot.rb -gem 'bootsnap', '~> 1.7.3', require: false +if RUBY_PLATFORM =~ /mswin/ + gem 'bootsnap', '>= 1.1.0', '< 1.4.2', require: false +else + gem 'bootsnap', '~> 1.7.3', require: false +end group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console diff --git a/Gemfile.lock b/Gemfile.lock index 76798cd..a694ac7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,56 +1,56 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.3.5) - actionpack (= 6.0.3.5) + actioncable (6.0.3.6) + actionpack (= 6.0.3.6) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.3.5) - actionpack (= 6.0.3.5) - activejob (= 6.0.3.5) - activerecord (= 6.0.3.5) - activestorage (= 6.0.3.5) - activesupport (= 6.0.3.5) + actionmailbox (6.0.3.6) + actionpack (= 6.0.3.6) + activejob (= 6.0.3.6) + activerecord (= 6.0.3.6) + activestorage (= 6.0.3.6) + activesupport (= 6.0.3.6) mail (>= 2.7.1) - actionmailer (6.0.3.5) - actionpack (= 6.0.3.5) - actionview (= 6.0.3.5) - activejob (= 6.0.3.5) + actionmailer (6.0.3.6) + actionpack (= 6.0.3.6) + actionview (= 6.0.3.6) + activejob (= 6.0.3.6) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.3.5) - actionview (= 6.0.3.5) - activesupport (= 6.0.3.5) + actionpack (6.0.3.6) + actionview (= 6.0.3.6) + activesupport (= 6.0.3.6) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.3.5) - actionpack (= 6.0.3.5) - activerecord (= 6.0.3.5) - activestorage (= 6.0.3.5) - activesupport (= 6.0.3.5) + actiontext (6.0.3.6) + actionpack (= 6.0.3.6) + activerecord (= 6.0.3.6) + activestorage (= 6.0.3.6) + activesupport (= 6.0.3.6) nokogiri (>= 1.8.5) - actionview (6.0.3.5) - activesupport (= 6.0.3.5) + actionview (6.0.3.6) + activesupport (= 6.0.3.6) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.3.5) - activesupport (= 6.0.3.5) + activejob (6.0.3.6) + activesupport (= 6.0.3.6) globalid (>= 0.3.6) - activemodel (6.0.3.5) - activesupport (= 6.0.3.5) - activerecord (6.0.3.5) - activemodel (= 6.0.3.5) - activesupport (= 6.0.3.5) - activestorage (6.0.3.5) - actionpack (= 6.0.3.5) - activejob (= 6.0.3.5) - activerecord (= 6.0.3.5) - marcel (~> 0.3.1) - activesupport (6.0.3.5) + activemodel (6.0.3.6) + activesupport (= 6.0.3.6) + activerecord (6.0.3.6) + activemodel (= 6.0.3.6) + activesupport (= 6.0.3.6) + activestorage (6.0.3.6) + actionpack (= 6.0.3.6) + activejob (= 6.0.3.6) + activerecord (= 6.0.3.6) + marcel (~> 1.0.0) + activesupport (6.0.3.6) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -96,55 +96,52 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_rooms (1.1.0.rc1) + docusign_rooms (1.1.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) erubi (1.10.0) - ethon (0.12.0) - ffi (>= 1.3.0) + ethon (0.13.0) + ffi (>= 1.15.0) execjs (2.7.0) - faraday (1.3.0) + faraday (1.4.1) + faraday-excon (~> 1.1) faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.1) multipart-post (>= 1.2, < 3) - ruby2_keywords + ruby2_keywords (>= 0.0.4) + faraday-excon (1.1.0) faraday-net_http (1.0.1) - ffi (1.15.0) + faraday-net_http_persistent (1.1.0) ffi (1.15.0-x64-mingw32) globalid (0.4.2) activesupport (>= 4.2.0) hashie (4.1.0) - i18n (1.8.9) + i18n (1.8.10) concurrent-ruby (~> 1.0) io-like (0.3.1) jbuilder (2.10.2) activesupport (>= 5.0.0) json (2.5.1) - jwt (2.2.2) + jwt (2.2.3) listen (3.2.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.9.0) + loofah (2.9.1) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) - marcel (0.3.3) - mimemagic (~> 0.3.2) + marcel (1.0.1) method_source (0.9.2) - mimemagic (0.3.5) - mini_mime (1.0.2) - mini_portile2 (2.5.0) + mini_mime (1.1.0) minitest (5.14.4) msgpack (1.4.2) multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) nio4r (2.5.7) - nokogiri (1.11.2) - mini_portile2 (~> 2.5.0) - racc (~> 1.4) - nokogiri (1.11.2-x64-mingw32) + nokogiri (1.11.3-x64-mingw32) racc (~> 1.4) oauth2 (1.4.7) faraday (>= 0.8, < 2.0) @@ -152,7 +149,7 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - omniauth (2.0.3) + omniauth (2.0.4) hashie (>= 3.4.6) rack (>= 1.6.2, < 3) rack-protection @@ -178,29 +175,29 @@ GEM rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.0.3.5) - actioncable (= 6.0.3.5) - actionmailbox (= 6.0.3.5) - actionmailer (= 6.0.3.5) - actionpack (= 6.0.3.5) - actiontext (= 6.0.3.5) - actionview (= 6.0.3.5) - activejob (= 6.0.3.5) - activemodel (= 6.0.3.5) - activerecord (= 6.0.3.5) - activestorage (= 6.0.3.5) - activesupport (= 6.0.3.5) + rails (6.0.3.6) + actioncable (= 6.0.3.6) + actionmailbox (= 6.0.3.6) + actionmailer (= 6.0.3.6) + actionpack (= 6.0.3.6) + actiontext (= 6.0.3.6) + actionview (= 6.0.3.6) + activejob (= 6.0.3.6) + activemodel (= 6.0.3.6) + activerecord (= 6.0.3.6) + activestorage (= 6.0.3.6) + activesupport (= 6.0.3.6) bundler (>= 1.3.0) - railties (= 6.0.3.5) + railties (= 6.0.3.6) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) - railties (6.0.3.5) - actionpack (= 6.0.3.5) - activesupport (= 6.0.3.5) + railties (6.0.3.6) + actionpack (= 6.0.3.6) + activesupport (= 6.0.3.6) method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) @@ -213,8 +210,6 @@ GEM rubyzip (2.3.0) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) - sassc (2.4.0) - ffi (~> 1.9) sassc (2.4.0-x64-mingw32) ffi (~> 1.9) sassc-rails (2.1.2) @@ -266,7 +261,6 @@ GEM zeitwerk (2.4.2) PLATFORMS - ruby x64-mingw32 DEPENDENCIES @@ -298,7 +292,7 @@ DEPENDENCIES web-console (~> 4.0.1) RUBY VERSION - ruby 2.7.2p137 + ruby 2.7.3p183 BUNDLED WITH - 2.1.4 \ No newline at end of file + 2.2.16 diff --git a/README.md b/README.md index 90c61c6..a9e3d51 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,6 @@ ### Github repo: https://github.com/docusign/code-examples-ruby - -This GitHub repo includes code examples for DocuSign APIs. - To switch between API code examples, modify the `examples_API` setting at the end of the configuration file. Set only one API type to `true` and set the remaining to `false`. If none of the API types are set to `true`, the DocuSign eSignature REST API code examples will be shown. If multiple API types are set to `true`, only the first will be shown. @@ -206,10 +203,10 @@ This example demonstrates how to use the Click API to get a list of clickwraps a ## 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 below as they were automatically performed for you. +**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. +1. A DocuSign app and integration key that is configured for authentication to use either [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) or [JWT Grant](https://developers.docusign.com/platform/auth/jwt/). This [video](https://www.youtube.com/watch?v=eiRI4fe5HgM) demonstrates how to obtain an integration key. @@ -313,7 +310,6 @@ To use the payments code example, create a test payment gateway on the [**Paymen Once you've created a payment gateway, save the **Gateway Account ID** GUID to appsettings.yml. - ## License and additional information ### License diff --git a/app/services/api_creator.rb b/app/services/api_creator.rb index 6e3d04c..3cc5b29 100644 --- a/app/services/api_creator.rb +++ b/app/services/api_creator.rb @@ -13,15 +13,15 @@ def create_initial_api_client(host: nil, debugging: false) end def create_account_api(args) - # Step 1. Obtain your OAuth token + # Obtain your OAuth token configuration = DocuSign_eSign::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_eSign::ApiClient.new configuration - # Step 2. Construct your API headers + # Construct your API headers api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" - # Step 3: Construct your request body + # Construct your request body accounts_api = DocuSign_eSign::AccountsApi.new api_client end @@ -34,13 +34,14 @@ def create_template_api(args) end def create_envelope_api(args) - # Step 1. Obtain your OAuth token + # Obtain your OAuth token + # Step 2 start configuration = DocuSign_eSign::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_eSign::ApiClient.new configuration - # Step 2. Construct your API headers api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" + # Step 2 end DocuSign_eSign::EnvelopesApi.new api_client end diff --git a/app/services/e_sign/eg007_envelope_get_doc_service.rb b/app/services/e_sign/eg007_envelope_get_doc_service.rb index 9baace9..441470c 100644 --- a/app/services/e_sign/eg007_envelope_get_doc_service.rb +++ b/app/services/e_sign/eg007_envelope_get_doc_service.rb @@ -22,13 +22,14 @@ def call private - # ***DS.snippet.0.start def worker + # Step 3 start envelope_api = create_envelope_api(args) document_id = args['document_id'] temp_file = envelope_api.get_document args[:account_id], document_id, args[:envelope_id] + # Step 3 end # Find the matching document information item doc_item = args['envelope_documents']['documents'].find { |item| item['document_id'] == document_id } @@ -53,4 +54,4 @@ def worker end { 'mime_type' => mime_type, 'doc_name' => doc_name, 'data' => File.binread(temp_file.path) } end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg013_add_doc_to_template_service.rb b/app/services/e_sign/eg013_add_doc_to_template_service.rb index 85d1dbe..130381c 100644 --- a/app/services/e_sign/eg013_add_doc_to_template_service.rb +++ b/app/services/e_sign/eg013_add_doc_to_template_service.rb @@ -91,7 +91,7 @@ def make_envelope(args) # Add the roles via an inlineTemplate inlineTemplates: [ DocuSign_eSign::InlineTemplate.new( - 'sequence' => '1', + 'sequence' => '2', 'recipients' => recipients_server_template ) ] @@ -136,7 +136,7 @@ def make_envelope(args) # Add the recipients via an inlineTemplate inlineTemplates: [ DocuSign_eSign::InlineTemplate.new( - sequence: '2', recipients: recipients_added_doc + sequence: '1', recipients: recipients_added_doc ) ], document: doc1 From dd9abc3dc732dc6dc012cbcd75ec5da7c13d09b6 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Wed, 28 Apr 2021 09:57:51 -0700 Subject: [PATCH 078/363] Update gemfile (#25) (#39) * Master (#25) * add info about scopes to README and update JWT scopes (#9) * Arr workflow (#11) * Added ARR workflow * Changed text and update readme * Changed default input value * Resolved comments * Resolved comments * add steps comments and catch ARR error * add save page to session and remove incorrect files * fix comments Co-authored-by: Karissa.Jacobsen Co-authored-by: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Co-authored-by: Aaron Wilde Co-authored-by: RustamAbdul <63346609+RustamAbdul@users.noreply.github.com> * Update README.md * Update README.md * Master (#26) * Added 5 clickwrap examples * Master (#28) * Add Rooms Q4 updates Co-authored-by: Aaron Wilde Co-authored-by: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Co-authored-by: RustamAbdul <63346609+RustamAbdul@users.noreply.github.com> Co-authored-by: Inbar Gazit Co-authored-by: Karissa.Jacobsen Co-authored-by: Aaron Wilde Co-authored-by: RustamAbdul <63346609+RustamAbdul@users.noreply.github.com> Co-authored-by: Inbar Gazit Co-authored-by: Anatoly Tkachenko * Bump nokogiri from 1.10.10 to 1.11.1 (#27) Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.10.10 to 1.11.1. - [Release notes](https://github.com/sparklemotion/nokogiri/releases) - [Changelog](https://github.com/sparklemotion/nokogiri/blob/master/CHANGELOG.md) - [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.10.10...v1.11.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Master (#29) * add info about scopes to README and update JWT scopes (#9) * update readme * Master (#30) * update readme * renaming variable to match other code example languages. * Renaming one variable to match other code examples * Various updates including adding step 8 of bulk send * Various updates including step 8 of bulk send * Updating gem package versions * Updating gem package versions * Updating README.md * updating README.md * Added Step 3 comments * Added Step 2 comments; removed other numbers in comments * bundler update omniauth to address CVE-2015-9284 * bundle install, Ruby 2.7.2 * Update PAYMENTS_INSTALLATION.md * synced with private * Update README.md * synced with private * delete first sentence * sync with private * removed note about broken jwt * removed broken jwt note * sync with private * sync with private * update gemfile * Devdocs 4539 (#34) * update Gemfiles * updated URL * removed below * removed below * bundler * Quickstart auth (#35) * update Gemfile * set quickstart to automatically use auth code grant * Auth (#37) * update Gemfile * set quickstart to automatically use auth code grant * update route for quickstart auth * removed "name" * Updated sequence values for eg013. * Deleted strange line * Deleted more strange lines * update README * sync public readme and update gemfile Co-authored-by: Aaron Wilde Co-authored-by: RustamAbdul <63346609+RustamAbdul@users.noreply.github.com> Co-authored-by: Inbar Gazit Co-authored-by: Anatoly Tkachenko Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: meihDS <70775251+meihDS@users.noreply.github.com> Co-authored-by: robert-knight Co-authored-by: Aaron Wilde Co-authored-by: RustamAbdul <63346609+RustamAbdul@users.noreply.github.com> Co-authored-by: Inbar Gazit Co-authored-by: Anatoly Tkachenko Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: meihDS <70775251+meihDS@users.noreply.github.com> Co-authored-by: robert-knight --- Gemfile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 6e57591..0064ce8 100644 --- a/Gemfile +++ b/Gemfile @@ -36,7 +36,11 @@ gem 'jbuilder', '~> 2.10.0' # gem 'capistrano-rails', group: :development # Reduces boot times through caching; required in config/boot.rb -gem 'bootsnap', '>= 1.1.0', '< 1.4.2', require: false +if RUBY_PLATFORM =~ /mswin/ + gem 'bootsnap', '>= 1.1.0', '< 1.4.2', require: false +else + gem 'bootsnap', '~> 1.7.3', require: false +end group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console From 81a46f563f485ef4f56cc69c4f4d664ab0e73261 Mon Sep 17 00:00:00 2001 From: Anatoly Tkachenko Date: Wed, 5 May 2021 21:15:00 +0300 Subject: [PATCH 079/363] monitor api example implemented (#20) * monitor api example implemented * update monitor example and text * update appsettings file * update index file Co-authored-by: Karissa Jacobsen --- Gemfile | 1 + Gemfile.lock | 16 ++++++- README.md | 6 +++ app/controllers/ds_common_controller.rb | 2 + ...eg001_get_monitoring_dataset_controller.rb | 27 +++++++++++ app/services/api_creator.rb | 21 ++++++--- .../eg001_get_monitoring_dataset_service.rb | 47 +++++++++++++++++++ app/views/ds_common/ds_must_authenticate.erb | 2 + .../eg001_get_monitoring_dataset/get.html.erb | 14 ++++++ app/views/monitor_api/index.html.erb | 38 +++++++++++++++ config/appsettings.example.yml | 2 + config/routes.rb | 7 +++ 12 files changed, 175 insertions(+), 8 deletions(-) create mode 100644 app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb create mode 100644 app/services/monitor_api/eg001_get_monitoring_dataset_service.rb create mode 100644 app/views/monitor_api/eg001_get_monitoring_dataset/get.html.erb create mode 100644 app/views/monitor_api/index.html.erb diff --git a/Gemfile b/Gemfile index 0064ce8..a803a99 100644 --- a/Gemfile +++ b/Gemfile @@ -67,6 +67,7 @@ group :test do end gem 'docusign_esign', '~> 3.8.0.rc1' +gem 'docusign_monitor', '~> 1.0.1.pre.alpha' gem 'docusign_rooms', '~> 1.1.0.rc1' gem 'docusign_click', '~> 1.0.0' gem 'omniauth-oauth2', '~> 1.7.1' diff --git a/Gemfile.lock b/Gemfile.lock index a694ac7..0ec4c95 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -61,7 +61,7 @@ GEM archive-zip (0.12.0) io-like (~> 0.3.0) bindex (0.8.1) - bootsnap (1.4.1) + bootsnap (1.7.4) msgpack (~> 1.0) builder (3.2.4) byebug (11.1.3) @@ -96,6 +96,11 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) + docusign_monitor (1.0.1.pre.alpha) + addressable (~> 2.7, >= 2.7.0) + json (~> 2.1, >= 2.1.0) + jwt (~> 2.2, >= 2.2.1) + typhoeus (~> 1.0, >= 1.0.1) docusign_rooms (1.1.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -113,6 +118,7 @@ GEM faraday-excon (1.1.0) faraday-net_http (1.0.1) faraday-net_http_persistent (1.1.0) + ffi (1.15.0) ffi (1.15.0-x64-mingw32) globalid (0.4.2) activesupport (>= 4.2.0) @@ -143,6 +149,8 @@ GEM nio4r (2.5.7) nokogiri (1.11.3-x64-mingw32) racc (~> 1.4) + nokogiri (1.11.3-x86_64-darwin) + racc (~> 1.4) oauth2 (1.4.7) faraday (>= 0.8, < 2.0) jwt (>= 1.0, < 3.0) @@ -210,6 +218,8 @@ GEM rubyzip (2.3.0) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) + sassc (2.4.0) + ffi (~> 1.9) sassc (2.4.0-x64-mingw32) ffi (~> 1.9) sassc-rails (2.1.2) @@ -262,15 +272,17 @@ GEM PLATFORMS x64-mingw32 + x86_64-darwin-20 DEPENDENCIES - bootsnap (>= 1.1.0, < 1.4.2) + bootsnap (~> 1.7.3) byebug (~> 11.1.1) capybara (~> 3.31.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) docusign_click (~> 1.0.0) docusign_esign (~> 3.8.0.rc1) + docusign_monitor (~> 1.0.1.pre.alpha) docusign_rooms (~> 1.1.0.rc1) jbuilder (~> 2.10.0) listen (~> 3.2.1) diff --git a/README.md b/README.md index a9e3d51..d908aab 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,12 @@ This example demonstrates how to use the Click API to get a list of clickwraps a [Source.](./app/services/clickwrap/eg005_clickwrap_responses_service.rb) This example demonstrates how to use the Click API to get a list of clickwraps associated with a specific DocuSign user. +## Monitor API +**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/). +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/). + +1. **Get monitoring data.** [Source](app/services/monitor_api/eg001_get_monitoring_dataset_service.rb) + Demonstrates how to get and display all of your organization’s monitoring data. ## Installation diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index 26d187f..ae220a5 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -10,6 +10,8 @@ def index render 'room_api/index' elsif Rails.configuration.examples_API['Click'] == true render 'clickwrap/index' + elsif Rails.configuration.examples_API['Monitor'] == true + render 'monitor_api/index' else @show_doc = Rails.application.config.documentation if Rails.configuration.quickstart == true && session[:been_here].nil? diff --git a/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb b/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb new file mode 100644 index 0000000..358c5a9 --- /dev/null +++ b/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb @@ -0,0 +1,27 @@ +class MonitorApi::Eg001GetMonitoringDatasetController < EgController + before_action :check_auth + + def create + results = MonitorApi::Eg001GetMonitoringDatasetService.new(session, nil).call + + @title = "Monitoring data result" + @h1 = "Monitoring data result" + @message = "Results from DataSet:GetStreamForDataset method:" + @json = results.to_json.to_json + + render 'ds_common/example_done' + end + + private + + def check_auth + minimum_buffer_min = 10 + token_ok = check_token(minimum_buffer_min) + unless token_ok + flash[:messages] = 'Sorry, you need to re-authenticate.' + # We could store the parameters of the requested operation so it could be restarted automatically + # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication + redirect_to '/ds/mustAuthenticate' + end + end +end diff --git a/app/services/api_creator.rb b/app/services/api_creator.rb index 3cc5b29..7ad2298 100644 --- a/app/services/api_creator.rb +++ b/app/services/api_creator.rb @@ -2,16 +2,25 @@ module ApiCreator def create_initial_api_client(host: nil, debugging: false) - configuration = DocuSign_eSign::Configuration.new - - # https://github.com/docusign/docusign-ruby-client/blob/master/lib/docusign_esign/configuration.rb#L55-L60 - configuration.debugging = debugging - - api_client = DocuSign_eSign::ApiClient.new(configuration) + if Rails.configuration.examples_API['Rooms'] == true + api_client = new_client(DocuSign_Rooms, debugging) + elsif Rails.configuration.examples_API['Click'] == true + api_client = new_client(DocuSign_Click, debugging) + elsif Rails.configuration.examples_API['Monitor'] == true + api_client = new_client(DocuSign_Monitor, debugging) + else + api_client = new_client(DocuSign_eSign, debugging) + end api_client.set_oauth_base_path(host) api_client end + def new_client(client_module, debugging) + configuration = client_module::Configuration.new + configuration.debugging = debugging + client_module::ApiClient.new(configuration) + end + def create_account_api(args) # Obtain your OAuth token configuration = DocuSign_eSign::Configuration.new diff --git a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb new file mode 100644 index 0000000..38a4f1d --- /dev/null +++ b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +class MonitorApi::Eg001GetMonitoringDatasetService + attr_reader :args + + def initialize(session, _request) + @args = { + # account_id: session[:ds_account_id], + access_token: session[:ds_access_token] + } + @cursor = '' + @results_memo = [] + @last_result = '' + end + + def call + # step 2 start + configuration = DocuSign_Monitor::Configuration.new + configuration.host = Rails.configuration.monitor_host + configuration.debugging = true + api_client = DocuSign_Monitor::ApiClient.new configuration + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + # step 2 end + + # step 3 start + while true do + monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) + options = DocuSign_Monitor::GetStreamForDatasetOptions.default + options.cursor = @cursor + response = monitor_api.get_stream_for_dataset('monitor', '2.0', options).first + + # 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 + break if response[:endCursor] == @cursor + + @results_memo.push(response[:data]) + @last_result = response[:data] + @cursor = response[:endCursor] + end + # step 3 end + + Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" + Rails.logger.info @results_memo.inspect + + return @last_result + end +end diff --git a/app/views/ds_common/ds_must_authenticate.erb b/app/views/ds_common/ds_must_authenticate.erb index 959a806..c722e3d 100644 --- a/app/views/ds_common/ds_must_authenticate.erb +++ b/app/views/ds_common/ds_must_authenticate.erb @@ -5,7 +5,9 @@ <%= hidden_field_tag :authenticity_token, form_authenticity_token %>


diff --git a/app/views/monitor_api/eg001_get_monitoring_dataset/get.html.erb b/app/views/monitor_api/eg001_get_monitoring_dataset/get.html.erb new file mode 100644 index 0000000..898ca82 --- /dev/null +++ b/app/views/monitor_api/eg001_get_monitoring_dataset/get.html.erb @@ -0,0 +1,14 @@ +

1. Get monitoring data

+

Demonstrates how to get and display all of your organization’s monitoring data.

+ +

API method used: + DataSet:GetStreamForDataset +

+ +

+ View source file <%= @source_file %> on GitHub. +

+ +
+ +
\ No newline at end of file diff --git a/app/views/monitor_api/index.html.erb b/app/views/monitor_api/index.html.erb new file mode 100644 index 0000000..ec1ff52 --- /dev/null +++ b/app/views/monitor_api/index.html.erb @@ -0,0 +1,38 @@ +
+
+ + + + + + + +
+

Ruby Launcher

+

Welcome to the Ruby code examples for DocuSign Monitor API with JWT Grant authentication

+
+ +
+
+ +
+ + <% if @show_doc %> +

Documentation on using JWT Authorization from a Ruby Rails application.

+ <% end %> + +

Monitor API Code Examples

+ +

1. Get monitoring data

+

+ Demonstrates how to get and display all of your organization’s monitoring data. +

+

+ API method used: + DataSet:GetStreamForDataset +

+ +
+ + + \ No newline at end of file diff --git a/config/appsettings.example.yml b/config/appsettings.example.yml index 22d5d39..c02d6f3 100644 --- a/config/appsettings.example.yml +++ b/config/appsettings.example.yml @@ -9,6 +9,7 @@ default: &default eSignature: true Rooms: false Click: false + Monitor: false # NOTE: The terms "client_id" and "Integration key" are synonyms. They refer to the same thing # The integration_key value is the same between the development account and production account integration_key: {INTEGRATION_KEY_AUTH_CODE} @@ -26,6 +27,7 @@ default: &default authorization_server: https://account-d.docusign.com aud: account-d.docusign.com rooms_host: "https://demo.rooms.docusign.com/restapi" + monitor_host: "https://lens-d.docusign.net" allow_silent_authentication: true # A user can be silently authenticated if they have an # Active login session on another tab of the same browser # Set if you want a specific DocuSign AccountId, If false, the users default account will be used. diff --git a/config/routes.rb b/config/routes.rb index d87ea50..fcdcb43 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -48,6 +48,11 @@ get 'eg005' => 'eg005_clickwrap_responses#get' post 'eg005' => 'eg005_clickwrap_responses#create' end + elsif Rails.configuration.examples_API['Monitor'] == true + scope module: 'monitor_api' do + get 'eg001' => 'eg001_get_monitoring_dataset#get' + post 'eg001' => 'eg001_get_monitoring_dataset#create' + end else scope module: 'e_sign' do # Example controllers... @@ -177,6 +182,8 @@ get '/ds_common-return' => 'ds_common#ds_return' get '/ds/mustAuthenticate' => 'ds_common#ds_must_authenticate' post '/ds/mustAuthenticate' => 'ds_common#ds_must_authenticate' + get '/ds/mustAuthenticateJwt' => 'ds_common#ds_must_authenticate_jwt' + post '/ds/mustAuthenticateJwt' => 'ds_common#ds_must_authenticate' get '/ds/session' => 'session#show' # default root From f7b85e44632224ab3591d2209776a0632c6f5642 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Thu, 6 May 2021 14:04:09 -0700 Subject: [PATCH 080/363] update JWT flow --- app/controllers/ds_common_controller.rb | 49 ++++++++++++++----------- app/services/api_creator.rb | 20 ++-------- app/services/jwt_auth/jwt_creator.rb | 9 ++++- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index ae220a5..ed0d65e 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -30,6 +30,9 @@ def ds_return end def ds_must_authenticate + if Rails.configuration.examples_API['Monitor'] == true + jwt_auth + end if Rails.configuration.quickstart == true redirect_to('/auth/docusign') end @@ -39,30 +42,34 @@ def ds_must_authenticate if params[:auth] == 'grand-auth' redirect_to('/auth/docusign') elsif params[:auth] == 'jwt-auth' - if JwtAuth::JwtCreator.new(session).check_jwt_token - if session[:eg] - url = "/" + session[:eg] - else - url = root_path - end + jwt_auth + end + end + + def jwt_auth + if JwtAuth::JwtCreator.new(session).check_jwt_token + if session[:eg] + url = "/" + session[:eg] else - session['omniauth.state'] = SecureRandom.hex - url = JwtAuth::JwtCreator.consent_url(session['omniauth.state']) - redirect_to root_path if session[:token].present? - end - if Rails.configuration.examples_API['Rooms'] == true - configuration = DocuSign_Rooms::Configuration.new - api_client = DocuSign_Rooms::ApiClient.new(configuration) - elsif Rails.configuration.examples_API['Click'] == true - configuration = DocuSign_Click::Configuration.new - api_client = DocuSign_Click::ApiClient.new configuration - end - resp = ::JwtAuth::JwtCreator.new(session).check_jwt_token - if resp.is_a? String - redirect_to resp + url = root_path end - redirect_to url + else + session['omniauth.state'] = SecureRandom.hex + url = JwtAuth::JwtCreator.consent_url(session['omniauth.state']) + redirect_to root_path if session[:token].present? + end + if Rails.configuration.examples_API['Rooms'] == true + configuration = DocuSign_Rooms::Configuration.new + api_client = DocuSign_Rooms::ApiClient.new(configuration) + elsif Rails.configuration.examples_API['Click'] == true + configuration = DocuSign_Click::Configuration.new + api_client = DocuSign_Click::ApiClient.new configuration + end + resp = ::JwtAuth::JwtCreator.new(session).check_jwt_token + if resp.is_a? String + redirect_to resp end + redirect_to url end def example_done; end diff --git a/app/services/api_creator.rb b/app/services/api_creator.rb index 7ad2298..47694b6 100644 --- a/app/services/api_creator.rb +++ b/app/services/api_creator.rb @@ -1,24 +1,12 @@ # frozen_string_literal: true module ApiCreator - def create_initial_api_client(host: nil, debugging: false) - if Rails.configuration.examples_API['Rooms'] == true - api_client = new_client(DocuSign_Rooms, debugging) - elsif Rails.configuration.examples_API['Click'] == true - api_client = new_client(DocuSign_Click, debugging) - elsif Rails.configuration.examples_API['Monitor'] == true - api_client = new_client(DocuSign_Monitor, debugging) - else - api_client = new_client(DocuSign_eSign, debugging) - end - api_client.set_oauth_base_path(host) - api_client - end - - def new_client(client_module, debugging) + def create_initial_api_client(host: nil, client_module: DocuSign_eSign, debugging: false) configuration = client_module::Configuration.new configuration.debugging = debugging - client_module::ApiClient.new(configuration) + api_client = client_module::ApiClient.new(configuration) + api_client.set_oauth_base_path(host) + api_client end def create_account_api(args) diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index 462409f..70984f1 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -32,14 +32,19 @@ def self.consent_url(state) def initialize(session) @session = session - @api_client = create_initial_api_client(host: Rails.configuration.aud, debugging: false) scope = "signature" + @client_module = DocuSign_eSign if Rails.configuration.examples_API['Rooms'] == true scope = "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" + @client_module = DocuSign_Rooms elsif Rails.configuration.examples_API['Click'] == true scope = "signature click.manage click.send" + @client_module = DocuSign_Click + elsif Rails.configuration.examples_API['Monitor'] == true + @client_module = DocuSign_Monitor end @scope = "#{scope} impersonation" + @api_client = create_initial_api_client(host: Rails.configuration.aud, client_module: @client_module, debugging: false) end # @return [Boolean] `true` if the token was successfully updated, `false` if consent still needs to be grant'ed @@ -57,7 +62,7 @@ def check_jwt_token else raise end - rescue DocuSign_eSign::ApiError => exception + rescue @client_module::ApiError => exception Rails.logger.warn exception.inspect body = JSON.parse(exception.response_body) From 7a150f00c61a2926d398389f9e66ac330ec1d20e Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Thu, 6 May 2021 14:27:54 -0700 Subject: [PATCH 081/363] remove unnecessary syntax --- app/controllers/ds_common_controller.rb | 16 ++++++++-------- app/services/jwt_auth/jwt_creator.rb | 10 +++++----- config/initializers/omniauth.rb | 4 ++-- config/routes.rb | 6 +++--- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index ed0d65e..4682bec 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -6,15 +6,15 @@ class DsCommonController < ApplicationController def index @show_doc = Rails.application.config.documentation - if Rails.configuration.examples_API['Rooms'] == true + if Rails.configuration.examples_API['Rooms'] render 'room_api/index' - elsif Rails.configuration.examples_API['Click'] == true + elsif Rails.configuration.examples_API['Click'] render 'clickwrap/index' - elsif Rails.configuration.examples_API['Monitor'] == true + elsif Rails.configuration.examples_API['Monitor'] render 'monitor_api/index' else @show_doc = Rails.application.config.documentation - if Rails.configuration.quickstart == true && session[:been_here].nil? + if Rails.configuration.quickstart && session[:been_here].nil? redirect_to '/eg001' end end @@ -30,10 +30,10 @@ def ds_return end def ds_must_authenticate - if Rails.configuration.examples_API['Monitor'] == true + if Rails.configuration.examples_API['Monitor'] jwt_auth end - if Rails.configuration.quickstart == true + if Rails.configuration.quickstart redirect_to('/auth/docusign') end @title = 'Authenticate with DocuSign' @@ -58,10 +58,10 @@ def jwt_auth url = JwtAuth::JwtCreator.consent_url(session['omniauth.state']) redirect_to root_path if session[:token].present? end - if Rails.configuration.examples_API['Rooms'] == true + if Rails.configuration.examples_API['Rooms'] configuration = DocuSign_Rooms::Configuration.new api_client = DocuSign_Rooms::ApiClient.new(configuration) - elsif Rails.configuration.examples_API['Click'] == true + elsif Rails.configuration.examples_API['Click'] configuration = DocuSign_Click::Configuration.new api_client = DocuSign_Click::ApiClient.new configuration end diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index 70984f1..77892f3 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -14,9 +14,9 @@ def self.consent_url(state) # This endpoint is used to obtain consent and is the first step in several authentication flows. # https://developers.docusign.com/platform/auth/reference/obtain-consent scope = "signature" - if Rails.configuration.examples_API['Rooms'] == true + if Rails.configuration.examples_API['Rooms'] scope = "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" - elsif Rails.configuration.examples_API['Click'] == true + elsif Rails.configuration.examples_API['Click'] scope = "signature click.manage click.send" end scope = "#{scope} impersonation" @@ -34,13 +34,13 @@ def initialize(session) @session = session scope = "signature" @client_module = DocuSign_eSign - if Rails.configuration.examples_API['Rooms'] == true + if Rails.configuration.examples_API['Rooms'] scope = "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" @client_module = DocuSign_Rooms - elsif Rails.configuration.examples_API['Click'] == true + elsif Rails.configuration.examples_API['Click'] scope = "signature click.manage click.send" @client_module = DocuSign_Click - elsif Rails.configuration.examples_API['Monitor'] == true + elsif Rails.configuration.examples_API['Monitor'] @client_module = DocuSign_Monitor end @scope = "#{scope} impersonation" diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 4dc2cd1..178aaf3 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -34,9 +34,9 @@ unless strategy.options[:allow_silent_authentication] strategy.options[:authorize_params].prompt = strategy.options.prompt end - if Rails.configuration.examples_API['Rooms'] == true + if Rails.configuration.examples_API['Rooms'] strategy.options[:authorize_params].scope = "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" - elsif Rails.configuration.examples_API['Click'] == true + elsif Rails.configuration.examples_API['Click'] strategy.options[:authorize_params].scope = "signature click.manage click.send" end } diff --git a/config/routes.rb b/config/routes.rb index fcdcb43..97cb804 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true Rails.application.routes.draw do - if Rails.configuration.examples_API['Rooms'] == true + if Rails.configuration.examples_API['Rooms'] scope module: 'room_api' do get 'eg001' => 'eg001_create_room_with_data#get' post 'eg001' => 'eg001_create_room_with_data#create' @@ -31,7 +31,7 @@ get 'eg009' => 'eg009_assign_form_to_form_group#get' post 'eg009' => 'eg009_assign_form_to_form_group#create' end - elsif Rails.configuration.examples_API['Click'] == true + elsif Rails.configuration.examples_API['Click'] scope module: 'clickwrap' do get 'eg001' => 'eg001_create_clickwrap#get' post 'eg001' => 'eg001_create_clickwrap#create' @@ -48,7 +48,7 @@ get 'eg005' => 'eg005_clickwrap_responses#get' post 'eg005' => 'eg005_clickwrap_responses#create' end - elsif Rails.configuration.examples_API['Monitor'] == true + elsif Rails.configuration.examples_API['Monitor'] scope module: 'monitor_api' do get 'eg001' => 'eg001_get_monitoring_dataset#get' post 'eg001' => 'eg001_get_monitoring_dataset#create' From 146afca935f7b5f508badece8502127c351d20af Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Thu, 6 May 2021 16:03:54 -0700 Subject: [PATCH 082/363] update JWT flow (#26) * update JWT flow --- app/controllers/ds_common_controller.rb | 59 ++++++++++++++----------- app/services/api_creator.rb | 20 ++------- app/services/jwt_auth/jwt_creator.rb | 17 ++++--- config/initializers/omniauth.rb | 4 +- config/routes.rb | 6 +-- 5 files changed, 53 insertions(+), 53 deletions(-) diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index ae220a5..4682bec 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -6,15 +6,15 @@ class DsCommonController < ApplicationController def index @show_doc = Rails.application.config.documentation - if Rails.configuration.examples_API['Rooms'] == true + if Rails.configuration.examples_API['Rooms'] render 'room_api/index' - elsif Rails.configuration.examples_API['Click'] == true + elsif Rails.configuration.examples_API['Click'] render 'clickwrap/index' - elsif Rails.configuration.examples_API['Monitor'] == true + elsif Rails.configuration.examples_API['Monitor'] render 'monitor_api/index' else @show_doc = Rails.application.config.documentation - if Rails.configuration.quickstart == true && session[:been_here].nil? + if Rails.configuration.quickstart && session[:been_here].nil? redirect_to '/eg001' end end @@ -30,7 +30,10 @@ def ds_return end def ds_must_authenticate - if Rails.configuration.quickstart == true + if Rails.configuration.examples_API['Monitor'] + jwt_auth + end + if Rails.configuration.quickstart redirect_to('/auth/docusign') end @title = 'Authenticate with DocuSign' @@ -39,30 +42,34 @@ def ds_must_authenticate if params[:auth] == 'grand-auth' redirect_to('/auth/docusign') elsif params[:auth] == 'jwt-auth' - if JwtAuth::JwtCreator.new(session).check_jwt_token - if session[:eg] - url = "/" + session[:eg] - else - url = root_path - end + jwt_auth + end + end + + def jwt_auth + if JwtAuth::JwtCreator.new(session).check_jwt_token + if session[:eg] + url = "/" + session[:eg] else - session['omniauth.state'] = SecureRandom.hex - url = JwtAuth::JwtCreator.consent_url(session['omniauth.state']) - redirect_to root_path if session[:token].present? - end - if Rails.configuration.examples_API['Rooms'] == true - configuration = DocuSign_Rooms::Configuration.new - api_client = DocuSign_Rooms::ApiClient.new(configuration) - elsif Rails.configuration.examples_API['Click'] == true - configuration = DocuSign_Click::Configuration.new - api_client = DocuSign_Click::ApiClient.new configuration + url = root_path end - resp = ::JwtAuth::JwtCreator.new(session).check_jwt_token - if resp.is_a? String - redirect_to resp - end - redirect_to url + else + session['omniauth.state'] = SecureRandom.hex + url = JwtAuth::JwtCreator.consent_url(session['omniauth.state']) + redirect_to root_path if session[:token].present? + end + if Rails.configuration.examples_API['Rooms'] + configuration = DocuSign_Rooms::Configuration.new + api_client = DocuSign_Rooms::ApiClient.new(configuration) + elsif Rails.configuration.examples_API['Click'] + configuration = DocuSign_Click::Configuration.new + api_client = DocuSign_Click::ApiClient.new configuration + end + resp = ::JwtAuth::JwtCreator.new(session).check_jwt_token + if resp.is_a? String + redirect_to resp end + redirect_to url end def example_done; end diff --git a/app/services/api_creator.rb b/app/services/api_creator.rb index 7ad2298..47694b6 100644 --- a/app/services/api_creator.rb +++ b/app/services/api_creator.rb @@ -1,24 +1,12 @@ # frozen_string_literal: true module ApiCreator - def create_initial_api_client(host: nil, debugging: false) - if Rails.configuration.examples_API['Rooms'] == true - api_client = new_client(DocuSign_Rooms, debugging) - elsif Rails.configuration.examples_API['Click'] == true - api_client = new_client(DocuSign_Click, debugging) - elsif Rails.configuration.examples_API['Monitor'] == true - api_client = new_client(DocuSign_Monitor, debugging) - else - api_client = new_client(DocuSign_eSign, debugging) - end - api_client.set_oauth_base_path(host) - api_client - end - - def new_client(client_module, debugging) + def create_initial_api_client(host: nil, client_module: DocuSign_eSign, debugging: false) configuration = client_module::Configuration.new configuration.debugging = debugging - client_module::ApiClient.new(configuration) + api_client = client_module::ApiClient.new(configuration) + api_client.set_oauth_base_path(host) + api_client end def create_account_api(args) diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index 462409f..77892f3 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -14,9 +14,9 @@ def self.consent_url(state) # This endpoint is used to obtain consent and is the first step in several authentication flows. # https://developers.docusign.com/platform/auth/reference/obtain-consent scope = "signature" - if Rails.configuration.examples_API['Rooms'] == true + if Rails.configuration.examples_API['Rooms'] scope = "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" - elsif Rails.configuration.examples_API['Click'] == true + elsif Rails.configuration.examples_API['Click'] scope = "signature click.manage click.send" end scope = "#{scope} impersonation" @@ -32,14 +32,19 @@ def self.consent_url(state) def initialize(session) @session = session - @api_client = create_initial_api_client(host: Rails.configuration.aud, debugging: false) scope = "signature" - if Rails.configuration.examples_API['Rooms'] == true + @client_module = DocuSign_eSign + if Rails.configuration.examples_API['Rooms'] scope = "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" - elsif Rails.configuration.examples_API['Click'] == true + @client_module = DocuSign_Rooms + elsif Rails.configuration.examples_API['Click'] scope = "signature click.manage click.send" + @client_module = DocuSign_Click + elsif Rails.configuration.examples_API['Monitor'] + @client_module = DocuSign_Monitor end @scope = "#{scope} impersonation" + @api_client = create_initial_api_client(host: Rails.configuration.aud, client_module: @client_module, debugging: false) end # @return [Boolean] `true` if the token was successfully updated, `false` if consent still needs to be grant'ed @@ -57,7 +62,7 @@ def check_jwt_token else raise end - rescue DocuSign_eSign::ApiError => exception + rescue @client_module::ApiError => exception Rails.logger.warn exception.inspect body = JSON.parse(exception.response_body) diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 4dc2cd1..178aaf3 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -34,9 +34,9 @@ unless strategy.options[:allow_silent_authentication] strategy.options[:authorize_params].prompt = strategy.options.prompt end - if Rails.configuration.examples_API['Rooms'] == true + if Rails.configuration.examples_API['Rooms'] strategy.options[:authorize_params].scope = "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" - elsif Rails.configuration.examples_API['Click'] == true + elsif Rails.configuration.examples_API['Click'] strategy.options[:authorize_params].scope = "signature click.manage click.send" end } diff --git a/config/routes.rb b/config/routes.rb index fcdcb43..97cb804 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true Rails.application.routes.draw do - if Rails.configuration.examples_API['Rooms'] == true + if Rails.configuration.examples_API['Rooms'] scope module: 'room_api' do get 'eg001' => 'eg001_create_room_with_data#get' post 'eg001' => 'eg001_create_room_with_data#create' @@ -31,7 +31,7 @@ get 'eg009' => 'eg009_assign_form_to_form_group#get' post 'eg009' => 'eg009_assign_form_to_form_group#create' end - elsif Rails.configuration.examples_API['Click'] == true + elsif Rails.configuration.examples_API['Click'] scope module: 'clickwrap' do get 'eg001' => 'eg001_create_clickwrap#get' post 'eg001' => 'eg001_create_clickwrap#create' @@ -48,7 +48,7 @@ get 'eg005' => 'eg005_clickwrap_responses#get' post 'eg005' => 'eg005_clickwrap_responses#create' end - elsif Rails.configuration.examples_API['Monitor'] == true + elsif Rails.configuration.examples_API['Monitor'] scope module: 'monitor_api' do get 'eg001' => 'eg001_get_monitoring_dataset#get' post 'eg001' => 'eg001_get_monitoring_dataset#create' From e47248c5655032819fe73782a3572b3b31f5623d Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 7 May 2021 11:26:57 -0700 Subject: [PATCH 083/363] add cursor and fix spacing issue --- .../eg001_get_monitoring_dataset_service.rb | 11 +++---- app/views/monitor_api/index.html.erb | 33 ++++++++++--------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb index 38a4f1d..7722e6a 100644 --- a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb +++ b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb @@ -10,7 +10,6 @@ def initialize(session, _request) } @cursor = '' @results_memo = [] - @last_result = '' end def call @@ -23,9 +22,10 @@ def call # step 2 end # step 3 start + monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) + options = DocuSign_Monitor::GetStreamForDatasetOptions.default + while true do - monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) - options = DocuSign_Monitor::GetStreamForDatasetOptions.default options.cursor = @cursor response = monitor_api.get_stream_for_dataset('monitor', '2.0', options).first @@ -33,8 +33,7 @@ def call # it means that you have reached the end of the records break if response[:endCursor] == @cursor - @results_memo.push(response[:data]) - @last_result = response[:data] + @results_memo.push(response) @cursor = response[:endCursor] end # step 3 end @@ -42,6 +41,6 @@ def call Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" Rails.logger.info @results_memo.inspect - return @last_result + return @results_memo end end diff --git a/app/views/monitor_api/index.html.erb b/app/views/monitor_api/index.html.erb index ec1ff52..054cdb1 100644 --- a/app/views/monitor_api/index.html.erb +++ b/app/views/monitor_api/index.html.erb @@ -17,22 +17,23 @@ - <% if @show_doc %> -

Documentation on using JWT Authorization from a Ruby Rails application.

- <% end %> +
+ <% if @show_doc %> +

Documentation on using JWT Authorization from a Ruby Rails application.

+ <% end %> -

Monitor API Code Examples

+

Monitor API Code Examples

-

1. Get monitoring data

-

- Demonstrates how to get and display all of your organization’s monitoring data. -

-

- API method used: - DataSet:GetStreamForDataset -

+

1. Get monitoring data

+

+ Demonstrates how to get and display all of your organization’s monitoring data. +

+

+ API method used: + DataSet:GetStreamForDataset +

-
- - - \ No newline at end of file + + + + \ No newline at end of file From 8518c0d2608307d6cf758b9b1d050fa18a936668 Mon Sep 17 00:00:00 2001 From: Paige Rossi <70241979+paigesrossi@users.noreply.github.com> Date: Wed, 19 May 2021 11:33:15 -0700 Subject: [PATCH 084/363] ssl error note --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index d908aab..5db2cc7 100644 --- a/README.md +++ b/README.md @@ -310,6 +310,17 @@ Modify the following two lines in the **configuration.rb** file, replacing `true Once this is complete, you can run your Ruby on Rails application again and you should be able to make API calls on your localhost. +### Troubleshooting macOS SSL issue +When using the Ruby launcher on OSX you may get the following error: + +``` +Faraday::SSLError (SSL_connect returned=1 errno=0 state=error: certificate verify failed (self signed certificate in certificate chain)) +``` +Please update SSL certificates if rvm is your version manager. Or check [other steps for different scenarios](https://gemfury.com/help/could-not-verify-ssl-certificate/#updating-ssl-certificates). +``` +$ rvm osx-ssl-certs status all +$ rvm osx-ssl-certs update all +``` ## 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. From 67229aaffcd6b0ab9f4c4485af1a48316f020686 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 May 2021 10:29:02 -0700 Subject: [PATCH 085/363] Bump nokogiri from 1.11.3 to 1.11.4 (#42) Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.11.3 to 1.11.4. - [Release notes](https://github.com/sparklemotion/nokogiri/releases) - [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md) - [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.11.3...v1.11.4) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index ac8f29e..754e6f9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -147,9 +147,11 @@ GEM multi_xml (0.6.0) multipart-post (2.1.1) nio4r (2.5.7) - nokogiri (1.11.3-x64-mingw32) + nokogiri (1.11.4-x64-mingw32) racc (~> 1.4) - nokogiri (1.11.3-x86_64-darwin) + nokogiri (1.11.4-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.11.4-x86_64-linux) racc (~> 1.4) oauth2 (1.4.7) faraday (>= 0.8, < 2.0) @@ -218,6 +220,8 @@ GEM rubyzip (2.3.0) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) + sassc (2.4.0) + ffi (~> 1.9) sassc (2.4.0-x64-mingw32) ffi (~> 1.9) sassc-rails (2.1.2) @@ -271,6 +275,7 @@ GEM PLATFORMS x64-mingw32 x86_64-darwin-20 + x86_64-linux DEPENDENCIES bootsnap (~> 1.7.3) From 8200369bcd29010e088cfe43cbc9ca5b14a69b75 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 May 2021 10:29:49 -0700 Subject: [PATCH 086/363] Bump puma from 4.3.7 to 4.3.8 (#41) Bumps [puma](https://github.com/puma/puma) from 4.3.7 to 4.3.8. - [Release notes](https://github.com/puma/puma/releases) - [Changelog](https://github.com/puma/puma/blob/master/History.md) - [Commits](https://github.com/puma/puma/compare/v4.3.7...v4.3.8) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index a803a99..a021b65 100644 --- a/Gemfile +++ b/Gemfile @@ -10,7 +10,7 @@ gem 'rails', '~> 6.0.3.5' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4.2' # Use Puma as the app server -gem 'puma', '~> 4.3.3' +gem 'puma', '~> 4.3.8' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets diff --git a/Gemfile.lock b/Gemfile.lock index 754e6f9..e70d28c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -153,6 +153,8 @@ GEM racc (~> 1.4) nokogiri (1.11.4-x86_64-linux) racc (~> 1.4) + nokogiri (1.11.3-x86_64-linux) + racc (~> 1.4) oauth2 (1.4.7) faraday (>= 0.8, < 2.0) jwt (>= 1.0, < 3.0) @@ -177,7 +179,7 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.6) - puma (4.3.7) + puma (4.3.8) nio4r (~> 2.0) racc (1.5.2) rack (2.2.3) @@ -293,7 +295,7 @@ DEPENDENCIES omniauth-rails_csrf_protection pry-nav (~> 0.3.0) pry-rails (~> 0.3.9) - puma (~> 4.3.3) + puma (~> 4.3.8) rails (~> 6.0.3.5) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) From 1ad7da1d01329827e3d40c7e6f6e45d3612f7cba Mon Sep 17 00:00:00 2001 From: an-tk Date: Tue, 25 May 2021 13:02:06 +0300 Subject: [PATCH 087/363] docusign_monitor monitor gem version update --- Gemfile | 4 ++-- Gemfile.lock | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Gemfile b/Gemfile index a803a99..6e83e20 100644 --- a/Gemfile +++ b/Gemfile @@ -67,7 +67,7 @@ group :test do end gem 'docusign_esign', '~> 3.8.0.rc1' -gem 'docusign_monitor', '~> 1.0.1.pre.alpha' +gem 'docusign_monitor', '~> 1.0.0.beta1' gem 'docusign_rooms', '~> 1.1.0.rc1' gem 'docusign_click', '~> 1.0.0' gem 'omniauth-oauth2', '~> 1.7.1' @@ -75,4 +75,4 @@ gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', '~> 1.2019.3', platforms: %i[mingw mswin x64_mingw jruby] -gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] \ No newline at end of file +gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] diff --git a/Gemfile.lock b/Gemfile.lock index 0ec4c95..1b5a9e2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -151,6 +151,8 @@ GEM racc (~> 1.4) nokogiri (1.11.3-x86_64-darwin) racc (~> 1.4) + nokogiri (1.11.3-x86_64-linux) + racc (~> 1.4) oauth2 (1.4.7) faraday (>= 0.8, < 2.0) jwt (>= 1.0, < 3.0) @@ -253,11 +255,8 @@ GEM ethon (>= 0.9.0) tzinfo (1.2.9) thread_safe (~> 0.1) - tzinfo-data (1.2019.3) - tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) - wdm (0.1.1) web-console (4.0.4) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -273,6 +272,7 @@ GEM PLATFORMS x64-mingw32 x86_64-darwin-20 + x86_64-linux DEPENDENCIES bootsnap (~> 1.7.3) @@ -282,7 +282,7 @@ DEPENDENCIES coffee-rails (~> 5.0.0) docusign_click (~> 1.0.0) docusign_esign (~> 3.8.0.rc1) - docusign_monitor (~> 1.0.1.pre.alpha) + docusign_monitor (~> 1.0.0.beta1) docusign_rooms (~> 1.1.0.rc1) jbuilder (~> 2.10.0) listen (~> 3.2.1) From f33053bbd1928e264c1ab3cdbd7ea3c98be96f15 Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Tue, 1 Jun 2021 13:09:06 -0700 Subject: [PATCH 088/363] readme updates --- README.md | 203 +++++------------------------------------------------- 1 file changed, 19 insertions(+), 184 deletions(-) diff --git a/README.md b/README.md index 5db2cc7..0fdfdc3 100644 --- a/README.md +++ b/README.md @@ -2,209 +2,44 @@ ### Github repo: https://github.com/docusign/code-examples-ruby -To switch between API code examples, modify the `examples_API` setting at the end of the configuration file. Set only one API type to `true` and set the remaining to `false`. +This GitHub repo includes code examples for the DocuSign eSignature REST API, Rooms API, Click API, and Monitor API. To switch between API code examples, modify the `examples_API` setting at the end of the configuration file. Set only one API type to `true` and set the remaining to `false`. If none of the API types are set to `true`, the DocuSign eSignature REST API code examples will be shown. If multiple API types are set to `true`, only the first will be shown. -Before you can make any API calls using [JWT Grant](https://developers.docusign.com/platform/auth/jwt/), you must get your user’s consent for your app to impersonate them. To do this, the `impersonation` scope is added when requesting a JSON Web Token. - - ## Introduction -This repo is a Ruby on Rails application. +This repo is a Ruby on Rails 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. ## eSignature API -For more information about the scopes used for obtaining authorization to use the eSignature API, see the [Required Scopes section](https://developers.docusign.com/docs/esign-rest-api/esign101/auth). - -1. **Use embedded signing.** - [Source.](app/services/e_sign/eg001_embedded_signing_service.rb) - This example sends an envelope, and then uses embedded signing for the first signer. - With embedded signing, the DocuSign signing is initiated from your website. -1. **Request a signature by email (Remote Signing).** - [Source.](app/services/e_sign/eg002_signing_via_email_service.rb) - 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.](app/services/e_sign/eg003_list_envelopes_service.rb) - The envelopes' current status is included. -1. **Get an envelope's basic information.** - [Source.](app/services/e_sign/eg004_envelope_info_service.rb) - The example lists the basic information about an envelope, including its overall status. -1. **List an envelope's recipients** - [Source.](./app/controllers/e_sign/eg005_envelope_recipients_controller.rb) - Includes current recipient status. -1. **List an envelope's documents.** - [Source.](app/services/e_sign/eg006_envelope_docs_service.rb) -1. **Download an envelope's documents.** - [Source.](app/services/e_sign/eg007_envelope_get_doc_service.rb) - The example can download individual - documents, the documents concatenated together, or a zip file of the documents. -1. **Programmatically create a template.** - [Source.](app/services/e_sign/eg008_create_template_service.rb) -1. **Request a signature by email using a template.** - The example creates an envelope using a template and sets the initial values for some of its tabs (fields). - [Source.](app/services/e_sign/eg009_use_template_service.rb) -1. **Send an envelope and upload its documents with multpart binary transfer.** - [Source.](app/services/e_sign/eg010_send_binary_docs_service.rb) - Binary transfer is 33% more efficient than using Base64 encoding. -1. **Use embedded sending.** - [Source.](app/services/e_sign/eg011_embedded_sending_service.rb) - Embeds the DocuSign web tool (NDSE) in your web app to finalize or update - the envelope and documents before they are sent. -1. **Embedded DocuSign web tool (NDSE).** - [Source.](app/services/e_sign/eg012_embedded_console_service.rb) -1. **Use embedded signing from a template with an added document.** - [Source.](app/services/e_sign/eg013_add_doc_to_template_service.rb) - 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.](app/services/e_sign/eg014_collect_payment_service.rb) - -1. **Get the envelope tab data.** - Retrieve the tab (field) values for all of the envelope's recipients. - [Source.](app/services/e_sign/eg015_get_envelope_tab_data_service.rb) -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.](app/services/e_sign/eg016_set_envelope_tab_data_service.rb) -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.](app/services/e_sign/eg017_set_template_tab_values_service.rb) -1. **Get the envelope custom field data (metadata).** - The example retrieves the custom metadata (custom data fields) stored with the envelope. - [Source.](app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb) -1. **Requiring an Access Code for a Recipient** - [Source.](app/services/e_sign/eg019_access_code_authentication_service.rb) - This example sends an envelope that requires an access-code for the purpose of multi-factor authentication. -1. **Requiring SMS authentication for a recipient** - [Source.](app/services/e_sign/eg020_sms_authentication_service.rb) - This example sends an 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.](app/services/e_sign/eg021_phone_authentication_service.rb) - This example sends an 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.](app/services/e_sign/eg022_kba_authentication_service.rb) - This example sends an 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.](app/services/e_sign/eg023_idv_authentication_service.rb) - This example sends an envelope that requires the recipient to upload a government issued id. - -1. **Creating a permission profile** - [Source.](app/services/e_sign/eg024_permission_create_service.rb) - 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.](app/services/e_sign/eg025_permissions_set_user_group_service.rb) - 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.](app/services/e_sign/eg026_permissions_change_single_setting_service.rb) - 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.](app/services/e_sign/eg027_permissions_delete_service.rb) - 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. - You cannot delete the Everyone nor the Administrator profile types as those are defaults. - -1. **Creating a brand** - [Source.](app/services/e_sign/eg028_brands_creating_service.rb) - 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.](app/services/e_sign/eg029_brands_apply_to_envelope_service.rb) - 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. - -1. **Applying a brand to a template** - [Source.](app/services/e_sign/eg030_brands_apply_to_template_service.rb) - 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.](app/services/e_sign/eg031_bulk_sending_envelopes_service.rb) - This example creates and sends a bulk envelope by generating a bulk recipient list and initiating a bulk send. - -1. **Pausing a signature workflow** - [Source.](app/services/e_sign/eg032_pauses_signature_workflow_service.rb) - This example demonstrates how to create an envelope where the workflow is paused before the envelope is sent to a second recipient. - -1. **Unpausing a signature workflow** - [Source.](app/services/e_sign/eg033_unpauses_signature_workflow_service.rb) - This example demonstrates how to resume an envelope workflow that has been paused. - -1. **Using conditional recipients** - [Source.](app/services/e_sign/eg034_use_conditional_recipients_service.rb) - This example demonstrates how to create an envelope where the workflow is routed to different recipients based on the value of a transaction. - -1. **Request a signature by SMS delivery** - [Source.](app/services/e_sign/eg035_sms_delivery_service.rb) - This code example demonstrates how to send a signature request via an SMS message using the [Envelopes: create](https://developers.docusign.com/esign-rest-api/reference/Envelopes/Envelopes/create) method. +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, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/esign-rest-api/how-to/code-launchers#examples-and-languages) on the DocuSign Developer Center. ## Rooms API -**Note:** To use the Rooms API, you must also [create a Rooms developer account](https://developers.docusign.com/docs/rooms-api/rooms101/create-account). -For more information about the scopes used for obtaining authorization to use the Rooms API, see the [Required Scopes section](https://developers.docusign.com/docs/rooms-api/rooms101/auth/). - -1. **Create a room with data.** - [Source.](./app/services/room_api/eg001_create_room_with_data_service.rb) - This example creates a new room in your DocuSign Rooms account to be used for a transaction. -1. **Create a room from a template.** - [Source.](./app/services/room_api/eg002_create_room_with_template_service.rb) - This example creates a new room using a template. -1. **Export data from a room.** - [Source.](./app/services/room_api/eg003_export_data_from_room_service.rb) - This example exports all the available data from a specific room in your DocuSign Rooms account. -1. **Add forms to a room.** - [Source.](./app/services/room_api/eg004_add_forms_to_room_service.rb) - This example adds a standard real estate related form to a specific room in your DocuSign Rooms account. -1. **Search for rooms with filters.** - [Source.](./app/services/room_api/eg005_get_rooms_with_filters_service.rb) - This example searches for rooms in your DocuSign Rooms account using a specific filter. -1. **Get an external form fillable session.** - [Source.](./app/services/room_api/eg006_create_an_external_form_fill_session_service.rb) - This example creates an external form that can be filled using DocuSign for a specific room in your DocuSign Rooms account. -1. **Creating a form group.** - [Source.](./app/services/room_api/eg007_create_form_group_service.rb) - This example creates a new form group with the name given in the name property of the request body. -1. **Grant office access to a form group.** - [Source.](./app/services/room_api/eg008_grant_office_access_to_form_group_service.rb) - This example assigns an office to a form group for your DocuSign Rooms. -1. **Assign a form to a form group.** - [Source.](./app/services/room_api/eg009_assign_form_to_form_group_service.rb) - This example assigns a form to a form group for your DocuSign Rooms. +**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/). +For a list of code examples that use the Rooms API, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/rooms-api/how-to/code-launchers#examples-and-languages) on the DocuSign Developer Center. ## Click API -For more information about the scopes used for obtaining authorization to use the Clickwrap API, see the [Required Scopes section](https://developers.docusign.com/docs/click-api/click101/auth). - -1. **Creating a clickwrap.** -[Source.](./app/services/clickwrap/eg001_create_clickwrap_service.rb) -This example demonstrates how to use the Click API to create a clickwrap that you can embed in your website or app. -1. **Activate a clickwrap.** -[Source.](./app/services/clickwrap/eg002_activate_clickwrap_service.rb) -This example demonstrates how to use the Click API to activate a new clickwrap that you have already created. -1. **Creating a new clickwrap version.** -[Source.](./app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb) -This example demonstrates how to use the Click API to create a new version of a clickwrap. -1. **Getting a list of clickwraps.** -[Source.](./app/services/clickwrap/eg004_list_clickwraps_service.rb) -This example demonstrates how to use the Click API to get a list of clickwraps associated with a specific DocuSign user. -1. **Getting clickwrap responses.** -[Source.](./app/services/clickwrap/eg005_clickwrap_responses_service.rb) -This example demonstrates how to use the Click API to get a list of clickwraps associated with a specific DocuSign user. +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). + +For a list of code examples that use the Click API, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/click-api/how-to/code-launchers#examples-and-languages) on the DocuSign Developer Center. ## Monitor API -**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/). + +**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/). 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/). -1. **Get monitoring data.** [Source](app/services/monitor_api/eg001_get_monitoring_dataset_service.rb) - Demonstrates how to get and display all of your organization’s monitoring data. +For a list of code examples that use the Monitor API, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/monitor-api/how-to/code-launchers/#examples-and-languages) on the DocuSign Developer Center. ## Installation @@ -247,7 +82,7 @@ For information about the scopes used for obtaining authorization to use the Mon 1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. 1. In your command-line environment, switch to the folder: `cd ` or `cd code-examples-ruby` -1. Install the dependencies: `bundler install` +1. To install dependencies, run: `bundler install` 1. To configure the launcher for [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. 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 appsettings.yml as your `integration_key`. 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 appsettings.yml as your `integration_secret`. From 2854aaca1b7db88848342b1f499756fee539fac0 Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Tue, 1 Jun 2021 16:19:35 -0700 Subject: [PATCH 089/363] responding to PR comments --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0fdfdc3..44a983c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Ruby Launcher Code Examples -### Github repo: https://github.com/docusign/code-examples-ruby +### Github repo: [code-examples-ruby](./) -This GitHub repo includes code examples for the DocuSign eSignature REST API, Rooms API, Click API, and Monitor API. To switch between API code examples, modify the `examples_API` setting at the end of the configuration file. Set only one API type to `true` and set the remaining to `false`. +This GitHub repo includes code examples for the DocuSign eSignature REST API, Rooms API, Click API, and Monitor API. To switch between API code examples, modify the `examples_API` setting in the appsettings.yml file. Set only one API type to `true` and set the remaining to `false`. If none of the API types are set to `true`, the DocuSign eSignature REST API code examples will be shown. If multiple API types are set to `true`, only the first will be shown. @@ -79,7 +79,7 @@ For a list of code examples that use the Monitor API, select the Ruby tab under ### 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-ruby repository. +1. Extract the Quickstart ZIP file, or download or clone the code-examples-ruby repository. 1. In your command-line environment, switch to the folder: `cd ` or `cd code-examples-ruby` 1. To install dependencies, run: `bundler install` From 229860c7abfd0aa9a8f4cce6fb599be2c42a4586 Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Tue, 1 Jun 2021 16:20:27 -0700 Subject: [PATCH 090/363] last small fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 44a983c..1becc0d 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ For a list of code examples that use the eSignature API, select the Ruby tab und ## Rooms API -**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. +**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/). For a list of code examples that use the Rooms API, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/rooms-api/how-to/code-launchers#examples-and-languages) on the DocuSign Developer Center. From 46063fbc5754e483426cc65dd6fcec8d17c986ab Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Thu, 3 Jun 2021 16:41:44 -0700 Subject: [PATCH 091/363] fix first link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1becc0d..64d5afd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Ruby Launcher Code Examples -### Github repo: [code-examples-ruby](./) +### GitHub repo: [code-examples-ruby](./README.md) This GitHub repo includes code examples for the DocuSign eSignature REST API, Rooms API, Click API, and Monitor API. To switch between API code examples, modify the `examples_API` setting in the appsettings.yml file. Set only one API type to `true` and set the remaining to `false`. From 83f840f614f3c91a5119c994d35cdb14200acfe2 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Thu, 3 Jun 2021 16:42:26 -0700 Subject: [PATCH 092/363] fix first link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1becc0d..64d5afd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Ruby Launcher Code Examples -### Github repo: [code-examples-ruby](./) +### GitHub repo: [code-examples-ruby](./README.md) This GitHub repo includes code examples for the DocuSign eSignature REST API, Rooms API, Click API, and Monitor API. To switch between API code examples, modify the `examples_API` setting in the appsettings.yml file. Set only one API type to `true` and set the remaining to `false`. From 3dc75a62c1c47e6e4b46fed7b9288c20dc14219d Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Fri, 4 Jun 2021 15:18:36 -0700 Subject: [PATCH 093/363] updating gem file to use new SDK --- Gemfile.lock | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 1b5a9e2..a2b2ca4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -96,7 +96,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_monitor (1.0.1.pre.alpha) + docusign_monitor (1.0.0.beta1) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -271,6 +271,7 @@ GEM PLATFORMS x64-mingw32 + x86_64-darwin-19 x86_64-darwin-20 x86_64-linux From 4fbe949fe292d62be33456653edab76935a80a83 Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Mon, 7 Jun 2021 12:54:27 -0700 Subject: [PATCH 094/363] updating to use new sdk and new method name --- .../eg001_get_monitoring_dataset_service.rb | 20 +++++-------------- .../eg001_get_monitoring_dataset/get.html.erb | 2 +- app/views/monitor_api/index.html.erb | 2 +- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb index 7722e6a..8fee741 100644 --- a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb +++ b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb @@ -23,24 +23,14 @@ def call # step 3 start monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) - options = DocuSign_Monitor::GetStreamForDatasetOptions.default + options = DocuSign_Monitor::GetStreamOptions.default + @response = monitor_api.get_stream('monitor', '2.0').data - while true do - options.cursor = @cursor - response = monitor_api.get_stream_for_dataset('monitor', '2.0', options).first - - # 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 - break if response[:endCursor] == @cursor - - @results_memo.push(response) - @cursor = response[:endCursor] - end - # step 3 end + # step 3 end Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" - Rails.logger.info @results_memo.inspect + Rails.logger.info @response.inspect - return @results_memo + return @response end end diff --git a/app/views/monitor_api/eg001_get_monitoring_dataset/get.html.erb b/app/views/monitor_api/eg001_get_monitoring_dataset/get.html.erb index 898ca82..c8838fa 100644 --- a/app/views/monitor_api/eg001_get_monitoring_dataset/get.html.erb +++ b/app/views/monitor_api/eg001_get_monitoring_dataset/get.html.erb @@ -2,7 +2,7 @@

Demonstrates how to get and display all of your organization’s monitoring data.

API method used: - DataSet:GetStreamForDataset + DataSet:GetStream

diff --git a/app/views/monitor_api/index.html.erb b/app/views/monitor_api/index.html.erb index 054cdb1..7f747c4 100644 --- a/app/views/monitor_api/index.html.erb +++ b/app/views/monitor_api/index.html.erb @@ -30,7 +30,7 @@

API method used: - DataSet:GetStreamForDataset + DataSet:GetStream

From 38f15bd4b847631b0b8e30128a2484a41b0a88ae Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Wed, 9 Jun 2021 09:49:02 -0700 Subject: [PATCH 095/363] update esign sdk and eg034 (#34) --- Gemfile | 2 +- Gemfile.lock | 9 +++++++-- .../e_sign/eg034_use_conditional_recipients_service.rb | 6 ++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 6e83e20..71fc08e 100644 --- a/Gemfile +++ b/Gemfile @@ -66,7 +66,7 @@ group :test do gem 'chromedriver-helper', '~> 2.1.1' end -gem 'docusign_esign', '~> 3.8.0.rc1' +gem 'docusign_esign', '~> 3.10.0.rc1' gem 'docusign_monitor', '~> 1.0.0.beta1' gem 'docusign_rooms', '~> 1.1.0.rc1' gem 'docusign_click', '~> 1.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index 713255a..5ec47f0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -92,7 +92,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.8.0.rc1) + docusign_esign (3.10.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) @@ -220,6 +220,8 @@ GEM rubyzip (2.3.0) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) + sassc (2.4.0) + ffi (~> 1.9) sassc (2.4.0-x64-mingw32) ffi (~> 1.9) sassc-rails (2.1.2) @@ -253,8 +255,11 @@ GEM ethon (>= 0.9.0) tzinfo (1.2.9) thread_safe (~> 0.1) + tzinfo-data (1.2019.3) + tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) + wdm (0.1.1) web-console (4.0.4) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -280,7 +285,7 @@ DEPENDENCIES chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) docusign_click (~> 1.0.0) - docusign_esign (~> 3.8.0.rc1) + docusign_esign (~> 3.10.0.rc1) docusign_monitor (~> 1.0.0.beta1) docusign_rooms (~> 1.1.0.rc1) jbuilder (~> 2.10.0) diff --git a/app/services/e_sign/eg034_use_conditional_recipients_service.rb b/app/services/e_sign/eg034_use_conditional_recipients_service.rb index 8cf17bf..0c09ef1 100644 --- a/app/services/e_sign/eg034_use_conditional_recipients_service.rb +++ b/app/services/e_sign/eg034_use_conditional_recipients_service.rb @@ -134,7 +134,8 @@ def call tabId: 'ApprovalTab', operator: 'equals', value: false, - tabLabel: 'ApproveWhenChecked' + tabLabel: 'ApproveWhenChecked', + tabType: 'checkbox' ) filter2 = DocuSign_eSign::ConditionalRecipientRuleFilter.new( scope: 'tabs', @@ -142,7 +143,8 @@ def call tabId: 'ApprovalTab', operator: 'equals', value: true, - tabLabel: 'ApproveWhenChecked' + tabLabel: 'ApproveWhenChecked', + tabType: 'checkbox' ) # Create conditionalRecipientRuleCondition models From 90015bd814942b30dc95d880e8e9d4a236036679 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Fri, 11 Jun 2021 12:24:17 -0700 Subject: [PATCH 096/363] move eg001_embedded_signing (#33) --- .../{e_sign => }/eg001_embedded_signing_controller.rb | 4 ++-- app/services/{e_sign => }/eg001_embedded_signing_service.rb | 2 +- app/views/{e_sign => }/eg001_embedded_signing/get.html.erb | 0 config/routes.rb | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) rename app/controllers/{e_sign => }/eg001_embedded_signing_controller.rb (81%) rename app/services/{e_sign => }/eg001_embedded_signing_service.rb (99%) rename app/views/{e_sign => }/eg001_embedded_signing/get.html.erb (100%) diff --git a/app/controllers/e_sign/eg001_embedded_signing_controller.rb b/app/controllers/eg001_embedded_signing_controller.rb similarity index 81% rename from app/controllers/e_sign/eg001_embedded_signing_controller.rb rename to app/controllers/eg001_embedded_signing_controller.rb index 3b00793..6e5a05d 100644 --- a/app/controllers/e_sign/eg001_embedded_signing_controller.rb +++ b/app/controllers/eg001_embedded_signing_controller.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class ESign::Eg001EmbeddedSigningController < EgController +class Eg001EmbeddedSigningController < EgController def create minimum_buffer_min = 10 token_ok = check_token(minimum_buffer_min) @@ -13,7 +13,7 @@ def create # authentication. redirect_to '/ds/mustAuthenticate' end - redirect_url = ESign::Eg001EmbeddedSigningService.new(session, request).call + redirect_url = Eg001EmbeddedSigningService.new(session, request).call redirect_to redirect_url end diff --git a/app/services/e_sign/eg001_embedded_signing_service.rb b/app/services/eg001_embedded_signing_service.rb similarity index 99% rename from app/services/e_sign/eg001_embedded_signing_service.rb rename to app/services/eg001_embedded_signing_service.rb index 8c398d5..9c8190a 100644 --- a/app/services/e_sign/eg001_embedded_signing_service.rb +++ b/app/services/eg001_embedded_signing_service.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class ESign::Eg001EmbeddedSigningService +class Eg001EmbeddedSigningService include ApiCreator attr_reader :signer_email, :signer_name, :args diff --git a/app/views/e_sign/eg001_embedded_signing/get.html.erb b/app/views/eg001_embedded_signing/get.html.erb similarity index 100% rename from app/views/e_sign/eg001_embedded_signing/get.html.erb rename to app/views/eg001_embedded_signing/get.html.erb diff --git a/config/routes.rb b/config/routes.rb index 97cb804..8c61a8e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -54,11 +54,11 @@ post 'eg001' => 'eg001_get_monitoring_dataset#create' end else + get '/eg001' => 'eg001_embedded_signing#get' + post '/eg001' => 'eg001_embedded_signing#create' + scope module: 'e_sign' do # Example controllers... - get 'eg001' => 'eg001_embedded_signing#get' - post 'eg001' => 'eg001_embedded_signing#create' - get 'eg002' => 'eg002_signing_via_email#get' post 'eg002' => 'eg002_signing_via_email#create' From c0ba7bc58e209105fad2280f6f9ef07d8d98e364 Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Thu, 17 Jun 2021 14:30:22 -0700 Subject: [PATCH 097/363] re-labeling example done page with correct method name --- .../e_sign/eg015_get_envelope_tab_data_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/e_sign/eg015_get_envelope_tab_data_controller.rb b/app/controllers/e_sign/eg015_get_envelope_tab_data_controller.rb index 9f6b6e2..20f7d24 100644 --- a/app/controllers/e_sign/eg015_get_envelope_tab_data_controller.rb +++ b/app/controllers/e_sign/eg015_get_envelope_tab_data_controller.rb @@ -8,7 +8,7 @@ def create if token_ok results = ESign::Eg015GetEnvelopeTabDataService.new(envelope_id, session).call @h1 = 'List envelopes results' - @message = 'Results from the Envelopes::listStatusChanges method:' + @message = 'Results from the EnvelopeFormData::get method:' @json = results.to_json.to_json render 'ds_common/example_done' else From 157ccc76f39256b41f7faff0449415204cd72644 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Jun 2021 21:55:08 +0000 Subject: [PATCH 098/363] Bump puma from 4.3.7 to 4.3.8 Bumps [puma](https://github.com/puma/puma) from 4.3.7 to 4.3.8. - [Release notes](https://github.com/puma/puma/releases) - [Changelog](https://github.com/puma/puma/blob/master/History.md) - [Commits](https://github.com/puma/puma/compare/v4.3.7...v4.3.8) --- updated-dependencies: - dependency-name: puma dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index e44be3a..a5f5477 100644 --- a/Gemfile +++ b/Gemfile @@ -10,7 +10,7 @@ gem 'rails', '~> 6.0.3.5' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4.2' # Use Puma as the app server -gem 'puma', '~> 4.3.3' +gem 'puma', '~> 4.3.8' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets diff --git a/Gemfile.lock b/Gemfile.lock index a9a9ab2..1ae1bcd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -170,7 +170,7 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.6) - puma (4.3.7) + puma (4.3.8) nio4r (~> 2.0) racc (1.5.2) rack (2.2.3) @@ -284,7 +284,7 @@ DEPENDENCIES omniauth-rails_csrf_protection pry-nav (~> 0.3.0) pry-rails (~> 0.3.9) - puma (~> 4.3.3) + puma (~> 4.3.8) rails (~> 6.0.3.5) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) From 92250fa345358a90cacc91cfa5b766f257563240 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Mon, 28 Jun 2021 13:24:56 -0700 Subject: [PATCH 099/363] Devdocs 5062 (#37) * Bump puma from 4.3.7 to 4.3.8 Bumps [puma](https://github.com/puma/puma) from 4.3.7 to 4.3.8. - [Release notes](https://github.com/puma/puma/releases) - [Changelog](https://github.com/puma/puma/blob/master/History.md) - [Commits](https://github.com/puma/puma/compare/v4.3.7...v4.3.8) Signed-off-by: dependabot[bot] * Bump nokogiri from 1.11.3 to 1.11.7 Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.11.3 to 1.11.7. - [Release notes](https://github.com/sparklemotion/nokogiri/releases) - [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md) - [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.11.3...v1.11.7) --- updated-dependencies: - dependency-name: nokogiri dependency-type: indirect ... Signed-off-by: dependabot[bot] * update dependencies * update gemfile.lock Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 136 ++++++++++++++++++++++++++------------------------- 2 files changed, 71 insertions(+), 67 deletions(-) diff --git a/Gemfile b/Gemfile index 71fc08e..f29ee6c 100644 --- a/Gemfile +++ b/Gemfile @@ -10,7 +10,7 @@ gem 'rails', '~> 6.0.3.5' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4.2' # Use Puma as the app server -gem 'puma', '~> 4.3.3' +gem 'puma', '~> 4.3.8' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets diff --git a/Gemfile.lock b/Gemfile.lock index 5ec47f0..dea001a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,56 +1,56 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.3.6) - actionpack (= 6.0.3.6) + actioncable (6.0.3.7) + actionpack (= 6.0.3.7) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.3.6) - actionpack (= 6.0.3.6) - activejob (= 6.0.3.6) - activerecord (= 6.0.3.6) - activestorage (= 6.0.3.6) - activesupport (= 6.0.3.6) + actionmailbox (6.0.3.7) + actionpack (= 6.0.3.7) + activejob (= 6.0.3.7) + activerecord (= 6.0.3.7) + activestorage (= 6.0.3.7) + activesupport (= 6.0.3.7) mail (>= 2.7.1) - actionmailer (6.0.3.6) - actionpack (= 6.0.3.6) - actionview (= 6.0.3.6) - activejob (= 6.0.3.6) + actionmailer (6.0.3.7) + actionpack (= 6.0.3.7) + actionview (= 6.0.3.7) + activejob (= 6.0.3.7) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.3.6) - actionview (= 6.0.3.6) - activesupport (= 6.0.3.6) + actionpack (6.0.3.7) + actionview (= 6.0.3.7) + activesupport (= 6.0.3.7) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.3.6) - actionpack (= 6.0.3.6) - activerecord (= 6.0.3.6) - activestorage (= 6.0.3.6) - activesupport (= 6.0.3.6) + actiontext (6.0.3.7) + actionpack (= 6.0.3.7) + activerecord (= 6.0.3.7) + activestorage (= 6.0.3.7) + activesupport (= 6.0.3.7) nokogiri (>= 1.8.5) - actionview (6.0.3.6) - activesupport (= 6.0.3.6) + actionview (6.0.3.7) + activesupport (= 6.0.3.7) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.3.6) - activesupport (= 6.0.3.6) + activejob (6.0.3.7) + activesupport (= 6.0.3.7) globalid (>= 0.3.6) - activemodel (6.0.3.6) - activesupport (= 6.0.3.6) - activerecord (6.0.3.6) - activemodel (= 6.0.3.6) - activesupport (= 6.0.3.6) - activestorage (6.0.3.6) - actionpack (= 6.0.3.6) - activejob (= 6.0.3.6) - activerecord (= 6.0.3.6) + activemodel (6.0.3.7) + activesupport (= 6.0.3.7) + activerecord (6.0.3.7) + activemodel (= 6.0.3.7) + activesupport (= 6.0.3.7) + activestorage (6.0.3.7) + actionpack (= 6.0.3.7) + activejob (= 6.0.3.7) + activerecord (= 6.0.3.7) marcel (~> 1.0.0) - activesupport (6.0.3.6) + activesupport (6.0.3.7) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -61,7 +61,7 @@ GEM archive-zip (0.12.0) io-like (~> 0.3.0) bindex (0.8.1) - bootsnap (1.7.4) + bootsnap (1.7.5) msgpack (~> 1.0) builder (3.2.4) byebug (11.1.3) @@ -85,7 +85,7 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.1.8) + concurrent-ruby (1.1.9) crass (1.0.6) docusign_click (1.0.0) addressable (~> 2.7, >= 2.7.0) @@ -96,7 +96,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_monitor (1.0.0.beta1) + docusign_monitor (1.0.1.pre.alpha) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -106,20 +106,24 @@ GEM jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) erubi (1.10.0) - ethon (0.13.0) + ethon (0.14.0) ffi (>= 1.15.0) - execjs (2.7.0) - faraday (1.4.1) + execjs (2.8.1) + faraday (1.4.3) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) faraday-net_http (~> 1.0) faraday-net_http_persistent (~> 1.1) multipart-post (>= 1.2, < 3) ruby2_keywords (>= 0.0.4) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-net_http (1.0.1) faraday-net_http_persistent (1.1.0) - ffi (1.15.0) - ffi (1.15.0-x64-mingw32) + ffi (1.15.3) + ffi (1.15.3-x64-mingw32) globalid (0.4.2) activesupport (>= 4.2.0) hashie (4.1.0) @@ -133,7 +137,7 @@ GEM listen (3.2.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.9.1) + loofah (2.10.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -147,11 +151,11 @@ GEM multi_xml (0.6.0) multipart-post (2.1.1) nio4r (2.5.7) - nokogiri (1.11.3-x64-mingw32) + nokogiri (1.11.7-x64-mingw32) racc (~> 1.4) - nokogiri (1.11.3-x86_64-darwin) + nokogiri (1.11.7-x86_64-darwin) racc (~> 1.4) - nokogiri (1.11.3-x86_64-linux) + nokogiri (1.11.7-x86_64-linux) racc (~> 1.4) oauth2 (1.4.7) faraday (>= 0.8, < 2.0) @@ -177,7 +181,7 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.6) - puma (4.3.7) + puma (4.3.8) nio4r (~> 2.0) racc (1.5.2) rack (2.2.3) @@ -185,34 +189,34 @@ GEM rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.0.3.6) - actioncable (= 6.0.3.6) - actionmailbox (= 6.0.3.6) - actionmailer (= 6.0.3.6) - actionpack (= 6.0.3.6) - actiontext (= 6.0.3.6) - actionview (= 6.0.3.6) - activejob (= 6.0.3.6) - activemodel (= 6.0.3.6) - activerecord (= 6.0.3.6) - activestorage (= 6.0.3.6) - activesupport (= 6.0.3.6) + rails (6.0.3.7) + actioncable (= 6.0.3.7) + actionmailbox (= 6.0.3.7) + actionmailer (= 6.0.3.7) + actionpack (= 6.0.3.7) + actiontext (= 6.0.3.7) + actionview (= 6.0.3.7) + activejob (= 6.0.3.7) + activemodel (= 6.0.3.7) + activerecord (= 6.0.3.7) + activestorage (= 6.0.3.7) + activesupport (= 6.0.3.7) bundler (>= 1.3.0) - railties (= 6.0.3.6) + railties (= 6.0.3.7) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) - railties (6.0.3.6) - actionpack (= 6.0.3.6) - activesupport (= 6.0.3.6) + railties (6.0.3.7) + actionpack (= 6.0.3.7) + activesupport (= 6.0.3.7) method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) rake (13.0.3) - rb-fsevent (0.10.4) + rb-fsevent (0.11.0) rb-inotify (0.10.1) ffi (~> 1.0) regexp_parser (1.8.2) @@ -265,7 +269,7 @@ GEM activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - websocket-driver (0.7.3) + websocket-driver (0.7.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) @@ -294,7 +298,7 @@ DEPENDENCIES omniauth-rails_csrf_protection pry-nav (~> 0.3.0) pry-rails (~> 0.3.9) - puma (~> 4.3.3) + puma (~> 4.3.8) rails (~> 6.0.3.5) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) From 5e4542347e72077df95be1569ca0734cb43f1d46 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Mon, 28 Jun 2021 15:31:46 -0700 Subject: [PATCH 100/363] update Monitor SDK version --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 71fc08e..b665475 100644 --- a/Gemfile +++ b/Gemfile @@ -67,7 +67,7 @@ group :test do end gem 'docusign_esign', '~> 3.10.0.rc1' -gem 'docusign_monitor', '~> 1.0.0.beta1' +gem 'docusign_monitor', '~> 1.0.0' gem 'docusign_rooms', '~> 1.1.0.rc1' gem 'docusign_click', '~> 1.0.0' gem 'omniauth-oauth2', '~> 1.7.1' diff --git a/Gemfile.lock b/Gemfile.lock index 5ec47f0..11796ec 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -96,7 +96,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_monitor (1.0.0.beta1) + docusign_monitor (1.0.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -286,7 +286,7 @@ DEPENDENCIES coffee-rails (~> 5.0.0) docusign_click (~> 1.0.0) docusign_esign (~> 3.10.0.rc1) - docusign_monitor (~> 1.0.0.beta1) + docusign_monitor (~> 1.0.0) docusign_rooms (~> 1.1.0.rc1) jbuilder (~> 2.10.0) listen (~> 3.2.1) From fc8e619bc82d75400535aeff39d6548c09a59ce9 Mon Sep 17 00:00:00 2001 From: Matthew Lusher Date: Mon, 12 Jul 2021 19:42:07 -0400 Subject: [PATCH 101/363] Updating links to DevCenter --- .../eg013_add_doc_to_template_service.rb | 2 +- app/views/ds_common/index.html.erb | 84 +++++++++---------- .../eg002_signing_via_email/get.html.erb | 4 +- .../e_sign/eg003_list_envelopes/get.html.erb | 2 +- .../e_sign/eg004_envelope_info/get.html.erb | 2 +- .../eg005_envelope_recipients/get.html.erb | 2 +- .../e_sign/eg006_envelope_docs/get.html.erb | 2 +- .../eg007_envelope_get_doc/get.html.erb | 2 +- .../e_sign/eg008_create_template/get.html.erb | 4 +- .../e_sign/eg009_use_template/get.html.erb | 2 +- .../eg010_send_binary_docs/get.html.erb | 2 +- .../eg011_embedded_sending/get.html.erb | 6 +- .../eg012_embedded_console/get.html.erb | 2 +- .../eg013_add_doc_to_template/get.html.erb | 6 +- .../e_sign/eg014_collect_payment/get.html.erb | 4 +- .../eg015_get_envelope_tab_data/get.html.erb | 2 +- .../eg016_set_envelope_tab_data/get.html.erb | 2 +- .../get.html.erb | 2 +- .../get.html.erb | 2 +- .../get.html.erb | 4 +- .../eg020_sms_authentication/get.html.erb | 4 +- .../eg021_phone_authentication/get.html.erb | 4 +- .../eg022_kba_authentication/get.html.erb | 4 +- .../eg023_idv_authentication/get.html.erb | 4 +- .../eg024_permission_create/get.html.erb | 2 +- .../get.html.erb | 2 +- .../get.html.erb | 2 +- .../e_sign/eg028_brands_creating/get.html.erb | 2 +- .../get.html.erb | 4 +- .../get.html.erb | 2 +- .../eg031_bulk_sending_envelopes/get.html.erb | 6 +- app/views/eg001_embedded_signing/get.html.erb | 4 +- 32 files changed, 89 insertions(+), 89 deletions(-) diff --git a/app/services/e_sign/eg013_add_doc_to_template_service.rb b/app/services/e_sign/eg013_add_doc_to_template_service.rb index 130381c..1e81e36 100644 --- a/app/services/e_sign/eg013_add_doc_to_template_service.rb +++ b/app/services/e_sign/eg013_add_doc_to_template_service.rb @@ -47,7 +47,7 @@ def worker # 3. Create the Recipient View request object authentication_method = 'None' # How is this application authenticating # the signer? See the `authenticationMethod' definition - # https://developers.docusign.com/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient + # https://developers.docusign.com/docs/esign-rest-api/reference/envelopes/envelopeviews/createrecipient/ recipient_view_request = DocuSign_eSign::RecipientViewRequest.new( authenticationMethod: authentication_method, returnUrl: envelope_args[:ds_return_url], diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index 25059b3..c799ac4 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -38,24 +38,24 @@ With embedded signing, the DocuSign signing is initiated from your website.

API methods used: - Envelopes::create and - EnvelopeViews::createRecipient. + 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) + (AutoPlace) is used to position the signing fields in the documents.

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

3. List envelopes in the user's account

List the envelopes created in the last 30 days.

API method used: - Envelopes::listStatusChanges. + Envelopes::listStatusChanges.

4. Get an envelope's basic information and status

@@ -64,14 +64,14 @@ envelope, its documents, recipients, etc.

API method used: - Envelopes::get. + 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. + EnvelopeRecipients::list.

6. List an envelope's documents

@@ -79,28 +79,28 @@ is also associated with every envelope.

API method used: - EnvelopeDocuments::list. + 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. + EnvelopeDocuments::get.

8. Create a template

Create a template with two roles, signer and cc.

API methods used: - Templates::list, - Templates::create. + 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. + Envelopes::create.

10. Send an envelope using binary document transfer

@@ -110,7 +110,7 @@ Binary transfer is not yet supported by the SDK.

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

11. Use embedded sending

@@ -119,94 +119,94 @@ to the envelope before it is sent.

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

12. Embedded DocuSign web tool

Redirect the user to the DocuSign web tool.

API method used: - EnvelopeViews::createConsole. + EnvelopeViews::createConsole.

13. 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 + Composite Templates feature.

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

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

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

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

15. Get the tab data from an envelope

-

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

+

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

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

16. Set tab values for a 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. + Envelopes::create.

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. + Envelopes::create.

18. List envelope custom metadata field values

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

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

Recipient Authentication

19. Send an envelope with Access Code Recipient Authentication

Submit an envelope with an access code for multi-factor authentication.

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

20. Send an envelope with SMS Recipient Authentication

Submit an envelope with a text message for multi-factor authentication.

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

21. Send an envelope with Phone Recipient Authentication

Submit an envelope with a voice call to provide multi-factor authentication.

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

22. Send an envelope with Recipient Knowledged Based Authentication

Submit an envelope with multiple choice, public records based questions to provide multi-factor authentication.

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

23. IDV Authentication

This is an example of an envelope utilizing Id verification authentication for a recipient.

API methods used: Accounts::getAccountIdentityVerificationsList. - Envelopes::create. + Envelopes::create.

24. Creating a Permission Profile

@@ -220,7 +220,7 @@

25. Setting a permission profile

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

API method used: - Groups::update. + Groups::update.

26. Modify a Permission Profile

@@ -228,60 +228,60 @@ This example updates an individual setting on a permission profile.

API method used: - AccountPermissionProfiles::update. + AccountPermissionProfiles::update.

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. + 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. + 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. + 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. + Envelopes::create.

31. Bulk sending envelopes to multiple recipients

This example will show you how to create and send an envelope to multiple recipients using bulk lists.

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

Advanced recipient routing

32. Pausing a signature workflow

Pauses signature workflow.

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

33. Unpausing a signature workflow

Unpauses a signature workflow.

API method used: - Envelopes::update. + Envelopes::update.

34. Using conditional recipients

Uses conditional recipients.

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

Premium Features

diff --git a/app/views/e_sign/eg002_signing_via_email/get.html.erb b/app/views/e_sign/eg002_signing_via_email/get.html.erb index 0fa0add..06b733c 100644 --- a/app/views/e_sign/eg002_signing_via_email/get.html.erb +++ b/app/views/e_sign/eg002_signing_via_email/get.html.erb @@ -1,6 +1,6 @@

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

The envelope includes a pdf, Word, and HTML document. Anchor text - (AutoPlace) + (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, @@ -11,7 +11,7 @@ <% end %>

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

diff --git a/app/views/e_sign/eg003_list_envelopes/get.html.erb b/app/views/e_sign/eg003_list_envelopes/get.html.erb index a3fb9c9..0466a86 100644 --- a/app/views/e_sign/eg003_list_envelopes/get.html.erb +++ b/app/views/e_sign/eg003_list_envelopes/get.html.erb @@ -7,7 +7,7 @@ <% end %>

API method used: - Envelopes::listStatusChanges. + Envelopes::listStatusChanges.

View source file <%= @source_file %> on GitHub. diff --git a/app/views/e_sign/eg004_envelope_info/get.html.erb b/app/views/e_sign/eg004_envelope_info/get.html.erb index 62324e6..2a36d02 100644 --- a/app/views/e_sign/eg004_envelope_info/get.html.erb +++ b/app/views/e_sign/eg004_envelope_info/get.html.erb @@ -14,7 +14,7 @@ <% end %>

API method used: - Envelopes::get. + Envelopes::get.

diff --git a/app/views/e_sign/eg005_envelope_recipients/get.html.erb b/app/views/e_sign/eg005_envelope_recipients/get.html.erb index b909ffa..7cf793a 100644 --- a/app/views/e_sign/eg005_envelope_recipients/get.html.erb +++ b/app/views/e_sign/eg005_envelope_recipients/get.html.erb @@ -6,7 +6,7 @@ <% end %>

API method used: - EnvelopeRecipients::list. + EnvelopeRecipients::list.

View source file <%= @source_file %> on GitHub. diff --git a/app/views/e_sign/eg006_envelope_docs/get.html.erb b/app/views/e_sign/eg006_envelope_docs/get.html.erb index 26b91b6..ea4a25d 100644 --- a/app/views/e_sign/eg006_envelope_docs/get.html.erb +++ b/app/views/e_sign/eg006_envelope_docs/get.html.erb @@ -11,7 +11,7 @@ <% end %>

API method used: - EnvelopeDocuments::list. + EnvelopeDocuments::list.

diff --git a/app/views/e_sign/eg007_envelope_get_doc/get.html.erb b/app/views/e_sign/eg007_envelope_get_doc/get.html.erb index 3e44943..9f9381f 100644 --- a/app/views/e_sign/eg007_envelope_get_doc/get.html.erb +++ b/app/views/e_sign/eg007_envelope_get_doc/get.html.erb @@ -16,7 +16,7 @@ <% end %>

API method used: - EnvelopeDocuments::get. + EnvelopeDocuments::get.

diff --git a/app/views/e_sign/eg008_create_template/get.html.erb b/app/views/e_sign/eg008_create_template/get.html.erb index da1fdf3..9dce1d7 100644 --- a/app/views/e_sign/eg008_create_template/get.html.erb +++ b/app/views/e_sign/eg008_create_template/get.html.erb @@ -14,8 +14,8 @@ <% end %>

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

diff --git a/app/views/e_sign/eg009_use_template/get.html.erb b/app/views/e_sign/eg009_use_template/get.html.erb index a989103..180d9c2 100644 --- a/app/views/e_sign/eg009_use_template/get.html.erb +++ b/app/views/e_sign/eg009_use_template/get.html.erb @@ -13,7 +13,7 @@ <% end %>

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

View source file <%= @source_file %> on GitHub. diff --git a/app/views/e_sign/eg010_send_binary_docs/get.html.erb b/app/views/e_sign/eg010_send_binary_docs/get.html.erb index bc0d219..00c7daa 100644 --- a/app/views/e_sign/eg010_send_binary_docs/get.html.erb +++ b/app/views/e_sign/eg010_send_binary_docs/get.html.erb @@ -12,7 +12,7 @@ <% end %>

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

diff --git a/app/views/e_sign/eg011_embedded_sending/get.html.erb b/app/views/e_sign/eg011_embedded_sending/get.html.erb index d217cbd..932a096 100644 --- a/app/views/e_sign/eg011_embedded_sending/get.html.erb +++ b/app/views/e_sign/eg011_embedded_sending/get.html.erb @@ -2,7 +2,7 @@

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) + (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. @@ -17,8 +17,8 @@ <% end %>

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

diff --git a/app/views/e_sign/eg012_embedded_console/get.html.erb b/app/views/e_sign/eg012_embedded_console/get.html.erb index 370fecc..2eccd5e 100644 --- a/app/views/e_sign/eg012_embedded_console/get.html.erb +++ b/app/views/e_sign/eg012_embedded_console/get.html.erb @@ -13,7 +13,7 @@ <% end %>

API method used: - EnvelopeViews::createConsole. + EnvelopeViews::createConsole.

diff --git a/app/views/e_sign/eg013_add_doc_to_template/get.html.erb b/app/views/e_sign/eg013_add_doc_to_template/get.html.erb index 9d7f4f4..788323e 100644 --- a/app/views/e_sign/eg013_add_doc_to_template/get.html.erb +++ b/app/views/e_sign/eg013_add_doc_to_template/get.html.erb @@ -4,7 +4,7 @@

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 + Composite Templates feature.

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

@@ -19,8 +19,8 @@ <% end %>

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

View source file <%= @source_file %> on GitHub. diff --git a/app/views/e_sign/eg014_collect_payment/get.html.erb b/app/views/e_sign/eg014_collect_payment/get.html.erb index 9216986..e1b9d73 100644 --- a/app/views/e_sign/eg014_collect_payment/get.html.erb +++ b/app/views/e_sign/eg014_collect_payment/get.html.erb @@ -1,7 +1,7 @@

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

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

@@ -10,7 +10,7 @@ <% end %>

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

diff --git a/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb b/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb index af61e84..80bf58e 100644 --- a/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb +++ b/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb @@ -12,7 +12,7 @@ <% end %>

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

diff --git a/app/views/e_sign/eg016_set_envelope_tab_data/get.html.erb b/app/views/e_sign/eg016_set_envelope_tab_data/get.html.erb index e144d94..76b49c2 100644 --- a/app/views/e_sign/eg016_set_envelope_tab_data/get.html.erb +++ b/app/views/e_sign/eg016_set_envelope_tab_data/get.html.erb @@ -13,7 +13,7 @@

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

diff --git a/app/views/e_sign/eg017_set_template_tab_values/get.html.erb b/app/views/e_sign/eg017_set_template_tab_values/get.html.erb index 83c6c47..2007f15 100644 --- a/app/views/e_sign/eg017_set_template_tab_values/get.html.erb +++ b/app/views/e_sign/eg017_set_template_tab_values/get.html.erb @@ -11,7 +11,7 @@ <% end %>

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

diff --git a/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb b/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb index 92d0f45..5620d21 100644 --- a/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb +++ b/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb @@ -15,7 +15,7 @@ <% end %>

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

diff --git a/app/views/e_sign/eg019_access_code_authentication/get.html.erb b/app/views/e_sign/eg019_access_code_authentication/get.html.erb index 70ca581..bf34e72 100644 --- a/app/views/e_sign/eg019_access_code_authentication/get.html.erb +++ b/app/views/e_sign/eg019_access_code_authentication/get.html.erb @@ -1,7 +1,7 @@

19. Requiring an Access Code for a Recipient

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

@@ -14,7 +14,7 @@

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

diff --git a/app/views/e_sign/eg020_sms_authentication/get.html.erb b/app/views/e_sign/eg020_sms_authentication/get.html.erb index 33fa6f3..ea735e4 100644 --- a/app/views/e_sign/eg020_sms_authentication/get.html.erb +++ b/app/views/e_sign/eg020_sms_authentication/get.html.erb @@ -1,7 +1,7 @@

20. Requiring an SMS Code for a Recipient

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

@@ -12,7 +12,7 @@ <% end %>

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

diff --git a/app/views/e_sign/eg021_phone_authentication/get.html.erb b/app/views/e_sign/eg021_phone_authentication/get.html.erb index e4544b0..d85f8e8 100644 --- a/app/views/e_sign/eg021_phone_authentication/get.html.erb +++ b/app/views/e_sign/eg021_phone_authentication/get.html.erb @@ -1,7 +1,7 @@

21. Requiring Phone Authentication for a Recipient

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

@@ -12,7 +12,7 @@ <% end %>

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

diff --git a/app/views/e_sign/eg022_kba_authentication/get.html.erb b/app/views/e_sign/eg022_kba_authentication/get.html.erb index fb39ead..21cdf28 100644 --- a/app/views/e_sign/eg022_kba_authentication/get.html.erb +++ b/app/views/e_sign/eg022_kba_authentication/get.html.erb @@ -1,7 +1,7 @@

22. Requiring Knowledge Based Authentication (KBA) for a Recipient

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

@@ -12,7 +12,7 @@ <% end %>

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

diff --git a/app/views/e_sign/eg023_idv_authentication/get.html.erb b/app/views/e_sign/eg023_idv_authentication/get.html.erb index 202af2c..b6e54e1 100644 --- a/app/views/e_sign/eg023_idv_authentication/get.html.erb +++ b/app/views/e_sign/eg023_idv_authentication/get.html.erb @@ -1,6 +1,6 @@

23. Send an envelope with recipient Id Verification authentication.

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

This is an example of an envelope utilizing IDV authentication for multi-factor verification of a recipient. IDV is a service offered by DocuSign that allows your reicpient to upload a photo of a government issued id for verification.

@@ -10,7 +10,7 @@ <% end %>

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

diff --git a/app/views/e_sign/eg024_permission_create/get.html.erb b/app/views/e_sign/eg024_permission_create/get.html.erb index 56eed5b..436e96e 100644 --- a/app/views/e_sign/eg024_permission_create/get.html.erb +++ b/app/views/e_sign/eg024_permission_create/get.html.erb @@ -5,7 +5,7 @@

API method used: - AccountPermissionProfiles::create. + AccountPermissionProfiles::create.

View source file <%= @source_file %> on GitHub. diff --git a/app/views/e_sign/eg025_permissions_set_user_group/get.html.erb b/app/views/e_sign/eg025_permissions_set_user_group/get.html.erb index 7608575..02ff483 100644 --- a/app/views/e_sign/eg025_permissions_set_user_group/get.html.erb +++ b/app/views/e_sign/eg025_permissions_set_user_group/get.html.erb @@ -5,7 +5,7 @@

API method used: - Groups::update. + Groups::update.

diff --git a/app/views/e_sign/eg026_permissions_change_single_setting/get.html.erb b/app/views/e_sign/eg026_permissions_change_single_setting/get.html.erb index a171adf..5a14206 100644 --- a/app/views/e_sign/eg026_permissions_change_single_setting/get.html.erb +++ b/app/views/e_sign/eg026_permissions_change_single_setting/get.html.erb @@ -5,7 +5,7 @@

API method used: - AccountPermissionProfiles::update. + AccountPermissionProfiles::update.

View source file <%= @source_file %> on GitHub. diff --git a/app/views/e_sign/eg028_brands_creating/get.html.erb b/app/views/e_sign/eg028_brands_creating/get.html.erb index 7eb5c49..a148952 100644 --- a/app/views/e_sign/eg028_brands_creating/get.html.erb +++ b/app/views/e_sign/eg028_brands_creating/get.html.erb @@ -7,7 +7,7 @@ <% end %>

API method used: - AccountsBrands::create. + AccountsBrands::create.

diff --git a/app/views/e_sign/eg029_brands_apply_to_envelope/get.html.erb b/app/views/e_sign/eg029_brands_apply_to_envelope/get.html.erb index f32ee07..7752aee 100644 --- a/app/views/e_sign/eg029_brands_apply_to_envelope/get.html.erb +++ b/app/views/e_sign/eg029_brands_apply_to_envelope/get.html.erb @@ -2,12 +2,12 @@

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

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

diff --git a/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb b/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb index 1c038ee..57c593d 100644 --- a/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb +++ b/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb @@ -5,7 +5,7 @@

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

diff --git a/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb b/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb index 184208f..acf833c 100644 --- a/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb +++ b/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb @@ -6,12 +6,12 @@

API method used: - EnvelopeRecipients::create, - Envelopes::create, + EnvelopeRecipients::create, + Envelopes::create, BulkEnvelopes::get, EnvelopeCustomFields::create, BulkSend::createBulkSendList, - EnvelopeRecipients::create + EnvelopeRecipients::create

diff --git a/app/views/eg001_embedded_signing/get.html.erb b/app/views/eg001_embedded_signing/get.html.erb index 753ca7d..1471f37 100644 --- a/app/views/eg001_embedded_signing/get.html.erb +++ b/app/views/eg001_embedded_signing/get.html.erb @@ -7,8 +7,8 @@ <% end %>

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

View source file <%= @source_file %> on GitHub. From 8fa48c175e70f25e9429b53c28026e31a9d324d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jul 2021 01:32:54 +0000 Subject: [PATCH 102/363] Bump addressable from 2.7.0 to 2.8.0 Bumps [addressable](https://github.com/sporkmonger/addressable) from 2.7.0 to 2.8.0. - [Release notes](https://github.com/sporkmonger/addressable/releases) - [Changelog](https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md) - [Commits](https://github.com/sporkmonger/addressable/compare/addressable-2.7.0...addressable-2.8.0) --- updated-dependencies: - dependency-name: addressable dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5aadd14..fa4a920 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -56,7 +56,7 @@ GEM minitest (~> 5.1) tzinfo (~> 1.1) zeitwerk (~> 2.2, >= 2.2.2) - addressable (2.7.0) + addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) archive-zip (0.12.0) io-like (~> 0.3.0) From 78c3bacdc12cfa0e78a030df1af2bc13cef9ca62 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jul 2021 17:16:44 +0000 Subject: [PATCH 103/363] Bump addressable from 2.7.0 to 2.8.0 Bumps [addressable](https://github.com/sporkmonger/addressable) from 2.7.0 to 2.8.0. - [Release notes](https://github.com/sporkmonger/addressable/releases) - [Changelog](https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md) - [Commits](https://github.com/sporkmonger/addressable/compare/addressable-2.7.0...addressable-2.8.0) --- updated-dependencies: - dependency-name: addressable dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5aadd14..fa4a920 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -56,7 +56,7 @@ GEM minitest (~> 5.1) tzinfo (~> 1.1) zeitwerk (~> 2.2, >= 2.2.2) - addressable (2.7.0) + addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) archive-zip (0.12.0) io-like (~> 0.3.0) From 7ba3c9240657fc0011e90458eb5c773c8a6f59d2 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Fri, 27 Aug 2021 13:34:25 -0700 Subject: [PATCH 104/363] Add admin api (#36) Add admin api code examples --- Gemfile | 3 +- Gemfile.lock | 156 +++++++++--------- README.md | 64 +++---- .../admin_api/eg001_create_user_controller.rb | 50 ++++++ ...create_active_clm_esign_user_controller.rb | 53 ++++++ .../eg003_bulk_export_user_data_controller.rb | 37 +++++ .../admin_api/eg004_import_user_controller.rb | 37 +++++ .../admin_api/eg005_audit_users_controller.rb | 38 +++++ app/controllers/ds_common_controller.rb | 5 + .../admin_api/eg001_create_user_service.rb | 72 ++++++++ ...02_create_active_clm_esign_user_service.rb | 72 ++++++++ .../eg003_bulk_export_user_data_service.rb | 74 +++++++++ .../admin_api/eg004_import_user_service.rb | 40 +++++ .../admin_api/eg005_audit_users_service.rb | 51 ++++++ app/services/admin_api/get_data_service.rb | 48 ++++++ app/services/jwt_auth/jwt_creator.rb | 5 + .../admin_api/eg001_create_user/get.html.erb | 57 +++++++ .../get.html.erb | 70 ++++++++ .../eg003_bulk_export_user_data/get.html.erb | 17 ++ .../admin_api/eg004_import_user/get.html.erb | 16 ++ .../admin_api/eg005_audit_users/get.html.erb | 17 ++ app/views/admin_api/index.html.erb | 77 +++++++++ config/appsettings.example.yml | 3 + config/initializers/omniauth.rb | 2 + config/routes.rb | 17 ++ data/userData.csv | 3 + 26 files changed, 976 insertions(+), 108 deletions(-) create mode 100644 app/controllers/admin_api/eg001_create_user_controller.rb create mode 100644 app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb create mode 100644 app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb create mode 100644 app/controllers/admin_api/eg004_import_user_controller.rb create mode 100644 app/controllers/admin_api/eg005_audit_users_controller.rb create mode 100644 app/services/admin_api/eg001_create_user_service.rb create mode 100644 app/services/admin_api/eg002_create_active_clm_esign_user_service.rb create mode 100644 app/services/admin_api/eg003_bulk_export_user_data_service.rb create mode 100644 app/services/admin_api/eg004_import_user_service.rb create mode 100644 app/services/admin_api/eg005_audit_users_service.rb create mode 100644 app/services/admin_api/get_data_service.rb create mode 100644 app/views/admin_api/eg001_create_user/get.html.erb create mode 100644 app/views/admin_api/eg002_create_active_clm_esign_user/get.html.erb create mode 100644 app/views/admin_api/eg003_bulk_export_user_data/get.html.erb create mode 100644 app/views/admin_api/eg004_import_user/get.html.erb create mode 100644 app/views/admin_api/eg005_audit_users/get.html.erb create mode 100644 app/views/admin_api/index.html.erb create mode 100644 data/userData.csv diff --git a/Gemfile b/Gemfile index 7766a69..9912882 100644 --- a/Gemfile +++ b/Gemfile @@ -6,7 +6,7 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '~>2.7.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 6.0.3.5' +gem 'rails', '~> 6.0.4.1' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4.2' # Use Puma as the app server @@ -70,6 +70,7 @@ gem 'docusign_esign', '~> 3.10.0.rc1' gem 'docusign_monitor', '~> 1.0.0' gem 'docusign_rooms', '~> 1.1.0.rc1' gem 'docusign_click', '~> 1.0.0' +gem 'docusign_admin', '~> 1.0.0.beta' gem 'omniauth-oauth2', '~> 1.7.1' gem 'omniauth-rails_csrf_protection' diff --git a/Gemfile.lock b/Gemfile.lock index fa4a920..69def96 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,56 +1,56 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.3.7) - actionpack (= 6.0.3.7) + actioncable (6.0.4.1) + actionpack (= 6.0.4.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.3.7) - actionpack (= 6.0.3.7) - activejob (= 6.0.3.7) - activerecord (= 6.0.3.7) - activestorage (= 6.0.3.7) - activesupport (= 6.0.3.7) + actionmailbox (6.0.4.1) + actionpack (= 6.0.4.1) + activejob (= 6.0.4.1) + activerecord (= 6.0.4.1) + activestorage (= 6.0.4.1) + activesupport (= 6.0.4.1) mail (>= 2.7.1) - actionmailer (6.0.3.7) - actionpack (= 6.0.3.7) - actionview (= 6.0.3.7) - activejob (= 6.0.3.7) + actionmailer (6.0.4.1) + actionpack (= 6.0.4.1) + actionview (= 6.0.4.1) + activejob (= 6.0.4.1) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.3.7) - actionview (= 6.0.3.7) - activesupport (= 6.0.3.7) + actionpack (6.0.4.1) + actionview (= 6.0.4.1) + activesupport (= 6.0.4.1) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.3.7) - actionpack (= 6.0.3.7) - activerecord (= 6.0.3.7) - activestorage (= 6.0.3.7) - activesupport (= 6.0.3.7) + actiontext (6.0.4.1) + actionpack (= 6.0.4.1) + activerecord (= 6.0.4.1) + activestorage (= 6.0.4.1) + activesupport (= 6.0.4.1) nokogiri (>= 1.8.5) - actionview (6.0.3.7) - activesupport (= 6.0.3.7) + actionview (6.0.4.1) + activesupport (= 6.0.4.1) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.3.7) - activesupport (= 6.0.3.7) + activejob (6.0.4.1) + activesupport (= 6.0.4.1) globalid (>= 0.3.6) - activemodel (6.0.3.7) - activesupport (= 6.0.3.7) - activerecord (6.0.3.7) - activemodel (= 6.0.3.7) - activesupport (= 6.0.3.7) - activestorage (6.0.3.7) - actionpack (= 6.0.3.7) - activejob (= 6.0.3.7) - activerecord (= 6.0.3.7) + activemodel (6.0.4.1) + activesupport (= 6.0.4.1) + activerecord (6.0.4.1) + activemodel (= 6.0.4.1) + activesupport (= 6.0.4.1) + activestorage (6.0.4.1) + actionpack (= 6.0.4.1) + activejob (= 6.0.4.1) + activerecord (= 6.0.4.1) marcel (~> 1.0.0) - activesupport (6.0.3.7) + activesupport (6.0.4.1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -61,7 +61,7 @@ GEM archive-zip (0.12.0) io-like (~> 0.3.0) bindex (0.8.1) - bootsnap (1.7.5) + bootsnap (1.7.7) msgpack (~> 1.0) builder (3.2.4) byebug (11.1.3) @@ -87,6 +87,10 @@ GEM coffee-script-source (1.12.2) concurrent-ruby (1.1.9) crass (1.0.6) + docusign_admin (1.0.0.beta) + json (~> 2.1, >= 2.1.0) + jwt (~> 2.2, >= 2.2.1) + typhoeus (~> 1.0, >= 1.0.1) docusign_click (1.0.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) @@ -109,23 +113,28 @@ GEM ethon (0.14.0) ffi (>= 1.15.0) execjs (2.8.1) - faraday (1.4.3) + faraday (1.7.0) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0.1) faraday-net_http (~> 1.0) faraday-net_http_persistent (~> 1.1) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) multipart-post (>= 1.2, < 3) ruby2_keywords (>= 0.0.4) faraday-em_http (1.0.0) faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) + faraday-httpclient (1.0.1) faraday-net_http (1.0.1) - faraday-net_http_persistent (1.1.0) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) ffi (1.15.3) - ffi (1.15.3-x64-mingw32) - globalid (0.4.2) - activesupport (>= 4.2.0) + globalid (0.5.2) + activesupport (>= 5.0) hashie (4.1.0) i18n (1.8.10) concurrent-ruby (~> 1.0) @@ -137,25 +146,21 @@ GEM listen (3.2.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.10.0) + loofah (2.12.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) marcel (1.0.1) method_source (0.9.2) - mini_mime (1.1.0) + mini_mime (1.1.1) minitest (5.14.4) msgpack (1.4.2) multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) - nio4r (2.5.7) - nokogiri (1.11.7-x64-mingw32) - racc (~> 1.4) - nokogiri (1.11.7-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.11.7-x86_64-linux) + nio4r (2.5.8) + nokogiri (1.12.3-x86_64-darwin) racc (~> 1.4) oauth2 (1.4.7) faraday (>= 0.8, < 2.0) @@ -189,45 +194,43 @@ GEM rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.0.3.7) - actioncable (= 6.0.3.7) - actionmailbox (= 6.0.3.7) - actionmailer (= 6.0.3.7) - actionpack (= 6.0.3.7) - actiontext (= 6.0.3.7) - actionview (= 6.0.3.7) - activejob (= 6.0.3.7) - activemodel (= 6.0.3.7) - activerecord (= 6.0.3.7) - activestorage (= 6.0.3.7) - activesupport (= 6.0.3.7) + rails (6.0.4.1) + actioncable (= 6.0.4.1) + actionmailbox (= 6.0.4.1) + actionmailer (= 6.0.4.1) + actionpack (= 6.0.4.1) + actiontext (= 6.0.4.1) + actionview (= 6.0.4.1) + activejob (= 6.0.4.1) + activemodel (= 6.0.4.1) + activerecord (= 6.0.4.1) + activestorage (= 6.0.4.1) + activesupport (= 6.0.4.1) bundler (>= 1.3.0) - railties (= 6.0.3.7) + railties (= 6.0.4.1) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.3.0) + rails-html-sanitizer (1.4.2) loofah (~> 2.3) - railties (6.0.3.7) - actionpack (= 6.0.3.7) - activesupport (= 6.0.3.7) + railties (6.0.4.1) + actionpack (= 6.0.4.1) + activesupport (= 6.0.4.1) method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) - rake (13.0.3) + rake (13.0.6) rb-fsevent (0.11.0) rb-inotify (0.10.1) ffi (~> 1.0) regexp_parser (1.8.2) - ruby2_keywords (0.0.4) - rubyzip (2.3.0) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) sassc (2.4.0) ffi (~> 1.9) - sassc (2.4.0-x64-mingw32) - ffi (~> 1.9) sassc-rails (2.1.2) railties (>= 4.0.0) sassc (>= 2.0) @@ -259,11 +262,8 @@ GEM ethon (>= 0.9.0) tzinfo (1.2.9) thread_safe (~> 0.1) - tzinfo-data (1.2019.3) - tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) - wdm (0.1.1) web-console (4.0.4) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -277,10 +277,7 @@ GEM zeitwerk (2.4.2) PLATFORMS - x64-mingw32 - x86_64-darwin-19 x86_64-darwin-20 - x86_64-linux DEPENDENCIES bootsnap (~> 1.7.3) @@ -288,6 +285,7 @@ DEPENDENCIES capybara (~> 3.31.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) + docusign_admin (~> 1.0.0.beta) docusign_click (~> 1.0.0) docusign_esign (~> 3.10.0.rc1) docusign_monitor (~> 1.0.0) @@ -298,8 +296,8 @@ DEPENDENCIES omniauth-rails_csrf_protection pry-nav (~> 0.3.0) pry-rails (~> 0.3.9) - puma (~> 4.3.8) - rails (~> 6.0.3.5) + puma (~> 4.3.3) + rails (~> 6.0.4.1) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) spring (~> 2.1.0) @@ -312,7 +310,7 @@ DEPENDENCIES web-console (~> 4.0.1) RUBY VERSION - ruby 2.7.3p183 + ruby 2.7.2p137 BUNDLED WITH 2.2.16 diff --git a/README.md b/README.md index 64d5afd..bb479ee 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,8 @@ For a list of code examples that use the eSignature API, select the Ruby tab und ## Rooms API -**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/). +**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/). For a list of code examples that use the Rooms API, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/rooms-api/how-to/code-launchers#examples-and-languages) on the DocuSign Developer Center. @@ -36,11 +36,19 @@ For a list of code examples that use the Click API, select the Ruby tab under [E ## Monitor API -**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/). +**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/). 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/). For a list of code examples that use the Monitor API, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/monitor-api/how-to/code-launchers/#examples-and-languages) on the DocuSign Developer Center. +## Admin API + +**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 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). + +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/). + +For a list of code examples that use the Admin API, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/admin-api/how-to/code-launchers/#examples-and-languages) on the DocuSign Developer Center. + ## Installation ### Prerequisites @@ -49,30 +57,30 @@ For a list of code examples that use the Monitor API, select the Ruby tab under 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 for authentication to use either [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) or [JWT Grant](https://developers.docusign.com/platform/auth/jwt/). - This [video](https://www.youtube.com/watch?v=eiRI4fe5HgM) demonstrates how to obtain an integration key. + 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 [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 API Username GUID of the impersonated user. See [Installation steps for JWT Grant authentication](#installation-steps-for-jwt-grant-authentication) 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 API Username GUID of the impersonated user. See [Installation steps for JWT Grant authentication](#installation-steps-for-jwt-grant-authentication) for details. + For both authentication flows: - For both authentication flows: - - If you use this launcher on your own workstation, the integration key must include a redirect URI of + If you use this launcher on your own workstation, the integration key must include a redirect URI of http://localhost:3000/auth/docusign/callback - If you host this launcher on a remote web server, set your redirect URI as - + If you host this launcher on a remote web server, set your redirect URI as + {base_url}/auth/docusign/callback - - where {base_url} is the URL for the web app. - + + where {base_url} is the URL for the web app. + 1. [Ruby version 2.7.2](https://www.ruby-lang.org/en/downloads/) or later 1. Update the Gemfile to use later versions of Ruby. 1. Windows x64 only: - 1. Ensure that your Ruby folder is appended with **-x64**, e.g. **Ruby27-x64** - 2. Install Curl for Ruby: [Download libcurl.dll](https://curl.haxx.se/windows/) - Save **libcurl-x64.dll** as **libcurl.dll** + 1. Ensure that your Ruby folder is appended with **-x64**, e.g. **Ruby27-x64** + 2. Install Curl for Ruby: [Download libcurl.dll](https://curl.haxx.se/windows/) + Save **libcurl-x64.dll** as **libcurl.dll** Place **libcurl.dll** in your Ruby folder, e.g. **C:\Ruby27-x64\bin** @@ -80,33 +88,33 @@ For a list of code examples that use the Monitor API, select the Ruby tab under **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-ruby repository. -1. In your command-line environment, switch to the folder: +1. In your command-line environment, switch to the folder: `cd ` or `cd code-examples-ruby` 1. To install dependencies, run: `bundler install` 1. To configure the launcher for [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. 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 appsettings.yml as your `integration_key`. 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 appsettings.yml as your `integration_secret`. - 1. Add the launcher’s redirect URI. Under **Additional settings**, select **+ ADD URI**, and set a redirect URI of http://localhost:3000/auth/docusign/callback. Select **SAVE**. - 1. Set a name and email address for the signer. In appsettings.yml, save an email address as `signer_email` and a name as `signer_name`. + 1. Add the launcher’s redirect URI. Under **Additional settings**, select **+ ADD URI**, and set a redirect URI of http://localhost:3000/auth/docusign/callback. Select **SAVE**. + 1. Set a name and email address for the signer. In appsettings.yml, save an email address as `signer_email` and a name as `signer_name`. **Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. 1. Run the launcher: `rails s` 1. Open a browser to http://localhost:3000 ### 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. +**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 config/appsettings.yml, change `quickstart` to `false`. 1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. -1. In your command-line environment, switch to the folder: +1. In your command-line environment, switch to the folder: `cd ` or `cd code-examples-ruby` 1. Install the dependencies: `bundler install` 1. To configure the launcher for [JWT Grant](https://developers.docusign.com/platform/auth/jwt/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. 1. Add your API Username. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **My Account Information**, copy the **API Username** GUID and save it in appsettings.yml as your `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 appsettings.yml as your `jwt_integration_key`. 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 config/docusign_private_key.txt. - 1. Add the launcher’s redirect URI. Under **Additional settings**, select **+ ADD URI**, and set a redirect URI of http://localhost:3000/auth/docusign/callback. Select **SAVE**. - 1. Set a name and email address for the signer. In appsettings.yml, save an email address as `signer_email` and a name as `signer_name`. + 1. Add the launcher’s redirect URI. Under **Additional settings**, select **+ ADD URI**, and set a redirect URI of http://localhost:3000/auth/docusign/callback. Select **SAVE**. + 1. Set a name and email address for the signer. In appsettings.yml, save an email address as `signer_email` and a name as `signer_name`. **Note:** Protect your personal information. Please make sure that appsettings.yml will not be stored in your source code repository. 1. Run the launcher: `rails s` 1. Open a browser to http://localhost:3000 @@ -120,12 +128,12 @@ When using the Ruby launcher on a Windows machine you may get the following erro **SSL peer certificate or SSH remote key was not OK** -This error occurs because you’re attempting to use the Ruby launcher with a self-signed certificate or without SSL/HTTP security. The API calls from Ruby SDKs are using a built-in Curl tool that is enforcing the SSL requirement. You can disable this security check to run the launcher in an insecure manner on your developer machine. +This error occurs because you’re attempting to use the Ruby launcher with a self-signed certificate or without SSL/HTTP security. The API calls from Ruby SDKs are using a built-in Curl tool that is enforcing the SSL requirement. You can disable this security check to run the launcher in an insecure manner on your developer machine. ```diff -- It is highly recommended that you don’t disable this security check -- in a production environment or in your integration. -- This method is offered here solely as a means to enable you to +- It is highly recommended that you don’t disable this security check +- in a production environment or in your integration. +- This method is offered here solely as a means to enable you to - develop quickly by lowering the security bar on your local machine. ``` Find the root folder for your Ruby gems (in this case, a 64-bit version of Ruby 2.7.0): diff --git a/app/controllers/admin_api/eg001_create_user_controller.rb b/app/controllers/admin_api/eg001_create_user_controller.rb new file mode 100644 index 0000000..b4b0c3c --- /dev/null +++ b/app/controllers/admin_api/eg001_create_user_controller.rb @@ -0,0 +1,50 @@ +class AdminApi::Eg001CreateUserController < EgController + include ApiCreator + before_action :check_auth + + def create + begin + results = AdminApi::Eg001CreateUserService.new(session, request).call + + @title = 'Create a new active eSignature user' + @h1 = 'Create a new active eSignature user' + @message = "Results from Users::addUsers method:" + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + error = JSON.parse e.response_body + @error_code = e.code + @error_message = error['error_description'] + render 'ds_common/error' + end + end + + def get + super + if session[:organization_id].nil? + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id + end + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'] + } + + accounts_api = create_account_api(args) + @permission_profiles = accounts_api.list_permissions(args[:account_id]).permission_profiles + + groups_api = create_group_api(args) + @groups = groups_api.list_groups(args[:account_id]).groups + end + + private + + def check_auth + minimum_buffer_min = 10 + token_ok = check_token(minimum_buffer_min) + unless token_ok + flash[:messages] = 'Sorry, you need to re-authenticate.' + redirect_to '/ds/mustAuthenticate' + end + end +end diff --git a/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb b/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb new file mode 100644 index 0000000..ff0c31c --- /dev/null +++ b/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb @@ -0,0 +1,53 @@ +class AdminApi::Eg002CreateActiveClmEsignUserController < EgController + before_action :check_auth + + def create + begin + results = AdminApi::Eg002CreateActiveClmEsignUserService.new(session, request).call + + @title = "Create a new active user for CLM and eSignature" + @h1 = "Create a new active user for CLM and eSignature" + @message = "Results from MultiProductUserManagement::addOrUpdateUser method:" + @json = results.to_json.to_json + + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + error = JSON.parse e.response_body + @error_code = e.code + @error_message = error['error_description'] + render 'ds_common/error' + end + end + + def get + super + if session[:organization_id].nil? + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id + end + product_permission_profiles = AdminApi::GetDataService.new(session).get_product_permission_profiles + + product_permission_profiles.each do |product_permission_profile| + if product_permission_profile['product_name'] == "CLM" + @clm_permission_profiles = product_permission_profile['permission_profiles'] + @clm_product_id = product_permission_profile['product_id'] + else + @esign_permission_profiles = product_permission_profile['permission_profiles'] + @esign_product_id = product_permission_profile['product_id'] + end + end + @ds_groups = AdminApi::GetDataService.new(session).get_ds_groups + end + + private + + def check_auth + minimum_buffer_min = 10 + token_ok = check_token(minimum_buffer_min) + unless token_ok + flash[:messages] = 'Sorry, you need to re-authenticate.' + # We could store the parameters of the requested operation so it could be restarted automatically + # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication + redirect_to '/ds/mustAuthenticate' + end + end + end diff --git a/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb b/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb new file mode 100644 index 0000000..5fc4d2f --- /dev/null +++ b/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb @@ -0,0 +1,37 @@ +class AdminApi::Eg003BulkExportUserDataController < EgController + before_action :check_auth + + def create + if session[:organization_id].nil? + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id + end + + file_path = File.expand_path(File.join(File.dirname(__FILE__), '../../../data/exportedUserData.csv')) + + begin + results = AdminApi::Eg003BulkExportUserDataService.new(session, request, file_path).call + + @title = 'Bulk-export user data' + @h1 = 'Bulk-export user data' + @message = "Results from UserExport::getUserListExport method:" + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + error = JSON.parse e.response_body + @error_code = e.code + @error_message = error['error_description'] + render 'ds_common/error' + end + end + + private + + def check_auth + minimum_buffer_min = 10 + token_ok = check_token(minimum_buffer_min) + unless token_ok + flash[:messages] = 'Sorry, you need to re-authenticate.' + redirect_to '/ds/mustAuthenticate' + end + end +end diff --git a/app/controllers/admin_api/eg004_import_user_controller.rb b/app/controllers/admin_api/eg004_import_user_controller.rb new file mode 100644 index 0000000..bf1b848 --- /dev/null +++ b/app/controllers/admin_api/eg004_import_user_controller.rb @@ -0,0 +1,37 @@ +class AdminApi::Eg004ImportUserController < EgController + before_action :check_auth + + def create + if session[:organization_id].nil? + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id + end + + file_path = File.expand_path(File.join(File.dirname(__FILE__), '../../../data/userData.csv')) + + begin + results = AdminApi::Eg004ImportUserService.new(session, request, file_path).call + + @title = 'Add users via bulk import' + @h1 = 'Add users via bulk import' + @message = "Results from UserImport::addBulkUserImport method:" + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + error = JSON.parse e.response_body + @error_code = e.code + @error_message = error['error_description'] + render 'ds_common/error' + end + end + + private + + def check_auth + minimum_buffer_min = 10 + token_ok = check_token(minimum_buffer_min) + unless token_ok + flash[:messages] = 'Sorry, you need to re-authenticate.' + redirect_to '/ds/mustAuthenticate' + end + end +end diff --git a/app/controllers/admin_api/eg005_audit_users_controller.rb b/app/controllers/admin_api/eg005_audit_users_controller.rb new file mode 100644 index 0000000..a49cd1e --- /dev/null +++ b/app/controllers/admin_api/eg005_audit_users_controller.rb @@ -0,0 +1,38 @@ +class AdminApi::Eg005AuditUsersController < EgController + before_action :check_auth + + def create + if session[:organization_id].nil? + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id + end + + begin + results = AdminApi::Eg005AuditUsersService.new(session, request).call + + @title = "Audit users" + @h1 = "Audit users" + @message = "Results from Users::getUserProfiles method:" + @json = results.to_json.to_json + + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + error = JSON.parse e.response_body + @error_code = e.code + @error_message = error['error_description'] + render 'ds_common/error' + end + end + + private + + def check_auth + minimum_buffer_min = 10 + token_ok = check_token(minimum_buffer_min) + unless token_ok + flash[:messages] = 'Sorry, you need to re-authenticate.' + # We could store the parameters of the requested operation so it could be restarted automatically + # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication + redirect_to '/ds/mustAuthenticate' + end + end + end diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index 4682bec..59903f8 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -12,6 +12,8 @@ def index render 'clickwrap/index' elsif Rails.configuration.examples_API['Monitor'] render 'monitor_api/index' + elsif Rails.configuration.examples_API['Admin'] + render 'admin_api/index' else @show_doc = Rails.application.config.documentation if Rails.configuration.quickstart && session[:been_here].nil? @@ -64,6 +66,9 @@ def jwt_auth elsif Rails.configuration.examples_API['Click'] configuration = DocuSign_Click::Configuration.new api_client = DocuSign_Click::ApiClient.new configuration + elsif Rails.configuration.examples_API['Admin'] + configuration = DocuSign_Admin::Configuration.new + api_client = DocuSign_Admin::ApiClient.new configuration end resp = ::JwtAuth::JwtCreator.new(session).check_jwt_token if resp.is_a? String diff --git a/app/services/admin_api/eg001_create_user_service.rb b/app/services/admin_api/eg001_create_user_service.rb new file mode 100644 index 0000000..02c0581 --- /dev/null +++ b/app/services/admin_api/eg001_create_user_service.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +class AdminApi::Eg001CreateUserService + attr_reader :args, :user_data + + def initialize(session, request) + @args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + organization_id: session['organization_id'] + } + + # Step 3 start + @user_data = { + user_name: request.params['user_name'].gsub(/([^\w \-\@\.\,])+/, ''), + first_name: request.params['first_name'].gsub(/([^\w \-\@\.\,])+/, ''), + last_name: request.params['last_name'].gsub(/([^\w \-\@\.\,])+/, ''), + email: request.params['email'].gsub(/([^\w \-\@\.\,])+/, ''), + auto_activate_memberships: true, + accounts: [ + { + id: args[:account_id], + permission_profile: { + id: request['permission_profile_id'] + }, + groups: [ + { + id: request['group_id'] + } + ] + } + ] + } + # Step 3 end + end + + def call + worker + end + + def worker + # Step 2 start + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + # Step 2 end + + # Step 4 start + users_api = DocuSign_Admin::UsersApi.new(api_client) + response = users_api.create_user(args[:organization_id], user_data) + # Step 4 end + end + + def self.get_permission_profiles_and_groups + configuration = DocuSign_eSign::Configuration.new + configuration.host = args[:ds_base_path] + + api_client = DocuSign_eSign::ApiClient.new(configuration) + api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + + accounts_api = DocuSign_eSign::AccountsApi.new(api_client) + profiles = accounts_api.list_permissions(args[:account_id]) + + groups_api = DocuSign_eSign::GroupsApi.new(api_client) + groups = groups_api.list_groups(args[:account_id]) + + return profiles, groups + end +end diff --git a/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb b/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb new file mode 100644 index 0000000..eac32b7 --- /dev/null +++ b/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +class AdminApi::Eg002CreateActiveClmEsignUserService + attr_reader :args + + def initialize(session, request) + @args = { + user_name: request.params[:user_name], + first_name: request.params[:first_name], + last_name: request.params[:last_name], + email: request.params[:email], + clm_permission_profile_id: request.params[:clm_permission_profile_id], + esign_permission_profile_id: request.params[:esign_permission_profile_id], + clm_product_id: request.params[:clm_product_id], + esign_product_id: request.params[:esign_product_id], + ds_group_id: request.params[:ds_group_id], + account_id: session[:ds_account_id], + organization_id: Rails.configuration.organization_id, + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } + end + + def call + worker + end + + private + + def worker + # Step 2 start + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + # Step 2 end + + # Step 6 start + users_api = DocuSign_Admin::UsersApi.new(api_client) + response = users_api.add_or_update_user(args[:organization_id], args[:account_id], body) + # Step 6 end + end + + # Step 5 start + def body + { + user_name: args[:user_name], + first_name: args[:first_name], + last_name: args[:last_name], + email: args[:email], + auto_activate_memberships: true, + product_permission_profiles: [ + { + permission_profile_id: args[:esign_permission_profile_id], + product_id: args[:esign_product_id] + }, + { + permission_profile_id: args[:clm_permission_profile_id], + product_id: args[:clm_product_id] + } + ], + ds_groups: [ + { + ds_group_id: args[:ds_group_id] + } + ] + } + end + # Step 5 end + +end \ No newline at end of file diff --git a/app/services/admin_api/eg003_bulk_export_user_data_service.rb b/app/services/admin_api/eg003_bulk_export_user_data_service.rb new file mode 100644 index 0000000..88ca8b8 --- /dev/null +++ b/app/services/admin_api/eg003_bulk_export_user_data_service.rb @@ -0,0 +1,74 @@ +class AdminApi::Eg003BulkExportUserDataService + attr_reader :args, :request_body, :bulk_exports_api + + def initialize(session, request, file_path) + @args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + organization_id: session['organization_id'], + file_path: file_path + } + @request_body = { + type: 'organization_memberships_export' + } + end + + def call + worker + end + + # Step 5 start + def get_exported_user_data(export_id) + bulk_export_response = bulk_exports_api.get_user_list_export(args[:organization_id], export_id) + data_url = bulk_export_response.results[0].url + + uri = URI(data_url) + + req = Net::HTTP::Get.new(uri) + req['Authorization'] = "Bearer #{args[:access_token]}" + + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = true + + http.request(req) do |response| + File.open(args[:file_path], 'w') do |file| + response.read_body do |chunk| + file.write(chunk) + end + end + end + end + # Step 5 end + + def worker + # Step 2 start + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + # Step 2 end + + # Step 3 start + @bulk_exports_api = DocuSign_Admin::BulkExportsApi.new(api_client) + response = bulk_exports_api.create_user_list_export(args[:organization_id], request_body) + # Step 3 end + + # Step 4 start + retry_count = 5 + while retry_count >= 0 + if response.results + get_exported_user_data(response.id) + break + else + retry_count -= 1 + sleep(5) + response = bulk_exports_api.get_user_list_export(args[:organization_id], response.id) + end + end + # Step 4 end + + return response + end +end \ No newline at end of file diff --git a/app/services/admin_api/eg004_import_user_service.rb b/app/services/admin_api/eg004_import_user_service.rb new file mode 100644 index 0000000..8e8165b --- /dev/null +++ b/app/services/admin_api/eg004_import_user_service.rb @@ -0,0 +1,40 @@ +require 'uri' +require 'net/http' + +class AdminApi::Eg004ImportUserService + attr_reader :args, :user_data + + def initialize(session, request, csv_file_path) + @args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + organization_id: session['organization_id'], + csv_file_path: csv_file_path + } + + end + + def call + worker + end + + def worker + # Step 2 start + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + # Step 2 end + + # Step 3 start + csv_file_data = File.open(args[:csv_file_path]).read + csv_file_data = csv_file_data.gsub('{account_id}', args[:account_id]) + + @bulk_imports_api = DocuSign_Admin::BulkImportsApi.new(api_client) + response = @bulk_imports_api.create_bulk_import_add_users_request(args[:organization_id], csv_file_data) + # Step 3 end + return response + end +end \ No newline at end of file diff --git a/app/services/admin_api/eg005_audit_users_service.rb b/app/services/admin_api/eg005_audit_users_service.rb new file mode 100644 index 0000000..c553fb4 --- /dev/null +++ b/app/services/admin_api/eg005_audit_users_service.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +class AdminApi::Eg005AuditUsersService + attr_reader :args + + def initialize(session, request) + @args = { + account_id: session[:ds_account_id], + organization_id: Rails.configuration.organization_id, + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } + end + + def call + worker + end + + private + + def worker + # Step 2 start + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + # Step 2 end + + # Step 3 start + options = DocuSign_Admin::GetUsersOptions.new + options.account_id = args[:account_id] + options.last_modified_since = (Date.today - 10).strftime('%Y/%m/%d') + + users_api = DocuSign_Admin::UsersApi.new(api_client) + modified_users = users_api.get_users(args[:organization_id], options).as_json['users'] + # Step 3 end + + # Step 5 start + results = [] + modified_users.each do |user| + userProfilesOptions = DocuSign_Admin::GetUserProfilesOptions.new + userProfilesOptions.email = user['email'] + result = users_api.get_user_profiles(args[:organization_id], userProfilesOptions) + results.push(result) + end + # Step 5 end + + return results + end +end \ No newline at end of file diff --git a/app/services/admin_api/get_data_service.rb b/app/services/admin_api/get_data_service.rb new file mode 100644 index 0000000..fbb5917 --- /dev/null +++ b/app/services/admin_api/get_data_service.rb @@ -0,0 +1,48 @@ +class AdminApi::GetDataService + attr_reader :args + + def initialize(session, options = {}) + @args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + organization_id: session[:organization_id] + } + end + + def get_product_permission_profiles + worker + + # Step 3 start + product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(@api_client) + product_permission_profiles = product_permission_profiles_api.get_product_permission_profiles(args[:organization_id], args[:account_id]) + product_permission_profiles.as_json['product_permission_profiles'] + # Step 3 end + end + + def get_ds_groups + worker + + # Step 4 start + ds_groups_api = DocuSign_Admin::DSGroupsApi.new(@api_client) + ds_groups = ds_groups_api.get_ds_groups(args[:organization_id], args[:account_id]) + ds_groups.as_json['ds_groups'] + # Step 4 end + end + + def get_organization_id + worker + puts "\n\n getting org_id \n\n" + accounts_api = DocuSign_Admin::AccountsApi.new(@api_client) + accounts_api.get_organizations().organizations[0].as_json['id'] + end + + private + + def worker + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + @api_client = DocuSign_Admin::ApiClient.new(configuration) + @api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + end + end \ No newline at end of file diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index 77892f3..0c252cd 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -18,6 +18,8 @@ def self.consent_url(state) scope = "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" elsif Rails.configuration.examples_API['Click'] scope = "signature click.manage click.send" + elsif Rails.configuration.examples_API['Admin'] + scope = "signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" end scope = "#{scope} impersonation" base_uri = "#{Rails.configuration.authorization_server}/oauth/auth" @@ -42,6 +44,9 @@ def initialize(session) @client_module = DocuSign_Click elsif Rails.configuration.examples_API['Monitor'] @client_module = DocuSign_Monitor + elsif Rails.configuration.examples_API['Admin'] + scope = "signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" + @client_module = DocuSign_Admin end @scope = "#{scope} impersonation" @api_client = create_initial_api_client(host: Rails.configuration.aud, client_module: @client_module, debugging: false) diff --git a/app/views/admin_api/eg001_create_user/get.html.erb b/app/views/admin_api/eg001_create_user/get.html.erb new file mode 100644 index 0000000..88c8790 --- /dev/null +++ b/app/views/admin_api/eg001_create_user/get.html.erb @@ -0,0 +1,57 @@ +

1. Create a new eSignature user with active status

+

Demonstrates how to create a new eSignature user and activate their account automatically.

+ +

+ API methods used: + Accounts::listPermissions, + UserGroups::listGroups, and + Users::addUsers. +

+ +

+ View source file <%= @source_file %> on GitHub. +

+ + +
+ + +
+
+ + +
+
+ + +
+
+ + + We will never share your email with anyone else. +
+ <% if @permission_profiles.present? %> +
+ + <%= select_tag "permission_profile_id", options_for_select(@permission_profiles.map { |obj| [obj.permission_profile_name, obj.permission_profile_id] }), { :class => 'form-control' } %> +
+ <% else %> +
+

Problem: Please first create a DocuSign permission profile. +
Thank you.

+
+ <% end %> + <% if @groups.present? %> +
+ + <%= select_tag "group_id", options_for_select(@groups.map { |obj| [obj.group_name, obj.group_id] }), { :class => 'form-control' } %> +
+ <% else %> +
+

Problem: Please first create a DocuSign group. +
Thank you.

+
+ <% end %> + +
diff --git a/app/views/admin_api/eg002_create_active_clm_esign_user/get.html.erb b/app/views/admin_api/eg002_create_active_clm_esign_user/get.html.erb new file mode 100644 index 0000000..bf4140d --- /dev/null +++ b/app/views/admin_api/eg002_create_active_clm_esign_user/get.html.erb @@ -0,0 +1,70 @@ +

2. Create a new active user for CLM and eSignature

+

Demonstrates how to create a new DocuSign user (valid for both CLM and eSignature) and activate their account automatically.

+ +

+ API methods used: + ProductPermissionProfiles::getProductPermissionProfiles, + DsGroups::getDsGroups, and + MultiProductUserManagement::addOrUpdateUser. +

+ +

+ View source file <%= @source_file %> on GitHub. +

+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + + We will never share your email with anyone else. +
+ <% if @esign_permission_profiles.present? %> +
+ + <%= select_tag "esign_permission_profile_id", options_for_select(@esign_permission_profiles.map { |obj| [obj['permission_profile_name'], obj['permission_profile_id']] }), { :class => 'form-control' } %> +
+ <% else %> +
+

Problem: Please first create an eSignature permission profile. +
Thank you.

+
+ <% end %> + <% if @clm_permission_profiles.present? %> +
+ + <%= select_tag "clm_permission_profile_id", options_for_select(@clm_permission_profiles.map { |obj| [obj['permission_profile_name'], obj['permission_profile_id']] }), { :class => 'form-control' } %> +
+ <% else %> +
+

Problem: Please first create a CLM permission profile. +
Thank you.

+
+ <% end %> + <% if @ds_groups.present? %> +
+ + <%= select_tag "ds_group_id", options_for_select(@ds_groups.map { |obj| [obj['group_name'], obj['ds_group_id']] }), { :class => 'form-control' } %> +
+ <% else %> +
+

Problem: Please first create a DocuSign Admin group. +
Thank you.

+
+ <% end %> + + + +
diff --git a/app/views/admin_api/eg003_bulk_export_user_data/get.html.erb b/app/views/admin_api/eg003_bulk_export_user_data/get.html.erb new file mode 100644 index 0000000..4404b92 --- /dev/null +++ b/app/views/admin_api/eg003_bulk_export_user_data/get.html.erb @@ -0,0 +1,17 @@ +

3. Bulk-export user data

+

+ Demonstrates how to bulk-export user accounts within an organization into a CSV (comma-separated value) file. +

+ +

API methods used: + UserExport::createUserListExport and + UserExport::getUserListExport. +

+ +

+ View source file <%= @source_file %> on GitHub. +

+ +
+ +
\ No newline at end of file diff --git a/app/views/admin_api/eg004_import_user/get.html.erb b/app/views/admin_api/eg004_import_user/get.html.erb new file mode 100644 index 0000000..5745110 --- /dev/null +++ b/app/views/admin_api/eg004_import_user/get.html.erb @@ -0,0 +1,16 @@ +

4. Add users via bulk import

+

+ Demonstrates how to bulk-import users and add user data from an example CSV (comma-separated value) file into a DocuSign Admin organization. +

+ +

API method used: + UserImport::addBulkUserImport. +

+ +

+ View source file <%= @source_file %> on GitHub. +

+ +
+ +
\ No newline at end of file diff --git a/app/views/admin_api/eg005_audit_users/get.html.erb b/app/views/admin_api/eg005_audit_users/get.html.erb new file mode 100644 index 0000000..12b114d --- /dev/null +++ b/app/views/admin_api/eg005_audit_users/get.html.erb @@ -0,0 +1,17 @@ +

5. Audit users

+

+ Demonstrates how to audit the users in your account by retrieving the profiles of users that were modified after a specified date. +

+ +

API methods used: + Users::getUsers and + Users::getUserProfiles. +

+ +

+ View source file <%= @source_file %> on GitHub. +

+ +
+ +
diff --git a/app/views/admin_api/index.html.erb b/app/views/admin_api/index.html.erb new file mode 100644 index 0000000..b9e4cae --- /dev/null +++ b/app/views/admin_api/index.html.erb @@ -0,0 +1,77 @@ +
+
+ + + + + + + +
+

Ruby Launcher

+

Run and explore DocuSign Admin API code examples with Authorization Code Grant or JWT Grant authentication

+
+ +
+
+
+ +
+ <% if @show_doc %> +

Documentation on using JWT Grant or Authorization Code Grant from a Ruby on Rails application.

+ <% end %> + +

DocuSign Admin API Code Examples

+ +

1. Create a new active eSignature user

+

+ Demonstrates how to create a new eSignature user and activate their account automatically.

+

+ API method used: + Accounts::listPermissions. + UserGroups::listGroups. + Users::addUsers. +

+ +

2. Create a new active user for CLM and eSignature

+

+ Demonstrates how to create a new DocuSign user (valid for both CLM and eSignature) and activate their account automatically. +

+

+ API methods used: + ProductPermissionProfiles::getProductPermissionProfiles, + DsGroups::getDsGroups, + MultiProductUserManagement::addOrUpdateUser +

+ +

3. Bulk-export user data

+

+ Demonstrates how to bulk-export user accounts within an organization into a CSV (comma-separated value) file.

+

+ API methods used: + UserExport::createUserListExport, + UserExport::getUserListExport +

+ +

4. Add users via bulk import

+

+ Demonstrates how to bulk import users and add user data from an example CSV (comma-separated value) file into a DocuSign Admin organization.

+

+ API method used: + UserImport::addBulkUserImport +

+ +

5. Audit users

+

+ Demonstrates how to audit the users in your account by retrieving the profiles of users that were modified after a specified date. +

+

+ API methods used: + Users::getUsers, + Users::getUserProfiles +

+ +
+ + + diff --git a/config/appsettings.example.yml b/config/appsettings.example.yml index c02d6f3..bd4bbfe 100644 --- a/config/appsettings.example.yml +++ b/config/appsettings.example.yml @@ -10,6 +10,7 @@ default: &default Rooms: false Click: false Monitor: false + Admin: false # NOTE: The terms "client_id" and "Integration key" are synonyms. They refer to the same thing # The integration_key value is the same between the development account and production account integration_key: {INTEGRATION_KEY_AUTH_CODE} @@ -22,12 +23,14 @@ default: &default impersonated_user_guid: {IMPERSONATED_USER_ID} signer_email: {SIGNER_EMAIL} signer_name: {SIGNER_NAME} + organization_id: {ORGANIZATION_ID} # Authentication service endpoint is different between production and development # https://developers.docusign.com/docs/esign-rest-api/go-live/after-go-live/ authorization_server: https://account-d.docusign.com aud: account-d.docusign.com rooms_host: "https://demo.rooms.docusign.com/restapi" monitor_host: "https://lens-d.docusign.net" + admin_host: "https://api-d.docusign.net/management" allow_silent_authentication: true # A user can be silently authenticated if they have an # Active login session on another tab of the same browser # Set if you want a specific DocuSign AccountId, If false, the users default account will be used. diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 178aaf3..693967f 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -38,6 +38,8 @@ strategy.options[:authorize_params].scope = "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" elsif Rails.configuration.examples_API['Click'] strategy.options[:authorize_params].scope = "signature click.manage click.send" + elsif Rails.configuration.examples_API['Admin'] + strategy.options[:authorize_params].scope = "signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" end } end diff --git a/config/routes.rb b/config/routes.rb index 8c61a8e..fa1c88a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -53,6 +53,23 @@ get 'eg001' => 'eg001_get_monitoring_dataset#get' post 'eg001' => 'eg001_get_monitoring_dataset#create' end + elsif Rails.configuration.examples_API['Admin'] + scope module: 'admin_api' do + get 'eg001' => 'eg001_create_user#get' + post 'eg001' => 'eg001_create_user#create' + + get 'eg002' => 'eg002_create_active_clm_esign_user#get' + post 'eg002' => 'eg002_create_active_clm_esign_user#create' + + get 'eg003' => 'eg003_bulk_export_user_data#get' + post 'eg003' => 'eg003_bulk_export_user_data#create' + + get 'eg004' => 'eg004_import_user#get' + post 'eg004' => 'eg004_import_user#create' + + get 'eg005' => 'eg005_audit_users#get' + post 'eg005' => 'eg005_audit_users#create' + end else get '/eg001' => 'eg001_embedded_signing#get' post '/eg001' => 'eg001_embedded_signing#create' diff --git a/data/userData.csv b/data/userData.csv new file mode 100644 index 0000000..125030a --- /dev/null +++ b/data/userData.csv @@ -0,0 +1,3 @@ +AccountID,FirstName,LastName,UserEmail,PermissionSet +{account_id},First1,Last1,example1@sampleemail.example,DS Admin +{account_id},First2,Last2,example2@sampleemail.example,DS Admin \ No newline at end of file From 176f83afbf9854f017d5c20d6bad5eb7cb2a40a7 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 27 Aug 2021 13:56:22 -0700 Subject: [PATCH 105/363] minor update --- .../admin_api/eg002_create_active_clm_esign_user_service.rb | 2 +- app/services/admin_api/eg005_audit_users_service.rb | 2 +- app/views/admin_api/index.html.erb | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb b/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb index eac32b7..0a55be4 100644 --- a/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb +++ b/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb @@ -15,7 +15,7 @@ def initialize(session, request) esign_product_id: request.params[:esign_product_id], ds_group_id: request.params[:ds_group_id], account_id: session[:ds_account_id], - organization_id: Rails.configuration.organization_id, + organization_id: session['organization_id'], base_path: session[:ds_base_path], access_token: session[:ds_access_token] } diff --git a/app/services/admin_api/eg005_audit_users_service.rb b/app/services/admin_api/eg005_audit_users_service.rb index c553fb4..66e2281 100644 --- a/app/services/admin_api/eg005_audit_users_service.rb +++ b/app/services/admin_api/eg005_audit_users_service.rb @@ -6,7 +6,7 @@ class AdminApi::Eg005AuditUsersService def initialize(session, request) @args = { account_id: session[:ds_account_id], - organization_id: Rails.configuration.organization_id, + organization_id: session['organization_id'], base_path: session[:ds_base_path], access_token: session[:ds_access_token] } diff --git a/app/views/admin_api/index.html.erb b/app/views/admin_api/index.html.erb index b9e4cae..93fbd0c 100644 --- a/app/views/admin_api/index.html.erb +++ b/app/views/admin_api/index.html.erb @@ -28,9 +28,9 @@ Demonstrates how to create a new eSignature user and activate their account automatically.

API method used: - Accounts::listPermissions. - UserGroups::listGroups. - Users::addUsers. + Accounts::listPermissions, + UserGroups::listGroups + Users::addUsers

2. Create a new active user for CLM and eSignature

From 8564a153a2e20ae03f4ab7602e2786d46a218453 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Mon, 13 Sep 2021 16:55:03 -0700 Subject: [PATCH 106/363] add step admin4 step 4 and update text (#40) * add step admin4 step 4 and update text --- README.md | 6 +-- .../admin_api/eg001_create_user_controller.rb | 2 +- .../eg003_bulk_export_user_data_controller.rb | 2 +- .../admin_api/eg004_import_user_controller.rb | 25 ++++++++++++ .../admin_api/eg005_audit_users_controller.rb | 2 +- app/services/admin_api/get_data_service.rb | 9 +++++ .../admin_api/eg001_create_user/get.html.erb | 17 ++++---- .../get.html.erb | 11 +++-- .../eg003_bulk_export_user_data/get.html.erb | 6 ++- .../admin_api/eg004_import_user/get.html.erb | 7 +++- .../eg004_import_user/get_status.html.erb | 17 ++++++++ .../admin_api/eg005_audit_users/get.html.erb | 6 ++- app/views/admin_api/index.html.erb | 40 +++++++++++++------ app/views/ds_common/example_done.erb | 4 ++ config/appsettings.example.yml | 3 +- config/routes.rb | 3 +- 16 files changed, 121 insertions(+), 39 deletions(-) create mode 100644 app/views/admin_api/eg004_import_user/get_status.html.erb diff --git a/README.md b/README.md index bb479ee..25b7f6f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ### GitHub repo: [code-examples-ruby](./README.md) -This GitHub repo includes code examples for the DocuSign eSignature REST API, Rooms API, Click API, and Monitor API. To switch between API code examples, modify the `examples_API` setting in the appsettings.yml file. Set only one API type to `true` and set the remaining to `false`. +This GitHub repo includes code examples for the DocuSign Admin API, Click API, eSignature REST API, Monitor API, and Rooms API. To switch between API code examples, modify the `examples_API` setting in the appsettings.yml file. Set only one API type to `true` and set the remaining to `false`. If none of the API types are set to `true`, the DocuSign eSignature REST API code examples will be shown. If multiple API types are set to `true`, only the first will be shown. @@ -43,9 +43,9 @@ For a list of code examples that use the Monitor API, select the Ruby tab under ## Admin API -**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 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). +**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). -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/). +For more 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/). For a list of code examples that use the Admin API, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/admin-api/how-to/code-launchers/#examples-and-languages) on the DocuSign Developer Center. diff --git a/app/controllers/admin_api/eg001_create_user_controller.rb b/app/controllers/admin_api/eg001_create_user_controller.rb index b4b0c3c..9c8d311 100644 --- a/app/controllers/admin_api/eg001_create_user_controller.rb +++ b/app/controllers/admin_api/eg001_create_user_controller.rb @@ -8,7 +8,7 @@ def create @title = 'Create a new active eSignature user' @h1 = 'Create a new active eSignature user' - @message = "Results from Users::addUsers method:" + @message = "Results from eSignUserManagement:createUser method:" @json = results.to_json.to_json render 'ds_common/example_done' rescue DocuSign_Admin::ApiError => e diff --git a/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb b/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb index 5fc4d2f..aec7426 100644 --- a/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb +++ b/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb @@ -13,7 +13,7 @@ def create @title = 'Bulk-export user data' @h1 = 'Bulk-export user data' - @message = "Results from UserExport::getUserListExport method:" + @message = "User data exported to #{file_path}.
Results from UserExport::getUserListExport method:" @json = results.to_json.to_json render 'ds_common/example_done' rescue DocuSign_Admin::ApiError => e diff --git a/app/controllers/admin_api/eg004_import_user_controller.rb b/app/controllers/admin_api/eg004_import_user_controller.rb index bf1b848..8f422a7 100644 --- a/app/controllers/admin_api/eg004_import_user_controller.rb +++ b/app/controllers/admin_api/eg004_import_user_controller.rb @@ -10,9 +10,11 @@ def create begin results = AdminApi::Eg004ImportUserService.new(session, request, file_path).call + session[:import_id] = results.id @title = 'Add users via bulk import' @h1 = 'Add users via bulk import' + @check_status=true, @message = "Results from UserImport::addBulkUserImport method:" @json = results.to_json.to_json render 'ds_common/example_done' @@ -24,6 +26,29 @@ def create end end + def check_status + if session[:organization_id].nil? + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id + end + + begin + import_id = session[:import_id] + results = AdminApi::GetDataService.new(session).check_import_status(import_id) + + @status = results.status + @title = 'Add users via bulk import' + @h1 = 'Add users via bulk import' + @message = "Results from UserImport::getbulkuserimportrequest method:" + @json = results.to_json.to_json + render 'admin_api/eg004_import_user/get_status.html.erb' + rescue DocuSign_Admin::ApiError => e + error = JSON.parse e.response_body + @error_code = e.code + @error_message = error['error_description'] + render 'ds_common/error' + end + end + private def check_auth diff --git a/app/controllers/admin_api/eg005_audit_users_controller.rb b/app/controllers/admin_api/eg005_audit_users_controller.rb index a49cd1e..cd4fb50 100644 --- a/app/controllers/admin_api/eg005_audit_users_controller.rb +++ b/app/controllers/admin_api/eg005_audit_users_controller.rb @@ -11,7 +11,7 @@ def create @title = "Audit users" @h1 = "Audit users" - @message = "Results from Users::getUserProfiles method:" + @message = "Results from eSignUserManagement:getUserProfiles method:" @json = results.to_json.to_json render 'ds_common/example_done' diff --git a/app/services/admin_api/get_data_service.rb b/app/services/admin_api/get_data_service.rb index fbb5917..ed7361b 100644 --- a/app/services/admin_api/get_data_service.rb +++ b/app/services/admin_api/get_data_service.rb @@ -37,6 +37,15 @@ def get_organization_id accounts_api.get_organizations().organizations[0].as_json['id'] end + def check_import_status(import_id) + worker + bulk_imports_api = DocuSign_Admin::BulkImportsApi.new(@api_client) + # Step 4 start + response = bulk_imports_api.get_bulk_user_import_request(args[:organization_id], import_id); + # Step 4 end + return response + end + private def worker diff --git a/app/views/admin_api/eg001_create_user/get.html.erb b/app/views/admin_api/eg001_create_user/get.html.erb index 88c8790..723fb7d 100644 --- a/app/views/admin_api/eg001_create_user/get.html.erb +++ b/app/views/admin_api/eg001_create_user/get.html.erb @@ -2,10 +2,13 @@

Demonstrates how to create a new eSignature user and activate their account automatically.

- API methods used: - Accounts::listPermissions, - UserGroups::listGroups, and - Users::addUsers. + API methods used: + AccountPermissionProfiles:list, + Groups:list, + eSignUserManagement:createUser.

@@ -33,7 +36,7 @@ <% if @permission_profiles.present? %>

- + <%= select_tag "permission_profile_id", options_for_select(@permission_profiles.map { |obj| [obj.permission_profile_name, obj.permission_profile_id] }), { :class => 'form-control' } %>
<% else %> @@ -44,12 +47,12 @@ <% end %> <% if @groups.present? %>
- + <%= select_tag "group_id", options_for_select(@groups.map { |obj| [obj.group_name, obj.group_id] }), { :class => 'form-control' } %>
<% else %>
-

Problem: Please first create a DocuSign group. +

Problem: Please first create an eSignature group.
Thank you.

<% end %> diff --git a/app/views/admin_api/eg002_create_active_clm_esign_user/get.html.erb b/app/views/admin_api/eg002_create_active_clm_esign_user/get.html.erb index bf4140d..83c9d69 100644 --- a/app/views/admin_api/eg002_create_active_clm_esign_user/get.html.erb +++ b/app/views/admin_api/eg002_create_active_clm_esign_user/get.html.erb @@ -2,10 +2,13 @@

Demonstrates how to create a new DocuSign user (valid for both CLM and eSignature) and activate their account automatically.

- API methods used: - ProductPermissionProfiles::getProductPermissionProfiles, - DsGroups::getDsGroups, and - MultiProductUserManagement::addOrUpdateUser. + API methods used: + MultiProductUserManagement:getProductPermissionProfiles, + MultiProductUserManagement:getDsGroups, + MultiProductUserManagement:addOrUpdateUser.

diff --git a/app/views/admin_api/eg003_bulk_export_user_data/get.html.erb b/app/views/admin_api/eg003_bulk_export_user_data/get.html.erb index 4404b92..87c7988 100644 --- a/app/views/admin_api/eg003_bulk_export_user_data/get.html.erb +++ b/app/views/admin_api/eg003_bulk_export_user_data/get.html.erb @@ -4,8 +4,10 @@

API methods used: - UserExport::createUserListExport and - UserExport::getUserListExport. + UserExport:createUserListExport, + UserExport:getUserListExport.

diff --git a/app/views/admin_api/eg004_import_user/get.html.erb b/app/views/admin_api/eg004_import_user/get.html.erb index 5745110..9c4c768 100644 --- a/app/views/admin_api/eg004_import_user/get.html.erb +++ b/app/views/admin_api/eg004_import_user/get.html.erb @@ -3,8 +3,11 @@ Demonstrates how to bulk-import users and add user data from an example CSV (comma-separated value) file into a DocuSign Admin organization.

-

API method used: - UserImport::addBulkUserImport. +

API methods used: + UserImport:addBulkUserImport, + UserImport:getBulkUserImportRequest.

diff --git a/app/views/admin_api/eg004_import_user/get_status.html.erb b/app/views/admin_api/eg004_import_user/get_status.html.erb new file mode 100644 index 0000000..94819d2 --- /dev/null +++ b/app/views/admin_api/eg004_import_user/get_status.html.erb @@ -0,0 +1,17 @@ +<% if @status == "completed" %> + +

<%= @h1 %>

+ <% if !@message.nil? %> +

<%= @message.html_safe %>

+ <% end %> + + + +

+ +

Continue

+ +<% else %> +

Request not complete

+

The request has not completed, please refresh this page

+<% end %> diff --git a/app/views/admin_api/eg005_audit_users/get.html.erb b/app/views/admin_api/eg005_audit_users/get.html.erb index 12b114d..552db48 100644 --- a/app/views/admin_api/eg005_audit_users/get.html.erb +++ b/app/views/admin_api/eg005_audit_users/get.html.erb @@ -4,8 +4,10 @@

API methods used: - Users::getUsers and - Users::getUserProfiles. + Users:getUsers, + eSignUserManagement:getUserProfiles.

diff --git a/app/views/admin_api/index.html.erb b/app/views/admin_api/index.html.erb index 93fbd0c..93122d3 100644 --- a/app/views/admin_api/index.html.erb +++ b/app/views/admin_api/index.html.erb @@ -28,9 +28,12 @@ Demonstrates how to create a new eSignature user and activate their account automatically.

API method used: - Accounts::listPermissions, - UserGroups::listGroups - Users::addUsers + AccountPermissionProfiles:list, + Groups:list, + eSignUserManagement:createUser

2. Create a new active user for CLM and eSignature

@@ -39,9 +42,12 @@

API methods used: - ProductPermissionProfiles::getProductPermissionProfiles, - DsGroups::getDsGroups, - MultiProductUserManagement::addOrUpdateUser + MultiProductUserManagement:getProductPermissionProfiles, + MultiProductUserManagement:getDsGroups, + MultiProductUserManagement:addOrUpdateUser

3. Bulk-export user data

@@ -49,8 +55,10 @@ Demonstrates how to bulk-export user accounts within an organization into a CSV (comma-separated value) file.

API methods used: - UserExport::createUserListExport, - UserExport::getUserListExport + UserExport:createUserListExport, + UserExport:getUserListExport

4. Add users via bulk import

@@ -58,8 +66,12 @@ Demonstrates how to bulk import users and add user data from an example CSV (comma-separated value) file into a DocuSign Admin organization.

API method used: - UserImport::addBulkUserImport -

+ UserImport:addBulkUserImport, + UserImport:getBulkUserImportRequest + +

5. Audit users

@@ -67,9 +79,11 @@

API methods used: - Users::getUsers, - Users::getUserProfiles -

+ Users:getUsers, + eSignUserManagement:getUserProfiles +

diff --git a/app/views/ds_common/example_done.erb b/app/views/ds_common/example_done.erb index 3d3bda0..64d63f7 100644 --- a/app/views/ds_common/example_done.erb +++ b/app/views/ds_common/example_done.erb @@ -11,4 +11,8 @@ <% end %> +<% if @check_status %> +

Check the request status

+<% end %> +

Continue

\ No newline at end of file diff --git a/config/appsettings.example.yml b/config/appsettings.example.yml index bd4bbfe..389557d 100644 --- a/config/appsettings.example.yml +++ b/config/appsettings.example.yml @@ -5,7 +5,7 @@ default: &default # quickstart is an optional setting and can be enabled by setting it to: true quickstart: {QUICKSTART_VALUE} # Set only one examples_API type to 'true' and set the remaining to 'false'. - examples_API: + examples_API: eSignature: true Rooms: false Click: false @@ -23,7 +23,6 @@ default: &default impersonated_user_guid: {IMPERSONATED_USER_ID} signer_email: {SIGNER_EMAIL} signer_name: {SIGNER_NAME} - organization_id: {ORGANIZATION_ID} # Authentication service endpoint is different between production and development # https://developers.docusign.com/docs/esign-rest-api/go-live/after-go-live/ authorization_server: https://account-d.docusign.com diff --git a/config/routes.rb b/config/routes.rb index fa1c88a..149f684 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -66,6 +66,7 @@ get 'eg004' => 'eg004_import_user#get' post 'eg004' => 'eg004_import_user#create' + get 'eg004status' => 'eg004_import_user#check_status' get 'eg005' => 'eg005_audit_users#get' post 'eg005' => 'eg005_audit_users#create' @@ -201,7 +202,7 @@ post '/ds/mustAuthenticate' => 'ds_common#ds_must_authenticate' get '/ds/mustAuthenticateJwt' => 'ds_common#ds_must_authenticate_jwt' post '/ds/mustAuthenticateJwt' => 'ds_common#ds_must_authenticate' - + get '/ds/session' => 'session#show' # default root From a7b241630e7539a844238692efd968ba09fcb557 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Mon, 20 Sep 2021 09:17:28 -0700 Subject: [PATCH 107/363] Devdocs 5628 (#41) * phone auth --- ... eg020_phone_authentication_controller.rb} | 11 ++- .../eg020_sms_authentication_controller.rb | 28 ------- ... => eg020_phone_authentication_service.rb} | 75 ++++++++++++----- .../eg020_sms_authentication_service.rb | 84 ------------------- app/views/ds_common/index.html.erb | 41 ++++----- .../eg020_phone_authentication/get.html.erb | 52 ++++++++++++ .../eg020_sms_authentication/get.html.erb | 41 --------- .../eg021_phone_authentication/get.html.erb | 41 --------- config/routes.rb | 7 +- 9 files changed, 135 insertions(+), 245 deletions(-) rename app/controllers/e_sign/{eg021_phone_authentication_controller.rb => eg020_phone_authentication_controller.rb} (63%) delete mode 100644 app/controllers/e_sign/eg020_sms_authentication_controller.rb rename app/services/e_sign/{eg021_phone_authentication_service.rb => eg020_phone_authentication_service.rb} (54%) delete mode 100644 app/services/e_sign/eg020_sms_authentication_service.rb create mode 100644 app/views/e_sign/eg020_phone_authentication/get.html.erb delete mode 100644 app/views/e_sign/eg020_sms_authentication/get.html.erb delete mode 100644 app/views/e_sign/eg021_phone_authentication/get.html.erb diff --git a/app/controllers/e_sign/eg021_phone_authentication_controller.rb b/app/controllers/e_sign/eg020_phone_authentication_controller.rb similarity index 63% rename from app/controllers/e_sign/eg021_phone_authentication_controller.rb rename to app/controllers/e_sign/eg020_phone_authentication_controller.rb index 023a588..2a3fe51 100644 --- a/app/controllers/e_sign/eg021_phone_authentication_controller.rb +++ b/app/controllers/e_sign/eg020_phone_authentication_controller.rb @@ -1,20 +1,23 @@ # frozen_string_literal: true -class ESign::Eg021PhoneAuthenticationController < EgController +class ESign::Eg020PhoneAuthenticationController < EgController def create minimum_buffer_min = 3 if check_token(minimum_buffer_min) begin - results = ESign::Eg021PhoneAuthenticationService.new(request, session).call + results = ESign::Eg020PhoneAuthenticationService.new(request, session).call session[:envelope_id] = results.envelope_id - @title = 'Envelope sent' - @h1 = 'Envelope sent' + @title = 'Require Phone Authentication for a Recipient' + @h1 = 'Require Phone Authentication for a Recipient' @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." render 'ds_common/example_done' rescue DocuSign_eSign::ApiError => e error = JSON.parse e.response_body @error_code = error['errorCode'] @error_message = error['message'] + if error['errorCode']["IDENTITY_WORKFLOW_INVALID_ID"] + @error_information = "Please contact Support to enable recipient phone authentication in your account." + end render 'ds_common/error' end else diff --git a/app/controllers/e_sign/eg020_sms_authentication_controller.rb b/app/controllers/e_sign/eg020_sms_authentication_controller.rb deleted file mode 100644 index 19eaaae..0000000 --- a/app/controllers/e_sign/eg020_sms_authentication_controller.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -class ESign::Eg020SmsAuthenticationController < EgController - def create - minimum_buffer_min = 3 - if check_token(minimum_buffer_min) - begin - results = ESign::Eg020SmsAuthenticationService.new(request, session).call - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/' - end - end - # ***DS.snippet.0.end -end diff --git a/app/services/e_sign/eg021_phone_authentication_service.rb b/app/services/e_sign/eg020_phone_authentication_service.rb similarity index 54% rename from app/services/e_sign/eg021_phone_authentication_service.rb rename to app/services/e_sign/eg020_phone_authentication_service.rb index 2398dfb..cf42355 100644 --- a/app/services/e_sign/eg021_phone_authentication_service.rb +++ b/app/services/e_sign/eg020_phone_authentication_service.rb @@ -1,23 +1,26 @@ # frozen_string_literal: true -class ESign::Eg021PhoneAuthenticationService +class ESign::Eg020PhoneAuthenticationService include ApiCreator attr_reader :args, :envelope_args, :request, :session def initialize(request, session) - @envelope_args = { - signer_email: request.params['signerEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name: request.params['signerName'].gsub(/([^\w \-\@\.\,])+/, ''), - status: 'sent' - } + @request = request + @session = session @args = { account_id: session['ds_account_id'], base_path: session['ds_base_path'], access_token: session['ds_access_token'], envelope_args: @envelope_args } - @request = request - @session = session + @envelope_args = { + signer_email: request.params['signer_email'].gsub(/([^\w \-\@\.\,])+/, ''), + signer_name: request.params['signer_name'].gsub(/([^\w \-\@\.\,])+/, ''), + country_code: request.params['country_code'].gsub(/([^\w \-\@\.\,])+/, ''), + phone_number: request.params['phone_number'].gsub(/([^\w \-\@\.\,])+/, ''), + workflow_id: get_workflow(@args), + status: 'sent' + } end def call @@ -33,7 +36,7 @@ def call document1 = DocuSign_eSign::Document.new( # Create the DocuSign Document object documentBase64: Base64.encode64(File.binread(File.join('data', pdf_filename))), - name: 'NDA', # Can be different from actual file name + name: 'Lorem', # Can be different from actual file name fileExtension: 'pdf', # Many different document types are accepted documentId: '1' # A label used to reference the doc ) @@ -44,10 +47,31 @@ def call signer1 = DocuSign_eSign::Signer.new signer1.email = envelope_args[:signer_email] signer1.name = envelope_args[:signer_name] + signer1.role_name = '' + signer1.note = '' + signer1.status = 'created' + signer1.delivery_method = 'email' signer1.recipient_id = '1' signer1.routing_order = '1' + phone_number = DocuSign_eSign::RecipientIdentityPhoneNumber.new + phone_number.country_code = envelope_args[:country_code] + phone_number.number = envelope_args[:phone_number] + + input_option = DocuSign_eSign::RecipientIdentityInputOption.new + input_option.name = 'phone_number_list' + input_option.value_type = 'PhoneNumberList' + input_option.phone_number_list = [phone_number] + + identity_verification = DocuSign_eSign::RecipientIdentityVerification.new + + identity_verification.workflow_id = session[:workflow_id] + identity_verification.input_options = [input_option] + + signer1.identity_verification = identity_verification + sign_here1 = DocuSign_eSign::SignHere.new + sign_here1.name = 'SignHereTab' sign_here1.anchor_string = '/sn1/' sign_here1.anchor_units = 'pixels' sign_here1.anchor_x_offset = '20' @@ -60,16 +84,6 @@ def call }) signer1.tabs = signer1_tabs - signer1.id_check_configuration_name = 'Phone Auth $' - - phoneAuth = DocuSign_eSign::RecipientPhoneAuthentication.new - phoneAuth.record_voice_print = 'false' - phoneAuth.validate_recip_provided_number = 'false' - phoneAuth.recip_may_provide_number = 'true' - - phoneAuth.sender_provided_numbers = [request.params[:phoneNumber]] - signer1.phone_authentication = phoneAuth - # Add the recipients to the Envelope object recipients = DocuSign_eSign::Recipients.new( signers: [signer1] @@ -83,4 +97,27 @@ def call results = envelope_api.create_envelope args[:account_id], envelope_definition # ***DS.snippet.0.end end + + def get_workflow(args) + #Retrieve the workflow id + begin + workflow_details = create_account_api(args) + workflow_response = workflow_details.get_account_identity_verification(args[:account_id]) + + # Check that idv authentication is enabled + # The workflow ID is a hard-coded value which is unique to this phone authentication workflow + if workflow_response.identity_verification + session[:workflow_id] = "c368e411-1592-4001-a3df-dca94ac539ae" + return session[:workflow_id] + else + return None + end + + rescue DocuSign_Admin::ApiError => e + error = JSON.parse e.response_body + @error_code = e.code + @error_message = error['error_description'] + render 'ds_common/error' + end + end end \ No newline at end of file diff --git a/app/services/e_sign/eg020_sms_authentication_service.rb b/app/services/e_sign/eg020_sms_authentication_service.rb deleted file mode 100644 index ae29007..0000000 --- a/app/services/e_sign/eg020_sms_authentication_service.rb +++ /dev/null @@ -1,84 +0,0 @@ -# frozen_string_literal: true - -class ESign::Eg020SmsAuthenticationService - include ApiCreator - attr_reader :args, :envelope_args, :request, :session - - def initialize(request, session) - @envelope_args = { - signer_email: request.params['signerEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name: request.params['signerName'].gsub(/([^\w \-\@\.\,])+/, ''), - status: 'sent' - } - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: @envelope_args - } - @request = request - @session = session - end - - def call - # ***DS.snippet.0.start - envelope_api = create_envelope_api(args) - - # Step 3: Construct your envelope JSON body - envelope_definition = DocuSign_eSign::EnvelopeDefinition.new - envelope_definition.email_subject = 'Please sign this document set' - - # Add the documents and create the document models - pdf_filename = 'World_Wide_Corp_lorem.pdf' - document1 = DocuSign_eSign::Document.new( - # Create the DocuSign Document object - documentBase64: Base64.encode64(File.binread(File.join('data', pdf_filename))), - name: 'NDA', # Can be different from actual file name - fileExtension: 'pdf', # Many different document types are accepted - documentId: '1' # A label used to reference the doc - ) - - envelope_definition.documents = [document1] - - # Create the signer recipient model - signer1 = DocuSign_eSign::Signer.new - signer1.email = envelope_args[:signer_email] - signer1.name = envelope_args[:signer_name] - signer1.recipient_id = '1' - signer1.routing_order = '1' - signer1.require_id_lookup = 'true' - signer1.id_check_configuration_name = 'SMS Auth $' - - sms = DocuSign_eSign::RecipientSMSAuthentication.new - sms.sender_provided_numbers = [request.params[:phoneNumber]] - signer1.sms_authentication = sms - - sign_here1 = DocuSign_eSign::SignHere.new - sign_here1.anchor_string = '/sn1/' - sign_here1.anchor_units = 'pixels' - sign_here1.anchor_x_offset = '20' - sign_here1.anchor_y_offset = '10' - - # Add the tabs model (including the sign_here tabs) to the signer - # The Tabs object wants arrays of the different field/tab types - signer1_tabs = DocuSign_eSign::Tabs.new ({ - signHereTabs: [sign_here1] - }) - signer1.tabs = signer1_tabs - - # Add the recipients to the envelope object - recipients = DocuSign_eSign::Recipients.new( - signers: [signer1] - ) - # Request that the envelope be sent by setting status to "sent" - # To request that the envelope be created as a draft, set status to "created" - envelope_definition.recipients = recipients - envelope_definition.status = envelope_args[:status] - - # Step 4. Call the eSignature REST API - results = envelope_api.create_envelope args[:account_id], envelope_definition - session[:envelope_id] = results.envelope_id - results - # ***DS.snippet.0.end - end -end \ No newline at end of file diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index c799ac4..cd5d66d 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -6,7 +6,7 @@

Ruby Launcher

-

Welcome to the DocuSign Ruby examples using multiple OAuth flows (JWT and Authorization Code Grant).

+

Run and explore eSignature REST API code examples with Authorization Code Grant or JWT Grant authentication

@@ -24,15 +24,12 @@ %>
-

Welcome

-

This launcher both demonstrates use of JWT and OAuth Authorization Code Grant flow and includes multiple usage examples for the DocuSign eSignature REST API.

<% if @show_doc %> -

Documentation on using JWT or OAuth Authorization Code Grant from a Node Express application.

+

Documentation on using JWT or OAuth Authorization Code Grant from a Ruby on Rails application.

<% end %> -

Basic Examples

- +

Basic examples

1. Use embedded signing

This example sends an envelope, and then uses embedded signing for the first signer. With embedded signing, the DocuSign signing is initiated from your website. @@ -138,7 +135,8 @@ Envelopes::create and EnvelopeViews::createRecipient.

- + +

Payments

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

Anchor text (AutoPlace) @@ -148,7 +146,7 @@ Envelopes::create.

- +

Tabs

15. Get the tab data from an envelope

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

@@ -177,43 +175,38 @@ EnvelopeCustomFields::list.

-

Recipient Authentication

+

Recipient authentication

19. Send an envelope with Access Code Recipient Authentication

Submit an envelope with an access code for multi-factor authentication.

API method used: Envelopes::create.

-

20. Send an envelope with SMS Recipient Authentication

-

Submit an envelope with a text message for multi-factor authentication.

+

20. Require Phone Authentication for a Recipient

+

Sends an envelope that requires entering a six-digit code from a text message or phone call for the purpose of multifactor authentication.

API method used: Envelopes::create.

-

21. Send an envelope with Phone Recipient Authentication

-

Submit an envelope with a voice call to provide multi-factor authentication.

-

API method used: - Envelopes::create. -

-

22. Send an envelope with Recipient Knowledged Based Authentication

Submit an envelope with multiple choice, public records based questions to provide multi-factor authentication.

API method used: Envelopes::create.

- +

23. IDV Authentication

This is an example of an envelope utilizing Id verification authentication for a recipient.

API methods used: Accounts::getAccountIdentityVerificationsList. Envelopes::create.

- + +

Permissions

24. Creating a Permission Profile

This example demonstrates how to create a user group's permission profile.

-

API method used: +

API method used: Groups::create.

@@ -237,12 +230,13 @@ AccountPermissionProfiles::create.

+

Brands

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: @@ -255,10 +249,11 @@ Envelopes::create.

+

Bulk operations

31. Bulk sending envelopes to multiple recipients

This example will show you how to create and send an envelope to multiple recipients using bulk lists.

API methods used: - Envelopes::create. + Envelopes::create. BulkEnvelopes::get, EnvelopeCustomFields::create, BulkSend::createBulkSendList, @@ -284,7 +279,7 @@ Envelopes::create.

-

Premium Features

+

Premium features

35. Request Signature by SMS

This example demonstrates how to send a signature request for a signer (and CC) to read and sign via an SMS message. diff --git a/app/views/e_sign/eg020_phone_authentication/get.html.erb b/app/views/e_sign/eg020_phone_authentication/get.html.erb new file mode 100644 index 0000000..5dfc75d --- /dev/null +++ b/app/views/e_sign/eg020_phone_authentication/get.html.erb @@ -0,0 +1,52 @@ +

20. Require Phone Authentication for a Recipient

+ +

+ Sends an envelope that requires entering a six-digit code from a text message or phone call for the purpose of multifactor authentication. +

+ +

+ The envelope includes a PDF file. Anchor text + (AutoPlace) + is used to position the signing fields in the documents. +

+ +<% if @show_doc %> +

Documentation about this example.

+<% end %> + +

API method used: + Envelopes:create. +

+ +

+ View source file <%= @source_file %> on GitHub. +

+ +
+
+ + + The country code for the phone number below. +
+
+ + + This phone number will receive a notification. We'll never share your phone number with anyone else. +
+
+ + + We'll never share your email with anyone else. +
+
+ + +
+ + +
diff --git a/app/views/e_sign/eg020_sms_authentication/get.html.erb b/app/views/e_sign/eg020_sms_authentication/get.html.erb deleted file mode 100644 index ea735e4..0000000 --- a/app/views/e_sign/eg020_sms_authentication/get.html.erb +++ /dev/null @@ -1,41 +0,0 @@ -

20. Requiring an SMS Code 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 an SMS Code for Recipient Authentication. -

-<% if @show_doc %> -

Documentation about this example.

-<% end %> - -

API method used: - Envelopes::create. -

- -

- View source file <%= @source_file %> on GitHub. -

- -
-
- - - We'll never share your phone number with anyone else. - - - We'll never share your email with anyone else. -
-
- - -
- -
\ No newline at end of file diff --git a/app/views/e_sign/eg021_phone_authentication/get.html.erb b/app/views/e_sign/eg021_phone_authentication/get.html.erb deleted file mode 100644 index d85f8e8..0000000 --- a/app/views/e_sign/eg021_phone_authentication/get.html.erb +++ /dev/null @@ -1,41 +0,0 @@ -

21. Requiring Phone Authentication 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 a phone call for Recipient Authentication. -

-<% if @show_doc %> -

Documentation about this example.

-<% end %> - -

API method used: - Envelopes::create. -

- -

- View source file <%= @source_file %> on GitHub. -

- -
-
- - - We'll never share your phone number with anyone else. - - - We'll never share your email with anyone else. -
-
- - -
- -
\ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 149f684..759a704 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -131,11 +131,8 @@ get 'eg019' => 'eg019_access_code_authentication#get' post 'eg019' => 'eg019_access_code_authentication#create' - get 'eg020' => 'eg020_sms_authentication#get' - post 'eg020' => 'eg020_sms_authentication#create' - - get 'eg021' => 'eg021_phone_authentication#get' - post 'eg021' => 'eg021_phone_authentication#create' + get 'eg020' => 'eg020_phone_authentication#get' + post 'eg020' => 'eg020_phone_authentication#create' get 'eg022' => 'eg022_kba_authentication#get' post 'eg022' => 'eg022_kba_authentication#create' From 42433ebd0980f0c3d1b84fe46159c68f890330d2 Mon Sep 17 00:00:00 2001 From: MattLusher Date: Mon, 20 Sep 2021 12:25:13 -0400 Subject: [PATCH 108/363] Fixes to index pages (#42) * Fixes to index pages --- app/views/clickwrap/index.html.erb | 2 +- app/views/ds_common/index.html.erb | 174 ++++++++++++++------------- app/views/monitor_api/index.html.erb | 2 +- app/views/room_api/index.html.erb | 2 +- 4 files changed, 96 insertions(+), 84 deletions(-) diff --git a/app/views/clickwrap/index.html.erb b/app/views/clickwrap/index.html.erb index f843cc9..956c975 100644 --- a/app/views/clickwrap/index.html.erb +++ b/app/views/clickwrap/index.html.erb @@ -28,7 +28,7 @@

Documentation on using JWT or OAuth Authorization Code Grant from a Ruby Rails application.

<% end %> -

Basic Examples

+

Basic examples

1. Creating a clickwrap

diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index cd5d66d..2fcbffd 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -5,8 +5,8 @@ -

Ruby Launcher

-

Run and explore eSignature REST API code examples with Authorization Code Grant or JWT Grant authentication

+

DocuSign Code Launcher: Ruby

+

This launcher both demonstrates use of Authorization Code Grant and JWT OAuth flows and includes multiple usage examples for the DocuSign eSignature REST API.

@@ -26,13 +26,16 @@
<% if @show_doc %> -

Documentation on using JWT or OAuth Authorization Code Grant from a Ruby on Rails application.

+

Documentation on using JWT or OAuth Authorization Code Grant from a Node Express application.

<% end %> + +

Basic examples

+

1. Use embedded signing

-

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

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

API methods used: Envelopes::create and @@ -40,7 +43,7 @@

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

-

The envelope includes a pdf, Word, and HTML document. Anchor text +

The envelope includes three documents: one each in PDF, Word, and HTML format. Anchor text (AutoPlace) is used to position the signing fields in the documents.

@@ -48,31 +51,31 @@ Envelopes::create.

-

3. List envelopes in the user's account

-

List the envelopes created in the last 30 days. +

3. List envelopes whose status has changed

+

This example lists the envelopes whose status has changed within 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. +

4. Get an envelope’s basic information and status

+

This example lists 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. + envelope, its documents, recipients, and more.

API method used: Envelopes::get.

-

5. List an envelope's recipients and their status

-

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

5. List an envelope’s recipients and their status

+

This example lists 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 +

This example demonstrates how to list an envelope's documents. A Certificate of Completion document is also associated with every envelope.

API method used: @@ -80,7 +83,7 @@

7. Download a document from an envelope

-

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

This example demonstrates how to download a document from a given envelope. An envelope’s documents can be downloaded one by one or as a complete set.

API method used: EnvelopeDocuments::get. @@ -89,45 +92,39 @@

8. Create a template

Create a template with two roles, signer and cc.

API methods used: - Templates::list, + Templates::list and 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.

+

This example demonstrates a common pattern for DocuSign integrations: envelopes will be sent programmatically, defined by a 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.

+

The envelope includes three documents: one each in PDF, Word, and HTML format.

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. + Binary transfer is 33% more efficient than Base64 encoding and is recommended for documents over 15 MB. Binary transfer is not yet supported by the SDK.

API method used: Envelopes::create.

11. Use 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. -

+

This example demonstrates how to embed the DocuSign sender view within your web app. An envelope will be created in draft mode. Your browser will then be redirected to the DocuSign UI, where the envelope can be (optionally) updated and then sent.

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

12. Embedded DocuSign web tool

-

Redirect the user to the DocuSign web tool.

+

12. Embedded DocuSign UI

+

This example demonstrates how to embed the DocuSign UI in your app. Use this API call to open the DocuSign UI with the user already logged in.

API method used: EnvelopeViews::createConsole.

-

13. 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 +

13. 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 feature.

@@ -135,8 +132,10 @@ Envelopes::create and EnvelopeViews::createRecipient.

- -

Payments

+ + + +

Payments Example

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

Anchor text (AutoPlace) @@ -146,38 +145,43 @@ Envelopes::create.

-

Tabs

+ + +

Tabs examples

15. Get the tab data from an envelope

-

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

+

This example retrieves the tab (field) values from an envelope for all of the envelope’s recipients.

API method used: EnvelopeFormData::get.

16. Set tab values for a envelope

-

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

+

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. + API methods 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.

+

This example sets the tab (field) values for a template being used by an envelope. It includes setting radio button and checkbox tabs.

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

18. List envelope custom metadata field values

-

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

+

This example lists an envelope’s custom metadata field values.

API method used: EnvelopeCustomFields::list.

-

Recipient authentication

-

19. Send an envelope with Access Code Recipient Authentication

-

Submit an envelope with an access code for multi-factor authentication.

+

Recipient Authentication

+

19. Send an envelope with access code authentication

+

This example sends an envelope requiring the recipient to enter an access code for multifactor authentication.

API method used: Envelopes::create.

@@ -197,92 +201,100 @@

23. IDV Authentication

This is an example of an envelope utilizing Id verification authentication for a recipient.

API methods used: - Accounts::getAccountIdentityVerificationsList. - Envelopes::create. + Accounts::getAccountIdentityVerificationsList and Envelopes::create.

-

Permissions

-

24. Creating a Permission Profile

+ +

Permissions

+

24. Create a permission profile

- This example demonstrates how to create a user group's permission profile. + This example creates a user group’s permission profile.

API method used: - Groups::create. + AccountPermissionProfiles::create.

-

25. Setting a permission profile

-

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

+

25. Set a permission profile

+

This example updates the group name and modifies, or sets, the permission profile for the group.

API method used: Groups::update.

-

26. Modify a Permission Profile

+

26. Update individual permission profile settings

- This example updates an individual setting on a permission profile. + This example updates an individual setting on a user group’s permission profile.

API method used: AccountPermissionProfiles::update.

-

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.

+

27. Delete a permission profile

+

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

API method used: - AccountPermissionProfiles::create. + AccountPermissionProfiles::delete.

-

Brands

+ +

Brands

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.

+

This example creates an account brand that can be used to apply customization to your envelopes, including 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.

+

29. Apply a brand to an envelope

+

This example creates 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

+

30. Apply a brand and template to an envelope

+

This example creates an envelope from a template while applying any of the created brands on your account.

API method used: Envelopes::create.

-

Bulk operations

-

31. Bulk sending envelopes to multiple recipients

-

This example will show you how to create and send an envelope to multiple recipients using bulk lists.

+

Bulk operations

+

31. Bulk send envelopes

+

This example creates and sends an envelope to multiple recipients using bulk lists.

API methods used: - Envelopes::create. - BulkEnvelopes::get, - EnvelopeCustomFields::create, - BulkSend::createBulkSendList, - EnvelopeRecipients::create + Envelopes::create, + EnvelopeCustomFields::create, + EnvelopeRecipients::create, + BulkSend::createBulkSendList, + BulkSend::createBulkSendRequest, and + BulkSend::getBulkSendBatchStatus

Advanced recipient routing

-

32. Pausing a signature workflow

-

Pauses signature workflow.

+

32. Pause a signature workflow

+

This example creates an envelope where the workflow is paused before the envelope is sent to a second recipient.

API method used: Envelopes::create.

-

33. Unpausing a signature workflow

-

Unpauses a signature workflow.

+

33. Unpause a signature workflow

+

This example resumes a signature workflow for an envelope whose workflow has been paused.

API method used: Envelopes::update.

-

34. Using conditional recipients

-

Uses conditional recipients.

+

34. Use conditional recipients

+

This example creates an envelope whose workflow routes it to different recipients based on the value of a transaction.

API method used: Envelopes::create.

-

Premium features

-

35. Request Signature by SMS

+

Premium Features

+

35. Send an envelope by SMS delivery

- This example demonstrates how to send a signature request for a signer (and CC) to read and sign via an SMS message. + This example demonstrates how to send an envelope via an SMS message for a signer (and CC) to read and sign.

API method used: diff --git a/app/views/monitor_api/index.html.erb b/app/views/monitor_api/index.html.erb index 7f747c4..a0ee4cd 100644 --- a/app/views/monitor_api/index.html.erb +++ b/app/views/monitor_api/index.html.erb @@ -22,7 +22,7 @@

Documentation on using JWT Authorization from a Ruby Rails application.

<% end %> -

Monitor API Code Examples

+

Monitor API Code examples

1. Get monitoring data

diff --git a/app/views/room_api/index.html.erb b/app/views/room_api/index.html.erb index a259b94..511eb26 100644 --- a/app/views/room_api/index.html.erb +++ b/app/views/room_api/index.html.erb @@ -30,7 +30,7 @@ from a Ruby Rails application.

<% end %> -

Basic Examples

+

Basic examples

1. Create room with data

From 5afcb3b8f0617a03edcd63fbf2af0c5a7d5c0ac9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Sep 2021 17:09:11 -0700 Subject: [PATCH 109/363] Bump nokogiri from 1.12.3 to 1.12.5 (#43) Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.12.3 to 1.12.5. - [Release notes](https://github.com/sparklemotion/nokogiri/releases) - [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md) - [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.12.3...v1.12.5) --- updated-dependencies: - dependency-name: nokogiri dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 69def96..6b81d93 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -160,7 +160,9 @@ GEM multi_xml (0.6.0) multipart-post (2.1.1) nio4r (2.5.8) - nokogiri (1.12.3-x86_64-darwin) + nokogiri (1.12.5-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.12.5-x86_64-linux) racc (~> 1.4) oauth2 (1.4.7) faraday (>= 0.8, < 2.0) @@ -278,6 +280,7 @@ GEM PLATFORMS x86_64-darwin-20 + x86_64-linux DEPENDENCIES bootsnap (~> 1.7.3) @@ -296,7 +299,7 @@ DEPENDENCIES omniauth-rails_csrf_protection pry-nav (~> 0.3.0) pry-rails (~> 0.3.9) - puma (~> 4.3.3) + puma (~> 4.3.8) rails (~> 6.0.4.1) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) From 49d0bdd980ed31d5eafe25bfbf412f3a5fd107f9 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Fri, 1 Oct 2021 11:46:22 -0700 Subject: [PATCH 110/363] Devdocs 5567 (#44) * add sign here tabs for bulk send --- .../eg031_bulk_sending_envelopes_service.rb | 76 +++++++++++++++---- 1 file changed, 63 insertions(+), 13 deletions(-) diff --git a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb index 77809eb..0374ec6 100644 --- a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb +++ b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb @@ -143,7 +143,7 @@ def recipients_data status: "created", templateAccessCodeRequired: "null", deliveryMethod: "email", - recipientId: "10", + recipientId: "1", recipientType: "signer" ) @@ -156,9 +156,21 @@ def recipients_data status: "created", templateAccessCodeRequired: "null", deliveryMethod: "email", - recipientId: "11", + recipientId: "2", recipientType: "signer" ) + # The DocuSign platform searches throughout your envelope's documents for matching + # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 + # since they use the same anchor string for their "signer 1" tabs. + sign_here = DocuSign_eSign::SignHere.new + sign_here.anchor_string = '/sn1/' + sign_here.anchor_units = 'pixels' + sign_here.anchor_x_offset = '20' + sign_here.anchor_y_offset = '10' + # Tabs are set per recipient/signer + tabs = DocuSign_eSign::Tabs.new + tabs.sign_here_tabs = [sign_here] + signer.tabs = tabs [signer, cc] end @@ -166,23 +178,61 @@ def make_envelope # Create the envelope definition envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document set' + pdf_filename = 'World_Wide_Corp_lorem.pdf' # Add the documents - doc_b64 = "DQoNCg0KCQkJCXRleHQgZG9jDQoNCg0KDQoNCg0KUk0gIwlSTSAjCVJNICMNCg0KDQoNClxzMVwNCg0KLy9hbmNoMSANCgkvL2FuY2gyDQoJCS8vYW5jaDM=" - - # Create the document models - doc = DocuSign_eSign::Document.new( - # Create the DocuSign Document object - documentBase64: doc_b64, - name: 'NDA', # Can be different from the actual file name - fileExtension: 'txt', # Many different document types are accepted - documentId: '1' # A label used to reference the doc + doc = DocuSign_eSign::Document.new + doc.document_base64 = Base64.encode64(File.binread(File.join('data', pdf_filename))) + doc.name = 'Lorem Ipsum' + doc.file_extension = 'pdf' + doc.document_id = '2' + + signer = DocuSign_eSign::Signer.new( + name: "Multi Bulk Recipient::signer", + email: "multiBulkRecipients-signer@docusign.com", + roleName: "signer", + note: "", + routingOrder: 1, + status: "created", + templateAccessCodeRequired: "null", + deliveryMethod: "email", + recipientId: "1", + recipientType: "signer" + ) + + cc = DocuSign_eSign::Signer.new( + name: "Multi Bulk Recipient::cc", + email: "multiBulkRecipients-cc@docusign.com", + roleName: "cc", + note: "", + routingOrder: 1, + status: "created", + templateAccessCodeRequired: "null", + deliveryMethod: "email", + recipientId: "2", + recipientType: "signer" ) - + # The DocuSign platform searches throughout your envelope's documents for matching + # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 + # since they use the same anchor string for their "signer 1" tabs. + sign_here = DocuSign_eSign::SignHere.new + sign_here.anchor_string = '/sn1/' + sign_here.anchor_units = 'pixels' + sign_here.anchor_x_offset = '20' + sign_here.anchor_y_offset = '10' + # Tabs are set per recipient/signer + tabs = DocuSign_eSign::Tabs.new + tabs.sign_here_tabs = [sign_here] + signer.tabs = tabs + # Add the recipients to the envelope object + recipients = DocuSign_eSign::Recipients.new + recipients.signers = [signer, cc] + + envelope_definition.recipients = recipients # The order in the docs array determines the order in the envelope envelope_definition.documents = [doc] envelope_definition.envelope_id_stamping = "true" envelope_definition.status = "created" envelope_definition end - + end \ No newline at end of file From fc748e52db23c7da30e8d458e5d177ae71b10200 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Fri, 1 Oct 2021 15:28:08 -0700 Subject: [PATCH 111/363] update step comments --- .../admin_api/eg001_create_user_service.rb | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/app/services/admin_api/eg001_create_user_service.rb b/app/services/admin_api/eg001_create_user_service.rb index 02c0581..fd8aa0b 100644 --- a/app/services/admin_api/eg001_create_user_service.rb +++ b/app/services/admin_api/eg001_create_user_service.rb @@ -11,7 +11,7 @@ def initialize(session, request) organization_id: session['organization_id'] } - # Step 3 start + # Step 5 start @user_data = { user_name: request.params['user_name'].gsub(/([^\w \-\@\.\,])+/, ''), first_name: request.params['first_name'].gsub(/([^\w \-\@\.\,])+/, ''), @@ -32,7 +32,7 @@ def initialize(session, request) } ] } - # Step 3 end + # Step 5 end end def call @@ -48,10 +48,10 @@ def worker api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") # Step 2 end - # Step 4 start + # Step 6 start users_api = DocuSign_Admin::UsersApi.new(api_client) response = users_api.create_user(args[:organization_id], user_data) - # Step 4 end + # Step 6 end end def self.get_permission_profiles_and_groups @@ -60,13 +60,16 @@ def self.get_permission_profiles_and_groups api_client = DocuSign_eSign::ApiClient.new(configuration) api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") - + + # Step 3 start accounts_api = DocuSign_eSign::AccountsApi.new(api_client) profiles = accounts_api.list_permissions(args[:account_id]) - + # Step 3 end + + # Step 4 start groups_api = DocuSign_eSign::GroupsApi.new(api_client) groups = groups_api.list_groups(args[:account_id]) - + # Step 4 end return profiles, groups end end From 5d80cd1a83d474b797b2688cbc66be437e310886 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 11 Oct 2021 11:39:36 -0700 Subject: [PATCH 112/363] added step comments --- .../e_sign/eg020_phone_authentication_service.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/services/e_sign/eg020_phone_authentication_service.rb b/app/services/e_sign/eg020_phone_authentication_service.rb index cf42355..66224e4 100644 --- a/app/services/e_sign/eg020_phone_authentication_service.rb +++ b/app/services/e_sign/eg020_phone_authentication_service.rb @@ -27,7 +27,8 @@ def call # ***DS.snippet.0.start envelope_api = create_envelope_api(args) - # Step 3: Construct your envelope JSON body + # Construct your envelope JSON body + # Step 3 start envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document set' @@ -92,10 +93,12 @@ def call # To request that the envelope be created as a draft, set to "created" envelope_definition.recipients = recipients envelope_definition.status = envelope_args[:status] - - # Step 4. Call the eSignature REST API + # Step 3 end + + # Call the eSignature REST API + # Step 4 start results = envelope_api.create_envelope args[:account_id], envelope_definition - # ***DS.snippet.0.end + # Step 4 end end def get_workflow(args) @@ -120,4 +123,4 @@ def get_workflow(args) render 'ds_common/error' end end -end \ No newline at end of file +end From bf401e74c6605fd15a8e907b313c81819169fa15 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 11 Oct 2021 11:40:20 -0700 Subject: [PATCH 113/363] removed ds comment --- app/services/e_sign/eg020_phone_authentication_service.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/services/e_sign/eg020_phone_authentication_service.rb b/app/services/e_sign/eg020_phone_authentication_service.rb index 66224e4..ae30aab 100644 --- a/app/services/e_sign/eg020_phone_authentication_service.rb +++ b/app/services/e_sign/eg020_phone_authentication_service.rb @@ -24,7 +24,6 @@ def initialize(request, session) end def call - # ***DS.snippet.0.start envelope_api = create_envelope_api(args) # Construct your envelope JSON body From 75b21592cb2cd83f910dd2514fef4bca6e01462f Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Tue, 12 Oct 2021 15:53:36 -0700 Subject: [PATCH 114/363] Devdocs 5567 (#45) update bulk send --- Gemfile | 6 +- Gemfile.lock | 15 ++-- .../eg031_bulk_sending_envelopes_service.rb | 72 +++++++++++-------- .../eg031_bulk_sending_envelopes/get.html.erb | 16 ++--- 4 files changed, 61 insertions(+), 48 deletions(-) diff --git a/Gemfile b/Gemfile index 9912882..1cab8eb 100644 --- a/Gemfile +++ b/Gemfile @@ -66,11 +66,11 @@ group :test do gem 'chromedriver-helper', '~> 2.1.1' end -gem 'docusign_esign', '~> 3.10.0.rc1' +gem 'docusign_esign', '~> 3.13.0.rc1' gem 'docusign_monitor', '~> 1.0.0' -gem 'docusign_rooms', '~> 1.1.0.rc1' +gem 'docusign_rooms', '~> 1.2.0.rc1' gem 'docusign_click', '~> 1.0.0' -gem 'docusign_admin', '~> 1.0.0.beta' +gem 'docusign_admin', '~> 1.0.0' gem 'omniauth-oauth2', '~> 1.7.1' gem 'omniauth-rails_csrf_protection' diff --git a/Gemfile.lock b/Gemfile.lock index 6b81d93..1402112 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -87,7 +87,8 @@ GEM coffee-script-source (1.12.2) concurrent-ruby (1.1.9) crass (1.0.6) - docusign_admin (1.0.0.beta) + docusign_admin (1.0.0) + addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) @@ -96,7 +97,8 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.10.0) + docusign_esign (3.13.0.rc1) + addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) @@ -105,7 +107,8 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_rooms (1.1.0) + docusign_rooms (1.2.0.rc1) + addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) @@ -288,11 +291,11 @@ DEPENDENCIES capybara (~> 3.31.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_admin (~> 1.0.0.beta) + docusign_admin (~> 1.0.0) docusign_click (~> 1.0.0) - docusign_esign (~> 3.10.0.rc1) + docusign_esign (~> 3.13.0.rc1) docusign_monitor (~> 1.0.0) - docusign_rooms (~> 1.1.0.rc1) + docusign_rooms (~> 1.2.0.rc1) jbuilder (~> 2.10.0) listen (~> 3.2.1) omniauth-oauth2 (~> 1.7.1) diff --git a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb index 0374ec6..418184d 100644 --- a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb +++ b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb @@ -25,40 +25,53 @@ def initialize(request, session) end def call - # Step 1. Obtain your OAuth token + # Construct your API headers + # Step 2 start configuration = DocuSign_eSign::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_eSign::ApiClient.new configuration - - # Step 2. Construct your API headers construct_api_headers(api_client) + # Step end - # Step 3. Create and submit the bulk sending list + # Create and submit the bulk sending list + # Step 3-1 start bulk_envelopes_api = DocuSign_eSign::BulkEnvelopesApi.new api_client bulk_sending_list = create_bulk_sending_list bulk_list = bulk_envelopes_api.create_bulk_send_list(args[:account_id], bulk_sending_list) bulk_list_id = bulk_list.list_id + # Step 3-1 end - # Step 4. Create the draft envelope + # Create the draft envelope + # Step 4-1 start envelope_api = create_envelope_api(args) envelope_definition = make_envelope envelope = envelope_api.create_envelope(args[:account_id], envelope_definition, options = DocuSign_eSign::CreateEnvelopeOptions.default) envelope_id = envelope.envelope_id + # Step 4-1 end - # Step 5. Attach your bulk list ID to the envelope + # Attach your bulk list ID to the envelope + # Step 5-1 start envelope_api.create_custom_fields(args[:account_id], envelope_id, custom_fields(bulk_list_id)) + # Step 5-1 end - # Step 6. Add placeholder recipients - recipients = DocuSign_eSign::Recipients.new(signers: recipients_data) + # Add placeholder recipients + # Step 6-1 start + recipients = recipients_data + recipients = DocuSign_eSign::Recipients.new(signers: [recipients[0]], cc: [recipients[1]]) envelope_api.create_recipient(args[:account_id], envelope_id, recipients, options = DocuSign_eSign::CreateRecipientOptions.default) + # Step 6-1 end - # Step 7. Initiate bulk send + # Initiate bulk send + # Step 7 start bulk_send_request = DocuSign_eSign::BulkSendRequest.new(envelopeOrTemplateId: envelope_id) batch = bulk_envelopes_api.create_bulk_send_request(args[:account_id], bulk_list_id, bulk_send_request) batch_id = batch.batch_id + # Step 7 end - # Step 8. Confirm successful batch send + # Confirm successful batch send + # Step 8 start bulk_envelopes_api.get_bulk_send_batch_status(args[:account_id], batch_id) + # Step 8 end end private @@ -71,6 +84,7 @@ def construct_api_headers(api_client) api_client.default_headers['Accept-Language'] = "en-US,en;q=0.9" end + # Step 3-2 start def create_bulk_sending_list bulk_copies = [] recipient1 = DocuSign_eSign::BulkSendingCopyRecipient.new( @@ -119,7 +133,9 @@ def create_bulk_sending_list ) bulk_sending_list end + # Step 3-2 end + # Step 5-2 start def custom_fields(bulk_list_id) text_custom_fields = DocuSign_eSign::TextCustomField.new( name:'mailingListId', @@ -132,7 +148,9 @@ def custom_fields(bulk_list_id) textCustomFields: [text_custom_fields] ) end + # Step 5-2 end + # Step 6-2 start def recipients_data signer = DocuSign_eSign::Signer.new( name: "Multi Bulk Recipient::signer", @@ -147,33 +165,23 @@ def recipients_data recipientType: "signer" ) - cc = DocuSign_eSign::Signer.new( + cc = DocuSign_eSign::CarbonCopy.new( name: "Multi Bulk Recipient::cc", email: "multiBulkRecipients-cc@docusign.com", roleName: "cc", note: "", routingOrder: 1, status: "created", - templateAccessCodeRequired: "null", deliveryMethod: "email", recipientId: "2", - recipientType: "signer" + recipientType: "cc" ) - # The DocuSign platform searches throughout your envelope's documents for matching - # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 - # since they use the same anchor string for their "signer 1" tabs. - sign_here = DocuSign_eSign::SignHere.new - sign_here.anchor_string = '/sn1/' - sign_here.anchor_units = 'pixels' - sign_here.anchor_x_offset = '20' - sign_here.anchor_y_offset = '10' - # Tabs are set per recipient/signer - tabs = DocuSign_eSign::Tabs.new - tabs.sign_here_tabs = [sign_here] - signer.tabs = tabs + [signer, cc] end + # Step 6-2 end + # Step 4-2 start def make_envelope # Create the envelope definition envelope_definition = DocuSign_eSign::EnvelopeDefinition.new @@ -199,18 +207,18 @@ def make_envelope recipientType: "signer" ) - cc = DocuSign_eSign::Signer.new( + cc = DocuSign_eSign::CarbonCopy.new( name: "Multi Bulk Recipient::cc", email: "multiBulkRecipients-cc@docusign.com", roleName: "cc", note: "", routingOrder: 1, status: "created", - templateAccessCodeRequired: "null", deliveryMethod: "email", recipientId: "2", - recipientType: "signer" + recipientType: "cc" ) + # The DocuSign platform searches throughout your envelope's documents for matching # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 # since they use the same anchor string for their "signer 1" tabs. @@ -223,9 +231,12 @@ def make_envelope tabs = DocuSign_eSign::Tabs.new tabs.sign_here_tabs = [sign_here] signer.tabs = tabs + # Add the recipients to the envelope object - recipients = DocuSign_eSign::Recipients.new - recipients.signers = [signer, cc] + recipients = DocuSign_eSign::Recipients.new( + signers: [signer], + carbonCopies: [cc] + ) envelope_definition.recipients = recipients # The order in the docs array determines the order in the envelope @@ -234,5 +245,6 @@ def make_envelope envelope_definition.status = "created" envelope_definition end + # Step 4-2 end end \ No newline at end of file diff --git a/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb b/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb index acf833c..04a06d2 100644 --- a/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb +++ b/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb @@ -1,13 +1,13 @@

31. Bulk sending envelopes to multiple recipients

- Method BulkSend:createBulkSendList creates a bulk list that you can to use an envelope to up + Method BulkSend:createBulkSendList creates a bulk list that you can to use an envelope to up to 1,000 recipients at once.

API method used: EnvelopeRecipients::create, - Envelopes::create, + Envelopes::create, BulkEnvelopes::get, EnvelopeCustomFields::create, BulkSend::createBulkSendList, @@ -24,13 +24,12 @@

+ aria-describedby="emailHelp" placeholder="pat@example.com" required>
+ required>
@@ -51,13 +50,12 @@
+ aria-describedby="emailHelp" placeholder="pat@example.com" required>
+ required>
@@ -73,4 +71,4 @@
- \ No newline at end of file + \ No newline at end of file From 6b7b033bfb93272df1472ef9682703863300b0bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Oct 2021 15:55:27 -0700 Subject: [PATCH 115/363] Bump puma from 4.3.8 to 4.3.9 (#50) Bumps [puma](https://github.com/puma/puma) from 4.3.8 to 4.3.9. - [Release notes](https://github.com/puma/puma/releases) - [Changelog](https://github.com/puma/puma/blob/master/History.md) - [Commits](https://github.com/puma/puma/compare/v4.3.8...v4.3.9) --- updated-dependencies: - dependency-name: puma dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 1cab8eb..e54ef5d 100644 --- a/Gemfile +++ b/Gemfile @@ -10,7 +10,7 @@ gem 'rails', '~> 6.0.4.1' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4.2' # Use Puma as the app server -gem 'puma', '~> 4.3.8' +gem 'puma', '~> 4.3.9' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets diff --git a/Gemfile.lock b/Gemfile.lock index 1402112..f6e68ab 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -191,7 +191,7 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.6) - puma (4.3.8) + puma (4.3.9) nio4r (~> 2.0) racc (1.5.2) rack (2.2.3) @@ -302,7 +302,7 @@ DEPENDENCIES omniauth-rails_csrf_protection pry-nav (~> 0.3.0) pry-rails (~> 0.3.9) - puma (~> 4.3.8) + puma (~> 4.3.9) rails (~> 6.0.4.1) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) From 4ec05550ae7d8eababadd7ad4a151f11a5dfa200 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Oct 2021 15:55:43 -0700 Subject: [PATCH 116/363] Bump puma from 4.3.8 to 4.3.9 (#46) Bumps [puma](https://github.com/puma/puma) from 4.3.8 to 4.3.9. - [Release notes](https://github.com/puma/puma/releases) - [Changelog](https://github.com/puma/puma/blob/master/History.md) - [Commits](https://github.com/puma/puma/compare/v4.3.8...v4.3.9) --- updated-dependencies: - dependency-name: puma dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 1cab8eb..e54ef5d 100644 --- a/Gemfile +++ b/Gemfile @@ -10,7 +10,7 @@ gem 'rails', '~> 6.0.4.1' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4.2' # Use Puma as the app server -gem 'puma', '~> 4.3.8' +gem 'puma', '~> 4.3.9' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets diff --git a/Gemfile.lock b/Gemfile.lock index 1402112..f6e68ab 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -191,7 +191,7 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.6) - puma (4.3.8) + puma (4.3.9) nio4r (~> 2.0) racc (1.5.2) rack (2.2.3) @@ -302,7 +302,7 @@ DEPENDENCIES omniauth-rails_csrf_protection pry-nav (~> 0.3.0) pry-rails (~> 0.3.9) - puma (~> 4.3.8) + puma (~> 4.3.9) rails (~> 6.0.4.1) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) From 22c7c5be1d48c9fd713c3de4ac218abeff723477 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Thu, 4 Nov 2021 12:49:07 -0700 Subject: [PATCH 117/363] Devdocs 6120 (#47) * update phone auth example Co-authored-by: meihDS <70775251+meihDS@users.noreply.github.com> --- .../eg020_phone_authentication_service.rb | 28 ++++++++----- app/views/ds_common/index.html.erb | 40 +++++++++---------- 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/app/services/e_sign/eg020_phone_authentication_service.rb b/app/services/e_sign/eg020_phone_authentication_service.rb index cf42355..5e3f4e1 100644 --- a/app/services/e_sign/eg020_phone_authentication_service.rb +++ b/app/services/e_sign/eg020_phone_authentication_service.rb @@ -24,10 +24,8 @@ def initialize(request, session) end def call - # ***DS.snippet.0.start - envelope_api = create_envelope_api(args) - - # Step 3: Construct your envelope JSON body + # Construct your envelope JSON body + # Step 4 start envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document set' @@ -64,8 +62,8 @@ def call input_option.phone_number_list = [phone_number] identity_verification = DocuSign_eSign::RecipientIdentityVerification.new - identity_verification.workflow_id = session[:workflow_id] + identity_verification.input_options = [input_option] signer1.identity_verification = identity_verification @@ -92,28 +90,38 @@ def call # To request that the envelope be created as a draft, set to "created" envelope_definition.recipients = recipients envelope_definition.status = envelope_args[:status] + # Step 4 end - # Step 4. Call the eSignature REST API + # Call the eSignature REST API + # Step 5 start + envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope_definition - # ***DS.snippet.0.end + # Step 5 end end def get_workflow(args) #Retrieve the workflow id + begin + # Step 3 start workflow_details = create_account_api(args) workflow_response = workflow_details.get_account_identity_verification(args[:account_id]) # Check that idv authentication is enabled - # The workflow ID is a hard-coded value which is unique to this phone authentication workflow if workflow_response.identity_verification - session[:workflow_id] = "c368e411-1592-4001-a3df-dca94ac539ae" + phone_auth_workflow = workflow_response.identity_verification.find{ |item| item.default_name == "Phone Authentication" } + if phone_auth_workflow + session[:workflow_id] = phone_auth_workflow.workflow_id return session[:workflow_id] + else + return None + end else return None end + # Step 3 end - rescue DocuSign_Admin::ApiError => e + rescue DocuSign_eSign::ApiError => e error = JSON.parse e.response_body @error_code = e.code @error_message = error['error_description'] diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index 2fcbffd..409fb19 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -5,8 +5,8 @@ -

DocuSign Code Launcher: Ruby

-

This launcher both demonstrates use of Authorization Code Grant and JWT OAuth flows and includes multiple usage examples for the DocuSign eSignature REST API.

+

Ruby Launcher

+

Run and explore eSignature REST API code examples with Authorization Code Grant or JWT Grant authentication

@@ -26,11 +26,10 @@
<% if @show_doc %> -

Documentation on using JWT or OAuth Authorization Code Grant from a Node Express application.

+

Documentation on using JWT or OAuth Authorization Code Grant from a Ruby on Rails application.

<% end %> -

Basic examples

1. Use embedded signing

@@ -133,9 +132,8 @@ EnvelopeViews::createRecipient.

- - -

Payments Example

+

Payments

+

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

Anchor text (AutoPlace) @@ -145,9 +143,7 @@ Envelopes::create.

- - -

Tabs examples

+

Tabs

15. Get the tab data from an envelope

This example retrieves the tab (field) values from an envelope for all of the envelope’s recipients.

@@ -179,34 +175,35 @@ EnvelopeCustomFields::list.

-

Recipient Authentication

-

19. Send an envelope with access code authentication

+

Recipient authentication

+ +

19. Require access code authentication for a recipient

This example sends an envelope requiring the recipient to enter an access code for multifactor authentication.

API method used: Envelopes::create.

-

20. Require Phone Authentication for a Recipient

+

20. Require phone authentication for a recipient

Sends an envelope that requires entering a six-digit code from a text message or phone call for the purpose of multifactor authentication.

API method used: Envelopes::create.

-

22. Send an envelope with Recipient Knowledged Based Authentication

+

22. Require knowledge based authentication (KBA) for a recipient

Submit an envelope with multiple choice, public records based questions to provide multi-factor authentication.

API method used: Envelopes::create.

-

23. IDV Authentication

-

This is an example of an envelope utilizing Id verification authentication for a recipient.

+

23. Require ID verification (IDV) for a recipient

+

This is an example of an envelope utilizing ID verification authentication for a recipient.

API methods used: Accounts::getAccountIdentityVerificationsList and Envelopes::create.

-

Permissions

-

24. Create a permission profile

+ +

24. Create a permission profile

This example creates a user group’s permission profile.

@@ -234,8 +231,8 @@ AccountPermissionProfiles::delete.

-

Brands

+

28. Create a brand

This example creates an account brand that can be used to apply customization to your envelopes, including your own logo, colors, and text elements.

API method used: @@ -255,6 +252,7 @@

Bulk operations

+

31. Bulk send envelopes

This example creates and sends an envelope to multiple recipients using bulk lists.

API methods used: @@ -273,6 +271,7 @@

Advanced recipient routing

+

32. Pause a signature workflow

This example creates an envelope where the workflow is paused before the envelope is sent to a second recipient.

API method used: @@ -291,7 +290,8 @@ Envelopes::create.

-

Premium Features

+

Premium features

+

35. Send an envelope by SMS delivery

This example demonstrates how to send an envelope via an SMS message for a signer (and CC) to read and sign. From d0e203b91c6f94c30bcb1eeb780895f4d61d5cb0 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Tue, 9 Nov 2021 09:07:26 -0800 Subject: [PATCH 118/363] Devdocs 6128 (#48) * add step admin4 step 4 and update text * update idv example * update comments eg023 * update error messages * IDV fix * edit eSign23 launcher homepage text * add additional workflow id check for phone auth Co-authored-by: meihDS <70775251+meihDS@users.noreply.github.com> --- .../eg020_phone_authentication_controller.rb | 17 +- .../eg023_idv_authentication_controller.rb | 12 +- .../eg020_phone_authentication_service.rb | 8 +- .../eg023_idv_authentication_service.rb | 147 ++++++++++-------- .../eg023_idv_authentication/get.html.erb | 6 +- 5 files changed, 106 insertions(+), 84 deletions(-) diff --git a/app/controllers/e_sign/eg020_phone_authentication_controller.rb b/app/controllers/e_sign/eg020_phone_authentication_controller.rb index 2a3fe51..6344227 100644 --- a/app/controllers/e_sign/eg020_phone_authentication_controller.rb +++ b/app/controllers/e_sign/eg020_phone_authentication_controller.rb @@ -6,11 +6,18 @@ def create if check_token(minimum_buffer_min) begin results = ESign::Eg020PhoneAuthenticationService.new(request, session).call - session[:envelope_id] = results.envelope_id - @title = 'Require Phone Authentication for a Recipient' - @h1 = 'Require Phone Authentication for a Recipient' - @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." - render 'ds_common/example_done' + if results.to_s == "phone_auth_not_enabled" + @error_code = "IDENTITY_WORKFLOW_INVALID_ID" + @error_message = "The identity workflow ID specified is not valid." + @error_information = "Please contact Support to enable ID verification in your account." + render 'ds_common/error' + else + session[:envelope_id] = results.envelope_id + @title = 'Require Phone Authentication for a Recipient' + @h1 = 'Require Phone Authentication for a Recipient' + @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." + render 'ds_common/example_done' + end rescue DocuSign_eSign::ApiError => e error = JSON.parse e.response_body @error_code = error['errorCode'] diff --git a/app/controllers/e_sign/eg023_idv_authentication_controller.rb b/app/controllers/e_sign/eg023_idv_authentication_controller.rb index ec62cde..7dcbe26 100644 --- a/app/controllers/e_sign/eg023_idv_authentication_controller.rb +++ b/app/controllers/e_sign/eg023_idv_authentication_controller.rb @@ -6,12 +6,12 @@ def create if check_token(minimum_buffer_min) begin results = ESign::Eg023IdvAuthenticationService.new(request, session).call - if results.to_s == 'needs_idv_activated' - @title = 'Error' - @h1 = 'Error' - @message = 'Please activate IDV on your account to use this example.' - render 'ds_common/example_done' - + if results.to_s == "idv_not_enabled" + @error_code = "IDENTITY_WORKFLOW_INVALID_ID" + @error_message = "The identity workflow ID specified is not valid." + @error_information = "Please contact Support to enable ID verification in your account." + render 'ds_common/error' + else @title = 'Envelope sent' @h1 = 'Envelope sent' diff --git a/app/services/e_sign/eg020_phone_authentication_service.rb b/app/services/e_sign/eg020_phone_authentication_service.rb index 5e3f4e1..bcd6b85 100644 --- a/app/services/e_sign/eg020_phone_authentication_service.rb +++ b/app/services/e_sign/eg020_phone_authentication_service.rb @@ -24,6 +24,10 @@ def initialize(request, session) end def call + if session[:workflow_id].blank? + return "phone_auth_not_enabled" + end + # Construct your envelope JSON body # Step 4 start envelope_definition = DocuSign_eSign::EnvelopeDefinition.new @@ -114,10 +118,10 @@ def get_workflow(args) session[:workflow_id] = phone_auth_workflow.workflow_id return session[:workflow_id] else - return None + return "" end else - return None + return "" end # Step 3 end diff --git a/app/services/e_sign/eg023_idv_authentication_service.rb b/app/services/e_sign/eg023_idv_authentication_service.rb index 15951dd..07f228e 100644 --- a/app/services/e_sign/eg023_idv_authentication_service.rb +++ b/app/services/e_sign/eg023_idv_authentication_service.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: true +# frozen_string_literal: true class ESign::Eg023IdvAuthenticationService include ApiCreator @@ -21,75 +21,86 @@ def initialize(request, session) end def call - # ***DS.snippet.0.start - - # Step 3. Obtain your workflow ID + # Obtain your workflow ID + # Step 3 start accounts_api = create_account_api(args) - wf_res = accounts_api.get_account_identity_verification args[:account_id] - workflow_id = wf_res.identity_verification[0].workflow_id - + workflow_response = accounts_api.get_account_identity_verification args[:account_id] + if workflow_response.identity_verification + idv_workflow = workflow_response.identity_verification.find{ |item| item.default_name == "DocuSign ID Verification" } + if idv_workflow + workflow_id = idv_workflow.workflow_id + end + end + # Step 3 end + if workflow_id.blank? - "needs_idv_activated" - - else - # Step 4. Construct your envelope JSON body - envelope_definition = DocuSign_eSign::EnvelopeDefinition.new - envelope_definition.email_subject = 'Please sign this document set' - - # Add the documents - pdf_filename = "World_Wide_Corp_lorem.pdf" - - # Create the document models - document1 = DocuSign_eSign::Document.new( - # Create the DocuSign Document object - documentBase64: Base64.encode64(File.binread(File.join('data', pdf_filename))), - name: 'Lorem', # Can be different from the actual file name - fileExtension: 'pdf', # Many different document types are accepted - documentId: '1' # A label used to reference the doc - ) - - envelope_definition.documents = [document1] - - # Create the signer recipient model - signer1 = DocuSign_eSign::Signer.new - signer1.email = envelope_args[:signer_email] - signer1.name = envelope_args[:signer_name] - signer1.recipient_id = '1' - signer1.routing_order = '1' - - sign_here1 = DocuSign_eSign::SignHere.new - sign_here1.anchor_string = '/sn1/' - sign_here1.anchor_units = 'pixels' - sign_here1.anchor_x_offset = '20' - sign_here1.anchor_y_offset = '10' - - # Add the tabs model (including the sign_here tabs) to the signer - # The Tabs object takes arrays of the different field/tab types - signer1_tabs = DocuSign_eSign::Tabs.new ({ - signHereTabs: [sign_here1] - }) - signer1.tabs = signer1_tabs - - wf = DocuSign_eSign::RecipientIdentityVerification.new - wf.workflow_id = workflow_id - signer1.identity_verification = wf - - # Add the recipients to the Envelope object - recipients = DocuSign_eSign::Recipients.new( - signers: [signer1] - ) - # Request that the envelope be sent by setting status to "sent" - # To request that the envelope be created as a draft, set status to "created" - envelope_definition.recipients = recipients - envelope_definition.status = envelope_args[:status] - - # Step 5. Call the eSignature REST API - envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope args[:account_id], envelope_definition - session[:envelope_id] = results.envelope_id - results - - # ***DS.snippet.0.end + return "idv_not_enabled" end + + puts "WORKFLOW ID: " + puts workflow_id + + + # Construct your envelope JSON body + # Step 4 start + envelope_definition = DocuSign_eSign::EnvelopeDefinition.new + envelope_definition.email_subject = 'Please sign this document set' + + # Add the documents + pdf_filename = "World_Wide_Corp_lorem.pdf" + + # Create the document models + document1 = DocuSign_eSign::Document.new( + # Create the DocuSign Document object + documentBase64: Base64.encode64(File.binread(File.join('data', pdf_filename))), + name: 'Lorem', # Can be different from the actual file name + fileExtension: 'pdf', # Many different document types are accepted + documentId: '1' # A label used to reference the doc + ) + + envelope_definition.documents = [document1] + + # Create the signer recipient model + signer1 = DocuSign_eSign::Signer.new + signer1.email = envelope_args[:signer_email] + signer1.name = envelope_args[:signer_name] + signer1.recipient_id = '1' + signer1.routing_order = '1' + + sign_here1 = DocuSign_eSign::SignHere.new + sign_here1.anchor_string = '/sn1/' + sign_here1.anchor_units = 'pixels' + sign_here1.anchor_x_offset = '20' + sign_here1.anchor_y_offset = '10' + + # Add the tabs model (including the sign_here tabs) to the signer + # The Tabs object takes arrays of the different field/tab types + signer1_tabs = DocuSign_eSign::Tabs.new ({ + signHereTabs: [sign_here1] + }) + signer1.tabs = signer1_tabs + + wf = DocuSign_eSign::RecipientIdentityVerification.new + wf.workflow_id = workflow_id + signer1.identity_verification = wf + + # Add the recipients to the Envelope object + recipients = DocuSign_eSign::Recipients.new( + signers: [signer1] + ) + # Request that the envelope be sent by setting status to "sent" + # To request that the envelope be created as a draft, set status to "created" + envelope_definition.recipients = recipients + envelope_definition.status = envelope_args[:status] + # Step 4 end + + # Call the eSignature REST API + # Step 5 start + envelope_api = create_envelope_api(args) + results = envelope_api.create_envelope args[:account_id], envelope_definition + # Step 5 end + + session[:envelope_id] = results.envelope_id + results end end \ No newline at end of file diff --git a/app/views/e_sign/eg023_idv_authentication/get.html.erb b/app/views/e_sign/eg023_idv_authentication/get.html.erb index b6e54e1..19666c4 100644 --- a/app/views/e_sign/eg023_idv_authentication/get.html.erb +++ b/app/views/e_sign/eg023_idv_authentication/get.html.erb @@ -1,9 +1,9 @@ -

23. Send an envelope with recipient Id Verification authentication.

+

23. Require ID verification (IDV) for a recipient

+

Sends an envelope that requires the recipient to upload a government-issued ID for the purpose of multifactor authentication.

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

-

This is an example of an envelope utilizing IDV authentication for multi-factor verification of a recipient. IDV is a service offered by DocuSign that allows your reicpient to upload a photo of a government issued id for verification.

<% if @show_doc %>

Documentation about this example.

@@ -31,4 +31,4 @@ value="<%= @config.signer_name %>" required>
- \ No newline at end of file + From 05e033800b84776cb28f1e661209b778096626a5 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Tue, 16 Nov 2021 11:13:27 -0800 Subject: [PATCH 119/363] Devdocs 5748 (#49) * add step admin4 step 4 and update text * working changes to dropdown api * update config file * routing constraints * update routes * update Gemfile * remove debug statements * updates to dropdown * update routes * remove export data * Revert "update routes" This reverts commit 4b680a53f0e088fa34a16086183ad8827fb97de7. * Revert "remove export data" This reverts commit 4d05ab7a6a3fb2e55969be5992f901e4dd60141c. * update routes and remove data * include banner when logged in * include default session api type * small quickstart related fix * fix jwt issue --- Gemfile.lock | 26 +++++++------- app/controllers/ds_common_controller.rb | 35 +++++++++++------- app/controllers/session_controller.rb | 4 +++ app/services/admin_api/get_data_service.rb | 1 - app/services/jwt_auth/jwt_creator.rb | 21 ++++++----- app/views/clickwrap/index.html.erb | 4 +-- app/views/ds_common/choose_api.erb | 19 ++++++++++ app/views/ds_common/ds_must_authenticate.erb | 2 +- app/views/layouts/_head.erb | 4 ++- app/views/room_api/index.html.erb | 38 ++++++++++---------- config/appsettings.example.yml | 7 ---- config/initializers/omniauth.rb | 13 +++++-- config/routes.rb | 18 +++++++--- 13 files changed, 118 insertions(+), 74 deletions(-) create mode 100644 app/views/ds_common/choose_api.erb diff --git a/Gemfile.lock b/Gemfile.lock index f6e68ab..7d57c57 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -97,7 +97,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.13.0.rc1) + docusign_esign (3.13.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -113,10 +113,10 @@ GEM jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) erubi (1.10.0) - ethon (0.14.0) + ethon (0.15.0) ffi (>= 1.15.0) execjs (2.8.1) - faraday (1.7.0) + faraday (1.8.0) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) @@ -135,17 +135,17 @@ GEM faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) faraday-rack (1.0.0) - ffi (1.15.3) + ffi (1.15.4) globalid (0.5.2) activesupport (>= 5.0) hashie (4.1.0) - i18n (1.8.10) + i18n (1.8.11) concurrent-ruby (~> 1.0) io-like (0.3.1) jbuilder (2.10.2) activesupport (>= 5.0.0) - json (2.5.1) - jwt (2.2.3) + json (2.6.1) + jwt (2.3.0) listen (3.2.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) @@ -154,9 +154,9 @@ GEM nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) - marcel (1.0.1) + marcel (1.0.2) method_source (0.9.2) - mini_mime (1.1.1) + mini_mime (1.1.2) minitest (5.14.4) msgpack (1.4.2) multi_json (1.15.0) @@ -177,7 +177,7 @@ GEM hashie (>= 3.4.6) rack (>= 1.6.2, < 3) rack-protection - omniauth-oauth2 (1.7.1) + omniauth-oauth2 (1.7.2) oauth2 (~> 1.4) omniauth (>= 1.9, < 3) omniauth-rails_csrf_protection (1.0.0) @@ -191,9 +191,9 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.6) - puma (4.3.9) + puma (4.3.10) nio4r (~> 2.0) - racc (1.5.2) + racc (1.6.0) rack (2.2.3) rack-protection (2.1.0) rack @@ -279,7 +279,7 @@ GEM websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.4.2) + zeitwerk (2.5.1) PLATFORMS x86_64-darwin-20 diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index 59903f8..34351a6 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -6,15 +6,16 @@ class DsCommonController < ApplicationController def index @show_doc = Rails.application.config.documentation - if Rails.configuration.examples_API['Rooms'] + if session[:examples_API] == 'Rooms' render 'room_api/index' - elsif Rails.configuration.examples_API['Click'] + elsif session[:examples_API] == 'Click' render 'clickwrap/index' - elsif Rails.configuration.examples_API['Monitor'] + elsif session[:examples_API] == 'Monitor' render 'monitor_api/index' - elsif Rails.configuration.examples_API['Admin'] + elsif session[:examples_API] == 'Admin' render 'admin_api/index' else + session[:examples_API] = 'eSignature' @show_doc = Rails.application.config.documentation if Rails.configuration.quickstart && session[:been_here].nil? redirect_to '/eg001' @@ -22,6 +23,16 @@ def index end end + def choose_api + render 'ds_common/choose_api' + end + + def api_selected + session.delete :eg + session[:examples_API] = params[:chosen_api] + redirect_to '/ds/mustAuthenticate' + end + def ds_return # To break out of the Quickstart loop an example has been completed session[:been_here] = true @@ -32,17 +43,17 @@ def ds_return end def ds_must_authenticate - if Rails.configuration.examples_API['Monitor'] + if session[:examples_API] == 'Monitor' jwt_auth end - if Rails.configuration.quickstart - redirect_to('/auth/docusign') + if Rails.configuration.quickstart and session[:been_here].nil? and session[:examples_API] == 'eSignature' + redirect_to "/auth/docusign" end @title = 'Authenticate with DocuSign' @show_doc = Rails.application.config.documentation if params[:auth] == 'grand-auth' - redirect_to('/auth/docusign') + redirect_to "/auth/docusign" elsif params[:auth] == 'jwt-auth' jwt_auth end @@ -57,16 +68,16 @@ def jwt_auth end else session['omniauth.state'] = SecureRandom.hex - url = JwtAuth::JwtCreator.consent_url(session['omniauth.state']) + url = JwtAuth::JwtCreator.consent_url(session['omniauth.state'], session['examples_API']) redirect_to root_path if session[:token].present? end - if Rails.configuration.examples_API['Rooms'] + if session[:examples_API] == 'Rooms' configuration = DocuSign_Rooms::Configuration.new api_client = DocuSign_Rooms::ApiClient.new(configuration) - elsif Rails.configuration.examples_API['Click'] + elsif session[:examples_API] == 'Click' configuration = DocuSign_Click::Configuration.new api_client = DocuSign_Click::ApiClient.new configuration - elsif Rails.configuration.examples_API['Admin'] + elsif session[:examples_API] == 'Admin' configuration = DocuSign_Admin::Configuration.new api_client = DocuSign_Admin::ApiClient.new configuration end diff --git a/app/controllers/session_controller.rb b/app/controllers/session_controller.rb index 151349d..7587824 100644 --- a/app/controllers/session_controller.rb +++ b/app/controllers/session_controller.rb @@ -24,6 +24,10 @@ def destroy redirect_to root_path end + # def switch_api + # internal_destroy + # end + # GET /auth/failure def omniauth_failure error_msg = "OmniAuth authentication failure message: #{params[:message]} for strategy: #{params[:strategy]} and HTTP_REFERER: #{params[:origin]}" diff --git a/app/services/admin_api/get_data_service.rb b/app/services/admin_api/get_data_service.rb index ed7361b..cff6905 100644 --- a/app/services/admin_api/get_data_service.rb +++ b/app/services/admin_api/get_data_service.rb @@ -32,7 +32,6 @@ def get_ds_groups def get_organization_id worker - puts "\n\n getting org_id \n\n" accounts_api = DocuSign_Admin::AccountsApi.new(@api_client) accounts_api.get_organizations().organizations[0].as_json['id'] end diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index 0c252cd..a687b07 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -9,16 +9,16 @@ class JwtCreator # DocuSign authorization URI to obtain individual consent # https://developers.docusign.com/platform/auth/jwt/jwt-get-token # https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/ - def self.consent_url(state) + def self.consent_url(state, examples_API) # GET /oauth/auth # This endpoint is used to obtain consent and is the first step in several authentication flows. # https://developers.docusign.com/platform/auth/reference/obtain-consent scope = "signature" - if Rails.configuration.examples_API['Rooms'] + if examples_API == 'Rooms' scope = "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" - elsif Rails.configuration.examples_API['Click'] + elsif examples_API == 'Click' scope = "signature click.manage click.send" - elsif Rails.configuration.examples_API['Admin'] + elsif examples_API == 'Admin' scope = "signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" end scope = "#{scope} impersonation" @@ -36,15 +36,15 @@ def initialize(session) @session = session scope = "signature" @client_module = DocuSign_eSign - if Rails.configuration.examples_API['Rooms'] + if session[:examples_API] == 'Rooms' scope = "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" @client_module = DocuSign_Rooms - elsif Rails.configuration.examples_API['Click'] + elsif session[:examples_API] == 'Click' scope = "signature click.manage click.send" @client_module = DocuSign_Click - elsif Rails.configuration.examples_API['Monitor'] + elsif session[:examples_API] == 'Monitor' @client_module = DocuSign_Monitor - elsif Rails.configuration.examples_API['Admin'] + elsif session[:examples_API] == 'Admin' scope = "signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" @client_module = DocuSign_Admin end @@ -69,6 +69,11 @@ def check_jwt_token end rescue @client_module::ApiError => exception Rails.logger.warn exception.inspect + + if exception.response_body == nil + return false + end + body = JSON.parse(exception.response_body) if body['error'] == "consent_required" diff --git a/app/views/clickwrap/index.html.erb b/app/views/clickwrap/index.html.erb index 956c975..469120b 100644 --- a/app/views/clickwrap/index.html.erb +++ b/app/views/clickwrap/index.html.erb @@ -1,5 +1,4 @@ -<% if !session[:ds_user_name] %> - +
@@ -18,7 +17,6 @@ -<% end %>

Welcome

diff --git a/app/views/ds_common/choose_api.erb b/app/views/ds_common/choose_api.erb new file mode 100644 index 0000000..27d3a6c --- /dev/null +++ b/app/views/ds_common/choose_api.erb @@ -0,0 +1,19 @@ +
+

Please Choose an API

+

+
+ <%= hidden_field_tag :authenticity_token, form_authenticity_token %> +

+
+ +
+ +

+
+
\ No newline at end of file diff --git a/app/views/ds_common/ds_must_authenticate.erb b/app/views/ds_common/ds_must_authenticate.erb index c722e3d..844cc22 100644 --- a/app/views/ds_common/ds_must_authenticate.erb +++ b/app/views/ds_common/ds_must_authenticate.erb @@ -5,7 +5,7 @@ <%= hidden_field_tag :authenticity_token, form_authenticity_token %>
- - - - - - -
-

Ruby Launcher

-

Welcome to the DocuSign Ruby examples using multiple OAuth flows (JWT and Authorization - Code Grant).

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

Ruby Launcher

+

Welcome to the DocuSign Ruby examples using multiple OAuth flows (JWT and Authorization + Code Grant).

+
+ +
-<% end %> +

Welcome

diff --git a/config/appsettings.example.yml b/config/appsettings.example.yml index 389557d..d301dcf 100644 --- a/config/appsettings.example.yml +++ b/config/appsettings.example.yml @@ -4,13 +4,6 @@ default: &default app_url: http://localhost:3000 # quickstart is an optional setting and can be enabled by setting it to: true quickstart: {QUICKSTART_VALUE} - # Set only one examples_API type to 'true' and set the remaining to 'false'. - examples_API: - eSignature: true - Rooms: false - Click: false - Monitor: false - Admin: false # NOTE: The terms "client_id" and "Integration key" are synonyms. They refer to the same thing # The integration_key value is the same between the development account and production account integration_key: {INTEGRATION_KEY_AUTH_CODE} diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 693967f..53dd780 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -23,6 +23,11 @@ # OAuth2 login response callback message configuration is in OmniAuth::Strategies::Docusign in lib/docusign.rb provider :docusign, config.integration_key, config.integration_secret, setup: lambda { |env| strategy = env['omniauth.strategy'] + + # params = strategy.request.params + # examples_API = params['examples_API'] + # strategy.request.params.delete('examples_API') + strategy.options[:client_options].site = config.app_url strategy.options[:prompt] = 'login' strategy.options[:oauth_base_uri] = config.authorization_server @@ -34,11 +39,13 @@ unless strategy.options[:allow_silent_authentication] strategy.options[:authorize_params].prompt = strategy.options.prompt end - if Rails.configuration.examples_API['Rooms'] + session = strategy.session + + if session[:examples_API] == "Rooms" strategy.options[:authorize_params].scope = "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" - elsif Rails.configuration.examples_API['Click'] + elsif session[:examples_API] == "Click" strategy.options[:authorize_params].scope = "signature click.manage click.send" - elsif Rails.configuration.examples_API['Admin'] + elsif session[:examples_API] == "Admin" strategy.options[:authorize_params].scope = "signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" end } diff --git a/config/routes.rb b/config/routes.rb index 759a704..7bd404a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true Rails.application.routes.draw do - if Rails.configuration.examples_API['Rooms'] + constraints lambda { |req| req.session[:examples_API] == "Rooms" } do scope module: 'room_api' do get 'eg001' => 'eg001_create_room_with_data#get' post 'eg001' => 'eg001_create_room_with_data#create' @@ -31,7 +31,8 @@ get 'eg009' => 'eg009_assign_form_to_form_group#get' post 'eg009' => 'eg009_assign_form_to_form_group#create' end - elsif Rails.configuration.examples_API['Click'] + end + constraints lambda { |req| req.session[:examples_API] == "Click" } do scope module: 'clickwrap' do get 'eg001' => 'eg001_create_clickwrap#get' post 'eg001' => 'eg001_create_clickwrap#create' @@ -48,12 +49,14 @@ get 'eg005' => 'eg005_clickwrap_responses#get' post 'eg005' => 'eg005_clickwrap_responses#create' end - elsif Rails.configuration.examples_API['Monitor'] + end + constraints lambda { |req| req.session[:examples_API] == "Monitor" } do scope module: 'monitor_api' do get 'eg001' => 'eg001_get_monitoring_dataset#get' post 'eg001' => 'eg001_get_monitoring_dataset#create' end - elsif Rails.configuration.examples_API['Admin'] + end + constraints lambda { |req| req.session[:examples_API] == "Admin" } do scope module: 'admin_api' do get 'eg001' => 'eg001_create_user#get' post 'eg001' => 'eg001_create_user#create' @@ -71,7 +74,8 @@ get 'eg005' => 'eg005_audit_users#get' post 'eg005' => 'eg005_audit_users#create' end - else + end + constraints lambda { |req| req.session[:examples_API] == "eSignature" } do get '/eg001' => 'eg001_embedded_signing#get' post '/eg001' => 'eg001_embedded_signing#create' @@ -200,6 +204,10 @@ get '/ds/mustAuthenticateJwt' => 'ds_common#ds_must_authenticate_jwt' post '/ds/mustAuthenticateJwt' => 'ds_common#ds_must_authenticate' + get '/ds/chooseApi' => 'ds_common#choose_api' + + post '/ds/apiSelected' => 'ds_common#api_selected' + get '/ds/session' => 'session#show' # default root From afd8f3771f022dfc195fe26ea1ebafea1a907fb4 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Tue, 16 Nov 2021 11:34:26 -0800 Subject: [PATCH 120/363] update phone auth --- .../e_sign/eg020_phone_authentication_service.rb | 9 --------- 1 file changed, 9 deletions(-) diff --git a/app/services/e_sign/eg020_phone_authentication_service.rb b/app/services/e_sign/eg020_phone_authentication_service.rb index fc938d1..c6978b8 100644 --- a/app/services/e_sign/eg020_phone_authentication_service.rb +++ b/app/services/e_sign/eg020_phone_authentication_service.rb @@ -94,14 +94,6 @@ def call # To request that the envelope be created as a draft, set to "created" envelope_definition.recipients = recipients envelope_definition.status = envelope_args[:status] -<<<<<<< HEAD - # Step 3 end - - # Call the eSignature REST API - # Step 4 start - results = envelope_api.create_envelope args[:account_id], envelope_definition - # Step 4 end -======= # Step 4 end # Call the eSignature REST API @@ -109,7 +101,6 @@ def call envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope_definition # Step 5 end ->>>>>>> 05e033800b84776cb28f1e661209b778096626a5 end def get_workflow(args) From 10157fae966fd0975c6f92c6c818774638306199 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Fri, 14 Jan 2022 16:55:58 -0800 Subject: [PATCH 121/363] Update bulk send example (#52) * Update bulk send example * update eSign SDK --- Gemfile | 2 +- Gemfile.lock | 140 +++++++++--------- ...eg031_bulk_sending_envelopes_controller.rb | 10 +- .../eg031_bulk_sending_envelopes_service.rb | 64 ++------ app/views/ds_common/index.html.erb | 26 ++-- .../eg031_bulk_sending_envelopes/get.html.erb | 118 +++++++-------- 6 files changed, 161 insertions(+), 199 deletions(-) diff --git a/Gemfile b/Gemfile index e54ef5d..98bec99 100644 --- a/Gemfile +++ b/Gemfile @@ -66,7 +66,7 @@ group :test do gem 'chromedriver-helper', '~> 2.1.1' end -gem 'docusign_esign', '~> 3.13.0.rc1' +gem 'docusign_esign', '~> 3.14.0' gem 'docusign_monitor', '~> 1.0.0' gem 'docusign_rooms', '~> 1.2.0.rc1' gem 'docusign_click', '~> 1.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index 7d57c57..1dc0be2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,56 +1,56 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.4.1) - actionpack (= 6.0.4.1) + actioncable (6.0.4.4) + actionpack (= 6.0.4.4) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.4.1) - actionpack (= 6.0.4.1) - activejob (= 6.0.4.1) - activerecord (= 6.0.4.1) - activestorage (= 6.0.4.1) - activesupport (= 6.0.4.1) + actionmailbox (6.0.4.4) + actionpack (= 6.0.4.4) + activejob (= 6.0.4.4) + activerecord (= 6.0.4.4) + activestorage (= 6.0.4.4) + activesupport (= 6.0.4.4) mail (>= 2.7.1) - actionmailer (6.0.4.1) - actionpack (= 6.0.4.1) - actionview (= 6.0.4.1) - activejob (= 6.0.4.1) + actionmailer (6.0.4.4) + actionpack (= 6.0.4.4) + actionview (= 6.0.4.4) + activejob (= 6.0.4.4) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.4.1) - actionview (= 6.0.4.1) - activesupport (= 6.0.4.1) + actionpack (6.0.4.4) + actionview (= 6.0.4.4) + activesupport (= 6.0.4.4) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.4.1) - actionpack (= 6.0.4.1) - activerecord (= 6.0.4.1) - activestorage (= 6.0.4.1) - activesupport (= 6.0.4.1) + actiontext (6.0.4.4) + actionpack (= 6.0.4.4) + activerecord (= 6.0.4.4) + activestorage (= 6.0.4.4) + activesupport (= 6.0.4.4) nokogiri (>= 1.8.5) - actionview (6.0.4.1) - activesupport (= 6.0.4.1) + actionview (6.0.4.4) + activesupport (= 6.0.4.4) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.4.1) - activesupport (= 6.0.4.1) + activejob (6.0.4.4) + activesupport (= 6.0.4.4) globalid (>= 0.3.6) - activemodel (6.0.4.1) - activesupport (= 6.0.4.1) - activerecord (6.0.4.1) - activemodel (= 6.0.4.1) - activesupport (= 6.0.4.1) - activestorage (6.0.4.1) - actionpack (= 6.0.4.1) - activejob (= 6.0.4.1) - activerecord (= 6.0.4.1) + activemodel (6.0.4.4) + activesupport (= 6.0.4.4) + activerecord (6.0.4.4) + activemodel (= 6.0.4.4) + activesupport (= 6.0.4.4) + activestorage (6.0.4.4) + actionpack (= 6.0.4.4) + activejob (= 6.0.4.4) + activerecord (= 6.0.4.4) marcel (~> 1.0.0) - activesupport (6.0.4.1) + activesupport (6.0.4.4) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -97,7 +97,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.13.0) + docusign_esign (3.14.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -116,29 +116,33 @@ GEM ethon (0.15.0) ffi (>= 1.15.0) execjs (2.8.1) - faraday (1.8.0) + faraday (1.9.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) - faraday-httpclient (~> 1.0.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) faraday-net_http (~> 1.0) - faraday-net_http_persistent (~> 1.1) + faraday-net_http_persistent (~> 1.0) faraday-patron (~> 1.0) faraday-rack (~> 1.0) - multipart-post (>= 1.2, < 3) + faraday-retry (~> 1.0) ruby2_keywords (>= 0.0.4) faraday-em_http (1.0.0) faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) + faraday-multipart (1.0.3) + multipart-post (>= 1.2, < 3) faraday-net_http (1.0.1) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) faraday-rack (1.0.0) - ffi (1.15.4) - globalid (0.5.2) + faraday-retry (1.0.3) + ffi (1.15.5) + globalid (1.0.0) activesupport (>= 5.0) - hashie (4.1.0) + hashie (5.0.0) i18n (1.8.11) concurrent-ruby (~> 1.0) io-like (0.3.1) @@ -149,7 +153,7 @@ GEM listen (3.2.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.12.0) + loofah (2.13.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -157,15 +161,15 @@ GEM marcel (1.0.2) method_source (0.9.2) mini_mime (1.1.2) - minitest (5.14.4) + minitest (5.15.0) msgpack (1.4.2) multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) nio4r (2.5.8) - nokogiri (1.12.5-x86_64-darwin) + nokogiri (1.13.1-x86_64-darwin) racc (~> 1.4) - nokogiri (1.12.5-x86_64-linux) + nokogiri (1.13.1-x86_64-linux) racc (~> 1.4) oauth2 (1.4.7) faraday (>= 0.8, < 2.0) @@ -199,29 +203,29 @@ GEM rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.0.4.1) - actioncable (= 6.0.4.1) - actionmailbox (= 6.0.4.1) - actionmailer (= 6.0.4.1) - actionpack (= 6.0.4.1) - actiontext (= 6.0.4.1) - actionview (= 6.0.4.1) - activejob (= 6.0.4.1) - activemodel (= 6.0.4.1) - activerecord (= 6.0.4.1) - activestorage (= 6.0.4.1) - activesupport (= 6.0.4.1) + rails (6.0.4.4) + actioncable (= 6.0.4.4) + actionmailbox (= 6.0.4.4) + actionmailer (= 6.0.4.4) + actionpack (= 6.0.4.4) + actiontext (= 6.0.4.4) + actionview (= 6.0.4.4) + activejob (= 6.0.4.4) + activemodel (= 6.0.4.4) + activerecord (= 6.0.4.4) + activestorage (= 6.0.4.4) + activesupport (= 6.0.4.4) bundler (>= 1.3.0) - railties (= 6.0.4.1) + railties (= 6.0.4.4) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.4.2) loofah (~> 2.3) - railties (6.0.4.1) - actionpack (= 6.0.4.1) - activesupport (= 6.0.4.1) + railties (6.0.4.4) + actionpack (= 6.0.4.4) + activesupport (= 6.0.4.4) method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) @@ -252,12 +256,12 @@ GEM sprockets (4.0.2) concurrent-ruby (~> 1.0) rack (> 1, < 3) - sprockets-rails (3.2.2) - actionpack (>= 4.0) - activesupport (>= 4.0) + sprockets-rails (3.4.2) + actionpack (>= 5.2) + activesupport (>= 5.2) sprockets (>= 3.0.0) sqlite3 (1.4.2) - thor (1.1.0) + thor (1.2.1) thread_safe (0.3.6) tilt (2.0.10) turbolinks (5.2.1) @@ -279,7 +283,7 @@ GEM websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.5.1) + zeitwerk (2.5.3) PLATFORMS x86_64-darwin-20 @@ -293,7 +297,7 @@ DEPENDENCIES coffee-rails (~> 5.0.0) docusign_admin (~> 1.0.0) docusign_click (~> 1.0.0) - docusign_esign (~> 3.13.0.rc1) + docusign_esign (~> 3.14.0) docusign_monitor (~> 1.0.0) docusign_rooms (~> 1.2.0.rc1) jbuilder (~> 2.10.0) diff --git a/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb b/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb index b9ebf41..1723135 100644 --- a/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb +++ b/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb @@ -5,13 +5,13 @@ class ESign::Eg031BulkSendingEnvelopesController < EgController def create minimum_buffer_min = 3 if check_token(minimum_buffer_min) - begin + begin results = ESign::Eg031BulkSendingEnvelopesService.new(request, session).call # Step 4. a) Call the eSignature API - # b) Display the JSON response - @title = 'Bulk sent' - @h1 = 'Bulk send envelope was successfully performed!' - @message = "Bulk request queued to #{results.queued} user lists." + # b) Display the JSON response + @title = 'Bulk send envelopes' + @h1 = 'Bulk send envelopes' + @message = 'Results from BulkSend:getBulkSendBatchStatus method:' @json = results.to_json.to_json render 'ds_common/example_done' diff --git a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb index 418184d..0eca8a9 100644 --- a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb +++ b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb @@ -6,16 +6,16 @@ class ESign::Eg031BulkSendingEnvelopesService def initialize(request, session) @signers = { - signer_email: request.params['signerEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name: request.params['signerName'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_email: request.params['ccEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_name: request.params['ccName'].gsub(/([^\w \-\@\.\,])+/, ''), + signer_email: request.params['signerEmail1'].gsub(/([^\w \-\@\.\,])+/, ''), + signer_name: request.params['signerName1'].gsub(/([^\w \-\@\.\,])+/, ''), + cc_email: request.params['ccEmail1'].gsub(/([^\w \-\@\.\,])+/, ''), + cc_name: request.params['ccName1'].gsub(/([^\w \-\@\.\,])+/, ''), status: 'created', - signer_email1: request.params['signerEmail1'].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name1: request.params['signerName1'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_email1: request.params['ccEmail1'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_name1: request.params['ccName1'].gsub(/([^\w \-\@\.\,])+/, '') + signer_email1: request.params['signerEmail2'].gsub(/([^\w \-\@\.\,])+/, ''), + signer_name1: request.params['signerName2'].gsub(/([^\w \-\@\.\,])+/, ''), + cc_email1: request.params['ccEmail2'].gsub(/([^\w \-\@\.\,])+/, ''), + cc_name1: request.params['ccName2'].gsub(/([^\w \-\@\.\,])+/, '') } @args = { account_id: session['ds_account_id'], @@ -54,24 +54,17 @@ def call envelope_api.create_custom_fields(args[:account_id], envelope_id, custom_fields(bulk_list_id)) # Step 5-1 end - # Add placeholder recipients - # Step 6-1 start - recipients = recipients_data - recipients = DocuSign_eSign::Recipients.new(signers: [recipients[0]], cc: [recipients[1]]) - envelope_api.create_recipient(args[:account_id], envelope_id, recipients, options = DocuSign_eSign::CreateRecipientOptions.default) - # Step 6-1 end - # Initiate bulk send - # Step 7 start + # Step 6 start bulk_send_request = DocuSign_eSign::BulkSendRequest.new(envelopeOrTemplateId: envelope_id) batch = bulk_envelopes_api.create_bulk_send_request(args[:account_id], bulk_list_id, bulk_send_request) batch_id = batch.batch_id - # Step 7 end + # Step 6 end # Confirm successful batch send - # Step 8 start + # Step 7 start bulk_envelopes_api.get_bulk_send_batch_status(args[:account_id], batch_id) - # Step 8 end + # Step 7 end end private @@ -150,37 +143,6 @@ def custom_fields(bulk_list_id) end # Step 5-2 end - # Step 6-2 start - def recipients_data - signer = DocuSign_eSign::Signer.new( - name: "Multi Bulk Recipient::signer", - email: "multiBulkRecipients-signer@docusign.com", - roleName: "signer", - note: "", - routingOrder: 1, - status: "created", - templateAccessCodeRequired: "null", - deliveryMethod: "email", - recipientId: "1", - recipientType: "signer" - ) - - cc = DocuSign_eSign::CarbonCopy.new( - name: "Multi Bulk Recipient::cc", - email: "multiBulkRecipients-cc@docusign.com", - roleName: "cc", - note: "", - routingOrder: 1, - status: "created", - deliveryMethod: "email", - recipientId: "2", - recipientType: "cc" - ) - - [signer, cc] - end - # Step 6-2 end - # Step 4-2 start def make_envelope # Create the envelope definition @@ -212,7 +174,7 @@ def make_envelope email: "multiBulkRecipients-cc@docusign.com", roleName: "cc", note: "", - routingOrder: 1, + routingOrder: 2, status: "created", deliveryMethod: "email", recipientId: "2", diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index 409fb19..05a5cdd 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -133,7 +133,7 @@

Payments

- +

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

Anchor text (AutoPlace) @@ -176,7 +176,7 @@

Recipient authentication

- +

19. Require access code authentication for a recipient

This example sends an envelope requiring the recipient to enter an access code for multifactor authentication.

API method used: @@ -202,7 +202,7 @@

Permissions

- +

24. Create a permission profile

This example creates a user group’s permission profile. @@ -232,7 +232,7 @@

Brands

- +

28. Create a brand

This example creates an account brand that can be used to apply customization to your envelopes, including your own logo, colors, and text elements.

API method used: @@ -252,26 +252,26 @@

Bulk operations

- +

31. Bulk send envelopes

-

This example creates and sends an envelope to multiple recipients using bulk lists.

+

Demonstrates how to send envelopes in bulk to multiple recipients. First, this example creates a bulk send recipients list, then creates an envelope. After that, + it initiates bulk envelope sending. +

API methods used: + BulkSend::createBulkSendList, Envelopes::create, EnvelopeCustomFields::create, EnvelopeRecipients::create, - BulkSend::createBulkSendList, + href="https://developers.docusign.com/docs/esign-rest-api/reference/bulkenvelopes/bulksend/createbulksendrequest/">BulkSend::createBulkSendRequest, BulkSend::createBulkSendRequest, and - BulkSend::getBulkSendBatchStatus

Advanced recipient routing

- +

32. Pause a signature workflow

This example creates an envelope where the workflow is paused before the envelope is sent to a second recipient.

API method used: @@ -291,7 +291,7 @@

Premium features

- +

35. Send an envelope by SMS delivery

This example demonstrates how to send an envelope via an SMS message for a signer (and CC) to read and sign. diff --git a/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb b/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb index 04a06d2..8d95701 100644 --- a/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb +++ b/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb @@ -1,74 +1,70 @@ -

31. Bulk sending envelopes to multiple recipients

+

31. Bulk send envelopes

- Method BulkSend:createBulkSendList creates a bulk list that you can to use an envelope to up - to 1,000 recipients at once. + Demonstrates how to send envelopes in bulk to multiple recipients. First, this example creates a bulk send recipients list, + then creates an envelope. After that, it initiates bulk envelope sending.

-

API method used: - EnvelopeRecipients::create, - Envelopes::create, - BulkEnvelopes::get, - EnvelopeCustomFields::create, - BulkSend::createBulkSendList, - EnvelopeRecipients::create +

API methods used: + BulkSend::createBulkSendList, + Envelopes::create, + EnvelopeCustomFields::create, + BulkSend::createBulkSendRequest, + BulkSend::getBulkSendBatchStatus

View source file <%= @source_file %> on GitHub.

-
-

Bulk copy #1

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

Bulk copy #2

-
-
- - -
-
- - -
-
-
-
- - -
-
- - +
+
+
Bulk copy #1
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
Bulk copy #2
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
-
- + + \ No newline at end of file From 5188182b4853b8fb8e220191adb638b4836920be Mon Sep 17 00:00:00 2001 From: Connor Lunsford Date: Wed, 19 Jan 2022 14:10:57 -0800 Subject: [PATCH 122/363] Changed API Username GUID > User ID GUID in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 25b7f6f..b764abe 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ For a list of code examples that use the Admin API, select the Ruby tab under [E 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 API Username GUID of the impersonated user. See [Installation steps for JWT Grant authentication](#installation-steps-for-jwt-grant-authentication) 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: @@ -110,7 +110,7 @@ Also, in order to select JSON Web Token authentication in the launcher, in confi `cd ` or `cd code-examples-ruby` 1. Install the dependencies: `bundler install` 1. To configure the launcher for [JWT Grant](https://developers.docusign.com/platform/auth/jwt/) authentication, create a copy of the file config/appsettings.example.yml and save the copy as config/appsettings.yml. - 1. Add your API Username. On the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=apiIntegratorKey) page, under **My Account Information**, copy the **API Username** GUID and save it in appsettings.yml as your `impersonated_user_guid`. + 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 appsettings.yml as your `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 appsettings.yml as your `jwt_integration_key`. 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 config/docusign_private_key.txt. 1. Add the launcher’s redirect URI. Under **Additional settings**, select **+ ADD URI**, and set a redirect URI of http://localhost:3000/auth/docusign/callback. Select **SAVE**. From 50cec7d608868d935252ec8e4867c648a53fada9 Mon Sep 17 00:00:00 2001 From: Connor Lunsford Date: Tue, 25 Jan 2022 10:19:08 -0800 Subject: [PATCH 123/363] Updated favicon --- public/favicon.ico | Bin 0 -> 33310 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/public/favicon.ico b/public/favicon.ico index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fd990b6942f717e57af521d6c65eb20998282e55 100644 GIT binary patch literal 33310 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 RZ?k$1)N`Po1HQ_E{{uWiH2VMm literal 0 HcmV?d00001 From dbda8c432934a02518ead1575cb943790e655db0 Mon Sep 17 00:00:00 2001 From: Connor Lunsford Date: Tue, 25 Jan 2022 10:24:06 -0800 Subject: [PATCH 124/363] Updated favicon --- app/assets/images/favicon.ico | Bin 7406 -> 33310 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/app/assets/images/favicon.ico b/app/assets/images/favicon.ico index b3b2dc49c82e19f6982d4f17e033fb9aa26931ea..fd990b6942f717e57af521d6c65eb20998282e55 100644 GIT binary patch literal 33310 zcmeHQYit}>6+V9L%Wu0*9p_<_rYKYbwSQ1)DWoY0h(AdDKte)LXcN-LiIX^v^YW`n zleAT#gc1-czbJve5L8uD8mhXKN+3kjl(s2(l!t`GPnyJDdv|8d`F8j0%+6zXc6WAn zX1gmLoq61Q&i9>r=H5GZW^AGcYN4(!Vm(Cbnu)$fME(8g{V>ra9~&A3v18d{N{!GXeUNL`6ZAvTP4Gd38@#XMX-V7|bNIvZ})+GN9LQrkFp>G$^WxO9f= zuT0R!+g1AT&6J&nh6G*VZ5#uS%Q@;JZvUE1mB%*fHa4dG!NxydwfAk+22G7BL9EU> zIo8t5^_z;X9||f28%}&xsSNrF?rMm;lVtzHiirCh)2~YST#w!O7L_(}E`H&5h3>jd zlMT1VIpK&w^v7Q& zSeEGZQwjP5%WJ1pLO(nEq(ZOS2+pAl1ohr|p|I;!u*{v)`T#lRmcDv6L0|s7l5BtU zQEu6VohxknOLu7fCh`RRmK#1`XVV?#ws*q^Y=6cV~94dKv~pr+8#%CX|@{K&X1-Pn%I^a*MNI!IFUStbHW34oZ3(3 z%jXmxP0o!)*M)}?@l_H@8 zg+ppef~<8C;%&VI0}4U($FQxhliW_*gKhYLFCz|cKwas}%cbE1zP#oiF~k>9rLq_%biU;}tyCN)?$>yWZ_(w(kjuAVIIy)mZQ;bX zU^sZ6yYrYrd<%v{+)i#>2l_l0+vvk&TXbKKdF%l0QZQg{DE39K>{sdB^RcYs4aE2E zFDkTZxf#RZk>W8-Z_oA*`&e%PC&2^Vm|n9xe_AzRD0NOdHJrjQIH1z|FKOc@)*1za ze$5XUR;S}|z@@(Nha;!Rq>tgtR^Yv9Q8e&SPy6%|BvMPG45Gd%G4h_s#9C zzj9AO`_9(xL5Vbvzx>h#f3qIi+7=Q(sfGuDC z9pkz(fAN|IuYC9s6R+VGJiwL@KXO6Jdri+UwtV>g9)IMR*WxaCoaF!6-^Te_-U6MN zh|yyQ8o`875a}tCE4G>2FpWi6SkASxbFdm zzdTp@`=NaKT0dXD@%TTlD|G&)%HIRI(WaMQQTQ2roY!p>diO zmdtxXIAHwwjF)f5ntEL8eMUV8{G9_>f5G=y(YNuYBU?Ee^d=ax=B-_e#5Z09TA%{FcQF&4qq%lHH@u!94*fRocWAeKFy=Cv+aGxD1Tmut+) zDSzY|;_Ww{c6h<%3UhMGAJ-!C(axUVj)M#O7^nPEw$}KgO`Y;bu5@+OPWvPOaZNkr zkG`V2#`-_>=}!6MyX@O;xyJ8m&C}qD1%B6Tfd-bvXn9|puJ6UTxRe%*k9xs)qe*YK zjGLO4ajI0UALnGegVy|~a4qXq>60H{C}{k18YlTqT{Pw!dXagEUZWk{5dAzyZ(sZi zCZ}BL<@`NYueYE7+VA9al*YHrai8I>=iHUZr3ZJ<^ZOX7_eA#GGf#^id)8mh7|iU5 zX1;}$x%4Pv@Da#^iEYfCpF0U}y{`2<0CzoKtL-t)1B~6}%)e^bPPV)5@Az49mt%YH zt*sawx<7xr3wP0oK`rzL#cO*7&EWL zV2b|^gx!4Ji1{mb*?)r~Wxu*WTHfCW?C|s>{v+i3Ilto>ua{6Q7|M+Beav)#7w@b%e@<)%|xNZCv z$4LyT-3Lq#TlasX_oQ-Oc#F3BhDzcPXfZ#d!nLsb+tzvDmHTAlde+{}*4z;T{J$9C zYt&Z!Q3o*?{Z4iaymo*5(AYdRHznxceYyK0d@pC@E&I8?#lf{Oc5kZB#h8nI$tkbs zv%kszE;+7o;cL{vK>lw5{`72h`Z~8_j2t)emi-Wa-{h7bui61e;cL|RzRRn)-NJ?M zrHs5~KOD+`{kVmrT6S8)_H*C}pQ{$GO8IST%^t_3?V%ByO5v!MpN=+r{`kJITDU6Z zx2xU$-mWd;@3GBE47)q+`M2}6;lzfY%k*~H^T)N}XKqfg_w~%#j(;Bo{>ysp`FC>P z;3S5AE^~dKJ^${G+ULKr-=06N4L`T76YMvwy~1k%isd@Ms^zuc{!U_4FXO*=`RZ*} RZ?k$1)N`Po1HQ_E{{uWiH2VMm literal 7406 zcmeHKNo*WN6n&naeeLeq_nxt5F}AUZ!5P_(WyNIicx;vfIUpe<1cW<65IDdAB!sxY z5s3?8JHQno5Ni-i0$w0-!V*hhLx>_F42ZL=Ay{rc}$*L+pK z{snY_1J8qcD-N505de}@wqLOV&(qw{P{now`>ExLLm?mL3U&wrDI#jQD1mu4W&=FkiC8$qmTWBiD%EFf951+=eJS% zgyIVn|M@odzVItX?*AUs?{1)fb{VD5wlMw9MeKgy2TZ-Vj^c-#=r5h57@B|kB6i*N z9r}y3&KKLt-t>{40X+j(Bm>@Nq#NM129k9MSdFeo9b85((M1p(4ngh{TzNTC9=>j2 zKAK8Jl?guTvDrMzgwJFVMT^N-i4ffOpurHdyM@X`nloE0W-eV@F(f&iQmAHnt^Ro2 zZ&hq>EF6y2nO^xn)!WMW-zHhsS&7;tHCdk-jOC8~R&=)b{sw8~4(6y;^-$K%;d@s| zUl&k#cnuTJoX5b;%ji3B0@vN~Ez@6Fd*>E+aNvzUnMRI1aTdi7HksyLd+RBtv$FQi ze6)#yo0c(r&l&P>AbZ0+4!(H-g(Is>m&YDIi@yC|F|8lC zHUo7cdX<$K131zn`q3Tv4DDIX7fs454;bml85w7uX3L#@E<>)E9dmO2h zG1N%#@jM?-SY(1F5hugflm$8j9?>oP-J*w#Cbw)Fs(wQYXD9qp%uR?%D(iRIy8VQ1 zTUYDnC)4GVnpSbsVP#NtUk!))%XMWua-Bj~MBGWOR;Sp=sG?G*$Tdpgp;cC=Ouf90 zJx`y*!M848^0{Bw{jYcLm$-)7;BBXoA74b_!BtGXv|g)KhHn1`<4^v~YL$Jj|H1B$ z`H3a;Qk$i_WZ}pf@?(n_zHbGikN(K+jpI+9WA)11!Vard1`mCW{GKJ`M~QcM1^Zt6 z9fOBXvwCIb=w@}tdaq|d&p?MWAnE9M21JdhJlK-g2#Xvbnj-d;CfFk;QIe3c=3<(V zvt>XJuyAIL;Mj)fvu@CYq(R>Q{{dpqXbe*BG(rr<{r-T(jq From 6aeb643119f647e73bff2087406f664a792d1246 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Sat, 19 Feb 2022 01:22:24 +0200 Subject: [PATCH 125/363] Feature/code examples refactoring (#50) * esign examples refactored * updated eg011 * click refactored * rooms refactored * monitor refactored * admin examples refactored * refactored esign examples & updated scopes * added methods to parent controllers * added initialize method * fixed worker call * fixed error handling * removed return statement --- .../admin_api/eg001_create_user_controller.rb | 44 ++- ...create_active_clm_esign_user_controller.rb | 36 +- .../eg003_bulk_export_user_data_controller.rb | 30 +- .../admin_api/eg004_import_user_controller.rb | 26 +- .../admin_api/eg005_audit_users_controller.rb | 27 +- .../eg001_create_clickwrap_controller.rb | 20 +- .../eg002_activate_clickwrap_controller.rb | 20 +- ...create_new_clickwrap_version_controller.rb | 21 +- .../eg004_list_clickwraps_controller.rb | 19 +- .../eg005_clickwrap_responses_controller.rb | 21 +- .../eg002_signing_via_email_controller.rb | 47 +-- .../e_sign/eg003_list_envelopes_controller.rb | 26 +- .../e_sign/eg004_envelope_info_controller.rb | 27 +- .../eg005_envelope_recipients_controller.rb | 32 +- .../e_sign/eg006_envelope_docs_controller.rb | 47 ++- .../eg007_envelope_get_doc_controller.rb | 30 +- .../eg008_create_template_controller.rb | 45 +-- .../e_sign/eg009_use_template_controller.rb | 36 +- .../eg010_send_binary_docs_controller.rb | 58 +-- .../eg011_embedded_sending_controller.rb | 46 +-- .../eg012_embedded_console_controller.rb | 36 +- .../eg013_add_doc_to_template_controller.rb | 39 +- .../eg014_collect_payment_controller.rb | 50 +-- .../eg015_get_envelope_tab_data_controller.rb | 30 +- .../eg016_set_envelope_tab_data_controller.rb | 28 +- ...g017_set_template_tab_values_controller.rb | 31 +- ...t_envelope_custom_field_data_controller.rb | 30 +- ...9_access_code_authentication_controller.rb | 47 ++- .../eg020_phone_authentication_controller.rb | 64 ++-- .../eg022_kba_authentication_controller.rb | 44 ++- .../eg023_idv_authentication_controller.rb | 56 +-- .../eg024_permission_create_controller.rb | 43 +-- ...5_permissions_set_user_group_controller.rb | 49 +-- ...ssions_change_single_setting_controller.rb | 50 +-- .../eg027_permissions_delete_controller.rb | 49 +-- .../eg028_brands_creating_controller.rb | 46 ++- ...029_brands_apply_to_envelope_controller.rb | 59 ++- ...030_brands_apply_to_template_controller.rb | 64 ++-- ...eg031_bulk_sending_envelopes_controller.rb | 55 +-- ...32_pauses_signature_workflow_controller.rb | 28 +- ..._unpauses_signature_workflow_controller.rb | 23 +- ...4_use_conditional_recipients_controller.rb | 32 +- .../e_sign/eg035_sms_delivery_controller.rb | 56 +-- .../eg001_embedded_signing_controller.rb | 13 +- app/controllers/eg_controller.rb | 22 ++ ...eg001_get_monitoring_dataset_controller.rb | 21 +- .../eg001_create_room_with_data_controller.rb | 24 +- ...02_create_room_with_template_controller.rb | 25 +- .../eg003_export_data_from_room_controller.rb | 22 +- .../eg004_add_forms_to_room_controller.rb | 23 +- ...eg005_get_rooms_with_filters_controller.rb | 23 +- ...n_external_form_fill_session_controller.rb | 23 +- .../eg007_create_form_group_controller.rb | 21 +- ..._office_access_to_form_group_controller.rb | 22 +- ...09_assign_form_to_form_group_controller.rb | 22 +- .../admin_api/eg001_create_user_service.rb | 53 +-- ...02_create_active_clm_esign_user_service.rb | 103 ++--- .../eg003_bulk_export_user_data_service.rb | 71 ++-- .../admin_api/eg004_import_user_service.rb | 20 +- .../admin_api/eg005_audit_users_service.rb | 79 ++-- .../eg001_create_clickwrap_service.rb | 11 +- .../eg002_activate_clickwrap_service.rb | 11 +- ...03_create_new_clickwrap_version_service.rb | 14 +- .../eg004_list_clickwraps_service.rb | 10 +- .../eg005_clickwrap_responses_service.rb | 12 +- .../e_sign/eg002_signing_via_email_service.rb | 36 +- .../e_sign/eg003_list_envelopes_service.rb | 12 +- .../e_sign/eg004_envelope_info_service.rb | 13 +- .../eg005_envelope_recipients_service.rb | 15 + .../e_sign/eg006_envelope_docs_service.rb | 39 +- .../e_sign/eg007_envelope_get_doc_service.rb | 24 +- .../e_sign/eg008_create_template_service.rb | 23 +- .../e_sign/eg009_use_template_service.rb | 25 +- .../e_sign/eg010_send_binary_docs_service.rb | 38 +- .../e_sign/eg011_embedded_sending_service.rb | 173 +++++++-- .../e_sign/eg012_embedded_console_service.rb | 22 +- .../eg013_add_doc_to_template_service.rb | 38 +- .../e_sign/eg014_collect_payment_service.rb | 32 +- .../eg015_get_envelope_tab_data_service.rb | 19 +- .../eg016_set_envelope_tab_data_service.rb | 38 +- .../eg017_set_template_tab_values_service.rb | 31 +- ..._get_envelope_custom_field_data_service.rb | 13 +- ...g019_access_code_authentication_service.rb | 25 +- .../eg020_phone_authentication_service.rb | 45 +-- .../eg022_kba_authentication_service.rb | 23 +- .../eg023_idv_authentication_service.rb | 28 +- .../e_sign/eg024_permission_create_service.rb | 15 +- ...g025_permissions_set_user_group_service.rb | 17 +- ...rmissions_change_single_setting_service.rb | 15 +- .../eg027_permissions_delete_service.rb | 16 +- .../e_sign/eg028_brands_creating_service.rb | 18 +- .../eg029_brands_apply_to_envelope_service.rb | 28 +- .../eg030_brands_apply_to_template_service.rb | 32 +- .../eg031_bulk_sending_envelopes_service.rb | 33 +- ...eg032_pauses_signature_workflow_service.rb | 22 +- ...033_unpauses_signature_workflow_service.rb | 16 +- ...g034_use_conditional_recipients_service.rb | 24 +- .../e_sign/eg035_sms_delivery_service.rb | 362 +++++++++--------- .../eg001_embedded_signing_service.rb | 38 +- app/services/jwt_auth/jwt_creator.rb | 36 +- .../eg001_get_monitoring_dataset_service.rb | 14 +- .../eg001_create_room_with_data_service.rb | 23 +- ...eg002_create_room_with_template_service.rb | 24 +- .../eg003_export_data_from_room_service.rb | 17 +- .../eg004_add_forms_to_room_service.rb | 22 +- .../eg005_get_rooms_with_filters_service.rb | 18 +- ...e_an_external_form_fill_session_service.rb | 22 +- .../eg007_create_form_group_service.rb | 20 +- ...ant_office_access_to_form_group_service.rb | 15 +- ...eg009_assign_form_to_form_group_service.rb | 21 +- 110 files changed, 1669 insertions(+), 2223 deletions(-) create mode 100644 app/services/e_sign/eg005_envelope_recipients_service.rb diff --git a/app/controllers/admin_api/eg001_create_user_controller.rb b/app/controllers/admin_api/eg001_create_user_controller.rb index 9c8d311..db516b1 100644 --- a/app/controllers/admin_api/eg001_create_user_controller.rb +++ b/app/controllers/admin_api/eg001_create_user_controller.rb @@ -4,7 +4,34 @@ class AdminApi::Eg001CreateUserController < EgController def create begin - results = AdminApi::Eg001CreateUserService.new(session, request).call + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + organization_id: session['organization_id'] + } + user_data = { + user_name: param_gsub(params['user_name']), + first_name: param_gsub(params['first_name']), + last_name: param_gsub(params['last_name']), + email: param_gsub(params['email']), + auto_activate_memberships: true, + accounts: [ + { + id: args[:account_id], + permission_profile: { + id: request['permission_profile_id'] + }, + groups: [ + { + id: request['group_id'] + } + ] + } + ] + } + + results = AdminApi::Eg001CreateUserService.new(args, user_data).worker @title = 'Create a new active eSignature user' @h1 = 'Create a new active eSignature user' @@ -12,10 +39,7 @@ def create @json = results.to_json.to_json render 'ds_common/example_done' rescue DocuSign_Admin::ApiError => e - error = JSON.parse e.response_body - @error_code = e.code - @error_message = error['error_description'] - render 'ds_common/error' + handle_error(e) end end @@ -37,14 +61,4 @@ def get @groups = groups_api.list_groups(args[:account_id]).groups end - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb b/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb index ff0c31c..3dcc509 100644 --- a/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb +++ b/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb @@ -3,7 +3,23 @@ class AdminApi::Eg002CreateActiveClmEsignUserController < EgController def create begin - results = AdminApi::Eg002CreateActiveClmEsignUserService.new(session, request).call + args = { + user_name: params[:user_name], + first_name: params[:first_name], + last_name: params[:last_name], + email: params[:email], + clm_permission_profile_id: params[:clm_permission_profile_id], + esign_permission_profile_id: params[:esign_permission_profile_id], + clm_product_id: params[:clm_product_id], + esign_product_id: params[:esign_product_id], + ds_group_id: params[:ds_group_id], + account_id: session[:ds_account_id], + organization_id: session['organization_id'], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } + + results = AdminApi::Eg002CreateActiveClmEsignUserService.new(args).worker @title = "Create a new active user for CLM and eSignature" @h1 = "Create a new active user for CLM and eSignature" @@ -12,10 +28,7 @@ def create render 'ds_common/example_done' rescue DocuSign_Admin::ApiError => e - error = JSON.parse e.response_body - @error_code = e.code - @error_message = error['error_description'] - render 'ds_common/error' + handle_error(e) end end @@ -37,17 +50,4 @@ def get end @ds_groups = AdminApi::GetDataService.new(session).get_ds_groups end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb b/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb index aec7426..e67b553 100644 --- a/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb +++ b/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb @@ -9,7 +9,19 @@ def create file_path = File.expand_path(File.join(File.dirname(__FILE__), '../../../data/exportedUserData.csv')) begin - results = AdminApi::Eg003BulkExportUserDataService.new(session, request, file_path).call + request_body = { + type: 'organization_memberships_export' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + organization_id: session['organization_id'], + file_path: file_path, + request_body: request_body + } + + results = AdminApi::Eg003BulkExportUserDataService.new(args).worker @title = 'Bulk-export user data' @h1 = 'Bulk-export user data' @@ -17,21 +29,7 @@ def create @json = results.to_json.to_json render 'ds_common/example_done' rescue DocuSign_Admin::ApiError => e - error = JSON.parse e.response_body - @error_code = e.code - @error_message = error['error_description'] - render 'ds_common/error' - end - end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - redirect_to '/ds/mustAuthenticate' + handle_error(e) end end end diff --git a/app/controllers/admin_api/eg004_import_user_controller.rb b/app/controllers/admin_api/eg004_import_user_controller.rb index 8f422a7..12598df 100644 --- a/app/controllers/admin_api/eg004_import_user_controller.rb +++ b/app/controllers/admin_api/eg004_import_user_controller.rb @@ -9,7 +9,15 @@ def create file_path = File.expand_path(File.join(File.dirname(__FILE__), '../../../data/userData.csv')) begin - results = AdminApi::Eg004ImportUserService.new(session, request, file_path).call + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + organization_id: session['organization_id'], + csv_file_path: file_path + } + + results = AdminApi::Eg004ImportUserService.new(args).worker session[:import_id] = results.id @title = 'Add users via bulk import' @@ -19,10 +27,7 @@ def create @json = results.to_json.to_json render 'ds_common/example_done' rescue DocuSign_Admin::ApiError => e - error = JSON.parse e.response_body - @error_code = e.code - @error_message = error['error_description'] - render 'ds_common/error' + handle_error(e) end end @@ -48,15 +53,4 @@ def check_status render 'ds_common/error' end end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/admin_api/eg005_audit_users_controller.rb b/app/controllers/admin_api/eg005_audit_users_controller.rb index cd4fb50..e9de6bf 100644 --- a/app/controllers/admin_api/eg005_audit_users_controller.rb +++ b/app/controllers/admin_api/eg005_audit_users_controller.rb @@ -7,7 +7,14 @@ def create end begin - results = AdminApi::Eg005AuditUsersService.new(session, request).call + args = { + account_id: session[:ds_account_id], + organization_id: session['organization_id'], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } + + results = AdminApi::Eg005AuditUsersService.new(args).worker @title = "Audit users" @h1 = "Audit users" @@ -16,23 +23,7 @@ def create render 'ds_common/example_done' rescue DocuSign_Admin::ApiError => e - error = JSON.parse e.response_body - @error_code = e.code - @error_message = error['error_description'] - render 'ds_common/error' - end - end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' + handle_error(e) end end end diff --git a/app/controllers/clickwrap/eg001_create_clickwrap_controller.rb b/app/controllers/clickwrap/eg001_create_clickwrap_controller.rb index 454396e..7d6a345 100644 --- a/app/controllers/clickwrap/eg001_create_clickwrap_controller.rb +++ b/app/controllers/clickwrap/eg001_create_clickwrap_controller.rb @@ -2,7 +2,14 @@ class Clickwrap::Eg001CreateClickwrapController < EgController before_action :check_auth def create - results = Clickwrap::Eg001CreateClickwrapService.new(session, request).call + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + clickwrap_name: request[:clickwrapName] + } + + results = Clickwrap::Eg001CreateClickwrapService.new(args).worker session[:clickwrap_id] = results.clickwrap_id session[:clickwrap_name] = results.clickwrap_name @@ -13,15 +20,4 @@ def create @json = results.to_json.to_json render 'ds_common/example_done' end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb b/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb index 239733f..89eae47 100644 --- a/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb +++ b/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb @@ -2,22 +2,18 @@ class Clickwrap::Eg002ActivateClickwrapController < EgController before_action :check_auth def create - results = Clickwrap::Eg002ActivateClickwrapService.new(session).call + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + clickwrap_id: session[:clickwrap_id] + } + + results = Clickwrap::Eg002ActivateClickwrapService.new(args).worker @title = 'Activating a new clickwrap' @h1 = 'Activating a new clickwrap' @message = "The clickwrap #{results.clickwrap_name} has been activated" render 'ds_common/example_done' end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/clickwrap/eg003_create_new_clickwrap_version_controller.rb b/app/controllers/clickwrap/eg003_create_new_clickwrap_version_controller.rb index 456078b..32e431b 100644 --- a/app/controllers/clickwrap/eg003_create_new_clickwrap_version_controller.rb +++ b/app/controllers/clickwrap/eg003_create_new_clickwrap_version_controller.rb @@ -2,22 +2,19 @@ class Clickwrap::Eg003CreateNewClickwrapVersionController < EgController before_action :check_auth def create - results = Clickwrap::Eg003CreateNewClickwrapVersionService.new(session).call + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + clickwrap_id: session[:clickwrap_id], + clickwrap_name: session[:clickwrap_name] + } + + results = Clickwrap::Eg003CreateNewClickwrapVersionService.new(args).worker puts results.to_json.to_json @title = 'Creating a new clickwrap version' @h1 = 'Creating a new clickwrap version' @message = "Version #{results.version_number} of clickwrap #{results.clickwrap_name} has been created" render 'ds_common/example_done' end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/clickwrap/eg004_list_clickwraps_controller.rb b/app/controllers/clickwrap/eg004_list_clickwraps_controller.rb index d345013..e942a22 100644 --- a/app/controllers/clickwrap/eg004_list_clickwraps_controller.rb +++ b/app/controllers/clickwrap/eg004_list_clickwraps_controller.rb @@ -2,7 +2,13 @@ class Clickwrap::Eg004ListClickwrapsController < EgController before_action :check_auth def create - results = Clickwrap::Eg004ListClickwrapsService.new(session, request).call + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } + + results = Clickwrap::Eg004ListClickwrapsService.new(args).worker @title = 'List clickwraps results' @h1 = 'List clickwraps results' @@ -10,15 +16,4 @@ def create @json = results.to_json.to_json render 'ds_common/example_done' end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/clickwrap/eg005_clickwrap_responses_controller.rb b/app/controllers/clickwrap/eg005_clickwrap_responses_controller.rb index c639807..3ab04bf 100644 --- a/app/controllers/clickwrap/eg005_clickwrap_responses_controller.rb +++ b/app/controllers/clickwrap/eg005_clickwrap_responses_controller.rb @@ -2,7 +2,15 @@ class Clickwrap::Eg005ClickwrapResponsesController < EgController before_action :check_auth def create - results = Clickwrap::Eg005ClickwrapResponsesService.new(session, request).call + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + clickwrap_id: session[:clickwrap_id], + client_user_id: request[:client_user_id] + } + + results = Clickwrap::Eg005ClickwrapResponsesService.new(args).worker @title = 'Getting clickwrap responses' @h1 = 'Getting clickwrap responses' @@ -10,15 +18,4 @@ def create @json = results.to_json.to_json render 'ds_common/example_done' end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/e_sign/eg002_signing_via_email_controller.rb b/app/controllers/e_sign/eg002_signing_via_email_controller.rb index 09d215f..6f4b1c4 100644 --- a/app/controllers/e_sign/eg002_signing_via_email_controller.rb +++ b/app/controllers/e_sign/eg002_signing_via_email_controller.rb @@ -1,30 +1,31 @@ # frozen_string_literal: true class ESign::Eg002SigningViaEmailController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 - if check_token(minimum_buffer_min) - begin - results = ESign::Eg002SigningViaEmailService.new(session, request, 'sent').call - session[:envelope_id] = results['envelope_id'] - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The envelope has been created and sent!
Envelope ID #{results['envelope_id']}." - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation - # so it could be restarted automatically. - # But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after - # authentication. - redirect_to '/' + begin + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + cc_email: param_gsub(params['ccEmail']), + cc_name: param_gsub(params['ccName']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + results = ESign::Eg002SigningViaEmailService.new(args).worker + session[:envelope_id] = results['envelope_id'] + @title = 'Envelope sent' + @h1 = 'Envelope sent' + @message = "The envelope has been created and sent!
Envelope ID #{results['envelope_id']}." + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end end diff --git a/app/controllers/e_sign/eg003_list_envelopes_controller.rb b/app/controllers/e_sign/eg003_list_envelopes_controller.rb index 235c808..06822b1 100644 --- a/app/controllers/e_sign/eg003_list_envelopes_controller.rb +++ b/app/controllers/e_sign/eg003_list_envelopes_controller.rb @@ -1,20 +1,18 @@ # frozen_string_literal: true class ESign::Eg003ListEnvelopesController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 - token_ok = check_token(minimum_buffer_min) - if token_ok - results = ESign::Eg003ListEnvelopesService.new(session).call - @h1 = 'List envelopes results' - @message = 'Results from the Envelopes::listStatusChanges method:' - @json = results.to_json.to_json - render 'ds_common/example_done' - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically. - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication. - redirect_to '/ds/mustAuthenticate' - end + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } + results = ESign::Eg003ListEnvelopesService.new(args).worker + @h1 = 'List envelopes results' + @message = 'Results from the Envelopes::listStatusChanges method:' + @json = results.to_json.to_json + render 'ds_common/example_done' end end diff --git a/app/controllers/e_sign/eg004_envelope_info_controller.rb b/app/controllers/e_sign/eg004_envelope_info_controller.rb index f598872..3a211a1 100644 --- a/app/controllers/e_sign/eg004_envelope_info_controller.rb +++ b/app/controllers/e_sign/eg004_envelope_info_controller.rb @@ -1,14 +1,20 @@ # frozen_string_literal: true class ESign::Eg004EnvelopeInfoController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 envelope_id = session[:envelope_id] - token_ok = check_token(minimum_buffer_min) - if token_ok && envelope_id + if envelope_id begin - results = ESign::Eg004EnvelopeInfoService.new(session, envelope_id).call + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_id: envelope_id + } + results = ESign::Eg004EnvelopeInfoService.new(args).worker # results is an object that implements ArrayAccess. Convert to a regular array: @title = 'Envelope status results' @h1 = 'Envelope status results' @@ -16,19 +22,8 @@ def create @json = results.to_json.to_json render 'ds_common/example_done' rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' + handle_error(e) end - elsif !token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation - # so it could be restarted automatically. - # But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after - # authentication. - redirect_to '/ds/mustAuthenticate' elsif !envelope_id @title = 'Envelope information' @envelope_ok = false diff --git a/app/controllers/e_sign/eg005_envelope_recipients_controller.rb b/app/controllers/e_sign/eg005_envelope_recipients_controller.rb index 2737183..e153a8a 100644 --- a/app/controllers/e_sign/eg005_envelope_recipients_controller.rb +++ b/app/controllers/e_sign/eg005_envelope_recipients_controller.rb @@ -2,14 +2,13 @@ class ESign::Eg005EnvelopeRecipientsController < EgController include ApiCreator + before_action :check_auth skip_before_action :set_meta - + def create - minimum_buffer_min = 3 envelope_id = session[:envelope_id] || nil - token_ok = check_token(minimum_buffer_min) - if token_ok && envelope_id + if envelope_id # 2. Call the worker method args = { account_id: session['ds_account_id'], @@ -19,39 +18,18 @@ def create } begin - results = worker args + results = ESign::Eg005EnvelopeRecipientsService.new(args).worker @title = 'Envelope recipients results' @h1 = 'List the envelope\'s recipients and their status' @message = 'Results from the EnvelopesRecipients::list method:' @json = results.to_json.to_json render 'ds_common/example_done' rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' + handle_error(e) end - elsif !token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation - # so it could be restarted automatically. - # But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after - # authentication. - redirect_to '/ds/mustAuthenticate' elsif !envelope_id @title = 'Envelope recipient information' @envelope_ok = false end end - - # ***DS.snippet.0.start - def worker(args) - # Step 1. List envelope recipients - # Exceptions will be caught by the calling function - envelope_api = create_envelope_api(args) - results = envelope_api.list_recipients args[:account_id], args[:envelope_id] - results - end - # ***DS.snippet.0.end end diff --git a/app/controllers/e_sign/eg006_envelope_docs_controller.rb b/app/controllers/e_sign/eg006_envelope_docs_controller.rb index c2869f1..0a3e883 100644 --- a/app/controllers/e_sign/eg006_envelope_docs_controller.rb +++ b/app/controllers/e_sign/eg006_envelope_docs_controller.rb @@ -1,14 +1,40 @@ # frozen_string_literal: true class ESign::Eg006EnvelopeDocsController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 envelope_id = session[:envelope_id] - token_ok = check_token(minimum_buffer_min) - if token_ok && envelope_id + if envelope_id begin - results = ESign::Eg006EnvelopeDocsService.new(request, session, envelope_id).call + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_id: envelope_id + } + + standart_doc_items = [ + { name: 'Combined', type: 'content', document_id: 'combined' }, + { name: 'Zip archive', type: 'zip', document_id: 'archive' } + ] + + results = ESign::Eg006EnvelopeDocsService.new(args).worker + # The certificate of completion is named "summary" + # We give it a better name below. + envelope_doc_items = results.envelope_documents.map do |doc| + if doc.document_id == 'certificate' + new = { document_id: doc.document_id, name: 'Certificate of completion', type: doc.type } + else + new = { document_id: doc.document_id, name: doc.name, type: doc.type } + end + new + end + + documents = standart_doc_items + envelope_doc_items + envelope_documents = { envelope_id: args[:envelope_id], documents: documents } + session[:envelope_documents] = envelope_documents @title = 'Envelope documents list' @h1 = 'List the envelope\'s documents' @@ -16,19 +42,8 @@ def create @json = results.to_json.to_json render 'ds_common/example_done' rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' + handle_error(e) end - elsif !token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation - # so it could be restarted automatically. - # But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after - # authentication. - redirect_to '/ds/mustAuthenticate' elsif !envelope_id @title = 'Envelope recipient information' @envelope_ok = false diff --git a/app/controllers/e_sign/eg007_envelope_get_doc_controller.rb b/app/controllers/e_sign/eg007_envelope_get_doc_controller.rb index d66b235..a72dff6 100644 --- a/app/controllers/e_sign/eg007_envelope_get_doc_controller.rb +++ b/app/controllers/e_sign/eg007_envelope_get_doc_controller.rb @@ -1,31 +1,29 @@ # frozen_string_literal: true class ESign::Eg007EnvelopeGetDocController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 envelope_id = session[:envelope_id] envelope_documents = session[:envelope_documents] - token_ok = check_token(minimum_buffer_min) - if token_ok && envelope_id && envelope_documents + if envelope_id && envelope_documents begin - results = ESign::Eg007EnvelopeGetDocService.new(request, session, envelope_id, envelope_documents).call + document_id = param_gsub(params['docSelect']) + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_id: envelope_id, + document_id: document_id, + envelope_documents: envelope_documents + } + results = ESign::Eg007EnvelopeGetDocService.new(args).worker send_data results['data'], filename: results['doc_name'], content_type: results['mime_type'], disposition: "attachment; filename=\"#{results['doc_name']}\"" rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' + handle_error(e) end - elsif !token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation - # so it could be restarted automatically. - # But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after - # authentication. - redirect_to '/ds/mustAuthenticate' elsif !envelope_id || !envelope_documents @title = 'Download an envelope\'s document' @envelope_ok = false diff --git a/app/controllers/e_sign/eg008_create_template_controller.rb b/app/controllers/e_sign/eg008_create_template_controller.rb index e2962b9..e991f1b 100644 --- a/app/controllers/e_sign/eg008_create_template_controller.rb +++ b/app/controllers/e_sign/eg008_create_template_controller.rb @@ -1,29 +1,30 @@ # frozen_string_literal: true class ESign::Eg008CreateTemplateController < EgController - def create - minimum_buffer_min = 3 - token_ok = check_token(minimum_buffer_min) + before_action :check_auth - if token_ok - begin - results = ESign::Eg008CreateTemplateService.new(session).call - msg = if results.fetch(:created_new_template) - 'The template has been created!' - else - 'Done. The template already existed in your account.' - end - @title = 'Template results' - @h1 = 'Template results' - @message = "#{msg}
Template name: #{results[:template_name]}, - ID #{results[:template_id]}." - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end + def create + begin + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + template_name: 'Example Signer and CC template' + } + results = ESign::Eg008CreateTemplateService.new(args).worker + session[:template_id] = results[:template_id] + msg = if results.fetch(:created_new_template) + 'The template has been created!' + else + 'Done. The template already existed in your account.' + end + @title = 'Template results' + @h1 = 'Template results' + @message = "#{msg}
Template name: #{results[:template_name]}, + ID #{results[:template_id]}." + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end end diff --git a/app/controllers/e_sign/eg009_use_template_controller.rb b/app/controllers/e_sign/eg009_use_template_controller.rb index 89be3c5..1c3729d 100644 --- a/app/controllers/e_sign/eg009_use_template_controller.rb +++ b/app/controllers/e_sign/eg009_use_template_controller.rb @@ -1,33 +1,37 @@ # frozen_string_literal: true class ESign::Eg009UseTemplateController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 template_id = session[:template_id] - token_ok = check_token(minimum_buffer_min) - if token_ok && template_id + if template_id begin - results = ESign::Eg009UseTemplateService.new(request, session, template_id).call + envelope_args = { + signer_email: params['signerEmail'], + signer_name: params['signerName'], + cc_email: params['ccEmail'], + cc_name: params['ccName'], + template_id: template_id + } + + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + + results = ESign::Eg009UseTemplateService.new(args).worker # results is an object that implements ArrayAccess. Convert to a regular array: @title = 'Envelope sent' @h1 = 'Envelope sent' @message = "The envelope has been created and sent!
Envelope ID #{results[:envelope_id]}." render 'ds_common/example_done' rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' + handle_error(e) end - elsif !token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation - # so it could be restarted automatically. - # But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after - # authentication. - redirect_to '/ds/mustAuthenticate' elsif !template_id @title = 'Use a template to send an envelope' @template_ok = false diff --git a/app/controllers/e_sign/eg010_send_binary_docs_controller.rb b/app/controllers/e_sign/eg010_send_binary_docs_controller.rb index e9a70bf..18992f9 100644 --- a/app/controllers/e_sign/eg010_send_binary_docs_controller.rb +++ b/app/controllers/e_sign/eg010_send_binary_docs_controller.rb @@ -1,32 +1,38 @@ class ESign::Eg010SendBinaryDocsController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 - if check_token minimum_buffer_min - begin - results = ESign::Eg010SendBinaryDocsService.new(request, session).call - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The envelope has been created and sent!
Envelope ID #{results['envelope_id']}." - render 'ds_common/example_done' - rescue Net::HTTPError => e - if !e.response.nil? - json_response = JSON.parse e.response - @error_code = json_response['errorCode'] - @error_message = json_response['message'] - else - @error_code = 'API request problem' - @error_message = e.to_s - end + begin + envelope_args = { + # Validation: Delete any non-usual characters + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + cc_email: param_gsub(params['ccEmail']), + cc_name: param_gsub(params['ccName']) + } + + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + + results = ESign::Eg010SendBinaryDocsService.new(args).worker + session[:envelope_id] = results['envelope_id'] + @title = 'Envelope sent' + @h1 = 'Envelope sent' + @message = "The envelope has been created and sent!
Envelope ID #{results['envelope_id']}." + render 'ds_common/example_done' + rescue Net::HTTPError => e + if !e.response.nil? + json_response = JSON.parse e.response + @error_code = json_response['errorCode'] + @error_message = json_response['message'] + else + @error_code = 'API request problem' + @error_message = e.to_s end - else - flash[:message] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation - # so it could be restarted automatically. - # But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after - # authentication. - session['eg'] = eg_name - redirect_to '/ds/mustAuthenticate' end end end diff --git a/app/controllers/e_sign/eg011_embedded_sending_controller.rb b/app/controllers/e_sign/eg011_embedded_sending_controller.rb index 2dce77c..8fc7d39 100644 --- a/app/controllers/e_sign/eg011_embedded_sending_controller.rb +++ b/app/controllers/e_sign/eg011_embedded_sending_controller.rb @@ -1,31 +1,31 @@ # frozen_string_literal: true class ESign::Eg011EmbeddedSendingController < EgController + before_action :check_auth + def create - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) + begin + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + cc_email: param_gsub(params['ccEmail']), + cc_name: param_gsub(params['ccName']), + status: 'created' + } + + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + starting_view: param_gsub(params['starting_view']), + envelope_args: envelope_args, + ds_return_url: "#{Rails.application.config.app_url}/ds_common-return" + } - if token_ok - begin - results = ESign::Eg011EmbeddedSendingService.new(request, session).call - redirect_to results['redirect_url'] - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end - elsif !token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation - # so it could be restarted automatically. - # But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after - # authentication. - redirect_to '/ds/mustAuthenticate' - elsif !template_id - @title = 'Use a template to send an envelope' - @template_ok = false + results = ESign::Eg011EmbeddedSendingService.new(args).worker + redirect_to results['redirect_url'] + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end end diff --git a/app/controllers/e_sign/eg012_embedded_console_controller.rb b/app/controllers/e_sign/eg012_embedded_console_controller.rb index cc9ac72..5eae80b 100644 --- a/app/controllers/e_sign/eg012_embedded_console_controller.rb +++ b/app/controllers/e_sign/eg012_embedded_console_controller.rb @@ -1,29 +1,25 @@ # frozen_string_literal: true class ESign::Eg012EmbeddedConsoleController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 envelope_id = session[:envelope_id] - token_ok = check_token(minimum_buffer_min) - if token_ok - begin - results = ESign::Eg012EmbeddedConsoleService.new(session, envelope_id, request).call - redirect_to results['redirect_url'] - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation - # so it could be restarted automatically. - # But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after - # authentication. - redirect_to '/ds/mustAuthenticate' + begin + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_id: envelope_id, + starting_view: params['starting_view'], + ds_return_url: "#{Rails.application.config.app_url}/ds_common-return" + } + + results = ESign::Eg012EmbeddedConsoleService.new(args).worker + redirect_to results['redirect_url'] + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end end diff --git a/app/controllers/e_sign/eg013_add_doc_to_template_controller.rb b/app/controllers/e_sign/eg013_add_doc_to_template_controller.rb index 5816582..9ca509f 100644 --- a/app/controllers/e_sign/eg013_add_doc_to_template_controller.rb +++ b/app/controllers/e_sign/eg013_add_doc_to_template_controller.rb @@ -1,18 +1,37 @@ # frozen_string_literal: true class ESign::Eg013AddDocToTemplateController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 template_id = session[:template_id] - token_ok = check_token(minimum_buffer_min) - if token_ok && template_id + if template_id # 2. Call the worker method # More data validation would be a good idea here # Strip anything other than characters listed begin - results = ESign::Eg013AddDocToTemplateService.new(request, session, template_id).call + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + cc_email: param_gsub(params['ccEmail']), + cc_name: param_gsub(params['ccName']), + item: param_gsub(params['item']), + quantity: param_gsub(params['quantity']).to_i, + signer_client_id: 1000, + template_id: template_id, + ds_return_url: "#{Rails.application.config.app_url}/ds_common-return" + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + results = ESign::Eg013AddDocToTemplateService.new(args).worker + # Save for use by other examples # which need an envelopeId + session[:envelope_id] = results[:envelope_id] # Redirect the user to the embedded signing # Don't use an iFrame! # State can be stored/recovered using the framework's session or a @@ -24,17 +43,9 @@ def create @error_message = error['message'] render 'ds_common/error' end - elsif !token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation - # so it could be restarted automatically. - # But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after - # authentication. - redirect_to '/ds/mustAuthenticate' elsif !template_id - @title = 'Use embedded signing from template and extra doc', - @template_ok = false + @title = 'Use embedded signing from template and extra doc' + @template_ok = false end end end diff --git a/app/controllers/e_sign/eg014_collect_payment_controller.rb b/app/controllers/e_sign/eg014_collect_payment_controller.rb index 154e9f2..fb16815 100644 --- a/app/controllers/e_sign/eg014_collect_payment_controller.rb +++ b/app/controllers/e_sign/eg014_collect_payment_controller.rb @@ -1,32 +1,34 @@ # frozen_string_literal: true class ESign::Eg014CollectPaymentController < EgController + before_action :check_auth + def create - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) + begin + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + cc_email: param_gsub(params['ccEmail']), + cc_name: param_gsub(params['ccName']), + gateway_account_id: Rails.application.config.gateway_account_id, + gateway_name: Rails.application.config.gateway_name, + gateway_display_name: Rails.application.config.gateway_display_name + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } - if token_ok - begin - results = ESign::Eg014CollectPaymentService.new(request, session).call - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The order form envelope has been created and sent!
- Envelope ID #{results[:envelope_id]}" - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation - # so it could be restarted automatically. - # But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after - # authentication. - redirect_to '/ds/mustAuthenticate' + results = ESign::Eg014CollectPaymentService.new(args).worker + @title = 'Envelope sent' + @h1 = 'Envelope sent' + @message = "The order form envelope has been created and sent!
+ Envelope ID #{results[:envelope_id]}" + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end end diff --git a/app/controllers/e_sign/eg015_get_envelope_tab_data_controller.rb b/app/controllers/e_sign/eg015_get_envelope_tab_data_controller.rb index 20f7d24..a3076ef 100644 --- a/app/controllers/e_sign/eg015_get_envelope_tab_data_controller.rb +++ b/app/controllers/e_sign/eg015_get_envelope_tab_data_controller.rb @@ -1,22 +1,22 @@ # frozen_string_literal: true class ESign::Eg015GetEnvelopeTabDataController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 envelope_id = session[:envelope_id] - token_ok = check_token(minimum_buffer_min) - if token_ok - results = ESign::Eg015GetEnvelopeTabDataService.new(envelope_id, session).call - @h1 = 'List envelopes results' - @message = 'Results from the EnvelopeFormData::get method:' - @json = results.to_json.to_json - render 'ds_common/example_done' - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end + + args = { + access_token: session['ds_access_token'], + base_path: session['ds_base_path'], + account_id: session['ds_account_id'], + envelope_id: envelope_id + } + + results = ESign::Eg015GetEnvelopeTabDataService.new(args).worker + @h1 = 'List envelopes results' + @message = 'Results from the EnvelopeFormData::get method:' + @json = results.to_json.to_json + render 'ds_common/example_done' end end diff --git a/app/controllers/e_sign/eg016_set_envelope_tab_data_controller.rb b/app/controllers/e_sign/eg016_set_envelope_tab_data_controller.rb index 20b6533..d429321 100644 --- a/app/controllers/e_sign/eg016_set_envelope_tab_data_controller.rb +++ b/app/controllers/e_sign/eg016_set_envelope_tab_data_controller.rb @@ -1,17 +1,23 @@ # frozen_string_literal: true class ESign::Eg016SetEnvelopeTabDataController < EgController + before_action :check_auth + def create - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - redirect_url = ESign::Eg016SetEnvelopeTabDataService.new(request, session).call - redirect_to redirect_url + args = { + # Validation: Delete any non-usual characters + signer_email: params['signerEmail'].gsub(/([^\w\-.+@, ])+/, ''), + signer_name: params['signerName'].gsub(/([^\w\-., ])+/, ''), + access_token: session['ds_access_token'], + base_path: session['ds_base_path'], + account_id: session['ds_account_id'] + } + + results = ESign::Eg016SetEnvelopeTabDataService.new(args).worker + + # Save for future use within the example launcher + session[:envelope_id] = results[:envelope_id] + + redirect_to results[:url] end end diff --git a/app/controllers/e_sign/eg017_set_template_tab_values_controller.rb b/app/controllers/e_sign/eg017_set_template_tab_values_controller.rb index 778c38e..ffd1f47 100644 --- a/app/controllers/e_sign/eg017_set_template_tab_values_controller.rb +++ b/app/controllers/e_sign/eg017_set_template_tab_values_controller.rb @@ -1,19 +1,28 @@ # frozen_string_literal: true class ESign::Eg017SetTemplateTabValuesController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 template_id = session[:template_id] - token_ok = check_token(minimum_buffer_min) - if token_ok && template_id - redirect_url = ESign::Eg017SetTemplateTabValuesService.new(request, session, template_id).call - redirect_to redirect_url - elsif !token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' + + if template_id + envelope_args = { + signer_email: params['signerEmail'], + signer_name: params['signerName'], + cc_email: params['ccEmail'], + cc_name: params['ccName'], + template_id: template_id + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + + redirect_url = ESign::Eg017SetTemplateTabValuesService.new(args).worker + redirect_to redirect_url elsif !template_id @title = 'Use a template to send an envelope' @template_ok = false diff --git a/app/controllers/e_sign/eg018_get_envelope_custom_field_data_controller.rb b/app/controllers/e_sign/eg018_get_envelope_custom_field_data_controller.rb index 0122b70..5b2182a 100644 --- a/app/controllers/e_sign/eg018_get_envelope_custom_field_data_controller.rb +++ b/app/controllers/e_sign/eg018_get_envelope_custom_field_data_controller.rb @@ -1,22 +1,22 @@ # frozen_string_literal: true class ESign::Eg018GetEnvelopeCustomFieldDataController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 envelope_id = session[:envelope_id] - token_ok = check_token(minimum_buffer_min) - if token_ok - results = ESign::Eg018GetEnvelopeCustomFieldDataService.new(session, envelope_id).call - @h1 = 'List envelopes results' - @message = 'Results from the Envelopes::listStatusChanges method:' - @json = results.to_json.to_json - render 'ds_common/example_done' - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end + + args = { + access_token: session['ds_access_token'], + base_path: session['ds_base_path'], + account_id: session['ds_account_id'], + envelope_id: envelope_id + } + + results = ESign::Eg018GetEnvelopeCustomFieldDataService.new(args).worker + @h1 = 'List envelopes results' + @message = 'Results from the Envelopes::listStatusChanges method:' + @json = results.to_json.to_json + render 'ds_common/example_done' end end diff --git a/app/controllers/e_sign/eg019_access_code_authentication_controller.rb b/app/controllers/e_sign/eg019_access_code_authentication_controller.rb index 88e8114..2e75eb3 100644 --- a/app/controllers/e_sign/eg019_access_code_authentication_controller.rb +++ b/app/controllers/e_sign/eg019_access_code_authentication_controller.rb @@ -1,28 +1,33 @@ # frozen_string_literal: true class ESign::Eg019AccessCodeAuthenticationController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 - if check_token(minimum_buffer_min) - begin - # ***DS.snippet.0.start - results = ESign::Eg019AccessCodeAuthenticationService.new(request, session).call - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/' + begin + # ***DS.snippet.0.start + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + accessCode: params['accessCode'], + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + + results = ESign::Eg019AccessCodeAuthenticationService.new(args).worker + session[:envelope_id] = results.envelope_id + + @title = 'Envelope sent' + @h1 = 'Envelope sent' + @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end # ***DS.snippet.0.end diff --git a/app/controllers/e_sign/eg020_phone_authentication_controller.rb b/app/controllers/e_sign/eg020_phone_authentication_controller.rb index 6344227..95e6186 100644 --- a/app/controllers/e_sign/eg020_phone_authentication_controller.rb +++ b/app/controllers/e_sign/eg020_phone_authentication_controller.rb @@ -1,38 +1,44 @@ # frozen_string_literal: true class ESign::Eg020PhoneAuthenticationController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 - if check_token(minimum_buffer_min) - begin - results = ESign::Eg020PhoneAuthenticationService.new(request, session).call - if results.to_s == "phone_auth_not_enabled" - @error_code = "IDENTITY_WORKFLOW_INVALID_ID" - @error_message = "The identity workflow ID specified is not valid." - @error_information = "Please contact Support to enable ID verification in your account." - render 'ds_common/error' - else - session[:envelope_id] = results.envelope_id - @title = 'Require Phone Authentication for a Recipient' - @h1 = 'Require Phone Authentication for a Recipient' - @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." - render 'ds_common/example_done' - end - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - if error['errorCode']["IDENTITY_WORKFLOW_INVALID_ID"] - @error_information = "Please contact Support to enable recipient phone authentication in your account." - end + begin + envelope_args = { + signer_email: param_gsub(params['signer_email']), + signer_name: param_gsub(params['signer_name']), + country_code: param_gsub(params['country_code']), + phone_number: param_gsub(params['phone_number']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + + phone_auth_service = ESign::Eg020PhoneAuthenticationService.new(args) + + # Retrieve the workflow id + workflow_id = phone_auth_service.get_workflow + session[:workflow_id] = workflow_id + + results = phone_auth_service.worker(workflow_id) + + if results.to_s == "phone_auth_not_enabled" + @error_code = "IDENTITY_WORKFLOW_INVALID_ID" + @error_message = "The identity workflow ID specified is not valid." + @error_information = "Please contact Support to enable ID verification in your account." render 'ds_common/error' + else + session[:envelope_id] = results.envelope_id + @title = 'Require Phone Authentication for a Recipient' + @h1 = 'Require Phone Authentication for a Recipient' + @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." + render 'ds_common/example_done' end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/' end end diff --git a/app/controllers/e_sign/eg022_kba_authentication_controller.rb b/app/controllers/e_sign/eg022_kba_authentication_controller.rb index 5433e48..e342091 100644 --- a/app/controllers/e_sign/eg022_kba_authentication_controller.rb +++ b/app/controllers/e_sign/eg022_kba_authentication_controller.rb @@ -1,27 +1,31 @@ # frozen_string_literal: true class ESign::Eg022KbaAuthenticationController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 - if check_token(minimum_buffer_min) - begin - results = ESign::Eg022KbaAuthenticationService.new(request, session).call - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/' + begin + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + + results = ESign::Eg022KbaAuthenticationService.new(args).worker + session[:envelope_id] = results.envelope_id + + @title = 'Envelope sent' + @h1 = 'Envelope sent' + @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end end diff --git a/app/controllers/e_sign/eg023_idv_authentication_controller.rb b/app/controllers/e_sign/eg023_idv_authentication_controller.rb index 7dcbe26..67da9eb 100644 --- a/app/controllers/e_sign/eg023_idv_authentication_controller.rb +++ b/app/controllers/e_sign/eg023_idv_authentication_controller.rb @@ -1,35 +1,41 @@ # frozen_string_literal: true class ESign::Eg023IdvAuthenticationController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 - if check_token(minimum_buffer_min) - begin - results = ESign::Eg023IdvAuthenticationService.new(request, session).call - if results.to_s == "idv_not_enabled" - @error_code = "IDENTITY_WORKFLOW_INVALID_ID" - @error_message = "The identity workflow ID specified is not valid." - @error_information = "Please contact Support to enable ID verification in your account." - render 'ds_common/error' + begin + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + + results = ESign::Eg023IdvAuthenticationService.new(args).worker - else - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." - render 'ds_common/example_done' - end - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] + if results.to_s == "idv_not_enabled" + @error_code = "IDENTITY_WORKFLOW_INVALID_ID" + @error_message = "The identity workflow ID specified is not valid." + @error_information = "Please contact Support to enable ID verification in your account." render 'ds_common/error' + else + session[:envelope_id] = results.envelope_id + @title = 'Envelope sent' + @h1 = 'Envelope sent' + @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." + render 'ds_common/example_done' end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/' + rescue DocuSign_eSign::ApiError => e + error = JSON.parse e.response_body + @error_code = error['errorCode'] + @error_message = error['message'] + render 'ds_common/error' end end diff --git a/app/controllers/e_sign/eg024_permission_create_controller.rb b/app/controllers/e_sign/eg024_permission_create_controller.rb index f94f1b1..7bea1ed 100644 --- a/app/controllers/e_sign/eg024_permission_create_controller.rb +++ b/app/controllers/e_sign/eg024_permission_create_controller.rb @@ -1,31 +1,28 @@ # frozen_string_literal: true class ESign::Eg024PermissionCreateController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 - if check_token(minimum_buffer_min) - begin - results = ESign::Eg024PermissionCreateService.new(session, request).call - # Step 4. a) Call the eSignature API - # b) Display the JSON response - @title = 'Creating a permission profile' - @h1 = 'Creating a permission profile' - @message = "Permission profile was created" - @json = results.to_json.to_json - render 'ds_common/example_done' + begin + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + permission_profile_name: params[:permission_profile_name] + } + + results = ESign::Eg024PermissionCreateService.new(args).worker + # Step 4. a) Call the eSignature API + # b) Display the JSON response + @title = 'Creating a permission profile' + @h1 = 'Creating a permission profile' + @message = "Permission profile was created" + @json = results.to_json.to_json + render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end end diff --git a/app/controllers/e_sign/eg025_permissions_set_user_group_controller.rb b/app/controllers/e_sign/eg025_permissions_set_user_group_controller.rb index 12d3a8f..c27d1c3 100644 --- a/app/controllers/e_sign/eg025_permissions_set_user_group_controller.rb +++ b/app/controllers/e_sign/eg025_permissions_set_user_group_controller.rb @@ -20,40 +20,25 @@ def get end def create - minimum_buffer_min = 3 - if check_token(minimum_buffer_min) - begin - results = ESign::Eg025PermissionsSetUserGroupService.new(session, request).call - # Step 4. a) Call the eSignature API - # b) Display the JSON response - @title = 'Setting a permission profile' - @h1 = 'Setting a permission profile' - @json = results.to_json.to_json - render 'ds_common/example_done' + begin + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + permission_profile_id: params[:lists], + group_id: params[:group_lists] + } - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - end + results = ESign::Eg025PermissionsSetUserGroupService.new(args).worker + # Step 4. a) Call the eSignature API + # b) Display the JSON response + @title = 'Setting a permission profile' + @h1 = 'Setting a permission profile' + @json = results.to_json.to_json + render 'ds_common/example_done' - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end end diff --git a/app/controllers/e_sign/eg026_permissions_change_single_setting_controller.rb b/app/controllers/e_sign/eg026_permissions_change_single_setting_controller.rb index 90aa89e..2d414fd 100644 --- a/app/controllers/e_sign/eg026_permissions_change_single_setting_controller.rb +++ b/app/controllers/e_sign/eg026_permissions_change_single_setting_controller.rb @@ -17,41 +17,25 @@ def get end def create - minimum_buffer_min = 3 - if check_token(minimum_buffer_min) - begin - results = ESign::Eg026PermissionsChangeSingleSettingService.new(session, request).call - # Step 4. a) Call the eSignature API - # b) Display the JSON response - @title = 'Updating individual permission settings' - @h1 = 'Updating individual permission settings' - @message = "Existing permission profile was changed" - @json = results.to_json.to_json - render 'ds_common/example_done' + begin + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + permission_profile_id: params[:lists] + } - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/' - end - end + results = ESign::Eg026PermissionsChangeSingleSettingService.new(args).worker + # Step 4. a) Call the eSignature API + # b) Display the JSON response + @title = 'Updating individual permission settings' + @h1 = 'Updating individual permission settings' + @message = "Existing permission profile was changed" + @json = results.to_json.to_json + render 'ds_common/example_done' - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end end diff --git a/app/controllers/e_sign/eg027_permissions_delete_controller.rb b/app/controllers/e_sign/eg027_permissions_delete_controller.rb index b7ddc0b..915e79d 100644 --- a/app/controllers/e_sign/eg027_permissions_delete_controller.rb +++ b/app/controllers/e_sign/eg027_permissions_delete_controller.rb @@ -3,6 +3,7 @@ class ESign::Eg027PermissionsDeleteController < EgController include ApiCreator before_action :check_auth + def get args = { account_id: session['ds_account_id'], @@ -16,40 +17,24 @@ def get end def create - minimum_buffer_min = 3 - if check_token(minimum_buffer_min) - begin - results = ESign::Eg027PermissionsDeleteService.new(session, request).call - # Step 4. a) Call the eSignature API - # b) Display the JSON response - @title = 'Permission profile from an account was deleted' - @h1 = 'Permission profile from an account was deleted' - @message = "Permission profile #{request.params[:lists]} was deleted" - render 'ds_common/example_done' + begin + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + permission_profile_id: params[:lists] + } - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/' - end - end + results = ESign::Eg027PermissionsDeleteService.new(args).worker + # Step 4. a) Call the eSignature API + # b) Display the JSON response + @title = 'Permission profile from an account was deleted' + @h1 = 'Permission profile from an account was deleted' + @message = "Permission profile #{params[:lists]} was deleted" + render 'ds_common/example_done' - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end end diff --git a/app/controllers/e_sign/eg028_brands_creating_controller.rb b/app/controllers/e_sign/eg028_brands_creating_controller.rb index 5328933..c7cbdc3 100644 --- a/app/controllers/e_sign/eg028_brands_creating_controller.rb +++ b/app/controllers/e_sign/eg028_brands_creating_controller.rb @@ -1,30 +1,28 @@ class ESign::Eg028BrandsCreatingController < EgController + before_action :check_auth + def create - minimum_buffer_min = 3 - if check_token(minimum_buffer_min) - begin - results = ESign::Eg028BrandsCreatingService.new(session, request).call - # Step 4. a) Call the eSignature API - # b) Display the JSON response - brand_id = results.brands[0].brand_id - @title = 'Brand creating' - @h1 = 'Brand creating' - @message = "The Brand has been created!
Brand ID: #{brand_id}." - @json = results.to_json.to_json - render 'ds_common/example_done' + begin + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + brandName: params[:brandName], + defaultBrandLanguage: params[:defaultBrandLanguage] + } + + results = ESign::Eg028BrandsCreatingService.new(args).worker + # Step 4. a) Call the eSignature API + # b) Display the JSON response + brand_id = results.brands[0].brand_id + @title = 'Brand creating' + @h1 = 'Brand creating' + @message = "The Brand has been created!
Brand ID: #{brand_id}." + @json = results.to_json.to_json + render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end end diff --git a/app/controllers/e_sign/eg029_brands_apply_to_envelope_controller.rb b/app/controllers/e_sign/eg029_brands_apply_to_envelope_controller.rb index 6d38fc6..d927abd 100644 --- a/app/controllers/e_sign/eg029_brands_apply_to_envelope_controller.rb +++ b/app/controllers/e_sign/eg029_brands_apply_to_envelope_controller.rb @@ -17,41 +17,34 @@ def get end def create - minimum_buffer_min = 3 - if check_token(minimum_buffer_min) - begin - results = ESign::Eg029BrandsApplyToEnvelopeService.new(session, request).call - # Step 4. a) Call the eSignature API - # b) Display the JSON response - @title = 'Applying a Brand to an envelope' - @h1 = 'Applying a Brand to an envelope' - @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." - @json = results.to_json.to_json - render 'ds_common/example_done' + begin + envelope_args = { + signer_email: param_gsub(params[:signerEmail]), + signer_name: param_gsub(params[:signerName]), + brand_id: params[:brands], + status: 'sent' + + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/' - end - end + results = ESign::Eg029BrandsApplyToEnvelopeService.new(args).worker + session[:envelope_id] = results.envelope_id + + # Step 4. a) Call the eSignature API + # b) Display the JSON response + @title = 'Applying a Brand to an envelope' + @h1 = 'Applying a Brand to an envelope' + @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." + @json = results.to_json.to_json + render 'ds_common/example_done' - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end end diff --git a/app/controllers/e_sign/eg030_brands_apply_to_template_controller.rb b/app/controllers/e_sign/eg030_brands_apply_to_template_controller.rb index 4c3df30..8e107b5 100644 --- a/app/controllers/e_sign/eg030_brands_apply_to_template_controller.rb +++ b/app/controllers/e_sign/eg030_brands_apply_to_template_controller.rb @@ -21,42 +21,38 @@ def get end def create - minimum_buffer_min = 3 - if check_token(minimum_buffer_min) - begin - results = ESign::Eg030BrandsApplyToTemplateService.new(session, request).call - # Step 4. a) Call the eSignature API - # b) Display the JSON response - # brand_id = results.brands[0].brand_id - @title = 'Applying a brand to an envelope using a template' - @h1 = 'Applying a brand to an envelope using a template' - @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." - @json = results.to_json.to_json - render 'ds_common/example_done' + begin + envelope_args = { + signer_email: param_gsub(params[:signerEmail]), + signer_name: param_gsub(params[:signerName]), + cc_email: param_gsub(params[:ccEmail]), + cc_name: param_gsub(params[:ccName]), + brand_id: params[:brands], + template_id: params[:templates], + status: 'sent' + + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/' - end - end + results = ESign::Eg030BrandsApplyToTemplateService.new(args).worker + session[:envelope_id] = results.envelope_id + + # Step 4. a) Call the eSignature API + # b) Display the JSON response + # brand_id = results.brands[0].brand_id + @title = 'Applying a brand to an envelope using a template' + @h1 = 'Applying a brand to an envelope using a template' + @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." + @json = results.to_json.to_json + render 'ds_common/example_done' - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end end diff --git a/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb b/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb index 1723135..3e66932 100644 --- a/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb +++ b/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb @@ -1,33 +1,40 @@ # frozen_string_literal: true class ESign::Eg031BulkSendingEnvelopesController < EgController + before_action :check_auth def create - minimum_buffer_min = 3 - if check_token(minimum_buffer_min) - begin - results = ESign::Eg031BulkSendingEnvelopesService.new(request, session).call - # Step 4. a) Call the eSignature API - # b) Display the JSON response - @title = 'Bulk send envelopes' - @h1 = 'Bulk send envelopes' - @message = 'Results from BulkSend:getBulkSendBatchStatus method:' - @json = results.to_json.to_json + begin + signers = { + signer_email: param_gsub(params['signerEmail1']), + signer_name: param_gsub(params['signerName1']), + cc_email: param_gsub(params['ccEmail1']), + cc_name: param_gsub(params['ccName1']), + status: 'created', + + signer_email1: param_gsub(params['signerEmail2']), + signer_name1: param_gsub(params['signerName2']), + cc_email1: param_gsub(params['ccEmail2']), + cc_name1: param_gsub(params['ccName2']) + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'] + } - render 'ds_common/example_done' + results = ESign::Eg031BulkSendingEnvelopesService.new(args, signers).worker + # Step 4. a) Call the eSignature API + # b) Display the JSON response + @title = 'Bulk send envelopes' + @h1 = 'Bulk send envelopes' + @message = "Results from BulkSend:getBulkSendBatchStatus method:" + @json = results.to_json.to_json - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted - # automatically. But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end + render 'ds_common/example_done' + + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end end end diff --git a/app/controllers/e_sign/eg032_pauses_signature_workflow_controller.rb b/app/controllers/e_sign/eg032_pauses_signature_workflow_controller.rb index 3b7e16f..bb11b95 100644 --- a/app/controllers/e_sign/eg032_pauses_signature_workflow_controller.rb +++ b/app/controllers/e_sign/eg032_pauses_signature_workflow_controller.rb @@ -4,24 +4,24 @@ class ESign::Eg032PausesSignatureWorkflowController < EgController before_action :check_auth def create - results = ESign::Eg032PausesSignatureWorkflowService.new(session, request).call + signers = { + signerEmail1: request['signerEmail1'], + signerName1: request['signerName1'], + signerEmail2: request['signerEmail2'], + signerName2: request['signerName2'] + } + args = { + accountId: session['ds_account_id'], + basePath: session['ds_base_path'], + accessToken: session['ds_access_token'], + status: 'sent' + } + + results = ESign::Eg032PausesSignatureWorkflowService.new(args, signers).worker @envelop_id = results.to_hash[:envelopeId].to_s session[:envelope_id] = @envelop_id render 'e_sign/eg032_pauses_signature_workflow/return' end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/e_sign/eg033_unpauses_signature_workflow_controller.rb b/app/controllers/e_sign/eg033_unpauses_signature_workflow_controller.rb index d9497db..cb9d7db 100644 --- a/app/controllers/e_sign/eg033_unpauses_signature_workflow_controller.rb +++ b/app/controllers/e_sign/eg033_unpauses_signature_workflow_controller.rb @@ -4,22 +4,17 @@ class ESign::Eg033UnpausesSignatureWorkflowController < EgController before_action :check_auth def update - results = ESign::Eg033UnpausesSignatureWorkflowService.new(session).call + args = { + accountId: session['ds_account_id'], + basePath: session['ds_base_path'], + accessToken: session['ds_access_token'], + envelopeId: session['envelope_id'], + status: 'in_progress' + } + + results = ESign::Eg033UnpausesSignatureWorkflowService.new(args).worker @envelop_id = results.to_hash[:envelopeId].to_s render 'e_sign/eg033_unpauses_signature_workflow/return' end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/e_sign/eg034_use_conditional_recipients_controller.rb b/app/controllers/e_sign/eg034_use_conditional_recipients_controller.rb index 870cea4..bb5f67e 100644 --- a/app/controllers/e_sign/eg034_use_conditional_recipients_controller.rb +++ b/app/controllers/e_sign/eg034_use_conditional_recipients_controller.rb @@ -5,7 +5,24 @@ class ESign::Eg034UseConditionalRecipientsController < EgController def create begin - results = ESign::Eg034UseConditionalRecipientsService.new(session, request).call + signers = { + signerEmail1: request['signerEmail1'], + signerName1: request['signerName1'], + + signerEmailNotChecked: request['signerEmailNotChecked'], + signerNameNotChecked: request['signerNameNotChecked'], + + signerEmailChecked: request['signerEmailChecked'], + signerNameChecked: request['signerNameChecked'] + } + + args = { + accountId: session['ds_account_id'], + basePath: session['ds_base_path'], + accessToken: session['ds_access_token'] + } + + results = ESign::Eg034UseConditionalRecipientsService.new(args, signers).worker @envelop_id = results.to_hash[:envelopeId].to_s render 'e_sign/eg034_use_conditional_recipients/return' rescue DocuSign_eSign::ApiError => e @@ -20,17 +37,4 @@ def create render 'ds_common/error' end end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/e_sign/eg035_sms_delivery_controller.rb b/app/controllers/e_sign/eg035_sms_delivery_controller.rb index 957e5e8..0657589 100644 --- a/app/controllers/e_sign/eg035_sms_delivery_controller.rb +++ b/app/controllers/e_sign/eg035_sms_delivery_controller.rb @@ -1,31 +1,37 @@ # frozen_string_literal: true class ESign::Eg035SmsDeliveryController < EgController - def create - minimum_buffer_min = 3 - if check_token(minimum_buffer_min) - begin - results = ESign::Eg035SmsDeliveryService.new(session, request, 'sent').call - session[:envelope_id] = results['envelope_id'] - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The envelope has been created and sent!
Envelope ID #{results['envelope_id']}." - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] - render 'ds_common/error' - end - else - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation - # so it could be restarted automatically. - # But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after - # authentication. - redirect_to '/' - end + before_action :check_auth + + def create + begin + envelope_args = { + signer_email: param_gsub(params['signer_email']), + signer_name: param_gsub(params['signer_name']), + cc_email: param_gsub(params['cc_email']), + cc_name: param_gsub(params['cc_name']), + cc_phone_number: param_gsub(params['cc_phone_number']), + cc_country_code: param_gsub(params['cc_country_code']), + phone_number: param_gsub(params['phone_number']), + country_code: param_gsub(params['country_code']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + + results = ESign::Eg035SmsDeliveryService.new(args).worker + session[:envelope_id] = results['envelope_id'] + @title = 'Envelope sent' + @h1 = 'Envelope sent' + @message = "The envelope has been created and sent!
Envelope ID #{results['envelope_id']}." + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end +end \ No newline at end of file diff --git a/app/controllers/eg001_embedded_signing_controller.rb b/app/controllers/eg001_embedded_signing_controller.rb index 6e5a05d..f0b9bc2 100644 --- a/app/controllers/eg001_embedded_signing_controller.rb +++ b/app/controllers/eg001_embedded_signing_controller.rb @@ -13,7 +13,18 @@ def create # authentication. redirect_to '/ds/mustAuthenticate' end - redirect_url = Eg001EmbeddedSigningService.new(session, request).call + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + signer_email: param_gsub(params[:signerEmail]), + signer_name: param_gsub(params[:signerName]), + ds_ping_url: Rails.application.config.app_url, + signer_client_id: 1000, + pdf_filename: 'data/World_Wide_Corp_lorem.pdf' + } + + redirect_url = Eg001EmbeddedSigningService.new(args).worker redirect_to redirect_url end diff --git a/app/controllers/eg_controller.rb b/app/controllers/eg_controller.rb index c3295bc..29aabc0 100644 --- a/app/controllers/eg_controller.rb +++ b/app/controllers/eg_controller.rb @@ -62,6 +62,28 @@ def time_in_words(duration) "#{Object.new.extend(ActionView::Helpers::DateHelper).distance_of_time_in_words(duration)}#{duration.negative? ? ' ago' : ''}" end + def param_gsub(parameter) + parameter.gsub(/([^\w \-\@\.\,])+/, '') + end + + def check_auth + minimum_buffer_min = 10 + token_ok = check_token(minimum_buffer_min) + unless token_ok + flash[:messages] = 'Sorry, you need to re-authenticate.' + # We could store the parameters of the requested operation so it could be restarted automatically + # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication + redirect_to '/ds/mustAuthenticate' + end + end + + def handle_error(e) + error = JSON.parse e.response_body + @error_code = e.code || error['errorCode'] + @error_message = error['error_description'] || error['message'] + render 'ds_common/error' + end + def create_source_path # code here end diff --git a/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb b/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb index 358c5a9..a3ff78a 100644 --- a/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb +++ b/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb @@ -2,7 +2,13 @@ class MonitorApi::Eg001GetMonitoringDatasetController < EgController before_action :check_auth def create - results = MonitorApi::Eg001GetMonitoringDatasetService.new(session, nil).call + args = { + access_token: session[:ds_access_token], + data_set_name: 'monitor', + version: '2.0' + } + + results = MonitorApi::Eg001GetMonitoringDatasetService.new(args).worker @title = "Monitoring data result" @h1 = "Monitoring data result" @@ -11,17 +17,4 @@ def create render 'ds_common/example_done' end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/room_api/eg001_create_room_with_data_controller.rb b/app/controllers/room_api/eg001_create_room_with_data_controller.rb index 91bbaa6..dfd3a53 100644 --- a/app/controllers/room_api/eg001_create_room_with_data_controller.rb +++ b/app/controllers/room_api/eg001_create_room_with_data_controller.rb @@ -2,7 +2,16 @@ class RoomApi::Eg001CreateRoomWithDataController < EgController before_action :check_auth def create - results = RoomApi::Eg001CreateRoomWithDataService.new(session, request).call + args = { + room_name: params[:roomName], + office_id: RoomApi::GetDataService.new(session).get_offices[0]['officeId'], + role_id: RoomApi::GetDataService.new(session).get_roles[2]['roleId'], + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } + + results = RoomApi::Eg001CreateRoomWithDataService.new(args).worker @title = "The room was successfully created" @h1 = "The room was successfully created" @@ -11,17 +20,4 @@ def create render 'ds_common/example_done' end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/room_api/eg002_create_room_with_template_controller.rb b/app/controllers/room_api/eg002_create_room_with_template_controller.rb index 27bcaac..5d54861 100644 --- a/app/controllers/room_api/eg002_create_room_with_template_controller.rb +++ b/app/controllers/room_api/eg002_create_room_with_template_controller.rb @@ -2,7 +2,17 @@ class RoomApi::Eg002CreateRoomWithTemplateController < EgController before_action :check_auth def create - results = RoomApi::Eg002CreateRoomWithTemplateService.new(session, request).call + args = { + room_name: params[:roomName], + office_id: RoomApi::GetDataService.new(session).get_offices[0]['officeId'], + role_id: RoomApi::GetDataService.new(session).get_roles[2]['roleId'], + template_id: params['templateId'], + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } + + results = RoomApi::Eg002CreateRoomWithTemplateService.new(args).worker @title = "The room was successfully created" @h1 = "The room was successfully created" @@ -15,17 +25,4 @@ def create def get @templates = RoomApi::GetDataService.new(session).get_templates end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/room_api/eg003_export_data_from_room_controller.rb b/app/controllers/room_api/eg003_export_data_from_room_controller.rb index 29bcbf9..99035a1 100644 --- a/app/controllers/room_api/eg003_export_data_from_room_controller.rb +++ b/app/controllers/room_api/eg003_export_data_from_room_controller.rb @@ -2,7 +2,14 @@ class RoomApi::Eg003ExportDataFromRoomController < EgController before_action :check_auth def create - results = RoomApi::Eg003ExportDataFromRoomService.new(session, request).call + args = { + room_id: params['roomId'], + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } + + results = RoomApi::Eg003ExportDataFromRoomService.new(args).worker @title = "The room data was successfully exported" @h1 = "The room data was successfully exported" @@ -15,17 +22,4 @@ def create def get @rooms = RoomApi::GetDataService.new(session).get_rooms end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/room_api/eg004_add_forms_to_room_controller.rb b/app/controllers/room_api/eg004_add_forms_to_room_controller.rb index bd70bdd..98d8b41 100644 --- a/app/controllers/room_api/eg004_add_forms_to_room_controller.rb +++ b/app/controllers/room_api/eg004_add_forms_to_room_controller.rb @@ -2,7 +2,15 @@ class RoomApi::Eg004AddFormsToRoomController < EgController before_action :check_auth def create - results = RoomApi::Eg004AddFormsToRoomService.new(session, request).call + args = { + form_id: params['formId'], + room_id: params['roomId'], + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } + + results = RoomApi::Eg004AddFormsToRoomService.new(args).worker @title = "The form was successfully added to a room" @h1 = "The form was successfully added to a room" @@ -16,17 +24,4 @@ def get @rooms = RoomApi::GetDataService.new(session).get_rooms @form_libraries = RoomApi::GetDataService.new(session).get_form_libraries end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/room_api/eg005_get_rooms_with_filters_controller.rb b/app/controllers/room_api/eg005_get_rooms_with_filters_controller.rb index 55679e4..7e39b88 100644 --- a/app/controllers/room_api/eg005_get_rooms_with_filters_controller.rb +++ b/app/controllers/room_api/eg005_get_rooms_with_filters_controller.rb @@ -2,7 +2,15 @@ class RoomApi::Eg005GetRoomsWithFiltersController < EgController before_action :check_auth def create - results = RoomApi::Eg005GetRoomsWithFiltersService.new(session, request).call + args = { + date_from: params[:date_from], + date_to: params[:date_to], + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } + + results = RoomApi::Eg005GetRoomsWithFiltersService.new(args).worker @title = "The rooms with filters were loaded" @h1 = "The rooms with filters were loaded" @@ -15,17 +23,4 @@ def create def get @rooms = RoomApi::GetDataService.new(session).get_rooms end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/room_api/eg006_create_an_external_form_fill_session_controller.rb b/app/controllers/room_api/eg006_create_an_external_form_fill_session_controller.rb index 3653789..5134dab 100644 --- a/app/controllers/room_api/eg006_create_an_external_form_fill_session_controller.rb +++ b/app/controllers/room_api/eg006_create_an_external_form_fill_session_controller.rb @@ -2,7 +2,15 @@ class RoomApi::Eg006CreateAnExternalFormFillSessionController < EgController before_action :check_auth def create - results = RoomApi::Eg006CreateAnExternalFormFillSessionService.new(session, request).call + args = { + form_id: params['formId'], + room_id: params['roomId'], + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } + + results = RoomApi::Eg006CreateAnExternalFormFillSessionService.new(args).worker @title = "External form fill session was successfully created" @h1 = "External form fill session was successfully created" @@ -19,17 +27,4 @@ def get_rooms def get_forms @form_libraries = RoomApi::GetDataService.new(session, params['roomId']).get_forms_from_room end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/room_api/eg007_create_form_group_controller.rb b/app/controllers/room_api/eg007_create_form_group_controller.rb index 5990003..2791f2f 100644 --- a/app/controllers/room_api/eg007_create_form_group_controller.rb +++ b/app/controllers/room_api/eg007_create_form_group_controller.rb @@ -2,7 +2,13 @@ class RoomApi::Eg007CreateFormGroupController < EgController before_action :check_auth def create - results = RoomApi::Eg007CreateFormGroupService.new(session, request).call + args = { + group_name: params[:group_name], + account_id: session[:ds_account_id], + access_token: session[:ds_access_token] + } + + results = RoomApi::Eg007CreateFormGroupService.new(args).worker @title = "The form group was successfully created" @h1 = "The form group was successfully created" @@ -11,17 +17,4 @@ def create render 'ds_common/example_done' end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/room_api/eg008_grant_office_access_to_form_group_controller.rb b/app/controllers/room_api/eg008_grant_office_access_to_form_group_controller.rb index d7eedee..7831296 100644 --- a/app/controllers/room_api/eg008_grant_office_access_to_form_group_controller.rb +++ b/app/controllers/room_api/eg008_grant_office_access_to_form_group_controller.rb @@ -2,7 +2,14 @@ class RoomApi::Eg008GrantOfficeAccessToFormGroupController < EgController before_action :check_auth def create - results = RoomApi::Eg008GrantOfficeAccessToFormGroupService.new(session, request).call + args = { + office_id: params[:office_id], + form_group_id: params[:form_group_id], + account_id: session[:ds_account_id], + access_token: session[:ds_access_token] + } + + results = RoomApi::Eg008GrantOfficeAccessToFormGroupService.new(args).worker result = results.to_json.to_json if result['exception'] @error_code = results[:exception] @@ -27,17 +34,4 @@ def get @form_groups = RoomApi::GetDataService.new(session).get_form_groups # Step 4 end end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/controllers/room_api/eg009_assign_form_to_form_group_controller.rb b/app/controllers/room_api/eg009_assign_form_to_form_group_controller.rb index 4ecde46..e94bc94 100644 --- a/app/controllers/room_api/eg009_assign_form_to_form_group_controller.rb +++ b/app/controllers/room_api/eg009_assign_form_to_form_group_controller.rb @@ -2,7 +2,14 @@ class RoomApi::Eg009AssignFormToFormGroupController < EgController before_action :check_auth def create - results = RoomApi::Eg009AssignFormToFormGroupService.new(session, request).call + args = { + form_id: params[:form_id], + form_group_id: params[:form_group_id], + account_id: session[:ds_account_id], + access_token: session[:ds_access_token] + } + + results = RoomApi::Eg009AssignFormToFormGroupService.new(args).worker result = results.to_json.to_json if result['exception'] @error_code = results[:exception] @@ -27,17 +34,4 @@ def get @form_groups = RoomApi::GetDataService.new(session).get_form_groups # Step 4 end end - - private - - def check_auth - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - end end diff --git a/app/services/admin_api/eg001_create_user_service.rb b/app/services/admin_api/eg001_create_user_service.rb index 02c0581..a951e25 100644 --- a/app/services/admin_api/eg001_create_user_service.rb +++ b/app/services/admin_api/eg001_create_user_service.rb @@ -3,40 +3,9 @@ class AdminApi::Eg001CreateUserService attr_reader :args, :user_data - def initialize(session, request) - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - organization_id: session['organization_id'] - } - - # Step 3 start - @user_data = { - user_name: request.params['user_name'].gsub(/([^\w \-\@\.\,])+/, ''), - first_name: request.params['first_name'].gsub(/([^\w \-\@\.\,])+/, ''), - last_name: request.params['last_name'].gsub(/([^\w \-\@\.\,])+/, ''), - email: request.params['email'].gsub(/([^\w \-\@\.\,])+/, ''), - auto_activate_memberships: true, - accounts: [ - { - id: args[:account_id], - permission_profile: { - id: request['permission_profile_id'] - }, - groups: [ - { - id: request['group_id'] - } - ] - } - ] - } - # Step 3 end - end - - def call - worker + def initialize(args, user_data) + @args = args + @user_data = user_data end def worker @@ -53,20 +22,4 @@ def worker response = users_api.create_user(args[:organization_id], user_data) # Step 4 end end - - def self.get_permission_profiles_and_groups - configuration = DocuSign_eSign::Configuration.new - configuration.host = args[:ds_base_path] - - api_client = DocuSign_eSign::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") - - accounts_api = DocuSign_eSign::AccountsApi.new(api_client) - profiles = accounts_api.list_permissions(args[:account_id]) - - groups_api = DocuSign_eSign::GroupsApi.new(api_client) - groups = groups_api.list_groups(args[:account_id]) - - return profiles, groups - end end diff --git a/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb b/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb index 0a55be4..0c96d04 100644 --- a/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb +++ b/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb @@ -1,72 +1,53 @@ # frozen_string_literal: true class AdminApi::Eg002CreateActiveClmEsignUserService - attr_reader :args + attr_reader :args - def initialize(session, request) - @args = { - user_name: request.params[:user_name], - first_name: request.params[:first_name], - last_name: request.params[:last_name], - email: request.params[:email], - clm_permission_profile_id: request.params[:clm_permission_profile_id], - esign_permission_profile_id: request.params[:esign_permission_profile_id], - clm_product_id: request.params[:clm_product_id], - esign_product_id: request.params[:esign_product_id], - ds_group_id: request.params[:ds_group_id], - account_id: session[:ds_account_id], - organization_id: session['organization_id'], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } - end - - def call - worker - end - - private + def initialize(args) + @args = args + end - def worker - # Step 2 start - configuration = DocuSign_Admin::Configuration.new - configuration.host = Rails.configuration.admin_host + def worker + # Step 2 start + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host - api_client = DocuSign_Admin::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") - # Step 2 end + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + # Step 2 end - # Step 6 start - users_api = DocuSign_Admin::UsersApi.new(api_client) - response = users_api.add_or_update_user(args[:organization_id], args[:account_id], body) - # Step 6 end - end + # Step 6 start + users_api = DocuSign_Admin::UsersApi.new(api_client) + response = users_api.add_or_update_user(args[:organization_id], args[:account_id], body(args)) + # Step 6 end + end - # Step 5 start - def body - { - user_name: args[:user_name], - first_name: args[:first_name], - last_name: args[:last_name], - email: args[:email], - auto_activate_memberships: true, - product_permission_profiles: [ - { - permission_profile_id: args[:esign_permission_profile_id], - product_id: args[:esign_product_id] - }, - { - permission_profile_id: args[:clm_permission_profile_id], - product_id: args[:clm_product_id] - } - ], - ds_groups: [ - { - ds_group_id: args[:ds_group_id] - } - ] - } + private + + # Step 5 start + def body(args) + { + user_name: args[:user_name], + first_name: args[:first_name], + last_name: args[:last_name], + email: args[:email], + auto_activate_memberships: true, + product_permission_profiles: [ + { + permission_profile_id: args[:esign_permission_profile_id], + product_id: args[:esign_product_id] + }, + { + permission_profile_id: args[:clm_permission_profile_id], + product_id: args[:clm_product_id] + } + ], + ds_groups: [ + { + ds_group_id: args[:ds_group_id] + } + ] + } end # Step 5 end - end \ No newline at end of file diff --git a/app/services/admin_api/eg003_bulk_export_user_data_service.rb b/app/services/admin_api/eg003_bulk_export_user_data_service.rb index 88ca8b8..66d750d 100644 --- a/app/services/admin_api/eg003_bulk_export_user_data_service.rb +++ b/app/services/admin_api/eg003_bulk_export_user_data_service.rb @@ -1,46 +1,10 @@ class AdminApi::Eg003BulkExportUserDataService - attr_reader :args, :request_body, :bulk_exports_api + attr_reader :bulk_exports_api, :args - def initialize(session, request, file_path) - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - organization_id: session['organization_id'], - file_path: file_path - } - @request_body = { - type: 'organization_memberships_export' - } + def initialize(args) + @args = args end - def call - worker - end - - # Step 5 start - def get_exported_user_data(export_id) - bulk_export_response = bulk_exports_api.get_user_list_export(args[:organization_id], export_id) - data_url = bulk_export_response.results[0].url - - uri = URI(data_url) - - req = Net::HTTP::Get.new(uri) - req['Authorization'] = "Bearer #{args[:access_token]}" - - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = true - - http.request(req) do |response| - File.open(args[:file_path], 'w') do |file| - response.read_body do |chunk| - file.write(chunk) - end - end - end - end - # Step 5 end - def worker # Step 2 start configuration = DocuSign_Admin::Configuration.new @@ -52,14 +16,14 @@ def worker # Step 3 start @bulk_exports_api = DocuSign_Admin::BulkExportsApi.new(api_client) - response = bulk_exports_api.create_user_list_export(args[:organization_id], request_body) + response = bulk_exports_api.create_user_list_export(args[:organization_id], args[:request_body]) # Step 3 end # Step 4 start retry_count = 5 while retry_count >= 0 if response.results - get_exported_user_data(response.id) + get_exported_user_data(args, response.id) break else retry_count -= 1 @@ -71,4 +35,29 @@ def worker return response end + + private + + # Step 5 start + def get_exported_user_data(args, export_id) + bulk_export_response = bulk_exports_api.get_user_list_export(args[:organization_id], export_id) + data_url = bulk_export_response.results[0].url + + uri = URI(data_url) + + req = Net::HTTP::Get.new(uri) + req['Authorization'] = "Bearer #{args[:access_token]}" + + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = true + + http.request(req) do |response| + File.open(args[:file_path], 'w') do |file| + response.read_body do |chunk| + file.write(chunk) + end + end + end + end + # Step 5 end end \ No newline at end of file diff --git a/app/services/admin_api/eg004_import_user_service.rb b/app/services/admin_api/eg004_import_user_service.rb index 8e8165b..71d4b95 100644 --- a/app/services/admin_api/eg004_import_user_service.rb +++ b/app/services/admin_api/eg004_import_user_service.rb @@ -1,22 +1,8 @@ -require 'uri' -require 'net/http' - class AdminApi::Eg004ImportUserService - attr_reader :args, :user_data - - def initialize(session, request, csv_file_path) - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - organization_id: session['organization_id'], - csv_file_path: csv_file_path - } - - end + attr_reader :args - def call - worker + def initialize(args) + @args = args end def worker diff --git a/app/services/admin_api/eg005_audit_users_service.rb b/app/services/admin_api/eg005_audit_users_service.rb index 66e2281..dc77674 100644 --- a/app/services/admin_api/eg005_audit_users_service.rb +++ b/app/services/admin_api/eg005_audit_users_service.rb @@ -1,51 +1,40 @@ # frozen_string_literal: true class AdminApi::Eg005AuditUsersService - attr_reader :args - - def initialize(session, request) - @args = { - account_id: session[:ds_account_id], - organization_id: session['organization_id'], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } + attr_reader :args + + def initialize(args) + @args = args + end + + def worker + # Step 2 start + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + # Step 2 end + + # Step 3 start + options = DocuSign_Admin::GetUsersOptions.new + options.account_id = args[:account_id] + options.last_modified_since = (Date.today - 10).strftime('%Y/%m/%d') + + users_api = DocuSign_Admin::UsersApi.new(api_client) + modified_users = users_api.get_users(args[:organization_id], options).as_json['users'] + # Step 3 end + + # Step 5 start + results = [] + modified_users.each do |user| + userProfilesOptions = DocuSign_Admin::GetUserProfilesOptions.new + userProfilesOptions.email = user['email'] + result = users_api.get_user_profiles(args[:organization_id], userProfilesOptions) + results.push(result) end + # Step 5 end - def call - worker - end - - private - - def worker - # Step 2 start - configuration = DocuSign_Admin::Configuration.new - configuration.host = Rails.configuration.admin_host - - api_client = DocuSign_Admin::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") - # Step 2 end - - # Step 3 start - options = DocuSign_Admin::GetUsersOptions.new - options.account_id = args[:account_id] - options.last_modified_since = (Date.today - 10).strftime('%Y/%m/%d') - - users_api = DocuSign_Admin::UsersApi.new(api_client) - modified_users = users_api.get_users(args[:organization_id], options).as_json['users'] - # Step 3 end - - # Step 5 start - results = [] - modified_users.each do |user| - userProfilesOptions = DocuSign_Admin::GetUserProfilesOptions.new - userProfilesOptions.email = user['email'] - result = users_api.get_user_profiles(args[:organization_id], userProfilesOptions) - results.push(result) - end - # Step 5 end - - return results - end + return results + end end \ No newline at end of file diff --git a/app/services/clickwrap/eg001_create_clickwrap_service.rb b/app/services/clickwrap/eg001_create_clickwrap_service.rb index d9a116b..3c2d798 100644 --- a/app/services/clickwrap/eg001_create_clickwrap_service.rb +++ b/app/services/clickwrap/eg001_create_clickwrap_service.rb @@ -3,16 +3,11 @@ class Clickwrap::Eg001CreateClickwrapService attr_reader :args - def initialize(session, request) - @args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - clickwrap_name: request[:clickwrapName] - } + def initialize(args) + @args = args end - def call + def worker # Step 2. Construct your API headers configuration = DocuSign_Click::Configuration.new configuration.host = args[:base_path] diff --git a/app/services/clickwrap/eg002_activate_clickwrap_service.rb b/app/services/clickwrap/eg002_activate_clickwrap_service.rb index 954c8e7..bc67256 100644 --- a/app/services/clickwrap/eg002_activate_clickwrap_service.rb +++ b/app/services/clickwrap/eg002_activate_clickwrap_service.rb @@ -3,16 +3,11 @@ class Clickwrap::Eg002ActivateClickwrapService attr_reader :args - def initialize(session) - @args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - clickwrap_id: session[:clickwrap_id] - } + def initialize(args) + @args = args end - def call + def worker # Step 2. Construct your API headers configuration = DocuSign_Click::Configuration.new configuration.host = args[:base_path] diff --git a/app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb b/app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb index 7ea4540..c416846 100644 --- a/app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb +++ b/app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb @@ -1,19 +1,13 @@ # frozen_string_literal: true class Clickwrap::Eg003CreateNewClickwrapVersionService - attr :args + attr_reader :args - def initialize(session) - @args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - clickwrap_id: session[:clickwrap_id], - clickwrap_name: session[:clickwrap_name] - } + def initialize(args) + @args = args end - def call + def worker # Step 2. Construct your API headers configuration = DocuSign_Click::Configuration.new configuration.host = args[:base_path] diff --git a/app/services/clickwrap/eg004_list_clickwraps_service.rb b/app/services/clickwrap/eg004_list_clickwraps_service.rb index c66d8a5..8f25046 100644 --- a/app/services/clickwrap/eg004_list_clickwraps_service.rb +++ b/app/services/clickwrap/eg004_list_clickwraps_service.rb @@ -3,15 +3,11 @@ class Clickwrap::Eg004ListClickwrapsService attr_reader :args - def initialize(session, _request) - @args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } + def initialize(args) + @args = args end - def call + def worker # Step 2. Construct your API headers configuration = DocuSign_Click::Configuration.new configuration.host = args[:base_path] diff --git a/app/services/clickwrap/eg005_clickwrap_responses_service.rb b/app/services/clickwrap/eg005_clickwrap_responses_service.rb index 079d0ae..31b9e26 100644 --- a/app/services/clickwrap/eg005_clickwrap_responses_service.rb +++ b/app/services/clickwrap/eg005_clickwrap_responses_service.rb @@ -3,17 +3,11 @@ class Clickwrap::Eg005ClickwrapResponsesService attr_reader :args - def initialize(session, request) - @args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - clickwrap_id: session[:clickwrap_id], - client_user_id: request[:client_user_id] - } + def initialize(args) + @args = args end - def call + def worker # Step 2. Construct your API headers configuration = DocuSign_Click::Configuration.new configuration.host = args[:base_path] diff --git a/app/services/e_sign/eg002_signing_via_email_service.rb b/app/services/e_sign/eg002_signing_via_email_service.rb index 2e5f827..a8cfd75 100644 --- a/app/services/e_sign/eg002_signing_via_email_service.rb +++ b/app/services/e_sign/eg002_signing_via_email_service.rb @@ -1,34 +1,16 @@ # frozen_string_literal: true class ESign::Eg002SigningViaEmailService + attr_reader :args include ApiCreator - attr_reader :args, :envelope_args - - def initialize(session, request, status) - @envelope_args = { - signer_email: request.params['signerEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name: request.params['signerName'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_email: request.params['ccEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_name: request.params['ccName'].gsub(/([^\w \-\@\.\,])+/, ''), - status: status - } - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: @envelope_args - } - end - def call - worker + def initialize(args) + @args = args end - private - def worker # 1. Create the envelope request object - envelope_definition = make_envelope + envelope_definition = make_envelope args[:envelope_args] # 2. Call Envelopes::create API method # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) @@ -38,7 +20,9 @@ def worker { 'envelope_id' => envelope_id } end - def make_envelope + private + + def make_envelope(envelope_args) # document 1 (HTML) has tag **signature_1** # document 2 (DOCX) has tag /sn1/ # document 3 (PDF) has tag /sn1/ @@ -55,7 +39,7 @@ def make_envelope envelope_definition.email_subject = 'Please sign this document set' # Add the documents - doc1_b64 = Base64.encode64(create_document1) + doc1_b64 = Base64.encode64(create_document1(envelope_args)) # Read files 2 and 3 from a local directory # The reads could raise an exception if the file is not available! doc_docx = Rails.application.config.doc_docx @@ -127,7 +111,7 @@ def make_envelope ) # Add the tabs model (including the sign_here tabs) to the signer # The Tabs object takes arrays of the different field/tab types - signer1_tabs = DocuSign_eSign::Tabs.new ({ + signer1_tabs = DocuSign_eSign::Tabs.new({ signHereTabs: [sign_here1, sign_here2] }) @@ -145,7 +129,7 @@ def make_envelope envelope_definition end - def create_document1 + def create_document1(args) " diff --git a/app/services/e_sign/eg003_list_envelopes_service.rb b/app/services/e_sign/eg003_list_envelopes_service.rb index 4d658a1..d4f7ddf 100644 --- a/app/services/e_sign/eg003_list_envelopes_service.rb +++ b/app/services/e_sign/eg003_list_envelopes_service.rb @@ -1,18 +1,14 @@ # frozen_string_literal: true class ESign::Eg003ListEnvelopesService - include ApiCreator attr_reader :args + include ApiCreator - def initialize(session) - @args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } + def initialize(args) + @args = args end - def call + def worker # Step 1. List the envelopes # The Envelopes::listStatusChanges method has many options # See https://developers.docusign.com/esign-rest-api/reference/Envelopes/Envelopes/listStatusChange# diff --git a/app/services/e_sign/eg004_envelope_info_service.rb b/app/services/e_sign/eg004_envelope_info_service.rb index 5d9c6d8..03e6d39 100644 --- a/app/services/e_sign/eg004_envelope_info_service.rb +++ b/app/services/e_sign/eg004_envelope_info_service.rb @@ -1,19 +1,14 @@ # frozen_string_literal: true class ESign::Eg004EnvelopeInfoService - include ApiCreator attr_reader :args + include ApiCreator - def initialize(session, envelope_id) - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_id: envelope_id - } + def initialize(args) + @args = args end - def call + def worker envelope_api = create_envelope_api(args) results = envelope_api.get_envelope(args[:account_id], args[:envelope_id]) end diff --git a/app/services/e_sign/eg005_envelope_recipients_service.rb b/app/services/e_sign/eg005_envelope_recipients_service.rb new file mode 100644 index 0000000..2309409 --- /dev/null +++ b/app/services/e_sign/eg005_envelope_recipients_service.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class ESign::Eg005EnvelopeRecipientsService + attr_reader :args + include ApiCreator + + def initialize(args) + @args = args + end + + def worker + envelope_api = create_envelope_api(args) + results = envelope_api.list_recipients args[:account_id], args[:envelope_id] + end +end diff --git a/app/services/e_sign/eg006_envelope_docs_service.rb b/app/services/e_sign/eg006_envelope_docs_service.rb index 49e299b..10874c4 100644 --- a/app/services/e_sign/eg006_envelope_docs_service.rb +++ b/app/services/e_sign/eg006_envelope_docs_service.rb @@ -1,46 +1,13 @@ # frozen_string_literal: true class ESign::Eg006EnvelopeDocsService + attr_reader :args include ApiCreator - attr_reader :args, :standart_doc_items, :session - def initialize(_request, session, envelope_id) - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_id: envelope_id - } - @session = session - # Save the envelopeId and its list of documents in the session so - # they can be used in example 7 (download a document) - @standart_doc_items = [ - { name: 'Combined', type: 'content', document_id: 'combined' }, - { name: 'Zip archive', type: 'zip', document_id: 'archive' } - ] + def initialize(args) + @args = args end - def call - results = worker - # The certificate of completion is named "summary" - # We give it a better name below. - envelope_doc_items = results.envelope_documents.map do |doc| - if doc.document_id == 'certificate' - new = { document_id: doc.document_id, name: 'Certificate of completion', type: doc.type } - else - new = { document_id: doc.document_id, name: doc.name, type: doc.type } - end - new - end - - documents = standart_doc_items + envelope_doc_items - envelope_documents = { envelope_id: args[:envelope_id], documents: documents } - session[:envelope_documents] = envelope_documents - results - end - - private - # ***DS.snippet.0.start def worker envelope_api = create_envelope_api(args) diff --git a/app/services/e_sign/eg007_envelope_get_doc_service.rb b/app/services/e_sign/eg007_envelope_get_doc_service.rb index 441470c..1d3a592 100644 --- a/app/services/e_sign/eg007_envelope_get_doc_service.rb +++ b/app/services/e_sign/eg007_envelope_get_doc_service.rb @@ -1,37 +1,23 @@ # frozen_string_literal: true class ESign::Eg007EnvelopeGetDocService + attr_reader :args include ApiCreator - attr_reader :args, :document_id - def initialize(request, session, envelope_id, envelope_documents) - document_id = request.params['docSelect'].gsub(/([^\w \-\@\.\,])+/, '') - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_id: envelope_id, - 'document_id' => document_id, - 'envelope_documents' => envelope_documents - } + def initialize(args) + @args = args end - def call - results = worker - end - - private - def worker # Step 3 start envelope_api = create_envelope_api(args) - document_id = args['document_id'] + document_id = args[:document_id] temp_file = envelope_api.get_document args[:account_id], document_id, args[:envelope_id] # Step 3 end # Find the matching document information item - doc_item = args['envelope_documents']['documents'].find { |item| item['document_id'] == document_id } + doc_item = args[:envelope_documents]['documents'].find { |item| item['document_id'] == document_id } doc_name = doc_item['name'] has_pdf_suffix = doc_name.upcase.end_with? '.PDF' diff --git a/app/services/e_sign/eg008_create_template_service.rb b/app/services/e_sign/eg008_create_template_service.rb index 319156e..084c8c7 100644 --- a/app/services/e_sign/eg008_create_template_service.rb +++ b/app/services/e_sign/eg008_create_template_service.rb @@ -1,34 +1,19 @@ # frozen_string_literal: true class ESign::Eg008CreateTemplateService + attr_reader :args include ApiCreator - attr_reader :args, :session, :template_name - def initialize(session) - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'] - } - @session = session - end - - def call - session[:template_id] = false # reset - @template_name = 'Example Signer and CC template' - results = worker - session[:template_id] = results[:template_id] - results + def initialize(args) + @args = args end - private - # ***DS.snippet.0.start def worker templates_api = create_template_api(args) # Step 1. Does the template exist? Try to look it up by name options = DocuSign_eSign::ListTemplatesOptions.new - options.search_text = template_name + options.search_text = args[:template_name] results = templates_api.list_templates(args[:account_id], options) created_new_template = false diff --git a/app/services/e_sign/eg009_use_template_service.rb b/app/services/e_sign/eg009_use_template_service.rb index 3cd81a5..0211dd2 100644 --- a/app/services/e_sign/eg009_use_template_service.rb +++ b/app/services/e_sign/eg009_use_template_service.rb @@ -1,32 +1,13 @@ # frozen_string_literal: true class ESign::Eg009UseTemplateService - include ApiCreator attr_reader :args + include ApiCreator - def initialize(request, session, template_id) - envelope_args = { - signer_email: request.params['signerEmail'], - signer_name: request.params['signerName'], - cc_email: request.params['ccEmail'], - cc_name: request.params['ccName'], - template_id: template_id - } - - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } - end - - def call - results = worker + def initialize(args) + @args = args end - private - # ***DS.snippet.0.start def worker envelope_args = args[:envelope_args] diff --git a/app/services/e_sign/eg010_send_binary_docs_service.rb b/app/services/e_sign/eg010_send_binary_docs_service.rb index e1e232d..ae75f96 100644 --- a/app/services/e_sign/eg010_send_binary_docs_service.rb +++ b/app/services/e_sign/eg010_send_binary_docs_service.rb @@ -1,38 +1,15 @@ class ESign::Eg010SendBinaryDocsService - attr_reader :args, :envelope_args, :session - - def initialize(request, session) - @envelope_args = { - # Validation: Delete any non-usual characters - signer_email: request.params['signerEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name: request.params['signerName'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_email: request.params['ccEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_name: request.params['ccName'].gsub(/([^\w \-\@\.\,])+/, '') - } - - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: @envelope_args - } + attr_reader :args - @session = session + def initialize(args) + @args = args end - def call - results = worker - session[:envelope_id] = results['envelope_id'] - results - end - - private - # ***DS.snippet.0.start def worker envelope_args = args[:envelope_args] # Step 1. Make the envelope JSON request body - envelopeJSON = make_envelope_json + envelopeJSON = make_envelope_json(envelope_args) # Step 2. Gather documents and their headers # Read files from a local directory # The reads could raise an exception if the file is not available! @@ -45,7 +22,7 @@ def worker filename: envelopeJSON[:documents][0][:name], document_id: envelopeJSON[:documents][0][:documentId], # See encoding note below for explanation - bytes: create_document1.force_encoding('ASCII-8BIT') }, + bytes: create_document1(envelope_args).force_encoding('ASCII-8BIT') }, { mime: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', filename: envelopeJSON[:documents][1][:name], document_id: envelopeJSON[:documents][1][:documentId], @@ -122,7 +99,6 @@ def worker if (response.code.to_i >= 200) && (response.code.to_i < 300) envelope_id = obj['envelopeId'] - session[:envelope_id] = envelope_id { 'envelope_id' => envelope_id } else raise Net::HTTPError.new(response.code, response.body) @@ -130,7 +106,7 @@ def worker end - def make_envelope_json + def make_envelope_json(envelope_args) # document 1 (HTML) has tag **signature_1** # document 2 (DOCX) has tag /sn1/ # document 3 (PDF) has tag /sn1/ @@ -217,7 +193,7 @@ def make_envelope_json env_json end - def create_document1 + def create_document1(args) " diff --git a/app/services/e_sign/eg011_embedded_sending_service.rb b/app/services/e_sign/eg011_embedded_sending_service.rb index 8c5e91e..cb157b8 100644 --- a/app/services/e_sign/eg011_embedded_sending_service.rb +++ b/app/services/e_sign/eg011_embedded_sending_service.rb @@ -1,34 +1,17 @@ # frozen_string_literal: true class ESign::Eg011EmbeddedSendingService + attr_reader :args include ApiCreator - attr_reader :args, :request, :session - - def initialize(request, session) - envelope_args = { - signer_email: request.params['signerEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name: request.params['signerName'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_email: request.params['ccEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_name: request.params['ccName'].gsub(/([^\w \-\@\.\,])+/, '') - } - - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - starting_view: request.params['starting_view'].gsub(/([^\w \-\@\.\,])+/, ''), - envelope_args: envelope_args, - ds_return_url: "#{Rails.application.config.app_url}/ds_common-return" - } - - @session = session - @request = request + + def initialize(args) + @args = args end - def call + def worker # Step 1. Create the envelope as a draft using eg002's worker # Exceptions will be caught by the calling function - results = ESign::Eg002SigningViaEmailService.new(session, request, 'created').call + results = create_envelope(args) envelope_id = results['envelope_id'] # Step 2. Create the sender view view_request = DocuSign_eSign::ReturnUrlRequest.new({ returnUrl: args[:ds_return_url] }) @@ -40,4 +23,148 @@ def call { 'envelope_id' => envelope_id, 'redirect_url' => url } end + + private + + def create_envelope(args) + envelope_definition = make_envelope args[:envelope_args] + # Exceptions will be caught by the calling function + envelope_api = create_envelope_api(args) + + results = envelope_api.create_envelope args[:account_id], envelope_definition + envelope_id = results.envelope_id + { 'envelope_id' => envelope_id } + end + + def make_envelope(envelope_args) + # 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 + + # Create the envelope definition + envelope_definition = DocuSign_eSign::EnvelopeDefinition.new + + envelope_definition.email_subject = 'Please sign this document set' + + # Add the documents + doc1_b64 = Base64.encode64(create_document1(envelope_args)) + # Read files 2 and 3 from a local directory + # The reads could raise an exception if the file is not available! + doc_docx = Rails.application.config.doc_docx + doc2_b64 = Base64.encode64(File.binread(File.join('data', doc_docx))) + doc_pdf = Rails.application.config.doc_pdf + doc3_b64 = Base64.encode64(File.binread(File.join('data', doc_pdf))) + + # Create the document models + document1 = DocuSign_eSign::Document.new( + # Create the DocuSign document object + documentBase64: doc1_b64, + name: 'Order acknowledgement', # Can be different from actual file name + fileExtension: 'html', # Many different document types are accepted + documentId: '1' # A label used to reference the doc + ) + document2 = DocuSign_eSign::Document.new( + # Create the DocuSign document object + documentBase64: doc2_b64, + name: 'Battle Plan', # Can be different from actual file name + fileExtension: 'docx', # Many different document types are accepted + documentId: '2' # A label used to reference the do + ) + document3 = DocuSign_eSign::Document.new( + # Create the DocuSign document object + documentBase64: doc3_b64, + name: 'Lorem Ipsum', # Can be different from actual file name + fileExtension: 'pdf', # Many different document types are accepted + documentId: '3' # A label used to reference the doc + ) + + # The order in the docs array determines the order in the envelope + envelope_definition.documents = [document1, document2, document3] + + # Create the signer recipient model + signer1 = DocuSign_eSign::Signer.new + signer1.email = envelope_args[:signer_email] + signer1.name = envelope_args[:signer_name] + signer1.recipient_id = '1' + signer1.routing_order = '1' + ## 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 + + # Create a cc recipient to receive a copy of the documents + cc1 = DocuSign_eSign::CarbonCopy.new( + email: envelope_args[:cc_email], + name: envelope_args[:cc_name], + routingOrder: '2', + recipientId: '2' + ) + # Create signHere fields (also known as tabs) on the documents + # We're using anchor (autoPlace) positioning + # + # The DocuSign platform searches throughout your envelope's documents for matching + # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 + # since they use the same anchor string for their "signer 1" tabs. + sign_here1 = DocuSign_eSign::SignHere.new( + anchorString: '**signature_1**', + anchorYOffset: '10', + anchorUnits: 'pixels', + anchorXOffset: '20' + ) + + sign_here2 = DocuSign_eSign::SignHere.new( + anchorString: '/sn1/', + anchorYOffset: '10', + anchorUnits: 'pixels', + anchorXOffset: '20' + ) + # Add the tabs model (including the sign_here tabs) to the signer + # The Tabs object takes arrays of the different field/tab types + signer1_tabs = DocuSign_eSign::Tabs.new ({ + signHereTabs: [sign_here1, sign_here2] + }) + + signer1.tabs = signer1_tabs + + # Add the recipients to the envelope object + recipients = DocuSign_eSign::Recipients.new( + signers: [signer1], + carbonCopies: [cc1] + ) + # Request that the envelope be sent by setting status to "sent". + # To request that the envelope be created as a draft, set status to "created" + envelope_definition.recipients = recipients + envelope_definition.status = envelope_args[:status] + envelope_definition + end + + def create_document1(args) + " + + + + + + +

World Wide Corp

+

Order Processing Division

+

Ordered by #{args[:signer_name]}

+

Email: #{args[:signer_email]}

+

Copy to: #{args[:cc_name]}, #{args[: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**/

+ + " + end end \ No newline at end of file diff --git a/app/services/e_sign/eg012_embedded_console_service.rb b/app/services/e_sign/eg012_embedded_console_service.rb index c5d312e..e01344f 100644 --- a/app/services/e_sign/eg012_embedded_console_service.rb +++ b/app/services/e_sign/eg012_embedded_console_service.rb @@ -1,29 +1,13 @@ # frozen_string_literal: true class ESign::Eg012EmbeddedConsoleService - include ApiCreator attr_reader :args + include ApiCreator - def initialize(session, envelope_id, request) - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_id: envelope_id, - starting_view: request.params['starting_view'], - ds_return_url: "#{Rails.application.config.app_url}/ds_common-return" - } - end - - def call - # Call the worker method - # More data validation would be a good idea here - # Strip anything other than characters listed - results = worker + def initialize(args) + @args = args end - private - # ***DS.snippet.0.start def worker # Step 1. Create the NDSE view request object diff --git a/app/services/e_sign/eg013_add_doc_to_template_service.rb b/app/services/e_sign/eg013_add_doc_to_template_service.rb index 1e81e36..6af6ed0 100644 --- a/app/services/e_sign/eg013_add_doc_to_template_service.rb +++ b/app/services/e_sign/eg013_add_doc_to_template_service.rb @@ -1,39 +1,13 @@ # frozen_string_literal: true class ESign::Eg013AddDocToTemplateService + attr_reader :args include ApiCreator - attr_reader :args, :envelope_args, :session - def initialize(request, session, template_id) - @envelope_args = { - signer_email: request.params['signerEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name: request.params['signerName'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_email: request.params['ccEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_name: request.params['ccName'].gsub(/([^\w \-\@\.\,])+/, ''), - item: request.params['item'].gsub(/([^\w \-\@\.\,])+/, ''), - quantity: request.params['quantity'].gsub(/([^\w \-\@\.\,])+/, '').to_i, - signer_client_id: 1000, - template_id: template_id, - ds_return_url: "#{Rails.application.config.app_url}/ds_common-return" - } - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } - @session = session + def initialize(args) + @args = args end - def call - results = worker - session[:envelope_id] = results[:envelope_id] # Save for use by other examples - results - end - - private - - # ***DS.snippet.0.start def worker envelope_args = args[:envelope_args] # 1. Create the envelope request object @@ -62,6 +36,8 @@ def worker { envelope_id: envelope_id, redirect_url: results.url } end + private + def make_envelope(args) # 1. Create recipients for server template. Note that the Recipients object # is used, not TemplateRole @@ -123,7 +99,7 @@ def make_envelope(args) ) # 6. Create the HTML document that will be added to the envelope - doc1_b64 = Base64.encode64(create_document1) + doc1_b64 = Base64.encode64(create_document1(args)) doc1 = DocuSign_eSign::Document.new( documentBase64: doc1_b64, name: 'Appendix 1--Sales order', # Can be different from actual file name @@ -150,7 +126,7 @@ def make_envelope(args) envelope_definition end - def create_document1 + def create_document1(args) <<~HEREDOC diff --git a/app/services/e_sign/eg014_collect_payment_service.rb b/app/services/e_sign/eg014_collect_payment_service.rb index 681decc..76e0e88 100644 --- a/app/services/e_sign/eg014_collect_payment_service.rb +++ b/app/services/e_sign/eg014_collect_payment_service.rb @@ -1,36 +1,16 @@ # frozen_string_literal: true class ESign::Eg014CollectPaymentService + attr_reader :args include ApiCreator - attr_reader :args, :envelope_args - - def initialize(request, session) - @envelope_args = { - signer_email: request.params['signerEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name: request.params['signerName'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_email: request.params['ccEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_name: request.params['ccName'].gsub(/([^\w \-\@\.\,])+/, ''), - gateway_account_id: Rails.application.config.gateway_account_id, - gateway_name: Rails.application.config.gateway_name, - gateway_display_name: Rails.application.config.gateway_display_name - } - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: @envelope_args - } - end - def call - results = worker args + def initialize(args) + @args = args end - private - # ***DS.snippet.0.start - def worker(args) - envelope_definition = make_envelope(envelope_args) + def worker + envelope_definition = make_envelope(args[:envelope_args]) # 2. Create and send the envelope # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) @@ -39,6 +19,8 @@ def worker(args) { envelope_id: envelope_id } end + private + def make_envelope(args) # This function creates the envelope definition for the order form # document 1 (html) has multiple tags: diff --git a/app/services/e_sign/eg015_get_envelope_tab_data_service.rb b/app/services/e_sign/eg015_get_envelope_tab_data_service.rb index abb5fe7..cb0382d 100644 --- a/app/services/e_sign/eg015_get_envelope_tab_data_service.rb +++ b/app/services/e_sign/eg015_get_envelope_tab_data_service.rb @@ -1,24 +1,13 @@ # frozen_string_literal: true class ESign::Eg015GetEnvelopeTabDataService + attr_reader :args include ApiCreator - attr_reader :args, :envelope_id - def initialize(envelope_id, session) - @args = { - access_token: session['ds_access_token'], - base_path: session['ds_base_path'], - account_id: session['ds_account_id'] - } - @envelope_id = envelope_id + def initialize(args) + @args = args end - def call - results = worker - end - - private - # ***DS.snippet.0.start def worker # Step 3. Call the eSignature REST API @@ -27,7 +16,7 @@ def worker # The get form data call requires an account ID and an envelope ID # Exceptions will be caught by the calling function - results = create_envelope_api(args).get_form_data args[:account_id], envelope_id + results = create_envelope_api(args).get_form_data args[:account_id], args[:envelope_id] end # ***DS.snippet.0.end end diff --git a/app/services/e_sign/eg016_set_envelope_tab_data_service.rb b/app/services/e_sign/eg016_set_envelope_tab_data_service.rb index 64bbaef..8394581 100644 --- a/app/services/e_sign/eg016_set_envelope_tab_data_service.rb +++ b/app/services/e_sign/eg016_set_envelope_tab_data_service.rb @@ -1,27 +1,13 @@ # frozen_string_literal: true class ESign::Eg016SetEnvelopeTabDataService + attr_reader :args include ApiCreator - attr_reader :args, :session - - def initialize(request, session) - @args = { - # Validation: Delete any non-usual characters - signer_email: request.params[:signerEmail].gsub(/([^\w\-.+@, ])+/, ''), - signer_name: request.params[:signerName].gsub(/([^\w\-., ])+/, ''), - access_token: session['ds_access_token'], - base_path: session['ds_base_path'], - account_id: session['ds_account_id'] - } - @session = session - end - def call - worker + def initialize(args) + @args = args end - private - # ***DS.snippet.0.start def worker ds_ping_url = Rails.application.config.app_url @@ -35,8 +21,6 @@ def worker # Step 5. Call the eSignature REST API results = create_envelope_api(args).create_envelope args[:account_id], envelope envelope_id = results.envelope_id - # Save for future use within the example launcher - session[:envelope_id] = envelope_id # Step 6. Create the View Request view_request = make_recipient_view_request(args[:signer_email], args[:signer_name], signer_client_id, ds_return_url, ds_ping_url) @@ -49,10 +33,10 @@ def worker # State can be stored/recovered using the framework's session or a # query parameter on the return URL (see the makeRecipientViewRequest method) # Redirect to results.url - results.url + { url: results.url, envelope_id: envelope_id } end - def make_recipient_view_request(_signer_email, _signer_name, signer_client_id, ds_return_url, ds_ping_url) + def make_recipient_view_request(signer_email, signer_name, signer_client_id, ds_return_url, ds_ping_url) view_request = DocuSign_eSign::RecipientViewRequest.new # Set the URL where you want the recipient to go once they are done signing; this # should typically be a callback route somewhere in your app. The query parameter @@ -66,8 +50,8 @@ def make_recipient_view_request(_signer_email, _signer_name, signer_client_id, d view_request.authentication_method = 'none' # Recipient information must match embedded recipient info we used to create the envelope - view_request.email = args[:signer_email] - view_request.user_name = args[:signer_name] + view_request.email = signer_email + view_request.user_name = signer_name view_request.client_user_id = signer_client_id # DocuSign recommends that you redirect to DocuSign for the embedded signing. There are @@ -81,7 +65,7 @@ def make_recipient_view_request(_signer_email, _signer_name, signer_client_id, d view_request end - def make_envelope(_signer_email, _signer_name, signer_client_id, pdf_filename) + def make_envelope(signer_email, signer_name, signer_client_id, pdf_filename) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document sent from Ruby SDK' @@ -96,7 +80,7 @@ def make_envelope(_signer_email, _signer_name, signer_client_id, pdf_filename) # Create a signer recipient to sign the document, identified by name and email # We're setting the parameters via the object creation signer1 = DocuSign_eSign::Signer.new ({ - email: args[:signer_email], name: args[:signer_name], + email: signer_email, name: signer_name, clientUserId: signer_client_id, recipientId: 1 }) @@ -117,7 +101,7 @@ def make_envelope(_signer_email, _signer_name, signer_client_id, pdf_filename) text_legal.font = 'Helvetica' text_legal.font_size = 'size11' text_legal.bold = 'true' - text_legal.value = args[:signer_name] + text_legal.value = signer_name text_legal.locked = 'false' text_legal.tab_id = 'legal_name' text_legal.tab_label = 'Legal name' @@ -130,7 +114,7 @@ def make_envelope(_signer_email, _signer_name, signer_client_id, pdf_filename) text_familiar.font = 'Helvetica' text_familiar.font_size = 'size11' text_familiar.bold = 'true' - text_familiar.value = args[:signer_name] + text_familiar.value = signer_name text_familiar.locked = 'false' text_familiar.tab_id = 'familiar_name' text_familiar.tab_label = 'Familiar name' diff --git a/app/services/e_sign/eg017_set_template_tab_values_service.rb b/app/services/e_sign/eg017_set_template_tab_values_service.rb index 1734e5c..d45da1c 100644 --- a/app/services/e_sign/eg017_set_template_tab_values_service.rb +++ b/app/services/e_sign/eg017_set_template_tab_values_service.rb @@ -1,30 +1,12 @@ # frozen_string_literal: true class ESign::Eg017SetTemplateTabValuesService -include ApiCreator -attr_reader :args, :envelope_args - -def initialize(request, session, template_id) - @envelope_args = { - signer_email: request.params['signerEmail'], - signer_name: request.params['signerName'], - cc_email: request.params['ccEmail'], - cc_name: request.params['ccName'], - template_id: template_id - } - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: @envelope_args - } -end - -def call - results = worker -end + attr_reader :args + include ApiCreator -private + def initialize(args) + @args = args + end # ***DS.snippet.0.start def worker @@ -41,7 +23,6 @@ def worker results = envelope_api.create_envelope args[:account_id], envelope_definition envelope_id = results.envelope_id - # Step 6. Create the View Request view_request = make_recipient_view_request(envelope_args[:signer_email], envelope_args[:signer_name], signer_client_id, ds_return_url, ds_ping_url) @@ -56,6 +37,8 @@ def worker results.url end +private + def make_envelope(args) # Create the envelope definition with the template_id envelope_definition = DocuSign_eSign::EnvelopeDefinition.new({ diff --git a/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb b/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb index ba7fd14..fb0156e 100644 --- a/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb +++ b/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb @@ -1,19 +1,14 @@ # frozen_string_literal: true class ESign::Eg018GetEnvelopeCustomFieldDataService - include ApiCreator attr_reader :args + include ApiCreator - def initialize(session, envelope_id) - @args = { - access_token: session['ds_access_token'], - base_path: session['ds_base_path'], - account_id: session['ds_account_id'], - envelope_id: envelope_id - } + def initialize(args) + @args = args end - def call + def worker # Step 3. Call the eSignature REST API results = create_envelope_api(args).list_custom_fields args[:account_id], args[:envelope_id] end diff --git a/app/services/e_sign/eg019_access_code_authentication_service.rb b/app/services/e_sign/eg019_access_code_authentication_service.rb index d721df1..89d3522 100644 --- a/app/services/e_sign/eg019_access_code_authentication_service.rb +++ b/app/services/e_sign/eg019_access_code_authentication_service.rb @@ -1,28 +1,17 @@ # frozen_string_literal: true class ESign::Eg019AccessCodeAuthenticationService + attr_reader :args include ApiCreator - attr_reader :args, :envelope_args, :request, :session - def initialize(request, session) - @envelope_args = { - signer_email: request.params['signerEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name: request.params['signerName'].gsub(/([^\w \-\@\.\,])+/, ''), - status: 'sent' - } - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: @envelope_args - } - @request = request - @session = session + def initialize(args) + @args = args end - def call + def worker # ***DS.snippet.0.start envelope_api = create_envelope_api(args) + envelope_args = args[:envelope_args] # Step 3: Construct your envelope JSON body envelope_definition = DocuSign_eSign::EnvelopeDefinition.new @@ -46,7 +35,7 @@ def call signer1.name = envelope_args[:signer_name] signer1.recipient_id = '1' signer1.routing_order = '1' - signer1.access_code = request.params['accessCode'] + signer1.access_code = args[:accessCode] sign_here1 = DocuSign_eSign::SignHere.new sign_here1.anchor_string = '/sn1/' @@ -71,8 +60,6 @@ def call envelope_definition.status = envelope_args[:status] # Step 4. Call the eSignature REST API results = envelope_api.create_envelope(args[:account_id], envelope_definition) - session[:envelope_id] = results.envelope_id - results # ***DS.snippet.0.end end end \ No newline at end of file diff --git a/app/services/e_sign/eg020_phone_authentication_service.rb b/app/services/e_sign/eg020_phone_authentication_service.rb index bcd6b85..0ae4906 100644 --- a/app/services/e_sign/eg020_phone_authentication_service.rb +++ b/app/services/e_sign/eg020_phone_authentication_service.rb @@ -1,33 +1,23 @@ # frozen_string_literal: true class ESign::Eg020PhoneAuthenticationService + attr_reader :args include ApiCreator - attr_reader :args, :envelope_args, :request, :session - - def initialize(request, session) - @request = request - @session = session - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: @envelope_args - } - @envelope_args = { - signer_email: request.params['signer_email'].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name: request.params['signer_name'].gsub(/([^\w \-\@\.\,])+/, ''), - country_code: request.params['country_code'].gsub(/([^\w \-\@\.\,])+/, ''), - phone_number: request.params['phone_number'].gsub(/([^\w \-\@\.\,])+/, ''), - workflow_id: get_workflow(@args), - status: 'sent' - } + + def initialize(args) + @args = args end - def call - if session[:workflow_id].blank? + def worker(workflow_id) + # ***DS.snippet.0.start + envelope_args = args[:envelope_args] + + if workflow_id.blank? return "phone_auth_not_enabled" end + envelope_api = create_envelope_api(args) + # Construct your envelope JSON body # Step 4 start envelope_definition = DocuSign_eSign::EnvelopeDefinition.new @@ -66,8 +56,8 @@ def call input_option.phone_number_list = [phone_number] identity_verification = DocuSign_eSign::RecipientIdentityVerification.new - identity_verification.workflow_id = session[:workflow_id] + identity_verification.workflow_id = workflow_id identity_verification.input_options = [input_option] signer1.identity_verification = identity_verification @@ -81,7 +71,7 @@ def call # Add the tabs model (including the sign_here tabs) to the signer # The Tabs object wants arrays of the different field/tab types - signer1_tabs = DocuSign_eSign::Tabs.new ({ + signer1_tabs = DocuSign_eSign::Tabs.new({ signHereTabs: [sign_here1] }) signer1.tabs = signer1_tabs @@ -99,11 +89,11 @@ def call # Call the eSignature REST API # Step 5 start envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope args[:account_id], envelope_definition + envelope_api.create_envelope args[:account_id], envelope_definition # Step 5 end end - def get_workflow(args) + def get_workflow #Retrieve the workflow id begin @@ -115,13 +105,12 @@ def get_workflow(args) if workflow_response.identity_verification phone_auth_workflow = workflow_response.identity_verification.find{ |item| item.default_name == "Phone Authentication" } if phone_auth_workflow - session[:workflow_id] = phone_auth_workflow.workflow_id - return session[:workflow_id] + phone_auth_workflow.workflow_id else return "" end else - return "" + return "" end # Step 3 end diff --git a/app/services/e_sign/eg022_kba_authentication_service.rb b/app/services/e_sign/eg022_kba_authentication_service.rb index 92c21c4..ed11917 100644 --- a/app/services/e_sign/eg022_kba_authentication_service.rb +++ b/app/services/e_sign/eg022_kba_authentication_service.rb @@ -1,28 +1,17 @@ # frozen_string_literal: true class ESign::Eg022KbaAuthenticationService + attr_reader :args include ApiCreator - attr_reader :args, :envelope_args, :request, :session - def initialize(request, session) - @envelope_args = { - signer_email: request.params['signerEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name: request.params['signerName'].gsub(/([^\w \-\@\.\,])+/, ''), - status: 'sent' - } - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: @envelope_args - } - @request = request - @session = session + def initialize(args) + @args = args end - def call + def worker # ***DS.snippet.0.start envelope_api = create_envelope_api(args) + envelope_args = args[:envelope_args] # Step 3: Construct your envelope JSON body envelope_definition = DocuSign_eSign::EnvelopeDefinition.new @@ -70,8 +59,6 @@ def call # Step 4. Call the eSignature REST API results = envelope_api.create_envelope args[:account_id], envelope_definition - session[:envelope_id] = results.envelope_id - results # ***DS.snippet.0.end end end \ No newline at end of file diff --git a/app/services/e_sign/eg023_idv_authentication_service.rb b/app/services/e_sign/eg023_idv_authentication_service.rb index 07f228e..4a678b3 100644 --- a/app/services/e_sign/eg023_idv_authentication_service.rb +++ b/app/services/e_sign/eg023_idv_authentication_service.rb @@ -1,28 +1,17 @@ # frozen_string_literal: true class ESign::Eg023IdvAuthenticationService + attr_reader :args include ApiCreator - attr_reader :args, :envelope_args, :request, :session - - def initialize(request, session) - @envelope_args = { - signer_email: request.params['signerEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name: request.params['signerName'].gsub(/([^\w \-\@\.\,])+/, ''), - status: 'sent' - } - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: @envelope_args - } - @request = request - @session = session + + def initialize(args) + @args = args end - def call - # Obtain your workflow ID - # Step 3 start + def worker + # ***DS.snippet.0.start + + # Step 3. Obtain your workflow ID accounts_api = create_account_api(args) workflow_response = accounts_api.get_account_identity_verification args[:account_id] if workflow_response.identity_verification @@ -40,7 +29,6 @@ def call puts "WORKFLOW ID: " puts workflow_id - # Construct your envelope JSON body # Step 4 start envelope_definition = DocuSign_eSign::EnvelopeDefinition.new diff --git a/app/services/e_sign/eg024_permission_create_service.rb b/app/services/e_sign/eg024_permission_create_service.rb index 60e7240..b4e2a1a 100644 --- a/app/services/e_sign/eg024_permission_create_service.rb +++ b/app/services/e_sign/eg024_permission_create_service.rb @@ -1,21 +1,16 @@ # frozen_string_literal: true class ESign::Eg024PermissionCreateService + attr_reader :args include ApiCreator - attr_reader :args, :request, :permission_profile_name - def initialize(session, request) - @args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } - @request = request - @permission_profile_name = request.params[:permission_profile_name] + def initialize(args) + @args = args end - def call + def worker accounts_api = create_account_api(args) + permission_profile_name = args[:permission_profile_name] permission_profile_settings = make_permission_profile_settings create_permission_account = accounts_api.create_permission_profile(args[:account_id], { permissionProfileName: permission_profile_name, settings: permission_profile_settings}, diff --git a/app/services/e_sign/eg025_permissions_set_user_group_service.rb b/app/services/e_sign/eg025_permissions_set_user_group_service.rb index 728dd14..171a3bb 100644 --- a/app/services/e_sign/eg025_permissions_set_user_group_service.rb +++ b/app/services/e_sign/eg025_permissions_set_user_group_service.rb @@ -1,25 +1,18 @@ # frozen_string_literal: true class ESign::Eg025PermissionsSetUserGroupService + attr_reader :args include ApiCreator - attr_reader :args, :permission_profile_id, :group_id - def initialize(session, request) - @args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } - @request = request - @permission_profile_id = request.params[:lists] - @group_id = request.params[:group_lists] + def initialize(args) + @args = args end - def call + def worker group_api = create_group_api(args) # Step 3: Construct the request body - params = {groups: [{permissionProfileId: permission_profile_id, groupId: group_id}]} + params = {groups: [{permissionProfileId: args[:permission_profile_id], groupId: args[:group_id]}]} # Step 4: Call the eSignature REST API result = group_api.update_groups(args[:account_id], params) diff --git a/app/services/e_sign/eg026_permissions_change_single_setting_service.rb b/app/services/e_sign/eg026_permissions_change_single_setting_service.rb index 31b0600..52ed413 100644 --- a/app/services/e_sign/eg026_permissions_change_single_setting_service.rb +++ b/app/services/e_sign/eg026_permissions_change_single_setting_service.rb @@ -1,22 +1,17 @@ # frozen_string_literal: true class ESign::Eg026PermissionsChangeSingleSettingService + attr_reader :args include ApiCreator - attr_reader :args, :request, :permission_profile_id - def initialize(session, request) - @args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } - @request = request - @permission_profile_id = request.params[:lists] + def initialize(args) + @args = args end - def call + def worker accounts_api = create_account_api(args) permission_profile_settings = make_permission_profile_settings + permission_profile_id = args[:permission_profile_id] update_permission_profile = accounts_api.update_permission_profile(args[:account_id], permission_profile_id, permission_profile_settings, options = DocuSign_eSign::UpdatePermissionProfileOptions.default) end diff --git a/app/services/e_sign/eg027_permissions_delete_service.rb b/app/services/e_sign/eg027_permissions_delete_service.rb index c9c2fd3..16d581c 100644 --- a/app/services/e_sign/eg027_permissions_delete_service.rb +++ b/app/services/e_sign/eg027_permissions_delete_service.rb @@ -1,22 +1,16 @@ # frozen_string_literal: true class ESign::Eg027PermissionsDeleteService + attr_reader :args include ApiCreator - attr_reader :args, :request, :permission_profile_id - def initialize(session, request) - @args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } - @request = request - @permission_profile_id = request.params[:lists] + def initialize(args) + @args = args end - def call + def worker # Step 3: Call the eSignature REST API accounts_api = create_account_api(args) - delete_permission_profile = accounts_api.delete_permission_profile(args[:account_id], permission_profile_id) + delete_permission_profile = accounts_api.delete_permission_profile(args[:account_id], args[:permission_profile_id]) end end \ No newline at end of file diff --git a/app/services/e_sign/eg028_brands_creating_service.rb b/app/services/e_sign/eg028_brands_creating_service.rb index 8f19665..48327eb 100644 --- a/app/services/e_sign/eg028_brands_creating_service.rb +++ b/app/services/e_sign/eg028_brands_creating_service.rb @@ -1,20 +1,14 @@ # frozen_string_literal: true class ESign::Eg028BrandsCreatingService + attr_reader :args include ApiCreator - attr_reader :args, :session, :request - def initialize(session, request) - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'] - } - @session = session - @request = request + def initialize(args) + @args = args end - def call + def worker # Step 1. Obtain your OAuth token configuration = DocuSign_eSign::Configuration.new configuration.host = args[:base_path] @@ -25,9 +19,9 @@ def call # Step 3: Construct your request body accounts_api = DocuSign_eSign::AccountsApi.new api_client - params = { brandName: request.params[:brandName], defaultBrandLanguage: request.params[:defaultBrandLanguage] } + params = { brandName: args[:brandName], defaultBrandLanguage: args[:defaultBrandLanguage] } # Step 4: Call the eSignature API - results = accounts_api.create_brand(session['ds_account_id'], params) + results = accounts_api.create_brand(args[:account_id], params) end end \ No newline at end of file diff --git a/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb b/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb index 1e59b63..2d2d90a 100644 --- a/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb +++ b/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb @@ -1,47 +1,33 @@ # frozen_string_literal: true class ESign::Eg029BrandsApplyToEnvelopeService + attr_reader :args include ApiCreator - attr_reader :envelope_args, :args, :session, :request - def initialize(session, request) - @envelope_args = { - signer_email: request.params[:signerEmail].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name: request.params[:signerName].gsub(/([^\w \-\@\.\,])+/, ''), - status: 'sent' - - } - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'] - } - @session = session - @request = request + def initialize(args) + @args = args end - def call + def worker # ***DS.snippet.0.start # Step 1. Obtain your OAuth token # Step 2. Construct your API headers envelope_api = create_envelope_api(args) # Step 3: Construct your envelope JSON body - envelope_definition = make_envelope + envelope_definition = make_envelope(args[:envelope_args]) # Step 4. Call the eSignature REST API results = envelope_api.create_envelope args[:account_id], envelope_definition - session[:envelope_id] = results.envelope_id - results # ***DS.snippet.0.end end private - def make_envelope + def make_envelope(envelope_args) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_blurb = 'Sample text for email body' envelope_definition.email_subject = 'Please Sign' envelope_definition.envelope_id_stamping = true - envelope_definition.brand_id = request.params[:brands] + envelope_definition.brand_id = envelope_args[:brands] # Add the documents and create the document models pdf_filename = 'World_Wide_Corp_lorem.pdf' diff --git a/app/services/e_sign/eg030_brands_apply_to_template_service.rb b/app/services/e_sign/eg030_brands_apply_to_template_service.rb index ea7e101..9eb5aba 100644 --- a/app/services/e_sign/eg030_brands_apply_to_template_service.rb +++ b/app/services/e_sign/eg030_brands_apply_to_template_service.rb @@ -1,49 +1,33 @@ # frozen_string_literal: true class ESign::Eg030BrandsApplyToTemplateService + attr_reader :args include ApiCreator - attr_reader :envelope_args, :args, :session, :request - def initialize(session, request) - @envelope_args = { - signer_email: request.params[:signerEmail].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name: request.params[:signerName].gsub(/([^\w \-\@\.\,])+/, ''), - cc_email: request.params['ccEmail'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_name: request.params['ccName'].gsub(/([^\w \-\@\.\,])+/, ''), - status: 'sent' - - } - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'] - } - @session = session - @request = request + def initialize(args) + @args = args end - def call + def worker # ***DS.snippet.0.start # Step 1. Obtain your OAuth token # Step 2. Construct your API headers envelope_api = create_envelope_api(args) # Step 3. Construct your envelope JSON body - envelope_definition = make_envelope + envelope_definition = make_envelope(args[:envelope_args]) # Step 4. Call the eSignature REST API results = envelope_api.create_envelope args[:account_id], envelope_definition - session[:envelope_id] = results.envelope_id - results # ***DS.snippet.0.end end private - def make_envelope + def make_envelope(envelope_args) # Create the envelope definition with the template_id envelope_definition = DocuSign_eSign::EnvelopeDefinition.new # envelope_definition.envelope_id_stamping = true - envelope_definition.template_id = request.params[:templates] - envelope_definition.brand_id = request.params[:brands] + envelope_definition.template_id = envelope_args[:template_id] + envelope_definition.brand_id = envelope_args[:brand_id] envelope_definition.status = envelope_args[:status] # Create the template role elements to connect the signer and cc recipients # to the template diff --git a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb index 0eca8a9..297b652 100644 --- a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb +++ b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb @@ -1,42 +1,27 @@ # frozen_string_literal: true class ESign::Eg031BulkSendingEnvelopesService - include ApiCreator attr_reader :args, :signers + include ApiCreator - def initialize(request, session) - @signers = { - signer_email: request.params['signerEmail1'].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name: request.params['signerName1'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_email: request.params['ccEmail1'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_name: request.params['ccName1'].gsub(/([^\w \-\@\.\,])+/, ''), - status: 'created', - - signer_email1: request.params['signerEmail2'].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name1: request.params['signerName2'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_email1: request.params['ccEmail2'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_name1: request.params['ccName2'].gsub(/([^\w \-\@\.\,])+/, '') - } - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'] - } + def initialize(args, signers) + @args = args + @signers = signers end - def call + def worker # Construct your API headers # Step 2 start configuration = DocuSign_eSign::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_eSign::ApiClient.new configuration - construct_api_headers(api_client) + construct_api_headers(api_client, args) # Step end # Create and submit the bulk sending list # Step 3-1 start bulk_envelopes_api = DocuSign_eSign::BulkEnvelopesApi.new api_client - bulk_sending_list = create_bulk_sending_list + bulk_sending_list = create_bulk_sending_list(signers) bulk_list = bulk_envelopes_api.create_bulk_send_list(args[:account_id], bulk_sending_list) bulk_list_id = bulk_list.list_id # Step 3-1 end @@ -69,7 +54,7 @@ def call private - def construct_api_headers(api_client) + def construct_api_headers(api_client, args) api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" api_client.default_headers['Content-Type'] = "application/json;charset=UTF-8" api_client.default_headers['Accept'] = "application/json, text/plain, */*" @@ -78,7 +63,7 @@ def construct_api_headers(api_client) end # Step 3-2 start - def create_bulk_sending_list + def create_bulk_sending_list(signers) bulk_copies = [] recipient1 = DocuSign_eSign::BulkSendingCopyRecipient.new( roleName: 'signer', diff --git a/app/services/e_sign/eg032_pauses_signature_workflow_service.rb b/app/services/e_sign/eg032_pauses_signature_workflow_service.rb index 9e805c3..5c4571a 100644 --- a/app/services/e_sign/eg032_pauses_signature_workflow_service.rb +++ b/app/services/e_sign/eg032_pauses_signature_workflow_service.rb @@ -1,27 +1,15 @@ # frozen_string_literal: true class ESign::Eg032PausesSignatureWorkflowService - include ApiCreator attr_reader :args, :signers + include ApiCreator - def initialize(session, request) - @signers = { - signerEmail1: request['signerEmail1'], - signerName1: request['signerName1'], - - signerEmail2: request['signerEmail2'], - signerName2: request['signerName2'] - } - - @args = { - accountId: session['ds_account_id'], - basePath: session['ds_base_path'], - accessToken: session['ds_access_token'], - status: 'sent' - } + def initialize(args, signers) + @args = args + @signers = signers end - def call + def worker # Step 2. Construct your API headers configuration = DocuSign_eSign::Configuration.new configuration.host = args[:basePath] diff --git a/app/services/e_sign/eg033_unpauses_signature_workflow_service.rb b/app/services/e_sign/eg033_unpauses_signature_workflow_service.rb index 325191f..2b30b9a 100644 --- a/app/services/e_sign/eg033_unpauses_signature_workflow_service.rb +++ b/app/services/e_sign/eg033_unpauses_signature_workflow_service.rb @@ -1,20 +1,14 @@ # frozen_string_literal: true class ESign::Eg033UnpausesSignatureWorkflowService + attr_reader :args include ApiCreator - attr_reader :args, :signers - - def initialize(session) - @args = { - accountId: session['ds_account_id'], - basePath: session['ds_base_path'], - accessToken: session['ds_access_token'], - envelopeId: session['envelope_id'], - status: 'in_progress' - } + + def initialize(args) + @args = args end - def call + def worker # Step 2. Construct your API headers configuration = DocuSign_eSign::Configuration.new configuration.host = args[:basePath] diff --git a/app/services/e_sign/eg034_use_conditional_recipients_service.rb b/app/services/e_sign/eg034_use_conditional_recipients_service.rb index 0c09ef1..6d8669e 100644 --- a/app/services/e_sign/eg034_use_conditional_recipients_service.rb +++ b/app/services/e_sign/eg034_use_conditional_recipients_service.rb @@ -1,29 +1,15 @@ # frozen_string_literal: true class ESign::Eg034UseConditionalRecipientsService - include ApiCreator attr_reader :args, :signers + include ApiCreator - def initialize(session, request) - @signers = { - signerEmail1: request['signerEmail1'], - signerName1: request['signerName1'], - - signerEmailNotChecked: request['signerEmailNotChecked'], - signerNameNotChecked: request['signerNameNotChecked'], - - signerEmailChecked: request['signerEmailChecked'], - signerNameChecked: request['signerNameChecked'] - } - - @args = { - accountId: session['ds_account_id'], - basePath: session['ds_base_path'], - accessToken: session['ds_access_token'] - } + def initialize(args, signers) + @args = args + @signers = signers end - def call + def worker # Step 2. Construct your API headers configuration = DocuSign_eSign::Configuration.new configuration.host = args[:basePath] diff --git a/app/services/e_sign/eg035_sms_delivery_service.rb b/app/services/e_sign/eg035_sms_delivery_service.rb index 2fc6186..3981fee 100644 --- a/app/services/e_sign/eg035_sms_delivery_service.rb +++ b/app/services/e_sign/eg035_sms_delivery_service.rb @@ -1,198 +1,178 @@ # frozen_string_literal: true class ESign::Eg035SmsDeliveryService - include ApiCreator - attr_reader :args, :envelope_args - - def initialize(session, request, status) - @envelope_args = { - signer_email: request.params['signer_email'].gsub(/([^\w \-\@\.\,])+/, ''), - signer_name: request.params['signer_name'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_email: request.params['cc_email'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_name: request.params['cc_name'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_phone_number: request.params['cc_phone_number'].gsub(/([^\w \-\@\.\,])+/, ''), - cc_country_code: request.params['cc_country_code'].gsub(/([^\w \-\@\.\,])+/, ''), - phone_number: request.params['phone_number'].gsub(/([^\w \-\@\.\,])+/, ''), - country_code: request.params['country_code'].gsub(/([^\w \-\@\.\,])+/, ''), - status: status - } - @args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: @envelope_args - } - end - - def call - worker - end - - private - - def worker - # Create the envelope request object - envelope_definition = make_envelope + attr_reader :args + include ApiCreator - # Step 3. Create and send the envelope - # Call Envelopes::create API method - # Exceptions will be caught by the calling function - envelope_api = create_envelope_api(args) - - results = envelope_api.create_envelope args[:account_id], envelope_definition - envelope_id = results.envelope_id - { 'envelope_id' => envelope_id } - end - - def make_envelope - # 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 via SMS - # After it is signed, a copy is sent to the cc person via SMS - - # Step 2. Create the envelope definition - envelope_definition = DocuSign_eSign::EnvelopeDefinition.new - - envelope_definition.email_subject = 'Please sign this document set' - - # Add the documents - doc1_b64 = Base64.encode64(create_document1) - # Read files 2 and 3 from a local directory - # The reads could raise an exception if the file is not available! - doc_docx = Rails.application.config.doc_docx - doc2_b64 = Base64.encode64(File.binread(File.join('data', doc_docx))) - doc_pdf = Rails.application.config.doc_pdf - doc3_b64 = Base64.encode64(File.binread(File.join('data', doc_pdf))) - - # Create the document models - document1 = DocuSign_eSign::Document.new( - # Create the DocuSign document object - documentBase64: doc1_b64, - name: 'Order acknowledgement', # Can be different from actual file name - fileExtension: 'html', # Many different document types are accepted - documentId: '1' # A label used to reference the doc - ) - document2 = DocuSign_eSign::Document.new( - # Create the DocuSign document object - documentBase64: doc2_b64, - name: 'Battle Plan', # Can be different from actual file name - fileExtension: 'docx', # Many different document types are accepted - documentId: '2' # A label used to reference the do - ) - document3 = DocuSign_eSign::Document.new( - # Create the DocuSign document object - documentBase64: doc3_b64, - name: 'Lorem Ipsum', # Can be different from actual file name - fileExtension: 'pdf', # Many different document types are accepted - documentId: '3' # A label used to reference the doc - ) - - # The order in the docs array determines the order in the envelope - envelope_definition.documents = [document1, document2, document3] + def initialize(args) + @args = args + end - phone_number = DocuSign_eSign::RecipientPhoneNumber.new - phone_number.country_code=envelope_args[:country_code] - phone_number.number=envelope_args[:phone_number] - - sms_notification = DocuSign_eSign::RecipientAdditionalNotification.new - sms_notification.phone_number = phone_number - sms_notification.secondary_delivery_method = "SMS" - - # Create the signer recipient model - signer1 = DocuSign_eSign::Signer.new - signer1.additional_notifications=[sms_notification] - signer1.email = envelope_args[:signer_email] - signer1.name = envelope_args[:signer_name] - signer1.recipient_id = '1' - signer1.routing_order = '1' - ## 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 + def worker + # Create the envelope request object + envelope_definition = make_envelope(args[:envelope_args]) - # Create a RecipientPhoneNumber and add it to the additional SMS notification - cc_phone_number = DocuSign_eSign::RecipientPhoneNumber.new - cc_phone_number.country_code=envelope_args[:cc_country_code] - cc_phone_number.number=envelope_args[:cc_phone_number] - + # Step 3. Create and send the envelope + # Call Envelopes::create API method + # Exceptions will be caught by the calling function + envelope_api = create_envelope_api(args) + + results = envelope_api.create_envelope args[:account_id], envelope_definition + envelope_id = results.envelope_id + { 'envelope_id' => envelope_id } + end - cc_sms_notification = DocuSign_eSign::RecipientAdditionalNotification.new - cc_sms_notification.phone_number=cc_phone_number - cc_sms_notification.secondary_delivery_method = "SMS" - - # Create a cc recipient to receive a copy of the documents - cc1 = DocuSign_eSign::CarbonCopy.new( - email: envelope_args[:cc_email], - name: envelope_args[:cc_name], - routingOrder: '2', - recipientId: '2', - additionalNotifications: [cc_sms_notification] - ) - # Create signHere fields (also known as tabs) on the documents - # We're using anchor (autoPlace) positioning - # - # The DocuSign platform searches throughout your envelope's documents for matching - # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 - # since they use the same anchor string for their "signer 1" tabs. - sign_here1 = DocuSign_eSign::SignHere.new( - anchorString: '**signature_1**', - anchorYOffset: '10', - anchorUnits: 'pixels', - anchorXOffset: '20' - ) - - sign_here2 = DocuSign_eSign::SignHere.new( - anchorString: '/sn1/', - anchorYOffset: '10', - anchorUnits: 'pixels', - anchorXOffset: '20' - ) - # Add the tabs model (including the sign_here tabs) to the signer - # The Tabs object takes arrays of the different field/tab types - signer1_tabs = DocuSign_eSign::Tabs.new ({ - signHereTabs: [sign_here1, sign_here2] - }) - - signer1.tabs = signer1_tabs - - # Add the recipients to the envelope object - recipients = DocuSign_eSign::Recipients.new( - signers: [signer1], - carbonCopies: [cc1] - ) - # Request that the envelope be sent by setting status to "sent". - # To request that the envelope be created as a draft, set status to "created" - envelope_definition.recipients = recipients - envelope_definition.status = envelope_args[:status] - envelope_definition - end - - def create_document1 - " - - - - - - -

World Wide Corp

-

Order Processing Division

-

Ordered by #{args[:signer_name]}

-

Email: #{args[:signer_email]}

-

Copy to: #{args[:cc_name]}, #{args[: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**/

- - " - end - end \ No newline at end of file + private + + def make_envelope(envelope_args) + # 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 via SMS + # After it is signed, a copy is sent to the cc person via SMS + + # Step 2. Create the envelope definition + envelope_definition = DocuSign_eSign::EnvelopeDefinition.new + + envelope_definition.email_subject = 'Please sign this document set' + + # Add the documents + doc1_b64 = Base64.encode64(create_document1(envelope_args)) + # Read files 2 and 3 from a local directory + # The reads could raise an exception if the file is not available! + doc_docx = Rails.application.config.doc_docx + doc2_b64 = Base64.encode64(File.binread(File.join('data', doc_docx))) + doc_pdf = Rails.application.config.doc_pdf + doc3_b64 = Base64.encode64(File.binread(File.join('data', doc_pdf))) + + # Create the document models + document1 = DocuSign_eSign::Document.new( + # Create the DocuSign document object + documentBase64: doc1_b64, + name: 'Order acknowledgement', # Can be different from actual file name + fileExtension: 'html', # Many different document types are accepted + documentId: '1' # A label used to reference the doc + ) + document2 = DocuSign_eSign::Document.new( + # Create the DocuSign document object + documentBase64: doc2_b64, + name: 'Battle Plan', # Can be different from actual file name + fileExtension: 'docx', # Many different document types are accepted + documentId: '2' # A label used to reference the do + ) + document3 = DocuSign_eSign::Document.new( + # Create the DocuSign document object + documentBase64: doc3_b64, + name: 'Lorem Ipsum', # Can be different from actual file name + fileExtension: 'pdf', # Many different document types are accepted + documentId: '3' # A label used to reference the doc + ) + + # The order in the docs array determines the order in the envelope + envelope_definition.documents = [document1, document2, document3] + + phone_number = DocuSign_eSign::RecipientPhoneNumber.new + phone_number.country_code=envelope_args[:country_code] + phone_number.number=envelope_args[:phone_number] + + sms_notification = DocuSign_eSign::RecipientAdditionalNotification.new + sms_notification.phone_number = phone_number + sms_notification.secondary_delivery_method = "SMS" + + # Create the signer recipient model + signer1 = DocuSign_eSign::Signer.new + signer1.additional_notifications=[sms_notification] + signer1.email = envelope_args[:signer_email] + signer1.name = envelope_args[:signer_name] + signer1.recipient_id = '1' + signer1.routing_order = '1' + ## 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 + + # Create a RecipientPhoneNumber and add it to the additional SMS notification + cc_phone_number = DocuSign_eSign::RecipientPhoneNumber.new + cc_phone_number.country_code=envelope_args[:cc_country_code] + cc_phone_number.number=envelope_args[:cc_phone_number] + + + cc_sms_notification = DocuSign_eSign::RecipientAdditionalNotification.new + cc_sms_notification.phone_number=cc_phone_number + cc_sms_notification.secondary_delivery_method = "SMS" + + # Create a cc recipient to receive a copy of the documents + cc1 = DocuSign_eSign::CarbonCopy.new( + email: envelope_args[:cc_email], + name: envelope_args[:cc_name], + routingOrder: '2', + recipientId: '2', + additionalNotifications: [cc_sms_notification] + ) + # Create signHere fields (also known as tabs) on the documents + # We're using anchor (autoPlace) positioning + # + # The DocuSign platform searches throughout your envelope's documents for matching + # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 + # since they use the same anchor string for their "signer 1" tabs. + sign_here1 = DocuSign_eSign::SignHere.new( + anchorString: '**signature_1**', + anchorYOffset: '10', + anchorUnits: 'pixels', + anchorXOffset: '20' + ) + + sign_here2 = DocuSign_eSign::SignHere.new( + anchorString: '/sn1/', + anchorYOffset: '10', + anchorUnits: 'pixels', + anchorXOffset: '20' + ) + # Add the tabs model (including the sign_here tabs) to the signer + # The Tabs object takes arrays of the different field/tab types + signer1_tabs = DocuSign_eSign::Tabs.new({ + signHereTabs: [sign_here1, sign_here2] + }) + + signer1.tabs = signer1_tabs + + # Add the recipients to the envelope object + recipients = DocuSign_eSign::Recipients.new( + signers: [signer1], + carbonCopies: [cc1] + ) + # Request that the envelope be sent by setting status to "sent". + # To request that the envelope be created as a draft, set status to "created" + envelope_definition.recipients = recipients + envelope_definition.status = envelope_args[:status] + envelope_definition + end + + def create_document1(args) + " + + + + + + +

World Wide Corp

+

Order Processing Division

+

Ordered by #{args[:signer_name]}

+

Email: #{args[:signer_email]}

+

Copy to: #{args[:cc_name]}, #{args[: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**/

+ + " + end +end \ No newline at end of file diff --git a/app/services/eg001_embedded_signing_service.rb b/app/services/eg001_embedded_signing_service.rb index 9c8190a..0bfebc7 100644 --- a/app/services/eg001_embedded_signing_service.rb +++ b/app/services/eg001_embedded_signing_service.rb @@ -1,34 +1,24 @@ # frozen_string_literal: true class Eg001EmbeddedSigningService + attr_reader :args include ApiCreator - attr_reader :signer_email, :signer_name, :args - - def initialize(session, request) - @signer_email = request.params[:signerEmail].gsub(/([^\w \-\@\.\,])+/, '') - @signer_name = request.params[:signerName].gsub(/([^\w \-\@\.\,])+/, '') - @args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } - end - def call - redirect_url = worker + def initialize(args) + @args = args end - private - # ***DS.snippet.0.start def worker - ds_ping_url = Rails.application.config.app_url + ds_ping_url = args[:ds_ping_url] ds_return_url = "#{ds_ping_url}/ds_common-return" - signer_client_id = 1000 - pdf_filename = 'World_Wide_Corp_lorem.pdf' + signer_client_id = args[:signer_client_id] + pdf_filename = args[:pdf_filename] + signer_email = args[:signer_email] + signer_name = args[:signer_name] # Step 1. Create the envelope definition - envelope = make_envelope(signer_client_id, pdf_filename) + envelope = make_envelope(args[:signer_client_id], pdf_filename, signer_email, signer_name) # Step 2. Call DocuSign to create the envelope envelope_api = create_envelope_api(args) @@ -39,7 +29,7 @@ def worker # session[:envelope_id] = envelope_id # Step 3. Create the recipient view for the embedded signing - view_request = make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url + view_request = make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, signer_email, signer_name ) # Call the CreateRecipientView API @@ -53,7 +43,9 @@ def worker results.url end - def make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url) + private + + def make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, signer_email, signer_name) view_request = DocuSign_eSign::RecipientViewRequest.new # 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. @@ -86,12 +78,12 @@ def make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url) view_request end - def make_envelope(signer_client_id, pdf_filename) + def make_envelope(signer_client_id, pdf_filename, signer_email, signer_name) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document sent from Ruby SDK' doc1 = DocuSign_eSign::Document.new - doc1.document_base64 = Base64.encode64(File.binread(File.join('data', pdf_filename))) + doc1.document_base64 = Base64.encode64(File.binread(pdf_filename)) doc1.name = 'Lorem Ipsum' doc1.file_extension = 'pdf' doc1.document_id = '1' diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index a687b07..6cf1da2 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -13,15 +13,17 @@ def self.consent_url(state, examples_API) # GET /oauth/auth # This endpoint is used to obtain consent and is the first step in several authentication flows. # https://developers.docusign.com/platform/auth/reference/obtain-consent - scope = "signature" + scope = "signature impersonation" if examples_API == 'Rooms' - scope = "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" - elsif examples_API == 'Click' - scope = "signature click.manage click.send" - elsif examples_API == 'Admin' - scope = "signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" + scope = "#{scope} 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" end - scope = "#{scope} impersonation" + if examples_API == 'Click' + scope = "#{scope} click.manage click.send" + end + if examples_API == 'Admin' + scope = "#{scope} organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" + end + base_uri = "#{Rails.configuration.authorization_server}/oauth/auth" response_type = "code" scopes = ERB::Util.url_encode(scope) # https://developers.docusign.com/platform/auth/reference/scopes/ @@ -34,21 +36,25 @@ def self.consent_url(state, examples_API) def initialize(session) @session = session - scope = "signature" + scope = "signature impersonation" @client_module = DocuSign_eSign if session[:examples_API] == 'Rooms' - scope = "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" + scope = "#{scope} 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" @client_module = DocuSign_Rooms - elsif session[:examples_API] == 'Click' - scope = "signature click.manage click.send" + end + if session[:examples_API] == 'Click' + scope = "#{scope} click.manage click.send" @client_module = DocuSign_Click - elsif session[:examples_API] == 'Monitor' + end + if session[:examples_API] == 'Monitor' @client_module = DocuSign_Monitor - elsif session[:examples_API] == 'Admin' - scope = "signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" + end + if session[:examples_API] == 'Admin' + scope = "#{scope} organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" @client_module = DocuSign_Admin end - @scope = "#{scope} impersonation" + + @scope = scope @api_client = create_initial_api_client(host: Rails.configuration.aud, client_module: @client_module, debugging: false) end diff --git a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb index 8fee741..378aa57 100644 --- a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb +++ b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb @@ -3,16 +3,11 @@ class MonitorApi::Eg001GetMonitoringDatasetService attr_reader :args - def initialize(session, _request) - @args = { - # account_id: session[:ds_account_id], - access_token: session[:ds_access_token] - } - @cursor = '' - @results_memo = [] + def initialize(args) + @args = args end - def call + def worker # step 2 start configuration = DocuSign_Monitor::Configuration.new configuration.host = Rails.configuration.monitor_host @@ -23,8 +18,7 @@ def call # step 3 start monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) - options = DocuSign_Monitor::GetStreamOptions.default - @response = monitor_api.get_stream('monitor', '2.0').data + @response = monitor_api.get_stream(args[:data_set_name], args[:version]).data # step 3 end diff --git a/app/services/room_api/eg001_create_room_with_data_service.rb b/app/services/room_api/eg001_create_room_with_data_service.rb index 141f70a..f6cf4cc 100644 --- a/app/services/room_api/eg001_create_room_with_data_service.rb +++ b/app/services/room_api/eg001_create_room_with_data_service.rb @@ -3,23 +3,10 @@ class RoomApi::Eg001CreateRoomWithDataService attr_reader :args - def initialize(session, request) - @args = { - room_name: request.params[:roomName], - office_id: RoomApi::GetDataService.new(session).get_offices[0]['officeId'], - role_id: RoomApi::GetDataService.new(session).get_roles[2]['roleId'], - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } + def initialize(args) + @args = args end - def call - worker - end - - private - def worker configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host @@ -29,10 +16,12 @@ def worker rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) - response = rooms_api.create_room(args[:account_id], body) + response = rooms_api.create_room(args[:account_id], body(args)) end - def body + private + + def body(args) DocuSign_Rooms::RoomForCreate.new( { name: args[:room_name], diff --git a/app/services/room_api/eg002_create_room_with_template_service.rb b/app/services/room_api/eg002_create_room_with_template_service.rb index c7dd105..fcbe052 100644 --- a/app/services/room_api/eg002_create_room_with_template_service.rb +++ b/app/services/room_api/eg002_create_room_with_template_service.rb @@ -3,24 +3,10 @@ class RoomApi::Eg002CreateRoomWithTemplateService attr_reader :args - def initialize(session, request) - @args = { - room_name: request.params[:roomName], - office_id: RoomApi::GetDataService.new(session).get_offices[0]['officeId'], - role_id: RoomApi::GetDataService.new(session).get_roles[2]['roleId'], - template_id: request.params['templateId'], - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } + def initialize(args) + @args = args end - def call - worker - end - - private - def worker configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host @@ -29,10 +15,12 @@ def worker api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) - response = rooms_api.create_room(args[:account_id], body) + response = rooms_api.create_room(args[:account_id], body(args)) end - def body + private + + def body(args) DocuSign_Rooms::RoomForCreate.new( { name: args[:room_name], diff --git a/app/services/room_api/eg003_export_data_from_room_service.rb b/app/services/room_api/eg003_export_data_from_room_service.rb index 7424de8..1242096 100644 --- a/app/services/room_api/eg003_export_data_from_room_service.rb +++ b/app/services/room_api/eg003_export_data_from_room_service.rb @@ -1,23 +1,12 @@ # frozen_string_literal: true class RoomApi::Eg003ExportDataFromRoomService - attr :args + attr_reader :args - def initialize(session, request) - @args = { - room_id: request.params['roomId'], - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } + def initialize(args) + @args = args end - def call - worker - end - - private - def worker configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host diff --git a/app/services/room_api/eg004_add_forms_to_room_service.rb b/app/services/room_api/eg004_add_forms_to_room_service.rb index 18771c3..28235e5 100644 --- a/app/services/room_api/eg004_add_forms_to_room_service.rb +++ b/app/services/room_api/eg004_add_forms_to_room_service.rb @@ -3,22 +3,10 @@ class RoomApi::Eg004AddFormsToRoomService attr_reader :args - def initialize(session, request) - @args = { - form_id: request.params['formId'], - room_id: request.params['roomId'], - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } + def initialize(args) + @args = args end - def call - worker - end - - private - def worker configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host @@ -28,12 +16,12 @@ def worker rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) - rooms_api.add_form_to_room(args[:room_id], args[:account_id], body) + rooms_api.add_form_to_room(args[:room_id], args[:account_id], body(args[:form_id])) end - def body + def body(form_id) DocuSign_Rooms::FormForAdd.new({ - formId: args[:form_id] + formId: form_id }) end end \ No newline at end of file diff --git a/app/services/room_api/eg005_get_rooms_with_filters_service.rb b/app/services/room_api/eg005_get_rooms_with_filters_service.rb index 0564517..daf5217 100644 --- a/app/services/room_api/eg005_get_rooms_with_filters_service.rb +++ b/app/services/room_api/eg005_get_rooms_with_filters_service.rb @@ -1,24 +1,12 @@ # frozen_string_literal: true class RoomApi::Eg005GetRoomsWithFiltersService - attr :args + attr_reader :args - def initialize(session, request) - @args = { - date_from: request.params[:date_from], - date_to: request.params[:date_to], - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } + def initialize(args) + @args = args end - def call - worker - end - - private - def worker configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host diff --git a/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb b/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb index a6e0707..21efb67 100644 --- a/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb +++ b/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb @@ -3,22 +3,10 @@ class RoomApi::Eg006CreateAnExternalFormFillSessionService attr_reader :args - def initialize(session, request) - @args = { - form_id: request.params['formId'], - room_id: request.params['roomId'], - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } + def initialize(args) + @args = args end - def call - worker - end - - private - def worker configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host @@ -29,13 +17,15 @@ def worker rooms_api = DocuSign_Rooms::ExternalFormFillSessionsApi.new(api_client) begin - rooms_api.create_external_form_fill_session(args[:account_id], body) + rooms_api.create_external_form_fill_session(args[:account_id], body(args)) rescue Exception => e return end end - def body + private + + def body(args) DocuSign_Rooms::ExternalFormFillSessionForCreate.new({ formId: args[:form_id], roomId: args[:room_id] diff --git a/app/services/room_api/eg007_create_form_group_service.rb b/app/services/room_api/eg007_create_form_group_service.rb index a6bd3d1..26e999f 100644 --- a/app/services/room_api/eg007_create_form_group_service.rb +++ b/app/services/room_api/eg007_create_form_group_service.rb @@ -3,20 +3,10 @@ class RoomApi::Eg007CreateFormGroupService attr_reader :args - def initialize(session, request) - @args = { - group_name: request.params[:group_name], - account_id: session[:ds_account_id], - access_token: session[:ds_access_token] - } + def initialize(args) + @args = args end - def call - worker - end - - private - def worker # Step 2 start configuration = DocuSign_Rooms::Configuration.new @@ -28,11 +18,13 @@ def worker # Step 4 start rooms_api = DocuSign_Rooms::FormGroupsApi.new(api_client) - rooms_api.create_form_group(args[:account_id], body) + rooms_api.create_form_group(args[:account_id], body(args)) # Step 4 end end - def body + private + + def body(args) # Step 3 start DocuSign_Rooms::RoomForCreate.new( { diff --git a/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb b/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb index b036f1a..9620517 100644 --- a/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb +++ b/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb @@ -3,21 +3,10 @@ class RoomApi::Eg008GrantOfficeAccessToFormGroupService attr_reader :args - def initialize(session, request) - @args = { - office_id: request.params[:office_id], - form_group_id: request.params[:form_group_id], - account_id: session[:ds_account_id], - access_token: session[:ds_access_token] - } + def initialize(args) + @args = args end - def call - worker - end - - private - def worker # Step 2 start configuration = DocuSign_Rooms::Configuration.new diff --git a/app/services/room_api/eg009_assign_form_to_form_group_service.rb b/app/services/room_api/eg009_assign_form_to_form_group_service.rb index a24d015..9694835 100644 --- a/app/services/room_api/eg009_assign_form_to_form_group_service.rb +++ b/app/services/room_api/eg009_assign_form_to_form_group_service.rb @@ -3,21 +3,10 @@ class RoomApi::Eg009AssignFormToFormGroupService attr_reader :args - def initialize(session, request) - @args = { - form_id: request.params[:form_id], - form_group_id: request.params[:form_group_id], - account_id: session[:ds_account_id], - access_token: session[:ds_access_token] - } + def initialize(args) + @args = args end - def call - worker - end - - private - def worker # Step 2 start configuration = DocuSign_Rooms::Configuration.new @@ -30,7 +19,7 @@ def worker # Step 6 start form_groups_api = DocuSign_Rooms::FormGroupsApi.new(api_client) begin - response = form_groups_api.assign_form_group_form(args[:form_group_id], args[:account_id], body) + response = form_groups_api.assign_form_group_form(args[:form_group_id], args[:account_id], body(args)) rescue Exception => e return { exception: 'Failed to assign a form to a form group' } end @@ -38,7 +27,9 @@ def worker response end - def body + private + + def body(args) # Step 5 start DocuSign_Rooms::FormGroupFormToAssign.new( { From 983f4e77eaadacf2307e26e2b580fdb20c3ddcb3 Mon Sep 17 00:00:00 2001 From: Anna Hileta <80112359+annahileta@users.noreply.github.com> Date: Sat, 19 Feb 2022 01:24:28 +0200 Subject: [PATCH 126/363] updated versions of external libraries and sdks (#51) Co-authored-by: Karissa Jacobsen --- Gemfile | 6 ++++-- Gemfile.lock | 30 +++++++++++++++++++----------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/Gemfile b/Gemfile index 98bec99..53bc59d 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '~>2.7.2' +ruby '~>3.0.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '~> 6.0.4.1' @@ -49,7 +49,7 @@ end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. - gem 'listen', '~> 3.2.1' + gem 'listen', '> 3.2.1' gem 'web-console', '~> 4.0.1' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'pry-nav', '~> 0.3.0' @@ -77,3 +77,5 @@ gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', '~> 1.2019.3', platforms: %i[mingw mswin x64_mingw jruby] gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] + +gem "webrick", "~> 1.7" diff --git a/Gemfile.lock b/Gemfile.lock index 1dc0be2..3686cf7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -113,7 +113,7 @@ GEM jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) erubi (1.10.0) - ethon (0.15.0) + ethon (0.14.0) ffi (>= 1.15.0) execjs (2.8.1) faraday (1.9.3) @@ -148,9 +148,9 @@ GEM io-like (0.3.1) jbuilder (2.10.2) activesupport (>= 5.0.0) - json (2.6.1) - jwt (2.3.0) - listen (3.2.1) + json (2.5.1) + jwt (2.2.3) + listen (3.7.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) loofah (2.13.0) @@ -158,7 +158,7 @@ GEM nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) - marcel (1.0.2) + marcel (1.0.1) method_source (0.9.2) mini_mime (1.1.2) minitest (5.15.0) @@ -181,7 +181,7 @@ GEM hashie (>= 3.4.6) rack (>= 1.6.2, < 3) rack-protection - omniauth-oauth2 (1.7.2) + omniauth-oauth2 (1.7.1) oauth2 (~> 1.4) omniauth (>= 1.9, < 3) omniauth-rails_csrf_protection (1.0.0) @@ -195,9 +195,9 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.6) - puma (4.3.10) + puma (4.3.9) nio4r (~> 2.0) - racc (1.6.0) + racc (1.5.2) rack (2.2.3) rack-protection (2.1.0) rack @@ -240,6 +240,8 @@ GEM sassc-rails (~> 2.1, >= 2.1.1) sassc (2.4.0) ffi (~> 1.9) + sassc (2.4.0-x64-mingw32) + ffi (~> 1.9) sassc-rails (2.1.2) railties (>= 4.0.0) sassc (>= 2.0) @@ -271,13 +273,17 @@ GEM ethon (>= 0.9.0) tzinfo (1.2.9) thread_safe (~> 0.1) + tzinfo-data (1.2019.3) + tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) + wdm (0.1.1) web-console (4.0.4) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) + webrick (1.7.0) websocket-driver (0.7.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) @@ -286,6 +292,7 @@ GEM zeitwerk (2.5.3) PLATFORMS + x64-mingw32 x86_64-darwin-20 x86_64-linux @@ -301,7 +308,7 @@ DEPENDENCIES docusign_monitor (~> 1.0.0) docusign_rooms (~> 1.2.0.rc1) jbuilder (~> 2.10.0) - listen (~> 3.2.1) + listen (> 3.2.1) omniauth-oauth2 (~> 1.7.1) omniauth-rails_csrf_protection pry-nav (~> 0.3.0) @@ -318,9 +325,10 @@ DEPENDENCIES uglifier (~> 4.2.0) wdm (>= 0.1.0) web-console (~> 4.0.1) + webrick (~> 1.7) RUBY VERSION - ruby 2.7.2p137 + ruby 3.0.2p107 BUNDLED WITH - 2.2.16 + 2.2.31 From 3312d0ac257acc478c6d20cc7d2a866d838b9e08 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Sat, 19 Feb 2022 01:29:14 +0200 Subject: [PATCH 127/363] Update api selection (#54) * updated routing and caching --- app/controllers/ds_common_controller.rb | 28 ++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index 34351a6..033dd36 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -6,7 +6,29 @@ class DsCommonController < ApplicationController def index @show_doc = Rails.application.config.documentation - if session[:examples_API] == 'Rooms' + handle_redirects + end + + def handle_redirects + if Rails.configuration.quickstart + if session[:quickstarted].nil? + session[:examples_API] = 'eSignature' + session[:quickstarted] = true + redirect_to "/auth/docusign" + elsif session[:been_here].nil? + redirect_to '/eg001' + else + render_examples + end + else + render_examples + end + end + + def render_examples + if session[:examples_API].nil? + choose_api + elsif session[:examples_API] == 'Rooms' render 'room_api/index' elsif session[:examples_API] == 'Click' render 'clickwrap/index' @@ -16,10 +38,6 @@ def index render 'admin_api/index' else session[:examples_API] = 'eSignature' - @show_doc = Rails.application.config.documentation - if Rails.configuration.quickstart && session[:been_here].nil? - redirect_to '/eg001' - end end end From 10fb19fac361339e21b50376bca0254e84da0644 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Feb 2022 15:29:29 -0800 Subject: [PATCH 128/363] Bump puma from 4.3.10 to 4.3.11 (#57) Bumps [puma](https://github.com/puma/puma) from 4.3.10 to 4.3.11. - [Release notes](https://github.com/puma/puma/releases) - [Changelog](https://github.com/puma/puma/blob/master/History.md) - [Commits](https://github.com/puma/puma/compare/v4.3.10...v4.3.11) --- updated-dependencies: - dependency-name: puma dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 53bc59d..de4f11c 100644 --- a/Gemfile +++ b/Gemfile @@ -10,7 +10,7 @@ gem 'rails', '~> 6.0.4.1' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4.2' # Use Puma as the app server -gem 'puma', '~> 4.3.9' +gem 'puma', '~> 4.3.11' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets diff --git a/Gemfile.lock b/Gemfile.lock index 3686cf7..d3fff8e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -140,6 +140,7 @@ GEM faraday-rack (1.0.0) faraday-retry (1.0.3) ffi (1.15.5) + ffi (1.15.5-x64-mingw32) globalid (1.0.0) activesupport (>= 5.0) hashie (5.0.0) @@ -167,6 +168,8 @@ GEM multi_xml (0.6.0) multipart-post (2.1.1) nio4r (2.5.8) + nokogiri (1.13.1-x64-mingw32) + racc (~> 1.4) nokogiri (1.13.1-x86_64-darwin) racc (~> 1.4) nokogiri (1.13.1-x86_64-linux) @@ -195,7 +198,7 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.6) - puma (4.3.9) + puma (4.3.11) nio4r (~> 2.0) racc (1.5.2) rack (2.2.3) @@ -313,7 +316,7 @@ DEPENDENCIES omniauth-rails_csrf_protection pry-nav (~> 0.3.0) pry-rails (~> 0.3.9) - puma (~> 4.3.9) + puma (~> 4.3.11) rails (~> 6.0.4.1) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) From e940b78cf2341bcf0e46df3d766ad77f702ac9e2 Mon Sep 17 00:00:00 2001 From: connorl-docusign <93227695+connorl-docusign@users.noreply.github.com> Date: Tue, 22 Feb 2022 10:27:45 -0800 Subject: [PATCH 129/363] Edited text on click1-6 to match standard (#53) * Edited text on click1-6 to match standard * Updated text for click1-5 * Minor text changes to click 5 * Edited text for click5 * Changed label on Click5 --- .../eg001_create_clickwrap_controller.rb | 6 ++-- .../eg002_activate_clickwrap_controller.rb | 6 ++-- ...create_new_clickwrap_version_controller.rb | 6 ++-- .../eg004_list_clickwraps_controller.rb | 4 +-- .../eg005_clickwrap_responses_controller.rb | 4 +-- .../eg001_create_clickwrap/get.html.erb | 5 ++- .../eg002_activate_clickwrap/get.html.erb | 9 ++--- .../get.html.erb | 13 ++++--- .../eg004_list_clickwraps/get.html.erb | 5 ++- .../eg005_clickwrap_responses/get.html.erb | 29 ++++++++++----- app/views/clickwrap/index.html.erb | 36 ++++++------------- 11 files changed, 57 insertions(+), 66 deletions(-) diff --git a/app/controllers/clickwrap/eg001_create_clickwrap_controller.rb b/app/controllers/clickwrap/eg001_create_clickwrap_controller.rb index 7d6a345..34b2916 100644 --- a/app/controllers/clickwrap/eg001_create_clickwrap_controller.rb +++ b/app/controllers/clickwrap/eg001_create_clickwrap_controller.rb @@ -14,9 +14,9 @@ def create session[:clickwrap_id] = results.clickwrap_id session[:clickwrap_name] = results.clickwrap_name - @title = 'Creating a new clickwrap' - @h1 = 'Creating a new clickwrap' - @message = "The clickwrap #{results.clickwrap_name} has been created!" + @title = 'Create a clickwrap' + @h1 = 'Create a clickwrap' + @message = "The clickwrap #{results.clickwrap_name} has been created." @json = results.to_json.to_json render 'ds_common/example_done' end diff --git a/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb b/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb index 89eae47..4621f57 100644 --- a/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb +++ b/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb @@ -11,9 +11,9 @@ def create results = Clickwrap::Eg002ActivateClickwrapService.new(args).worker - @title = 'Activating a new clickwrap' - @h1 = 'Activating a new clickwrap' - @message = "The clickwrap #{results.clickwrap_name} has been activated" + @title = 'Activate a new clickwrap' + @h1 = 'Activate a new clickwrap' + @message = "The clickwrap #{results.clickwrap_name} has been activated." render 'ds_common/example_done' end end diff --git a/app/controllers/clickwrap/eg003_create_new_clickwrap_version_controller.rb b/app/controllers/clickwrap/eg003_create_new_clickwrap_version_controller.rb index 32e431b..5980d5c 100644 --- a/app/controllers/clickwrap/eg003_create_new_clickwrap_version_controller.rb +++ b/app/controllers/clickwrap/eg003_create_new_clickwrap_version_controller.rb @@ -12,9 +12,9 @@ def create results = Clickwrap::Eg003CreateNewClickwrapVersionService.new(args).worker puts results.to_json.to_json - @title = 'Creating a new clickwrap version' - @h1 = 'Creating a new clickwrap version' - @message = "Version #{results.version_number} of clickwrap #{results.clickwrap_name} has been created" + @title = 'Create a new clickwrap version' + @h1 = 'Create a new clickwrap version' + @message = "Version #{results.version_number} of clickwrap #{results.clickwrap_name} has been created." render 'ds_common/example_done' end end diff --git a/app/controllers/clickwrap/eg004_list_clickwraps_controller.rb b/app/controllers/clickwrap/eg004_list_clickwraps_controller.rb index e942a22..d05e5b1 100644 --- a/app/controllers/clickwrap/eg004_list_clickwraps_controller.rb +++ b/app/controllers/clickwrap/eg004_list_clickwraps_controller.rb @@ -10,8 +10,8 @@ def create results = Clickwrap::Eg004ListClickwrapsService.new(args).worker - @title = 'List clickwraps results' - @h1 = 'List clickwraps results' + @title = 'Get a list of clickwraps' + @h1 = 'Get a list of clickwraps' @message = "Results from the ClickWraps::getClickwraps method:" @json = results.to_json.to_json render 'ds_common/example_done' diff --git a/app/controllers/clickwrap/eg005_clickwrap_responses_controller.rb b/app/controllers/clickwrap/eg005_clickwrap_responses_controller.rb index 3ab04bf..547abc6 100644 --- a/app/controllers/clickwrap/eg005_clickwrap_responses_controller.rb +++ b/app/controllers/clickwrap/eg005_clickwrap_responses_controller.rb @@ -12,8 +12,8 @@ def create results = Clickwrap::Eg005ClickwrapResponsesService.new(args).worker - @title = 'Getting clickwrap responses' - @h1 = 'Getting clickwrap responses' + @title = 'Get clickwrap responses' + @h1 = 'Get clickwrap responses' @message = "Results from the ClickWraps::getClickwrapAgreements method:" @json = results.to_json.to_json render 'ds_common/example_done' diff --git a/app/views/clickwrap/eg001_create_clickwrap/get.html.erb b/app/views/clickwrap/eg001_create_clickwrap/get.html.erb index 12d4592..9571832 100644 --- a/app/views/clickwrap/eg001_create_clickwrap/get.html.erb +++ b/app/views/clickwrap/eg001_create_clickwrap/get.html.erb @@ -1,6 +1,5 @@ -

1. Creating a clickwrap

-

This example demonstrates how to use the DocuSign Click API to create a - clickwrap that you can embed in your website or app.

+

1. Create a clickwrap

+

Creates a clickwrap that you can embed in your website or app.

API method used: ClickWraps::createClickwrap diff --git a/app/views/clickwrap/eg002_activate_clickwrap/get.html.erb b/app/views/clickwrap/eg002_activate_clickwrap/get.html.erb index c5d61dd..4b4e2a7 100644 --- a/app/views/clickwrap/eg002_activate_clickwrap/get.html.erb +++ b/app/views/clickwrap/eg002_activate_clickwrap/get.html.erb @@ -1,10 +1,7 @@ -

2. Activating a clickwrap

+

2. Activate a clickwrap

- This example demonstrates how to use the DocuSign Click API to activate a new - clickwrap that you have already created. -
- By default, new clickwraps are inactive. You must activate your clickwrap before - you can use it. + Activates a new clickwrap that you have already created. By default, new clickwraps are + inactive. You must activate your clickwrap before you can use it.

API method used: diff --git a/app/views/clickwrap/eg003_create_new_clickwrap_version/get.html.erb b/app/views/clickwrap/eg003_create_new_clickwrap_version/get.html.erb index ad9847b..6ecbfdb 100644 --- a/app/views/clickwrap/eg003_create_new_clickwrap_version/get.html.erb +++ b/app/views/clickwrap/eg003_create_new_clickwrap_version/get.html.erb @@ -1,11 +1,10 @@ -

3. Creating a new clickwrap version

+

3. Create a new clickwrap version

- This example demonstrates how to use the DocuSign Click API to create a new version - of a clickwrap. -
- You can specify whether you require users who have - previously accepted the clickwrap to accept the new version when they - return to your website. + Creates a new version of a clickwrap. +

+

+ You can specify whether you require users who have previously accepted the clickwrap + to accept the new version when they return to your website.

API method used: diff --git a/app/views/clickwrap/eg004_list_clickwraps/get.html.erb b/app/views/clickwrap/eg004_list_clickwraps/get.html.erb index 9aebd75..1444ff4 100644 --- a/app/views/clickwrap/eg004_list_clickwraps/get.html.erb +++ b/app/views/clickwrap/eg004_list_clickwraps/get.html.erb @@ -1,7 +1,6 @@ -

4. Getting a list of clickwraps

+

4. Get a list of clickwraps

- This example demonstrates how to use the DocuSign Click API to get a list of - clickwraps associated with a specific DocuSign user. + Gets a list of clickwraps associated with a specific DocuSign user.

API method used: diff --git a/app/views/clickwrap/eg005_clickwrap_responses/get.html.erb b/app/views/clickwrap/eg005_clickwrap_responses/get.html.erb index 2e6b860..70d276c 100644 --- a/app/views/clickwrap/eg005_clickwrap_responses/get.html.erb +++ b/app/views/clickwrap/eg005_clickwrap_responses/get.html.erb @@ -1,7 +1,6 @@ -

5. Getting clickwrap responses

+

5. Get clickwrap responses

- This example demonstrates how to use the DocuSign Click API to get a list of - clickwrap responses associated with a specific DocuSign user. + Gets user responses to your clickwrap agreements.

API method used: @@ -13,16 +12,30 @@

<% if session[:clickwrap_id] %> +

- The clickwrap you created via example 1 will be queried. -
- Please enter a value that uniquely identifies a user, such as an email - address or employee ID + First, test your clickwrap: +

+ +
    +
  • Log in to your developer account and select the Manage page. +
  • Select the Clickwraps tab. +
  • + In the list of active clickwraps, locate the one you want to test, then click + the dropdown arrow to the right of COPY CODE and select Test Clickwrap. +
  • +
  • In the Test Clickwrap dialog box, click TEST CLICKWRAP. +
  • In the Test Your Clickwrap browser page, in the Unique ID field, enter any string, then click Test Clickwrap. +
  • Review your displayed clickwrap and click I AGREE (or the equivalent button you configured) to complete the test. +
+ +

+ Then enter the same string you used to test your clickwrap in the field below.

- +
diff --git a/app/views/clickwrap/index.html.erb b/app/views/clickwrap/index.html.erb index 469120b..1886c12 100644 --- a/app/views/clickwrap/index.html.erb +++ b/app/views/clickwrap/index.html.erb @@ -6,7 +6,7 @@

Ruby Launcher

-

Welcome to the DocuSign Ruby examples using multiple OAuth flows (JWT and Authorization Code Grant).

+

Run and explore Click API code examples with Authorization Code Grant or JWT Grant authentication

@@ -19,19 +19,14 @@
-

Welcome

-

This launcher both demonstrates the use of JWT and OAuth Authorization Code Grant flow and includes multiple usage examples for the DocuSign Click API.

<% if @show_doc %>

Documentation on using JWT or OAuth Authorization Code Grant from a Ruby Rails application.

<% end %> -

Basic examples

- -

1. Creating a clickwrap

+

1. Create a clickwrap

- This example demonstrates how to use DocuSign Click to create a - clickwrap that you can embed in your website or app. + Creates a clickwrap that you can embed in your website or app.

API methods used: @@ -40,45 +35,34 @@

2. Activate a clickwrap

- This example demonstrates how to use DocuSign Click to activate a new - clickwrap that you have already created. -
- By default, new clickwraps are inactive. You must activate your clickwrap before - you can use it. + Activates a new clickwrap that you have already created.

API methods used: ClickWraps::updateClickwrapVersion

-

3. Creating a new clickwrap version

+

3. Create a new clickwrap version

- This example demonstrates how to use the Click API to create a new version - of a clickwrap. -
- You can specify whether you require users who have - previously accepted the clickwrap to accept the new version when they - return to your website. + Creates a new version of a clickwrap.

API methods used: ClickWraps::createClickwrapVersion

-

4. Getting a list of clickwraps

+

4. Get a list of clickwraps

- This example demonstrates how to use the Click API to get a list of - clickwraps associated with a specific DocuSign user. + Gets a list of clickwraps associated with a specific DocuSign user.

API methods used: ClickWraps::getClickwraps

-

5. Getting clickwrap responses

+

5. Get clickwrap responses

- This example demonstrates how to use the Click API to get a list of - clickwraps associated with a specific DocuSign user. + Gets user responses to your clickwrap agreements.

API methods used: From 5a296beef923567aef1a0b653cff5990a420447c Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Thu, 3 Mar 2022 18:14:59 -0800 Subject: [PATCH 130/363] scheduled sending and delayed routing (#60) * scheduled sending and delayed routing --- Gemfile | 2 +- .../eg035_scheduled_sending_controller.rb | 30 ++++ .../eg036_delayed_routing_controller.rb | 32 +++++ ...er.rb => eg037_sms_delivery_controller.rb} | 5 +- .../e_sign/eg035_scheduled_sending_service.rb | 106 ++++++++++++++ .../e_sign/eg036_delayed_routing_service.rb | 129 ++++++++++++++++++ ...rvice.rb => eg037_sms_delivery_service.rb} | 28 ++-- app/views/ds_common/index.html.erb | 23 +++- .../eg035_scheduled_sending/get.html.erb | 34 +++++ .../e_sign/eg036_delayed_routing/get.html.erb | 44 ++++++ .../get.html.erb | 6 +- config/routes.rb | 10 +- 12 files changed, 423 insertions(+), 26 deletions(-) create mode 100644 app/controllers/e_sign/eg035_scheduled_sending_controller.rb create mode 100644 app/controllers/e_sign/eg036_delayed_routing_controller.rb rename app/controllers/e_sign/{eg035_sms_delivery_controller.rb => eg037_sms_delivery_controller.rb} (90%) create mode 100644 app/services/e_sign/eg035_scheduled_sending_service.rb create mode 100644 app/services/e_sign/eg036_delayed_routing_service.rb rename app/services/e_sign/{eg035_sms_delivery_service.rb => eg037_sms_delivery_service.rb} (98%) create mode 100644 app/views/e_sign/eg035_scheduled_sending/get.html.erb create mode 100644 app/views/e_sign/eg036_delayed_routing/get.html.erb rename app/views/e_sign/{eg035_sms_delivery => eg037_sms_delivery}/get.html.erb (97%) diff --git a/Gemfile b/Gemfile index de4f11c..ad855b1 100644 --- a/Gemfile +++ b/Gemfile @@ -66,7 +66,7 @@ group :test do gem 'chromedriver-helper', '~> 2.1.1' end -gem 'docusign_esign', '~> 3.14.0' +gem 'docusign_esign', '~> 3.15.0' gem 'docusign_monitor', '~> 1.0.0' gem 'docusign_rooms', '~> 1.2.0.rc1' gem 'docusign_click', '~> 1.0.0' diff --git a/app/controllers/e_sign/eg035_scheduled_sending_controller.rb b/app/controllers/e_sign/eg035_scheduled_sending_controller.rb new file mode 100644 index 0000000..936756b --- /dev/null +++ b/app/controllers/e_sign/eg035_scheduled_sending_controller.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class ESign::Eg035ScheduledSendingController < EgController + before_action :check_auth + + def create + begin + envelope_args = { + signer_email: param_gsub(params['signer_email']), + signer_name: param_gsub(params['signer_name']), + resume_date: param_gsub(params['resume_date']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + results = ESign::Eg035ScheduledSendingService.new(args).worker + session[:envelope_id] = results['envelope_id'] + @title = 'Envelope scheduled' + @h1 = 'Envelope scheduled' + @message = "The envelope has been created and scheduled!
Envelope ID #{results['envelope_id']}." + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end + end +end diff --git a/app/controllers/e_sign/eg036_delayed_routing_controller.rb b/app/controllers/e_sign/eg036_delayed_routing_controller.rb new file mode 100644 index 0000000..9a0ffc3 --- /dev/null +++ b/app/controllers/e_sign/eg036_delayed_routing_controller.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +class ESign::Eg036DelayedRoutingController < EgController + before_action :check_auth + + def create + begin + envelope_args = { + signer1_email: param_gsub(params['signer1Email']), + signer1_name: param_gsub(params['signer1Name']), + signer2_email: param_gsub(params['signer2Email']), + signer2_name: param_gsub(params['signer2Name']), + delay: param_gsub(params['delay']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + results = ESign::Eg036DelayedRoutingService.new(args).worker + session[:envelope_id] = results['envelope_id'] + @title = 'Envelope sent' + @h1 = 'Envelope sent' + @message = "The envelope has been created and sent!
Envelope ID #{results['envelope_id']}." + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end + end +end diff --git a/app/controllers/e_sign/eg035_sms_delivery_controller.rb b/app/controllers/e_sign/eg037_sms_delivery_controller.rb similarity index 90% rename from app/controllers/e_sign/eg035_sms_delivery_controller.rb rename to app/controllers/e_sign/eg037_sms_delivery_controller.rb index 0657589..7d8517d 100644 --- a/app/controllers/e_sign/eg035_sms_delivery_controller.rb +++ b/app/controllers/e_sign/eg037_sms_delivery_controller.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class ESign::Eg035SmsDeliveryController < EgController +class ESign::Eg037SmsDeliveryController < EgController before_action :check_auth def create @@ -23,7 +23,7 @@ def create envelope_args: envelope_args } - results = ESign::Eg035SmsDeliveryService.new(args).worker + results = ESign::Eg037SmsDeliveryService.new(args).worker session[:envelope_id] = results['envelope_id'] @title = 'Envelope sent' @h1 = 'Envelope sent' @@ -34,4 +34,3 @@ def create end end end - \ No newline at end of file diff --git a/app/services/e_sign/eg035_scheduled_sending_service.rb b/app/services/e_sign/eg035_scheduled_sending_service.rb new file mode 100644 index 0000000..7871099 --- /dev/null +++ b/app/services/e_sign/eg035_scheduled_sending_service.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +class ESign::Eg035ScheduledSendingService + attr_reader :args + include ApiCreator + + def initialize(args) + @args = args + end + + def worker + # 1. Create the envelope request object + envelope_definition = make_envelope args[:envelope_args] + # 2. Call Envelopes::create API method + # Exceptions will be caught by the calling function + envelope_api = create_envelope_api(args) + + results = envelope_api.create_envelope args[:account_id], envelope_definition + envelope_id = results.envelope_id + { 'envelope_id' => envelope_id } + end + + private + + def make_envelope(envelope_args) + # document (PDF) has tag /sn1/ + # The envelope has one recipient + + # Create the envelope definition + envelope_definition = DocuSign_eSign::EnvelopeDefinition.new + + envelope_definition.email_subject = 'Please sign this document' + + # Add the document + # Read file from a local directory + # The reads could raise an exception if the file is not available! + doc_pdf = Rails.application.config.doc_pdf + doc_b64 = Base64.encode64(File.binread(File.join('data', doc_pdf))) + + # Create the document model + document = DocuSign_eSign::Document.new( + # Create the DocuSign document object + documentBase64: doc_b64, + name: 'Lorem Ipsum', # Can be different from actual file name + fileExtension: 'pdf', # Many different document types are accepted + documentId: '1' # A label used to reference the doc + ) + + # The order in the docs array determines the order in the envelope + envelope_definition.documents = [document] + + # Create the signer recipient model + signer1 = DocuSign_eSign::Signer.new + signer1.email = envelope_args[:signer_email] + signer1.name = envelope_args[:signer_name] + signer1.recipient_id = '1' + signer1.routing_order = '1' + ## 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 + + # Create a signHere field (also known as a tab) on the document + # We're using anchor (autoPlace) positioning + # + # The DocuSign platform searches throughout your envelope's documents for matching + # anchor strings. + sign_here = DocuSign_eSign::SignHere.new( + anchorString: '/sn1/', + anchorYOffset: '10', + anchorUnits: 'pixels', + anchorXOffset: '20' + ) + # Add the tabs model (including the sign_here tabs) to the signer + # The Tabs object takes arrays of the different field/tab types + signer1_tabs = DocuSign_eSign::Tabs.new({ + signHereTabs: [sign_here] + }) + + signer1.tabs = signer1_tabs + + # Add the recipients to the envelope object + recipients = DocuSign_eSign::Recipients.new( + signers: [signer1] + ) + envelope_definition.recipients = recipients + + # Create recipientRules model + rule = DocuSign_eSign::EnvelopeDelayRuleApiModel.new( + resumeDate: envelope_args[:resume_date].to_s + ) + + scheduled_sending = DocuSign_eSign::ScheduledSendingApiModel.new( + status: "pending", + rules: [rule] + ) + + workflow = DocuSign_eSign::Workflow.new(scheduledSending: scheduled_sending) + # Add the workflow to the envelope object + envelope_definition.workflow = workflow + + # Request that the envelope be sent by setting status to "sent". + # To request that the envelope be created as a draft, set status to "created" + envelope_definition.status = envelope_args[:status] + envelope_definition + end +end \ No newline at end of file diff --git a/app/services/e_sign/eg036_delayed_routing_service.rb b/app/services/e_sign/eg036_delayed_routing_service.rb new file mode 100644 index 0000000..3a85aa6 --- /dev/null +++ b/app/services/e_sign/eg036_delayed_routing_service.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +class ESign::Eg036DelayedRoutingService + attr_reader :args + include ApiCreator + + def initialize(args) + @args = args + end + + def worker + # 1. Create the envelope request object + envelope_definition = make_envelope args[:envelope_args] + # 2. Call Envelopes::create API method + # Exceptions will be caught by the calling function + envelope_api = create_envelope_api(args) + + results = envelope_api.create_envelope args[:account_id], envelope_definition + envelope_id = results.envelope_id + { 'envelope_id' => envelope_id } + end + + private + + def make_envelope(envelope_args) + + # Create the envelope definition + envelope_definition = DocuSign_eSign::EnvelopeDefinition.new + + envelope_definition.email_subject = 'Please sign this document' + + # Add the document + # Read file from a local directory + # The reads could raise an exception if the file is not available! + doc_pdf = Rails.application.config.doc_pdf + doc_b64 = Base64.encode64(File.binread(File.join('data', doc_pdf))) + + # Create the document model + document = DocuSign_eSign::Document.new( + # Create the DocuSign document object + documentBase64: doc_b64, + name: 'Lorem Ipsum', # Can be different from actual file name + fileExtension: 'pdf', # Many different document types are accepted + documentId: '1' # A label used to reference the doc + ) + + # The order in the docs array determines the order in the envelope + envelope_definition.documents = [document] + + # Create the signer recipient model + signer1 = DocuSign_eSign::Signer.new + signer1.email = envelope_args[:signer1_email] + signer1.name = envelope_args[:signer1_name] + signer1.recipient_id = '1' + signer1.routing_order = '1' + ## 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 + + signer2 = DocuSign_eSign::Signer.new + signer2.email = envelope_args[:signer2_email] + signer2.name = envelope_args[:signer2_name] + signer2.recipient_id = '2' + signer2.routing_order = '2' + + # Create signHere fields (also known as tabs) on the document + # We're using anchor (autoPlace) positioning for the sign_here1 tab + # and we're using absolute positioning for the sign_here2 tab. + # + # The DocuSign platform searches throughout your envelope's documents for matching + # anchor strings. + sign_here1 = DocuSign_eSign::SignHere.new( + anchorString: '/sn1/', + anchorYOffset: '10', + anchorUnits: 'pixels', + anchorXOffset: '20' + ) + + sign_here2 = DocuSign_eSign::SignHere.new( + xPosition: "320", + yPosition: "175", + pageNumber: "1", + documentId: "1" + ) + + # Add the tabs model (including the sign_here tabs) to the signer + # The Tabs object takes arrays of the different field/tab types + signer1_tabs = DocuSign_eSign::Tabs.new({ + signHereTabs: [sign_here1] + }) + + signer2_tabs = DocuSign_eSign::Tabs.new({ + signHereTabs: [sign_here2] + }) + + signer1.tabs = signer1_tabs + signer2.tabs = signer2_tabs + + # Add the recipients to the envelope object + recipients = DocuSign_eSign::Recipients.new( + signers: [signer1, signer2] + ) + + envelope_definition.recipients = recipients + + # Create recipientRules model + delay_time = "0." + envelope_args[:delay].to_s + ":00:00"; + rule = DocuSign_eSign::EnvelopeDelayRuleApiModel.new(delay: delay_time) + + delayed_routing = DocuSign_eSign::DelayedRoutingApiModel.new(rules: [rule]) + + # Create a workflow model + workflow_step = DocuSign_eSign::WorkflowStep.new( + action: 'pause_before', + triggerOnItem: 'routing_order', + itemId: 2, + status: 'pending', + delayedRouting: delayed_routing + ) + workflow = DocuSign_eSign::Workflow.new(workflowSteps: [workflow_step]) + # Add the workflow to the envelope object + envelope_definition.workflow = workflow + + # Request that the envelope be sent by setting status to "sent". + # To request that the envelope be created as a draft, set status to "created" + envelope_definition.status = envelope_args[:status] + envelope_definition + end +end \ No newline at end of file diff --git a/app/services/e_sign/eg035_sms_delivery_service.rb b/app/services/e_sign/eg037_sms_delivery_service.rb similarity index 98% rename from app/services/e_sign/eg035_sms_delivery_service.rb rename to app/services/e_sign/eg037_sms_delivery_service.rb index 3981fee..6d4e2dd 100644 --- a/app/services/e_sign/eg035_sms_delivery_service.rb +++ b/app/services/e_sign/eg037_sms_delivery_service.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class ESign::Eg035SmsDeliveryService +class ESign::Eg037SmsDeliveryService attr_reader :args include ApiCreator @@ -16,14 +16,14 @@ def worker # Call Envelopes::create API method # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) - + results = envelope_api.create_envelope args[:account_id], envelope_definition envelope_id = results.envelope_id { 'envelope_id' => envelope_id } end private - + def make_envelope(envelope_args) # document 1 (HTML) has tag **signature_1** # document 2 (DOCX) has tag /sn1/ @@ -34,12 +34,12 @@ def make_envelope(envelope_args) # recipient 2 - cc # The envelope will be sent first to the signer via SMS # After it is signed, a copy is sent to the cc person via SMS - + # Step 2. Create the envelope definition envelope_definition = DocuSign_eSign::EnvelopeDefinition.new - + envelope_definition.email_subject = 'Please sign this document set' - + # Add the documents doc1_b64 = Base64.encode64(create_document1(envelope_args)) # Read files 2 and 3 from a local directory @@ -48,7 +48,7 @@ def make_envelope(envelope_args) doc2_b64 = Base64.encode64(File.binread(File.join('data', doc_docx))) doc_pdf = Rails.application.config.doc_pdf doc3_b64 = Base64.encode64(File.binread(File.join('data', doc_pdf))) - + # Create the document models document1 = DocuSign_eSign::Document.new( # Create the DocuSign document object @@ -71,7 +71,7 @@ def make_envelope(envelope_args) fileExtension: 'pdf', # Many different document types are accepted documentId: '3' # A label used to reference the doc ) - + # The order in the docs array determines the order in the envelope envelope_definition.documents = [document1, document2, document3] @@ -82,7 +82,7 @@ def make_envelope(envelope_args) sms_notification = DocuSign_eSign::RecipientAdditionalNotification.new sms_notification.phone_number = phone_number sms_notification.secondary_delivery_method = "SMS" - + # Create the signer recipient model signer1 = DocuSign_eSign::Signer.new signer1.additional_notifications=[sms_notification] @@ -103,7 +103,7 @@ def make_envelope(envelope_args) cc_sms_notification = DocuSign_eSign::RecipientAdditionalNotification.new cc_sms_notification.phone_number=cc_phone_number cc_sms_notification.secondary_delivery_method = "SMS" - + # Create a cc recipient to receive a copy of the documents cc1 = DocuSign_eSign::CarbonCopy.new( email: envelope_args[:cc_email], @@ -124,7 +124,7 @@ def make_envelope(envelope_args) anchorUnits: 'pixels', anchorXOffset: '20' ) - + sign_here2 = DocuSign_eSign::SignHere.new( anchorString: '/sn1/', anchorYOffset: '10', @@ -136,9 +136,9 @@ def make_envelope(envelope_args) signer1_tabs = DocuSign_eSign::Tabs.new({ signHereTabs: [sign_here1, sign_here2] }) - + signer1.tabs = signer1_tabs - + # Add the recipients to the envelope object recipients = DocuSign_eSign::Recipients.new( signers: [signer1], @@ -150,7 +150,7 @@ def make_envelope(envelope_args) envelope_definition.status = envelope_args[:status] envelope_definition end - + def create_document1(args) " diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index 05a5cdd..6b4201c 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -1,4 +1,3 @@ -<% if !session[:ds_user_name] %>

@@ -17,7 +16,7 @@ -<% end %> + <% # Future: add a table of contents or navigation pane # Eg, see https://stackoverflow.com/questions/21868610/make-column-fixed-position-in-bootstrap @@ -290,9 +289,27 @@ Envelopes::create.

+

35. Schedule an envelope

+

+ Demonstrates how to schedule sending an envelope using the scheduled sending feature. +

+

+ API method used: + Envelopes:create. +

+

36. Send an envelope with delayed routing

+ +

+ Demonstrates how to delay an envelope’s delivery between recipients using the delayed routing feature. +

+

+ API method used: + Envelopes:create. +

+

Premium features

-

35. Send an envelope by SMS delivery

+

37. Send an envelope by SMS delivery

This example demonstrates how to send an envelope via an SMS message for a signer (and CC) to read and sign.

diff --git a/app/views/e_sign/eg035_scheduled_sending/get.html.erb b/app/views/e_sign/eg035_scheduled_sending/get.html.erb new file mode 100644 index 0000000..743da75 --- /dev/null +++ b/app/views/e_sign/eg035_scheduled_sending/get.html.erb @@ -0,0 +1,34 @@ +

35. Schedule an envelope

+

+ This example demonstrates how to schedule an envelope using the scheduled sending feature. +

+ +

+ API method used: + Envelopes::create. +

+ +

+ View source file <%= @source_file %> on GitHub. +

+ + +
+ + + We'll never share your email with anyone else. +
+
+ + +
+
+ + + Please choose a date in the future. +
+ + \ No newline at end of file diff --git a/app/views/e_sign/eg036_delayed_routing/get.html.erb b/app/views/e_sign/eg036_delayed_routing/get.html.erb new file mode 100644 index 0000000..0004ddd --- /dev/null +++ b/app/views/e_sign/eg036_delayed_routing/get.html.erb @@ -0,0 +1,44 @@ +

36. Send an envelope with delayed routing

+

+ This example demonstrates how to delay an envelope’s delivery between recipients using the delayed routing feature. +

+ +

+ API method used: + Envelopes::create. +

+ +

+ View source file <%= @source_file %> on GitHub. +

+ + +
+ + + We'll never share your email with anyone else. +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + \ No newline at end of file diff --git a/app/views/e_sign/eg035_sms_delivery/get.html.erb b/app/views/e_sign/eg037_sms_delivery/get.html.erb similarity index 97% rename from app/views/e_sign/eg035_sms_delivery/get.html.erb rename to app/views/e_sign/eg037_sms_delivery/get.html.erb index ee6a49c..140099d 100644 --- a/app/views/e_sign/eg035_sms_delivery/get.html.erb +++ b/app/views/e_sign/eg037_sms_delivery/get.html.erb @@ -1,4 +1,4 @@ -

35. Send an envelope via SMS delivery

+

37. Send an envelope via SMS delivery

This is a general example of creating and sending an envelope (a signing request) to a recipient and notifying that recipient via SMS delivery. @@ -18,7 +18,7 @@ This is a general example of creating and sending an envelope (a signing request The country code for the phone number below. - +

The country code for the phone number below. -
+
'eg034_use_conditional_recipients#get' post 'eg034' => 'eg034_use_conditional_recipients#create' - get 'eg035' => 'eg035_sms_delivery#get' - post 'eg035' => 'eg035_sms_delivery#create' + get 'eg035' => 'eg035_scheduled_sending#get' + post 'eg035' => 'eg035_scheduled_sending#create' + + get 'eg036' => 'eg036_delayed_routing#get' + post 'eg036' => 'eg036_delayed_routing#create' + + get 'eg037' => 'eg037_sms_delivery#get' + post 'eg037' => 'eg037_sms_delivery#create' end end From 0c128bbf439ab792cb22c8f952758b86f9c950e9 Mon Sep 17 00:00:00 2001 From: Connor Lunsford Date: Mon, 7 Mar 2022 15:54:39 -0800 Subject: [PATCH 131/363] Edited text in eSign18 --- .../eg018_get_envelope_custom_field_data/get.html.erb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb b/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb index 5620d21..044da21 100644 --- a/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb +++ b/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb @@ -23,14 +23,17 @@

<% if @envelope_ok %> -

The last envelope you created with the launcher will be queried.

+

+ The last envelope you created with the launcher will be queried.
+ Recommendation: Create an envelope using example 16 then use this example in order to see an example of custom tab values. +

<% else %> -

Problem: please first create an envelope using example 2.
+

Problem: Please first create an envelope using example 16.
Thank you.

From bb016fe8786e92728a71f53adf9ce5363f6d258b Mon Sep 17 00:00:00 2001 From: Connor Lunsford Date: Mon, 7 Mar 2022 15:59:52 -0800 Subject: [PATCH 132/363] Edited esign18 text --- .../eg018_get_envelope_custom_field_data/get.html.erb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb b/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb index 044da21..e63d71a 100644 --- a/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb +++ b/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb @@ -24,7 +24,7 @@ <% if @envelope_ok %>

- The last envelope you created with the launcher will be queried.
+ The last envelope you created with the launcher will be queried. Recommendation: Create an envelope using example 16 then use this example in order to see an example of custom tab values.

@@ -33,8 +33,8 @@ <% else %> -

Problem: Please first create an envelope using example 16.
- Thank you.

+

Problem: Please first create an envelope using example 16. +

From d4fa16c8ca387156d9e5866098d3575d49540a2f Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Wed, 9 Mar 2022 10:11:19 -0800 Subject: [PATCH 133/363] remove workflow status (#62) --- app/services/e_sign/eg035_scheduled_sending_service.rb | 1 - app/services/e_sign/eg036_delayed_routing_service.rb | 1 - 2 files changed, 2 deletions(-) diff --git a/app/services/e_sign/eg035_scheduled_sending_service.rb b/app/services/e_sign/eg035_scheduled_sending_service.rb index 7871099..af36bf3 100644 --- a/app/services/e_sign/eg035_scheduled_sending_service.rb +++ b/app/services/e_sign/eg035_scheduled_sending_service.rb @@ -90,7 +90,6 @@ def make_envelope(envelope_args) ) scheduled_sending = DocuSign_eSign::ScheduledSendingApiModel.new( - status: "pending", rules: [rule] ) diff --git a/app/services/e_sign/eg036_delayed_routing_service.rb b/app/services/e_sign/eg036_delayed_routing_service.rb index 3a85aa6..967be04 100644 --- a/app/services/e_sign/eg036_delayed_routing_service.rb +++ b/app/services/e_sign/eg036_delayed_routing_service.rb @@ -114,7 +114,6 @@ def make_envelope(envelope_args) action: 'pause_before', triggerOnItem: 'routing_order', itemId: 2, - status: 'pending', delayedRouting: delayed_routing ) workflow = DocuSign_eSign::Workflow.new(workflowSteps: [workflow_step]) From 2a56fd38617b0c7bdd7ce94105701e385e503e20 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 11 Mar 2022 11:19:50 -0800 Subject: [PATCH 134/363] update step comments for ss/dr --- app/services/e_sign/eg035_scheduled_sending_service.rb | 9 +++++++-- app/services/e_sign/eg036_delayed_routing_service.rb | 9 ++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/services/e_sign/eg035_scheduled_sending_service.rb b/app/services/e_sign/eg035_scheduled_sending_service.rb index af36bf3..b836267 100644 --- a/app/services/e_sign/eg035_scheduled_sending_service.rb +++ b/app/services/e_sign/eg035_scheduled_sending_service.rb @@ -9,13 +9,16 @@ def initialize(args) end def worker - # 1. Create the envelope request object + # Create the envelope request object envelope_definition = make_envelope args[:envelope_args] - # 2. Call Envelopes::create API method + # Call Envelopes::create API method # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) + # Step 3 start results = envelope_api.create_envelope args[:account_id], envelope_definition + # Step 3 end + envelope_id = results.envelope_id { 'envelope_id' => envelope_id } end @@ -26,6 +29,7 @@ def make_envelope(envelope_args) # document (PDF) has tag /sn1/ # The envelope has one recipient + # Step 2 start # Create the envelope definition envelope_definition = DocuSign_eSign::EnvelopeDefinition.new @@ -100,6 +104,7 @@ def make_envelope(envelope_args) # Request that the envelope be sent by setting status to "sent". # To request that the envelope be created as a draft, set status to "created" envelope_definition.status = envelope_args[:status] + # Step 2 end envelope_definition end end \ No newline at end of file diff --git a/app/services/e_sign/eg036_delayed_routing_service.rb b/app/services/e_sign/eg036_delayed_routing_service.rb index 967be04..40d934a 100644 --- a/app/services/e_sign/eg036_delayed_routing_service.rb +++ b/app/services/e_sign/eg036_delayed_routing_service.rb @@ -9,13 +9,15 @@ def initialize(args) end def worker - # 1. Create the envelope request object + # Create the envelope request object envelope_definition = make_envelope args[:envelope_args] - # 2. Call Envelopes::create API method + # Call Envelopes::create API method # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) + # Step 3 start results = envelope_api.create_envelope args[:account_id], envelope_definition + # Step 3 end envelope_id = results.envelope_id { 'envelope_id' => envelope_id } end @@ -23,7 +25,7 @@ def worker private def make_envelope(envelope_args) - + # Step 2 start # Create the envelope definition envelope_definition = DocuSign_eSign::EnvelopeDefinition.new @@ -123,6 +125,7 @@ def make_envelope(envelope_args) # Request that the envelope be sent by setting status to "sent". # To request that the envelope be created as a draft, set status to "created" envelope_definition.status = envelope_args[:status] + # Step 2 end envelope_definition end end \ No newline at end of file From a6a7462732892e4ae272ee339cd218744512b94e Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Tue, 22 Mar 2022 14:49:12 -0700 Subject: [PATCH 135/363] Devdocs 6974 (#61) update sms delivery --- .../e_sign/eg037_sms_delivery_controller.rb | 6 +-- .../e_sign/eg037_sms_delivery_service.rb | 48 ++++++++----------- app/views/ds_common/index.html.erb | 4 +- .../e_sign/eg037_sms_delivery/get.html.erb | 36 +++++--------- 4 files changed, 34 insertions(+), 60 deletions(-) diff --git a/app/controllers/e_sign/eg037_sms_delivery_controller.rb b/app/controllers/e_sign/eg037_sms_delivery_controller.rb index 7d8517d..53e09cb 100644 --- a/app/controllers/e_sign/eg037_sms_delivery_controller.rb +++ b/app/controllers/e_sign/eg037_sms_delivery_controller.rb @@ -6,9 +6,7 @@ class ESign::Eg037SmsDeliveryController < EgController def create begin envelope_args = { - signer_email: param_gsub(params['signer_email']), signer_name: param_gsub(params['signer_name']), - cc_email: param_gsub(params['cc_email']), cc_name: param_gsub(params['cc_name']), cc_phone_number: param_gsub(params['cc_phone_number']), cc_country_code: param_gsub(params['cc_country_code']), @@ -25,8 +23,8 @@ def create results = ESign::Eg037SmsDeliveryService.new(args).worker session[:envelope_id] = results['envelope_id'] - @title = 'Envelope sent' - @h1 = 'Envelope sent' + @title = 'Request a signature by SMS delivery' + @h1 = 'Request a signature by SMS delivery' @message = "The envelope has been created and sent!
Envelope ID #{results['envelope_id']}." render 'ds_common/example_done' rescue DocuSign_eSign::ApiError => e diff --git a/app/services/e_sign/eg037_sms_delivery_service.rb b/app/services/e_sign/eg037_sms_delivery_service.rb index 6d4e2dd..cbe5f0c 100644 --- a/app/services/e_sign/eg037_sms_delivery_service.rb +++ b/app/services/e_sign/eg037_sms_delivery_service.rb @@ -12,18 +12,19 @@ def worker # Create the envelope request object envelope_definition = make_envelope(args[:envelope_args]) - # Step 3. Create and send the envelope + # Create and send the envelope # Call Envelopes::create API method # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) - + # Step 3 start results = envelope_api.create_envelope args[:account_id], envelope_definition + # Step 3 end envelope_id = results.envelope_id { 'envelope_id' => envelope_id } end private - + # Step 2 start def make_envelope(envelope_args) # document 1 (HTML) has tag **signature_1** # document 2 (DOCX) has tag /sn1/ @@ -35,7 +36,7 @@ def make_envelope(envelope_args) # The envelope will be sent first to the signer via SMS # After it is signed, a copy is sent to the cc person via SMS - # Step 2. Create the envelope definition + # Create the envelope definition envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document set' @@ -75,18 +76,13 @@ def make_envelope(envelope_args) # The order in the docs array determines the order in the envelope envelope_definition.documents = [document1, document2, document3] - phone_number = DocuSign_eSign::RecipientPhoneNumber.new - phone_number.country_code=envelope_args[:country_code] - phone_number.number=envelope_args[:phone_number] - - sms_notification = DocuSign_eSign::RecipientAdditionalNotification.new - sms_notification.phone_number = phone_number - sms_notification.secondary_delivery_method = "SMS" + signer_phone_number = DocuSign_eSign::RecipientPhoneNumber.new + signer_phone_number.country_code=envelope_args[:country_code] + signer_phone_number.number=envelope_args[:phone_number] # Create the signer recipient model signer1 = DocuSign_eSign::Signer.new - signer1.additional_notifications=[sms_notification] - signer1.email = envelope_args[:signer_email] + signer1.phone_number = signer_phone_number signer1.name = envelope_args[:signer_name] signer1.recipient_id = '1' signer1.routing_order = '1' @@ -94,24 +90,17 @@ def make_envelope(envelope_args) # to the recipients. Parallel routing order is supported by using the # same integer as the order for two or more recipients - # Create a RecipientPhoneNumber and add it to the additional SMS notification cc_phone_number = DocuSign_eSign::RecipientPhoneNumber.new cc_phone_number.country_code=envelope_args[:cc_country_code] cc_phone_number.number=envelope_args[:cc_phone_number] - - cc_sms_notification = DocuSign_eSign::RecipientAdditionalNotification.new - cc_sms_notification.phone_number=cc_phone_number - cc_sms_notification.secondary_delivery_method = "SMS" - # Create a cc recipient to receive a copy of the documents - cc1 = DocuSign_eSign::CarbonCopy.new( - email: envelope_args[:cc_email], - name: envelope_args[:cc_name], - routingOrder: '2', - recipientId: '2', - additionalNotifications: [cc_sms_notification] - ) + cc1 = DocuSign_eSign::CarbonCopy.new + cc1.name = envelope_args[:cc_name] + cc1.routing_order = '2' + cc1.recipient_id = '2' + cc1.phone_number = cc_phone_number + # Create signHere fields (also known as tabs) on the documents # We're using anchor (autoPlace) positioning # @@ -165,8 +154,8 @@ def create_document1(args) margin-top: 0px;margin-bottom: 3.5em;font-size: 1em; color: darkblue;\">Order Processing Division

Ordered by #{args[:signer_name]}

-

Email: #{args[:signer_email]}

-

Copy to: #{args[:cc_name]}, #{args[:cc_email]}

+

Phone number: #{args[:phone_number]}

+

Copy to: #{args[:cc_name]}, #{args[:cc_phone_number]}

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.

@@ -175,4 +164,5 @@ def create_document1(args) " end -end \ No newline at end of file + # Step 2 end +end diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index 6b4201c..bcd5049 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -309,9 +309,9 @@

Premium features

-

37. Send an envelope by SMS delivery

+

37. Request a signature by SMS delivery

- This example demonstrates how to send an envelope via an SMS message for a signer (and CC) to read and sign. + Sends a signature request via an SMS message.

API method used: diff --git a/app/views/e_sign/eg037_sms_delivery/get.html.erb b/app/views/e_sign/eg037_sms_delivery/get.html.erb index 140099d..fc68c63 100644 --- a/app/views/e_sign/eg037_sms_delivery/get.html.erb +++ b/app/views/e_sign/eg037_sms_delivery/get.html.erb @@ -1,11 +1,10 @@ -

37. Send an envelope via SMS delivery

- +

37. Request a signature by SMS delivery

-This is a general example of creating and sending an envelope (a signing request) to a recipient and notifying that recipient via SMS delivery. +Sends a signature request via an SMS message.

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

@@ -16,44 +15,31 @@ This is a general example of creating and sending an envelope (a signing request

The country code for the phone number below.
This phone number will receive a notification. We'll never share your phone number with anyone else. -
-
- - - We'll never share your email with anyone else. + aria-describedby="accessHelp" placeholder="415-555-1212" required /> + This phone number will receive a notification. We'll never share your phone number.
+ value="<%= @config.signer_name %>" required />
The country code for the phone number below.
This phone number will receive a notification. We'll never share your phone number with anyone else. -
-
- - - The email for the cc recipient must be different from the signer's email. + aria-describedby="accessHelp" placeholder="415-555-1212" required /> + This phone number will receive a notification. We'll never share your phone number.
@@ -61,4 +47,4 @@ This is a general example of creating and sending an envelope (a signing request required />
- \ No newline at end of file + From f31969a09d7cdc94bdf03aad3db13e54c63f5b7a Mon Sep 17 00:00:00 2001 From: Connor Lunsford Date: Tue, 22 Mar 2022 15:18:30 -0700 Subject: [PATCH 136/363] Fixed mustView bug in Click1 and 3 --- app/services/clickwrap/eg001_create_clickwrap_service.rb | 1 - .../clickwrap/eg003_create_new_clickwrap_version_service.rb | 1 - 2 files changed, 2 deletions(-) diff --git a/app/services/clickwrap/eg001_create_clickwrap_service.rb b/app/services/clickwrap/eg001_create_clickwrap_service.rb index 3c2d798..ab807a5 100644 --- a/app/services/clickwrap/eg001_create_clickwrap_service.rb +++ b/app/services/clickwrap/eg001_create_clickwrap_service.rb @@ -24,7 +24,6 @@ def worker format: 'modal', hasAccept: true, mustRead: true, - mustView: true, requireAccept: true, size: 'medium', documentDisplay: 'document' diff --git a/app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb b/app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb index c416846..ac53ab2 100644 --- a/app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb +++ b/app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb @@ -23,7 +23,6 @@ def worker downloadable: false, format: 'modal', mustRead: true, - mustView: false, requireAccept: false, documentDisplay: 'document', sendToEmail: false From 8872d1723057c60d468682b5e4772e3f5e88d382 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Mon, 28 Mar 2022 16:59:32 -0700 Subject: [PATCH 137/363] Jwt project (#64) jwt_console_project --- .../eg002_signing_via_email_controller.rb | 4 +- .../e_sign/eg002_signing_via_email_service.rb | 6 +- jwt_console_project/jwt_config.example.yml | 4 + jwt_console_project/jwt_console.rb | 127 ++++++++++++++++++ 4 files changed, 136 insertions(+), 5 deletions(-) create mode 100644 jwt_console_project/jwt_config.example.yml create mode 100644 jwt_console_project/jwt_console.rb diff --git a/app/controllers/e_sign/eg002_signing_via_email_controller.rb b/app/controllers/e_sign/eg002_signing_via_email_controller.rb index 6f4b1c4..124231c 100644 --- a/app/controllers/e_sign/eg002_signing_via_email_controller.rb +++ b/app/controllers/e_sign/eg002_signing_via_email_controller.rb @@ -10,7 +10,9 @@ def create signer_name: param_gsub(params['signerName']), cc_email: param_gsub(params['ccEmail']), cc_name: param_gsub(params['ccName']), - status: 'sent' + status: 'sent', + doc_docx: File.join('data', Rails.application.config.doc_docx), + doc_pdf: File.join('data', Rails.application.config.doc_pdf) } args = { account_id: session['ds_account_id'], diff --git a/app/services/e_sign/eg002_signing_via_email_service.rb b/app/services/e_sign/eg002_signing_via_email_service.rb index a8cfd75..819a128 100644 --- a/app/services/e_sign/eg002_signing_via_email_service.rb +++ b/app/services/e_sign/eg002_signing_via_email_service.rb @@ -42,10 +42,8 @@ def make_envelope(envelope_args) doc1_b64 = Base64.encode64(create_document1(envelope_args)) # Read files 2 and 3 from a local directory # The reads could raise an exception if the file is not available! - doc_docx = Rails.application.config.doc_docx - doc2_b64 = Base64.encode64(File.binread(File.join('data', doc_docx))) - doc_pdf = Rails.application.config.doc_pdf - doc3_b64 = Base64.encode64(File.binread(File.join('data', doc_pdf))) + doc2_b64 = Base64.encode64(File.binread(envelope_args[:doc_docx])) + doc3_b64 = Base64.encode64(File.binread(envelope_args[:doc_pdf])) # Create the document models document1 = DocuSign_eSign::Document.new( diff --git a/jwt_console_project/jwt_config.example.yml b/jwt_console_project/jwt_config.example.yml new file mode 100644 index 0000000..8180e06 --- /dev/null +++ b/jwt_console_project/jwt_config.example.yml @@ -0,0 +1,4 @@ +jwt_integration_key: {INTEGRATION_KEY_JWT} +impersonated_user_guid: {IMPERSONATED_USER_ID} +authorization_server: account-d.docusign.com +pdf_filename: '../data/World_Wide_Corp_lorem.pdf' diff --git a/jwt_console_project/jwt_console.rb b/jwt_console_project/jwt_console.rb new file mode 100644 index 0000000..11dd966 --- /dev/null +++ b/jwt_console_project/jwt_console.rb @@ -0,0 +1,127 @@ +require 'bundler/inline' + +gemfile do + source 'https://rubygems.org' + gem 'docusign_esign',' ~> 3.15.0' +end + +class ESign +end + +require 'docusign_esign' +require_relative '../app/services/api_creator' +require_relative '../app/services/e_sign/eg002_signing_via_email_service.rb' +require 'yaml' + +$SCOPES = [ + "signature", "impersonation" +] + +def load_config_data + config_file_path = 'jwt_config.yml' + begin + config_file_contents = File.read(config_file_path) + rescue Errno::ENOENT + $stderr.puts "missing config file" + raise + end + YAML.load(config_file_contents) +end + +def get_consent + url_scopes = $SCOPES.join('+'); + # Construct consent URL + redirect_uri = "https://developers.docusign.com/platform/auth/consent"; + consent_url = "https://#{CONFIG["authorization_server"]}/oauth/auth?response_type=code&" + + "scope=#{url_scopes}&client_id=#{CONFIG["jwt_integration_key"]}&" + + "redirect_uri=#{redirect_uri}" + + puts "Open the following URL in your browser to grant consent to the application:" + puts consent_url + puts "Consent granted? \n 1)Yes \n 2)No" + continue = gets; + if continue.chomp == "1" + return true; + else + puts "Please grant consent" + exit + end +end + +def authenticate + configuration = DocuSign_eSign::Configuration.new + configuration.debugging = true + api_client = DocuSign_eSign::ApiClient.new(configuration) + api_client.set_oauth_base_path(CONFIG["authorization_server"]) + + rsa_pk = 'docusign_private_key.txt' + begin + token = api_client.request_jwt_user_token(CONFIG["jwt_integration_key"], CONFIG["impersonated_user_guid"], rsa_pk, expires_in=3600, $SCOPES) + user_info_response = api_client.get_user_info(token.access_token) + account = user_info_response.accounts.find(&:is_default) + + account_info = { + access_token: token.access_token, + account_id: account.account_id, + base_path: account.base_uri + } + account_info + rescue OpenSSL::PKey::RSAError => exception + Rails.logger.error exception.inspect + if File.read(rsa_pk).starts_with? '{RSA_PRIVATE_KEY}' + fail "Please add your private RSA key to: #{rsa_pk}" + else + raise + end + rescue DocuSign_eSign::ApiError => exception + body = JSON.parse(exception.response_body) + if body['error'] == "consent_required" + authenticate if get_consent + else + puts "API Error" + puts body['error'] + puts body['message'] + exit + end + end +end + +def get_args(apiAccountId, accessToken, basePath) + puts "Enter the signer's email address: " + signerEmail = gets.chomp + puts "Enter the signer's name: " + signerName = gets.chomp + puts "Enter the carbon copy's email address: " + ccSignerEmail = gets.chomp + puts "Enter the carbon copy's name: " + ccSignerName = gets.chomp + + envelope_args = { + signer_email: signerEmail, + signer_name: signerName, + cc_email: ccSignerEmail, + cc_name: ccSignerName, + status: 'sent', + doc_docx: '../data/World_Wide_Corp_Battle_Plan_Trafalgar.docx', + doc_pdf: '../data/World_Wide_Corp_lorem.pdf' + } + args = { + account_id: apiAccountId, + base_path: basePath, + access_token: accessToken, + envelope_args: envelope_args + } + + return args +end + +def main + load_config_data + account_info = authenticate + args = get_args(account_info[:account_id], account_info[:access_token], account_info[:base_path]) + results = ESign::Eg002SigningViaEmailService.new(args).worker + puts "Successfully sent envelope with envelope ID: #{results['envelope_id']}" +end + +CONFIG = load_config_data +main From 01d0f58ac826e035f4c8f07fe306a4648f85548e Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Mon, 11 Apr 2022 14:39:43 -0700 Subject: [PATCH 138/363] update README to include JWT console project (#67) --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index b764abe..27152f9 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,9 @@ Also, in order to select JSON Web Token authentication in the launcher, in confi 1. From the picklist, select **JSON Web Token (JWT) grant** > **Authenticate with DocuSign**. 1. Select your desired code example. +## 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. + ### Troubleshooting Windows SSL issue When using the Ruby launcher on a Windows machine you may get the following error: From ce63c762878caaf20ac6166d6f0c6881e20d2d47 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Wed, 20 Apr 2022 17:08:48 +0300 Subject: [PATCH 139/363] updated example (#58) --- ...030_brands_apply_to_template_controller.rb | 68 ++++++------- .../get.html.erb | 96 ++++++++++--------- 2 files changed, 85 insertions(+), 79 deletions(-) diff --git a/app/controllers/e_sign/eg030_brands_apply_to_template_controller.rb b/app/controllers/e_sign/eg030_brands_apply_to_template_controller.rb index 8e107b5..f86b14e 100644 --- a/app/controllers/e_sign/eg030_brands_apply_to_template_controller.rb +++ b/app/controllers/e_sign/eg030_brands_apply_to_template_controller.rb @@ -13,46 +13,48 @@ def get accounts_api = create_account_api(args) brand_lists = accounts_api.list_brands(args[:account_id], options = DocuSign_eSign::ListBrandsOptions.default) @brand_names = brand_lists.brands - # get the template lists - template_api = create_template_api(args) - template_lists = template_api.list_templates(args[:account_id], options = DocuSign_eSign::ListTemplatesOptions.default) - @templates = template_lists.envelope_templates super end def create - begin - envelope_args = { - signer_email: param_gsub(params[:signerEmail]), - signer_name: param_gsub(params[:signerName]), - cc_email: param_gsub(params[:ccEmail]), - cc_name: param_gsub(params[:ccName]), - brand_id: params[:brands], - template_id: params[:templates], - status: 'sent' - - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } + template_id = session[:template_id] - results = ESign::Eg030BrandsApplyToTemplateService.new(args).worker - session[:envelope_id] = results.envelope_id + if template_id + begin + envelope_args = { + signer_email: param_gsub(params[:signerEmail]), + signer_name: param_gsub(params[:signerName]), + cc_email: param_gsub(params[:ccEmail]), + cc_name: param_gsub(params[:ccName]), + brand_id: params[:brands], + template_id: template_id, + status: 'sent' - # Step 4. a) Call the eSignature API - # b) Display the JSON response - # brand_id = results.brands[0].brand_id - @title = 'Applying a brand to an envelope using a template' - @h1 = 'Applying a brand to an envelope using a template' - @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." - @json = results.to_json.to_json - render 'ds_common/example_done' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } - rescue DocuSign_eSign::ApiError => e - handle_error(e) + results = ESign::Eg030BrandsApplyToTemplateService.new(args).worker + session[:envelope_id] = results.envelope_id + + # Step 4. a) Call the eSignature API + # b) Display the JSON response + # brand_id = results.brands[0].brand_id + @title = 'Applying a brand to an envelope using a template' + @h1 = 'Applying a brand to an envelope using a template' + @message = "The envelope has been created and sent!
Envelope ID #{results.envelope_id}." + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end + elsif !template_id + @title = 'Use embedded signing from template and extra doc' + @template_ok = false end end end diff --git a/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb b/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb index 57c593d..8b31b61 100644 --- a/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb +++ b/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb @@ -1,8 +1,10 @@ -

30. Applying a brand to an envelope using a template

+

30. Applying a brand to an envelope using a template

-

- This code example demonstrates how to apply a brand to a template -

+<% if @template_ok %> +

+ This code example demonstrates how to apply a brand to a template +

+<% end %>

API method used: Envelopes::create. @@ -12,45 +14,47 @@ View source file <%= @source_file %> 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. -
-
- - -
-
- - -
-
- - -
- - +<% if @template_ok %> +
+
+ + + We'll never share your email with anyone else. +
+
+ + +
+
+ + + The email for the cc recipient must be different from the signer's email. +
+
+ + +
+
+ + +
+ + + +<% else %> +

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

+ +
+ + +<% end %> \ No newline at end of file From 074802af833e235089fe304342562e4eb7326f98 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Mon, 25 Apr 2022 18:56:34 +0300 Subject: [PATCH 140/363] Added responsive signing example (#65) * added the responsive signing example * update tabs * update file read and text changes Co-authored-by: Karissa Jacobsen --- .../eg038_responsive_signing_controller.rb | 27 ++++ .../eg038_responsive_signing_service.rb | 129 ++++++++++++++++++ app/views/ds_common/index.html.erb | 14 +- .../eg038_responsive_signing/get.html.erb | 42 ++++++ config/routes.rb | 3 + 5 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 app/controllers/e_sign/eg038_responsive_signing_controller.rb create mode 100644 app/services/e_sign/eg038_responsive_signing_service.rb create mode 100644 app/views/e_sign/eg038_responsive_signing/get.html.erb diff --git a/app/controllers/e_sign/eg038_responsive_signing_controller.rb b/app/controllers/e_sign/eg038_responsive_signing_controller.rb new file mode 100644 index 0000000..159d3d3 --- /dev/null +++ b/app/controllers/e_sign/eg038_responsive_signing_controller.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +class ESign::Eg038ResponsiveSigningController < EgController + before_action :check_auth + + def create + begin + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + signer_email: param_gsub(params[:signerEmail]), + signer_name: param_gsub(params[:signerName]), + cc_email: param_gsub(params[:ccEmail]), + cc_name: param_gsub(params[:ccName]), + ds_ping_url: Rails.application.config.app_url, + signer_client_id: 1000, + doc_file: 'data/order_form.html' + } + + redirect_url = ESign::Eg038ResponsiveSigningService.new(args).worker + redirect_to redirect_url + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end + end +end diff --git a/app/services/e_sign/eg038_responsive_signing_service.rb b/app/services/e_sign/eg038_responsive_signing_service.rb new file mode 100644 index 0000000..fc64ad7 --- /dev/null +++ b/app/services/e_sign/eg038_responsive_signing_service.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +class ESign::Eg038ResponsiveSigningService + attr_reader :args + include ApiCreator + + def initialize(args) + @args = args + end + + # ***DS.snippet.0.start + def worker + ds_return_url = "#{args[:ds_ping_url]}/ds_common-return" + + # Step 1. Create the envelope definition + envelope = make_envelope(args) + + # Step 2. Call DocuSign to create the envelope + envelope_api = create_envelope_api(args) + + results = envelope_api.create_envelope args[:account_id], envelope + envelope_id = results.envelope_id + # Save for future use within the example launcher + # session[:envelope_id] = envelope_id + + # Step 3. Create the recipient view for the embedded signing + view_request = make_recipient_view_request(args, ds_return_url) + + # Call the CreateRecipientView API + results = envelope_api.create_recipient_view args[:account_id], envelope_id, view_request + + # 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) + # Redirect to results.url + results.url + end + + private + + def make_recipient_view_request(args, ds_return_url) + view_request = DocuSign_eSign::RecipientViewRequest.new + # 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. + view_request.return_url = ds_return_url + '?state=123' + + # How has your app authenticated the user? In addition to your app's + # authentication, you can include authenticate steps from DocuSign; + # e.g., SMS authentication + view_request.authentication_method = 'none' + + # Recipient information must match the embedded recipient info + # that was used to create the envelope + view_request.email = args[:signer_email] + view_request.user_name = args[:signer_name] + view_request.client_user_id = args[: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 + view_request.ping_frequency = '600' # seconds + # NOTE: The pings will only be sent if the pingUrl is an HTTPS address + view_request.ping_url = args[:ds_ping_url] # Optional setting + + view_request + end + + def make_envelope(args) + envelope_definition = DocuSign_eSign::EnvelopeDefinition.new + envelope_definition.email_subject = 'Example Signing Document' + + html_definition = DocuSign_eSign::DocumentHtmlDefinition.new + html_definition.source = get_html_content(args) + + doc = DocuSign_eSign::Document.new + doc.name = 'doc1.html' + doc.document_id = '1' + doc.html_definition = html_definition + + # The order in the docs array determines the order in the envelope + envelope_definition.documents = [doc] + # Create a signer recipient to sign the document, identified by name and email + # We're setting the parameters via the object creation + signer = DocuSign_eSign::Signer.new ({ + email: args[:signer_email], + name: args[:signer_name], + clientUserId: args[:signer_client_id], + recipientId: 1, + role_name: "Signer" + }) + + cc = DocuSign_eSign::CarbonCopy.new ({ + email: args[:cc_email], name: args[:cc_name], recipientId: 2 + }) + + # Add the recipients to the envelope object + recipients = DocuSign_eSign::Recipients.new + recipients.signers = [signer] + recipients.carbon_copies = [cc] + + envelope_definition.recipients = recipients + # Request that the envelope be sent by setting status to "sent". + # To request that the envelope be created as a draft, set status to "created" + envelope_definition.status = 'sent' + envelope_definition + end + + def get_html_content(args) + doc_html = File.open(args[:doc_file]).read + # Substitute values into the HTML + # Substitute for: {signerName}, {signerEmail}, {ccName}, {ccEmail} + return doc_html.gsub('{signerName}', args[:signer_name]) \ + .gsub('{signerEmail}', args[:signer_email]) \ + .gsub('{ccName}', args[:cc_name]) \ + .gsub('{ccEmail}', args[:cc_email]) \ + .gsub("/sn1/", "") \ + .gsub("/l1q/", "") \ + .gsub("/l2q/", "") + + end + # ***DS.snippet.0.end +end \ No newline at end of file diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index bcd5049..55a7ca7 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -318,8 +318,18 @@ Envelopes::create.

-
- +

38. Create a signable HTML document

+

+ Demonstrates how to create an HTML document for responsive signing. +

+ API methods used: + Envelopes::create, + EnvelopeViews::createRecipient. +

+ + + diff --git a/app/views/e_sign/eg038_responsive_signing/get.html.erb b/app/views/e_sign/eg038_responsive_signing/get.html.erb new file mode 100644 index 0000000..047f511 --- /dev/null +++ b/app/views/e_sign/eg038_responsive_signing/get.html.erb @@ -0,0 +1,42 @@ +

38. Create a signable HTML document

+

Demonstrates how to create an HTML document for responsive signing.

+ +<% if @show_doc %> +

Documentation about this example.

+<% end %> + +

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

+ +

+ View source file <%= @source_file %> 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. +
+
+ + +
+ + \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 398c269..e0df0ae 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -185,6 +185,9 @@ get 'eg037' => 'eg037_sms_delivery#get' post 'eg037' => 'eg037_sms_delivery#create' + + get 'eg038' => 'eg038_responsive_signing#get' + post 'eg038' => 'eg038_responsive_signing#create' end end From 5748fb5194ea42e2c16241740e68543eee813d4a Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Thu, 28 Apr 2022 15:14:35 -0700 Subject: [PATCH 141/363] add step comments --- .../e_sign/eg038_responsive_signing_service.rb | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/services/e_sign/eg038_responsive_signing_service.rb b/app/services/e_sign/eg038_responsive_signing_service.rb index fc64ad7..6223f8b 100644 --- a/app/services/e_sign/eg038_responsive_signing_service.rb +++ b/app/services/e_sign/eg038_responsive_signing_service.rb @@ -8,14 +8,14 @@ def initialize(args) @args = args end - # ***DS.snippet.0.start + # Step 3 start def worker ds_return_url = "#{args[:ds_ping_url]}/ds_common-return" - # Step 1. Create the envelope definition + # Create the envelope definition envelope = make_envelope(args) - # Step 2. Call DocuSign to create the envelope + # Call DocuSign to create the envelope envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope @@ -23,7 +23,7 @@ def worker # Save for future use within the example launcher # session[:envelope_id] = envelope_id - # Step 3. Create the recipient view for the embedded signing + # Create the recipient view for the embedded signing view_request = make_recipient_view_request(args, ds_return_url) # Call the CreateRecipientView API @@ -71,7 +71,9 @@ def make_recipient_view_request(args, ds_return_url) view_request end + # Step 3 end + # Step 2 start def make_envelope(args) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Example Signing Document' @@ -125,5 +127,5 @@ def get_html_content(args) .gsub("/l2q/", "") end - # ***DS.snippet.0.end + # Step 2 end end \ No newline at end of file From 2001a3d199660d0bbe6fba318104f73f2ca2a755 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Thu, 28 Apr 2022 15:28:08 -0700 Subject: [PATCH 142/363] add step comments (#69) --- .../e_sign/eg038_responsive_signing_service.rb | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/services/e_sign/eg038_responsive_signing_service.rb b/app/services/e_sign/eg038_responsive_signing_service.rb index fc64ad7..6223f8b 100644 --- a/app/services/e_sign/eg038_responsive_signing_service.rb +++ b/app/services/e_sign/eg038_responsive_signing_service.rb @@ -8,14 +8,14 @@ def initialize(args) @args = args end - # ***DS.snippet.0.start + # Step 3 start def worker ds_return_url = "#{args[:ds_ping_url]}/ds_common-return" - # Step 1. Create the envelope definition + # Create the envelope definition envelope = make_envelope(args) - # Step 2. Call DocuSign to create the envelope + # Call DocuSign to create the envelope envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope @@ -23,7 +23,7 @@ def worker # Save for future use within the example launcher # session[:envelope_id] = envelope_id - # Step 3. Create the recipient view for the embedded signing + # Create the recipient view for the embedded signing view_request = make_recipient_view_request(args, ds_return_url) # Call the CreateRecipientView API @@ -71,7 +71,9 @@ def make_recipient_view_request(args, ds_return_url) view_request end + # Step 3 end + # Step 2 start def make_envelope(args) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Example Signing Document' @@ -125,5 +127,5 @@ def get_html_content(args) .gsub("/l2q/", "") end - # ***DS.snippet.0.end + # Step 2 end end \ No newline at end of file From 73b5e34d4aff1f9cbbbc16edead057e48a680c2b Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Tue, 24 May 2022 19:31:55 +0300 Subject: [PATCH 143/363] Added post web query code example (#72) * added new monitor example Co-authored-by: Karissa Jacobsen Co-authored-by: meihDS <70775251+meihDS@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 8 +-- ...eg001_get_monitoring_dataset_controller.rb | 6 +- .../eg002_post_web_query_controller.rb | 23 +++++++ .../eg002_post_web_query_service.rb | 56 ++++++++++++++++++ app/views/.DS_Store | Bin 6148 -> 6148 bytes .../eg002_post_web_query/get.html.erb | 25 ++++++++ app/views/monitor_api/index.html.erb | 15 +++-- config/routes.rb | 2 + 9 files changed, 125 insertions(+), 12 deletions(-) create mode 100644 app/controllers/monitor_api/eg002_post_web_query_controller.rb create mode 100644 app/services/monitor_api/eg002_post_web_query_service.rb create mode 100644 app/views/monitor_api/eg002_post_web_query/get.html.erb diff --git a/Gemfile b/Gemfile index ad855b1..bd0b81f 100644 --- a/Gemfile +++ b/Gemfile @@ -67,7 +67,7 @@ group :test do end gem 'docusign_esign', '~> 3.15.0' -gem 'docusign_monitor', '~> 1.0.0' +gem 'docusign_monitor', '~> 1.1.0' gem 'docusign_rooms', '~> 1.2.0.rc1' gem 'docusign_click', '~> 1.0.0' gem 'docusign_admin', '~> 1.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index d3fff8e..d280aa8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -97,12 +97,12 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.14.0) + docusign_esign (3.15.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_monitor (1.0.0) + docusign_monitor (1.1.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -307,8 +307,8 @@ DEPENDENCIES coffee-rails (~> 5.0.0) docusign_admin (~> 1.0.0) docusign_click (~> 1.0.0) - docusign_esign (~> 3.14.0) - docusign_monitor (~> 1.0.0) + docusign_esign (~> 3.15.0) + docusign_monitor (~> 1.1.0) docusign_rooms (~> 1.2.0.rc1) jbuilder (~> 2.10.0) listen (> 3.2.1) diff --git a/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb b/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb index a3ff78a..4326aca 100644 --- a/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb +++ b/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb @@ -10,9 +10,9 @@ def create results = MonitorApi::Eg001GetMonitoringDatasetService.new(args).worker - @title = "Monitoring data result" - @h1 = "Monitoring data result" - @message = "Results from DataSet:GetStreamForDataset method:" + @title = "Get monitoring data" + @h1 = "Get monitoring data" + @message = "Results from DataSet:getStream method:" @json = results.to_json.to_json render 'ds_common/example_done' diff --git a/app/controllers/monitor_api/eg002_post_web_query_controller.rb b/app/controllers/monitor_api/eg002_post_web_query_controller.rb new file mode 100644 index 0000000..a98e84a --- /dev/null +++ b/app/controllers/monitor_api/eg002_post_web_query_controller.rb @@ -0,0 +1,23 @@ +class MonitorApi::Eg002PostWebQueryController < EgController + before_action :check_auth + + def create + args = { + access_token: session[:ds_access_token], + data_set_name: 'monitor', + account_id: session['ds_account_id'], + version: '2.0', + start_date: params[:start_date], + end_date: params[:end_date] + } + + results = MonitorApi::Eg002PostWebQueryService.new(args).worker + + @title = "Query monitoring data with filters" + @h1 = "Query monitoring data with filters" + @message = "Results from DataSet:postWebQuery method:" + @json = results.to_json.to_json + + render 'ds_common/example_done' + end +end diff --git a/app/services/monitor_api/eg002_post_web_query_service.rb b/app/services/monitor_api/eg002_post_web_query_service.rb new file mode 100644 index 0000000..31aa087 --- /dev/null +++ b/app/services/monitor_api/eg002_post_web_query_service.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +class MonitorApi::Eg002PostWebQueryService + attr_reader :args + + def initialize(args) + @args = args + end + + def worker + # step 2 start + configuration = DocuSign_Monitor::Configuration.new + configuration.host = Rails.configuration.monitor_host + configuration.debugging = true + api_client = DocuSign_Monitor::ApiClient.new configuration + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + # step 2 end + + # step 3 start + monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) + @response = monitor_api.post_web_query(args[:data_set_name], args[:version], get_query) + + # step 3 end + + Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" + Rails.logger.info @response.inspect + + return @response + end + + def get_query + return { + "filters": [ + { + "FilterName": "Time", + "BeginTime": args[:start_date], + "EndTime": args[:end_date] + }, + { + "FilterName": "Has", + "ColumnName": "AccountId", + "Value": args[:account_id] + } + ], + "aggregations": [ + { + "aggregationName": "Raw", + "limit": "1", + "orderby": [ + "Timestamp, desc" + ] + } + ] + } + end +end diff --git a/app/views/.DS_Store b/app/views/.DS_Store index d4a0fa470f59959ca1974fb7586a6e34f187a60b..d1e123cf3eff3b29e86069c7c8d27fe83103cba1 100644 GIT binary patch delta 73 zcmZoMXfc=|#>B)qu~2NHo+2aD#(>?7lMO^zCX2A@Znj|&VcaajAB!ku~2NHo+2aL#(>?7ixZfc7}+KZG8=5RVG?09mu5(1NM|r$Fk~=g zhzGJ#8A^b3DnlMa8Ia6j$Y&@3((ypiM1~|FodTqR?8!Dv6WB~mbrcMZCtqT6swdN! zvf!e;ocz3W1_lO3AeIGM1#yfy(5hk}59F8Upe0#dZD?$%qo8YOWKpZ5P;G8*prc@7Y*t&#$sw+4XzQ7fTUk|I zQ(HG{@<%3l``MJ(&rm$sky&^%I|n}pFuXShGJj{D%rD}|0rV6T&|HSi5h81t0WYmr ATL1t6 diff --git a/app/views/monitor_api/eg002_post_web_query/get.html.erb b/app/views/monitor_api/eg002_post_web_query/get.html.erb new file mode 100644 index 0000000..0f758c9 --- /dev/null +++ b/app/views/monitor_api/eg002_post_web_query/get.html.erb @@ -0,0 +1,25 @@ +

2. Query monitoring data with filters

+

Demonstrates how to query an organization's data based on specified filters and aggregations.

+ +

API method used: + DataSet:postWebQuery. +

+ +

+ View source file <%= @source_file %> on GitHub. +

+ +

+ Please select start and end dates. +

+
+
+ + max=<%= Time.now %>> +
+
+ + max=<%= Time.now %>> +
+ + \ No newline at end of file diff --git a/app/views/monitor_api/index.html.erb b/app/views/monitor_api/index.html.erb index a0ee4cd..32d3f54 100644 --- a/app/views/monitor_api/index.html.erb +++ b/app/views/monitor_api/index.html.erb @@ -5,7 +5,7 @@

Ruby Launcher

-

Welcome to the Ruby code examples for DocuSign Monitor API with JWT Grant authentication

+

Run and explore Monitor API code examples with JWT Grant authentication

@@ -22,8 +22,6 @@

Documentation on using JWT Authorization from a Ruby Rails application.

<% end %> -

Monitor API Code examples

-

1. Get monitoring data

Demonstrates how to get and display all of your organization’s monitoring data. @@ -33,7 +31,16 @@ DataSet:GetStream

+

2. Query monitoring data with filters

+

+ Demonstrates how to query an organization's data based on specified filters and aggregations. +

+

+ API method used: + DataSet:postWebQuery. +

+ - \ No newline at end of file + diff --git a/config/routes.rb b/config/routes.rb index e0df0ae..b67a9d4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -54,6 +54,8 @@ scope module: 'monitor_api' do get 'eg001' => 'eg001_get_monitoring_dataset#get' post 'eg001' => 'eg001_get_monitoring_dataset#create' + get 'eg002' => 'eg002_post_web_query#get' + post 'eg002' => 'eg002_post_web_query#create' end end constraints lambda { |req| req.session[:examples_API] == "Admin" } do From bf0cecb53460a52a5ee59b30abf2dd4eb3fc44d0 Mon Sep 17 00:00:00 2001 From: Bharat Rele Date: Wed, 25 May 2022 16:39:57 -0700 Subject: [PATCH 144/363] Update Gemfile (#71) --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index bd0b81f..26ef872 100644 --- a/Gemfile +++ b/Gemfile @@ -70,7 +70,7 @@ gem 'docusign_esign', '~> 3.15.0' gem 'docusign_monitor', '~> 1.1.0' gem 'docusign_rooms', '~> 1.2.0.rc1' gem 'docusign_click', '~> 1.0.0' -gem 'docusign_admin', '~> 1.0.0' +gem 'docusign_admin', '~> 1.1.0' gem 'omniauth-oauth2', '~> 1.7.1' gem 'omniauth-rails_csrf_protection' From 99e4a472a748cb0495adabfb049f35b634deb7c6 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Fri, 3 Jun 2022 09:05:05 -0700 Subject: [PATCH 145/363] Devdocs 7075 (#74) * add step comments * update object names in new esign sdk version * update esign package --- Gemfile | 2 +- app/services/e_sign/eg035_scheduled_sending_service.rb | 4 ++-- app/services/e_sign/eg036_delayed_routing_service.rb | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 26ef872..cf3a5de 100644 --- a/Gemfile +++ b/Gemfile @@ -66,7 +66,7 @@ group :test do gem 'chromedriver-helper', '~> 2.1.1' end -gem 'docusign_esign', '~> 3.15.0' +gem 'docusign_esign', '~> 3.17.0' gem 'docusign_monitor', '~> 1.1.0' gem 'docusign_rooms', '~> 1.2.0.rc1' gem 'docusign_click', '~> 1.0.0' diff --git a/app/services/e_sign/eg035_scheduled_sending_service.rb b/app/services/e_sign/eg035_scheduled_sending_service.rb index b836267..b2e6a7c 100644 --- a/app/services/e_sign/eg035_scheduled_sending_service.rb +++ b/app/services/e_sign/eg035_scheduled_sending_service.rb @@ -89,11 +89,11 @@ def make_envelope(envelope_args) envelope_definition.recipients = recipients # Create recipientRules model - rule = DocuSign_eSign::EnvelopeDelayRuleApiModel.new( + rule = DocuSign_eSign::EnvelopeDelayRule.new( resumeDate: envelope_args[:resume_date].to_s ) - scheduled_sending = DocuSign_eSign::ScheduledSendingApiModel.new( + scheduled_sending = DocuSign_eSign::ScheduledSending.new( rules: [rule] ) diff --git a/app/services/e_sign/eg036_delayed_routing_service.rb b/app/services/e_sign/eg036_delayed_routing_service.rb index 40d934a..a18e8b6 100644 --- a/app/services/e_sign/eg036_delayed_routing_service.rb +++ b/app/services/e_sign/eg036_delayed_routing_service.rb @@ -107,9 +107,9 @@ def make_envelope(envelope_args) # Create recipientRules model delay_time = "0." + envelope_args[:delay].to_s + ":00:00"; - rule = DocuSign_eSign::EnvelopeDelayRuleApiModel.new(delay: delay_time) + rule = DocuSign_eSign::EnvelopeDelayRule.new(delay: delay_time) - delayed_routing = DocuSign_eSign::DelayedRoutingApiModel.new(rules: [rule]) + delayed_routing = DocuSign_eSign::DelayedRouting.new(rules: [rule]) # Create a workflow model workflow_step = DocuSign_eSign::WorkflowStep.new( From 694f066e4e883b4a9a5efe16f535a0ed8fc11acf Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Sat, 4 Jun 2022 01:42:51 +0300 Subject: [PATCH 146/363] Added eg006 and eg007 admin examples (#75) * added admin examples --- Gemfile | 2 +- Gemfile.lock | 21 +++++++------- ...06_get_user_profile_by_email_controller.rb | 28 +++++++++++++++++++ ..._get_user_profile_by_user_id_controller.rb | 28 +++++++++++++++++++ ...eg006_get_user_profile_by_email_service.rb | 27 ++++++++++++++++++ ...007_get_user_profile_by_user_id_service.rb | 24 ++++++++++++++++ .../get.html.erb | 21 ++++++++++++++ .../get.html.erb | 17 +++++++++++ app/views/admin_api/index.html.erb | 18 ++++++++++-- config/routes.rb | 6 ++++ 10 files changed, 179 insertions(+), 13 deletions(-) create mode 100644 app/controllers/admin_api/eg006_get_user_profile_by_email_controller.rb create mode 100644 app/controllers/admin_api/eg007_get_user_profile_by_user_id_controller.rb create mode 100644 app/services/admin_api/eg006_get_user_profile_by_email_service.rb create mode 100644 app/services/admin_api/eg007_get_user_profile_by_user_id_service.rb create mode 100644 app/views/admin_api/eg006_get_user_profile_by_email/get.html.erb create mode 100644 app/views/admin_api/eg007_get_user_profile_by_user_id/get.html.erb diff --git a/Gemfile b/Gemfile index cf3a5de..5c550e5 100644 --- a/Gemfile +++ b/Gemfile @@ -10,7 +10,7 @@ gem 'rails', '~> 6.0.4.1' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4.2' # Use Puma as the app server -gem 'puma', '~> 4.3.11' +gem 'puma', '~> 4.3.12' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets diff --git a/Gemfile.lock b/Gemfile.lock index d280aa8..15ce3d1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -87,7 +87,7 @@ GEM coffee-script-source (1.12.2) concurrent-ruby (1.1.9) crass (1.0.6) - docusign_admin (1.0.0) + docusign_admin (1.1.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -97,7 +97,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.15.0) + docusign_esign (3.17.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -168,11 +168,11 @@ GEM multi_xml (0.6.0) multipart-post (2.1.1) nio4r (2.5.8) - nokogiri (1.13.1-x64-mingw32) + nokogiri (1.13.6-x64-mingw32) racc (~> 1.4) - nokogiri (1.13.1-x86_64-darwin) + nokogiri (1.13.6-x86_64-darwin) racc (~> 1.4) - nokogiri (1.13.1-x86_64-linux) + nokogiri (1.13.6-x86_64-linux) racc (~> 1.4) oauth2 (1.4.7) faraday (>= 0.8, < 2.0) @@ -198,9 +198,9 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.6) - puma (4.3.11) + puma (4.3.12) nio4r (~> 2.0) - racc (1.5.2) + racc (1.6.0) rack (2.2.3) rack-protection (2.1.0) rack @@ -297,6 +297,7 @@ GEM PLATFORMS x64-mingw32 x86_64-darwin-20 + x86_64-darwin-21 x86_64-linux DEPENDENCIES @@ -305,9 +306,9 @@ DEPENDENCIES capybara (~> 3.31.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_admin (~> 1.0.0) + docusign_admin (~> 1.1.0) docusign_click (~> 1.0.0) - docusign_esign (~> 3.15.0) + docusign_esign (~> 3.17.0) docusign_monitor (~> 1.1.0) docusign_rooms (~> 1.2.0.rc1) jbuilder (~> 2.10.0) @@ -316,7 +317,7 @@ DEPENDENCIES omniauth-rails_csrf_protection pry-nav (~> 0.3.0) pry-rails (~> 0.3.9) - puma (~> 4.3.11) + puma (~> 4.3.12) rails (~> 6.0.4.1) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) diff --git a/app/controllers/admin_api/eg006_get_user_profile_by_email_controller.rb b/app/controllers/admin_api/eg006_get_user_profile_by_email_controller.rb new file mode 100644 index 0000000..b6a4796 --- /dev/null +++ b/app/controllers/admin_api/eg006_get_user_profile_by_email_controller.rb @@ -0,0 +1,28 @@ +class AdminApi::Eg006GetUserProfileByEmailController < EgController + include ApiCreator + before_action :check_auth + + def create + begin + if session[:organization_id].nil? + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id + end + + args = { + access_token: session['ds_access_token'], + organization_id: session['organization_id'], + email: param_gsub(params['email']) + } + + results = AdminApi::Eg006GetUserProfileByEmailService.new(args).worker + + @title = 'Retrieve the user’s DocuSign profile using an email address' + @h1 = 'Retrieve the user’s DocuSign profile using an email address' + @message = "Results from MultiProductUserManagement:getUserDSProfilesByEmail method:" + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) + end + end +end diff --git a/app/controllers/admin_api/eg007_get_user_profile_by_user_id_controller.rb b/app/controllers/admin_api/eg007_get_user_profile_by_user_id_controller.rb new file mode 100644 index 0000000..6f1c8ee --- /dev/null +++ b/app/controllers/admin_api/eg007_get_user_profile_by_user_id_controller.rb @@ -0,0 +1,28 @@ +class AdminApi::Eg007GetUserProfileByUserIdController < EgController + include ApiCreator + before_action :check_auth + + def create + begin + if session[:organization_id].nil? + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id + end + + args = { + access_token: session['ds_access_token'], + organization_id: session['organization_id'], + user_id: param_gsub(params['user_id']) + } + + results = AdminApi::Eg007GetUserProfileByUserIdService.new(args).worker + + @title = 'Retrieve the user’s DocuSign profile using a User ID' + @h1 = 'Retrieve the user’s DocuSign profile using a User ID' + @message = "Results from MultiProductUserManagement:getUserDSProfile method:" + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) + end + end +end diff --git a/app/services/admin_api/eg006_get_user_profile_by_email_service.rb b/app/services/admin_api/eg006_get_user_profile_by_email_service.rb new file mode 100644 index 0000000..6ebf2e8 --- /dev/null +++ b/app/services/admin_api/eg006_get_user_profile_by_email_service.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +class AdminApi::Eg006GetUserProfileByEmailService + attr_reader :args + + def initialize(args) + @args = args + end + + def worker + # Step 2 start + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + # Step 2 end + + # Step 3 start + users_api = DocuSign_Admin::UsersApi.new(api_client) + + options = DocuSign_Admin::GetUserDSProfilesByEmailOptions.new + options.email = args[:email] + response = users_api.get_user_ds_profiles_by_email(args[:organization_id], options) + # Step 3 end + end +end diff --git a/app/services/admin_api/eg007_get_user_profile_by_user_id_service.rb b/app/services/admin_api/eg007_get_user_profile_by_user_id_service.rb new file mode 100644 index 0000000..1a48395 --- /dev/null +++ b/app/services/admin_api/eg007_get_user_profile_by_user_id_service.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class AdminApi::Eg007GetUserProfileByUserIdService + attr_reader :args + + def initialize(args) + @args = args + end + + def worker + # Step 2 start + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + # Step 2 end + + # Step 3 start + users_api = DocuSign_Admin::UsersApi.new(api_client) + response = users_api.get_user_ds_profile(args[:organization_id], args[:user_id]) + # Step 3 end + end +end diff --git a/app/views/admin_api/eg006_get_user_profile_by_email/get.html.erb b/app/views/admin_api/eg006_get_user_profile_by_email/get.html.erb new file mode 100644 index 0000000..d240550 --- /dev/null +++ b/app/views/admin_api/eg006_get_user_profile_by_email/get.html.erb @@ -0,0 +1,21 @@ +

6. Retrieve the user's DocuSign profile using an email address

+

Demonstrates how to obtain the user’s DocuSign profile information across all DocuSign accounts by specifying the user’s email address.

+ +

API method used: + MultiProductUserManagement:getUserDSProfilesByEmail. +

+ +

+ View source file <%= @source_file %> on GitHub. +

+ +
+
+ + + We will never share your email with anyone else. +
+ +
diff --git a/app/views/admin_api/eg007_get_user_profile_by_user_id/get.html.erb b/app/views/admin_api/eg007_get_user_profile_by_user_id/get.html.erb new file mode 100644 index 0000000..fe00a18 --- /dev/null +++ b/app/views/admin_api/eg007_get_user_profile_by_user_id/get.html.erb @@ -0,0 +1,17 @@ +

7. Retrieve the user's DocuSign profile using a User ID

+

Demonstrates how to obtain the user’s DocuSign profile information across all DocuSign accounts by specifying the user’s User ID.

+ +

API method used: + MultiProductUserManagement:getUserDSProfile. +

+ +
+
+ + +
+ +
diff --git a/app/views/admin_api/index.html.erb b/app/views/admin_api/index.html.erb index 93122d3..ffdc89a 100644 --- a/app/views/admin_api/index.html.erb +++ b/app/views/admin_api/index.html.erb @@ -21,8 +21,6 @@

Documentation on using JWT Grant or Authorization Code Grant from a Ruby on Rails application.

<% end %> -

DocuSign Admin API Code Examples

-

1. Create a new active eSignature user

Demonstrates how to create a new eSignature user and activate their account automatically.

@@ -85,6 +83,22 @@ href="https://developers.docusign.com/docs/admin-api/reference/usermanagement/esignusermanagement/getuserprofiles/">eSignUserManagement:getUserProfiles

+

6. Retrieve the user's DocuSign profile using an email address

+

Demonstrates how to obtain the user’s DocuSign profile information across all DocuSign accounts by specifying the user’s email address.

+ +

API method used: + MultiProductUserManagement:getUserDSProfilesByEmail +

+ +

7. Retrieve the user's DocuSign profile using a User ID

+

Demonstrates how to obtain the user’s DocuSign profile information across all DocuSign accounts by specifying the user’s User ID.

+ +

API method used: + MultiProductUserManagement:getUserDSProfile +

+ diff --git a/config/routes.rb b/config/routes.rb index b67a9d4..44ccd7d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -75,6 +75,12 @@ get 'eg005' => 'eg005_audit_users#get' post 'eg005' => 'eg005_audit_users#create' + + get 'eg006' => 'eg006_get_user_profile_by_email#get' + post 'eg006' => 'eg006_get_user_profile_by_email#create' + + get 'eg007' => 'eg007_get_user_profile_by_user_id#get' + post 'eg007' => 'eg007_get_user_profile_by_user_id#create' end end constraints lambda { |req| req.session[:examples_API] == "eSignature" } do From 1f455a3acc5185756893f97f5289197c8c3261a4 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Wed, 15 Jun 2022 13:45:26 -0700 Subject: [PATCH 147/363] Devdocs 7910 (#77) change result limit to 100 --- app/services/monitor_api/eg002_post_web_query_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/monitor_api/eg002_post_web_query_service.rb b/app/services/monitor_api/eg002_post_web_query_service.rb index 31aa087..0bd370a 100644 --- a/app/services/monitor_api/eg002_post_web_query_service.rb +++ b/app/services/monitor_api/eg002_post_web_query_service.rb @@ -21,7 +21,7 @@ def worker @response = monitor_api.post_web_query(args[:data_set_name], args[:version], get_query) # step 3 end - + Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" Rails.logger.info @response.inspect @@ -45,7 +45,7 @@ def get_query "aggregations": [ { "aggregationName": "Raw", - "limit": "1", + "limit": "100", "orderby": [ "Timestamp, desc" ] From b02f9478ed5c98d345669f5b025650307174cfda Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Wed, 22 Jun 2022 09:07:20 -0700 Subject: [PATCH 148/363] minor fix for example 23 --- app/services/e_sign/eg023_idv_authentication_service.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/services/e_sign/eg023_idv_authentication_service.rb b/app/services/e_sign/eg023_idv_authentication_service.rb index 4a678b3..7d0a52d 100644 --- a/app/services/e_sign/eg023_idv_authentication_service.rb +++ b/app/services/e_sign/eg023_idv_authentication_service.rb @@ -9,7 +9,7 @@ def initialize(args) end def worker - # ***DS.snippet.0.start + envelope_args = args[:envelope_args] # Step 3. Obtain your workflow ID accounts_api = create_account_api(args) @@ -88,7 +88,6 @@ def worker results = envelope_api.create_envelope args[:account_id], envelope_definition # Step 5 end - session[:envelope_id] = results.envelope_id results end end \ No newline at end of file From 015f02aec3ddccf3f58a3e220f107e57b6bf5f35 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Thu, 30 Jun 2022 23:05:32 +0300 Subject: [PATCH 149/363] Added new Admin API eg008 and eg009 code examples (#78) * added admin api code examples --- ...create_active_clm_esign_user_controller.rb | 2 + ...r_product_permission_profile_controller.rb | 84 +++++++++++++++++ ...r_product_permission_profile_controller.rb | 89 +++++++++++++++++++ ...user_product_permission_profile_service.rb | 29 ++++++ ...user_product_permission_profile_service.rb | 45 ++++++++++ app/services/admin_api/get_data_service.rb | 14 +++ .../get.html.erb | 73 +++++++++++++++ .../get.html.erb | 37 ++++++++ app/views/admin_api/index.html.erb | 18 ++++ config/routes.rb | 6 ++ 10 files changed, 397 insertions(+) create mode 100644 app/controllers/admin_api/eg008_update_user_product_permission_profile_controller.rb create mode 100644 app/controllers/admin_api/eg009_delete_user_product_permission_profile_controller.rb create mode 100644 app/services/admin_api/eg008_update_user_product_permission_profile_service.rb create mode 100644 app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb create mode 100644 app/views/admin_api/eg008_update_user_product_permission_profile/get.html.erb create mode 100644 app/views/admin_api/eg009_delete_user_product_permission_profile/get.html.erb diff --git a/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb b/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb index 3dcc509..12e38ec 100644 --- a/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb +++ b/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb @@ -21,6 +21,8 @@ def create results = AdminApi::Eg002CreateActiveClmEsignUserService.new(args).worker + session[:clm_email] = params[:email] + @title = "Create a new active user for CLM and eSignature" @h1 = "Create a new active user for CLM and eSignature" @message = "Results from MultiProductUserManagement::addOrUpdateUser method:" diff --git a/app/controllers/admin_api/eg008_update_user_product_permission_profile_controller.rb b/app/controllers/admin_api/eg008_update_user_product_permission_profile_controller.rb new file mode 100644 index 0000000..2847328 --- /dev/null +++ b/app/controllers/admin_api/eg008_update_user_product_permission_profile_controller.rb @@ -0,0 +1,84 @@ +class AdminApi::Eg008UpdateUserProductPermissionProfileController < EgController + before_action :check_auth + + def create + clm_email = session[:clm_email] + get_data_service = AdminApi::GetDataService.new(session) + + unless clm_email && get_data_service.check_user_exists_by_email(clm_email) + @email_ok = false + return + end + + begin + product_permission_profiles = get_data_service.get_product_permission_profiles + product_id = params[:product_id] + permission_profile_id = nil + + product_permission_profiles.each { |profile| + if product_id == profile['product_id'] + if profile['product_name'] == "CLM" + permission_profile_id = params[:clm_permission_profile_id] + else + permission_profile_id = params[:esign_permission_profile_id] + end + end + } + + args = { + email: clm_email, + permission_profile_id: permission_profile_id, + product_id: product_id, + account_id: session[:ds_account_id], + organization_id: session['organization_id'], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } + + results = AdminApi::Eg008UpdateUserProductPermissionProfileService.new(args).worker + + @title = "Update user product permission profiles using an email address" + @h1 = "Update user product permission profiles using an email address" + @message = "Results from MultiProductUserManagement:addUserProductPermissionProfilesByEmail method:" + @json = results.to_json.to_json + + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) + end + end + + def get + super + get_data_service = AdminApi::GetDataService.new(session) + + if session[:organization_id].nil? + session[:organization_id] = get_data_service.get_organization_id + end + + clm_email = session[:clm_email] + + unless clm_email && get_data_service.check_user_exists_by_email(clm_email) + @email_ok = false + return + end + + product_permission_profiles = get_data_service.get_product_permission_profiles + + product_permission_profiles.each do |product_permission_profile| + if product_permission_profile['product_name'] == "CLM" + @clm_permission_profiles = product_permission_profile['permission_profiles'] + @clm_product_id = product_permission_profile['product_id'] + else + @esign_permission_profiles = product_permission_profile['permission_profiles'] + @esign_product_id = product_permission_profile['product_id'] + end + end + product_list = [] + product_list.push({ "product_id" => @clm_product_id, "product_name" => "CLM" }) + product_list.push({ "product_id" => @esign_product_id, "product_name" => "eSignature" }) + @product_list = product_list + @email_ok = true + @email = clm_email + end + end diff --git a/app/controllers/admin_api/eg009_delete_user_product_permission_profile_controller.rb b/app/controllers/admin_api/eg009_delete_user_product_permission_profile_controller.rb new file mode 100644 index 0000000..3248fb1 --- /dev/null +++ b/app/controllers/admin_api/eg009_delete_user_product_permission_profile_controller.rb @@ -0,0 +1,89 @@ +class AdminApi::Eg009DeleteUserProductPermissionProfileController < EgController + before_action :check_auth + + def create + clm_email = session[:clm_email] + get_data_service = AdminApi::GetDataService.new(session) + + unless clm_email && get_data_service.check_user_exists_by_email(clm_email) + @email_ok = false + return + end + + begin + args = { + email: clm_email, + product_id: params[:product_id], + account_id: session[:ds_account_id], + organization_id: session['organization_id'], + access_token: session[:ds_access_token] + } + + results = AdminApi::Eg009DeleteUserProductPermissionProfileService.new(args).worker + + @title = "Delete user product permission profiles using an email address" + @h1 = "Delete user product permission profiles using an email address" + @message = "Results from MultiProductUserManagement:removeUserProductPermission method:" + @json = results.to_json.to_json + + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) + end + end + + def get + super + get_data_service = AdminApi::GetDataService.new(session) + + if session[:organization_id].nil? + session[:organization_id] = get_data_service.get_organization_id + end + + clm_email = session[:clm_email] + + unless clm_email && get_data_service.check_user_exists_by_email(clm_email) + @email_ok = false + return + end + + args = { + email: clm_email, + account_id: session[:ds_account_id], + organization_id: session['organization_id'], + access_token: session[:ds_access_token] + } + + product_permission_profiles = AdminApi::Eg009DeleteUserProductPermissionProfileService.new(args).get_permission_profiles_by_email + permission_profile_list = [] + clm_product_id = nil + clm_permission_profile_name = nil + esign_product_id = nil + esign_permission_profile_name = nil + + product_permission_profiles.each do |product_permission_profile| + permission_profiles = product_permission_profile["permission_profiles"] + permission_profiles.each do |permission_profile| + if product_permission_profile['product_name'] == "CLM" + clm_permission_profile_name = permission_profile['permission_profile_name'] + clm_product_id = product_permission_profile['product_id'] + else + esign_permission_profile_name = permission_profile['permission_profile_name'] + esign_product_id = product_permission_profile['product_id'] + end + end + end + + if clm_product_id + permission_profile_list.push({"product_id" => clm_product_id, "permission_name" => "CLM - #{clm_permission_profile_name}"}) + end + + if esign_product_id + permission_profile_list.push({"product_id" => esign_product_id, "permission_name" => "eSignature - #{esign_permission_profile_name}"}) + end + + @permission_profile_list = permission_profile_list + @email_ok = true + @email = clm_email + end + end diff --git a/app/services/admin_api/eg008_update_user_product_permission_profile_service.rb b/app/services/admin_api/eg008_update_user_product_permission_profile_service.rb new file mode 100644 index 0000000..2e945d1 --- /dev/null +++ b/app/services/admin_api/eg008_update_user_product_permission_profile_service.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class AdminApi::Eg008UpdateUserProductPermissionProfileService + attr_reader :args + + def initialize(args) + @args = args + end + + def worker + # Step 2 start + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + # Step 2 end + + # Step 3 start + product_permission_profile = DocuSign_Admin::ProductPermissionProfileRequest.new({'permission_profile_id' => args[:permission_profile_id], 'product_id' => args[:product_id]}) + user_product_permission_profile_request = DocuSign_Admin::UserProductPermissionProfilesRequest.new({'email' => args[:email], 'product_permission_profiles' => [product_permission_profile]}) + # Step 3 end + + # Step 4 start + product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(api_client) + response = product_permission_profiles_api.add_user_product_permission_profiles_by_email(args[:organization_id], args[:account_id], user_product_permission_profile_request) + # Step 4 end + end +end \ No newline at end of file diff --git a/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb b/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb new file mode 100644 index 0000000..12794bc --- /dev/null +++ b/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +class AdminApi::Eg009DeleteUserProductPermissionProfileService + attr_reader :args + + def initialize(args) + @args = args + end + + def worker + # Step 2 start + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + # Step 2 end + + # Step 3 start + user_product_profile_delete_request = DocuSign_Admin::UserProductProfileDeleteRequest.new({'user_email' => args[:email], 'product_ids' => [args[:product_id]]}) + # Step 3 end + + # Step 4 start + product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(api_client) + response = product_permission_profiles_api.remove_user_product_permission(args[:organization_id], args[:account_id], user_product_profile_delete_request) + # Step 4 end + end + + def get_permission_profiles_by_email + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + + product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(api_client) + + options = DocuSign_Admin::GetUserProductPermissionProfilesByEmailOptions.new + options.email = args[:email] + + product_permission_profiles = product_permission_profiles_api.get_user_product_permission_profiles_by_email(args[:organization_id], args[:account_id], options) + product_permission_profiles.as_json['product_permission_profiles'] + + end +end \ No newline at end of file diff --git a/app/services/admin_api/get_data_service.rb b/app/services/admin_api/get_data_service.rb index cff6905..058db0c 100644 --- a/app/services/admin_api/get_data_service.rb +++ b/app/services/admin_api/get_data_service.rb @@ -45,6 +45,20 @@ def check_import_status(import_id) return response end + def check_user_exists_by_email(email) + worker + users_api = DocuSign_Admin::UsersApi.new(@api_client) + options = DocuSign_Admin::GetUsersOptions.new() + options.email = email + response = users_api.get_users(args[:organization_id], options) + + if response.users.length == 0 || response.users[0].user_status == "closed" + return false + end + + return true + end + private def worker diff --git a/app/views/admin_api/eg008_update_user_product_permission_profile/get.html.erb b/app/views/admin_api/eg008_update_user_product_permission_profile/get.html.erb new file mode 100644 index 0000000..95fe66b --- /dev/null +++ b/app/views/admin_api/eg008_update_user_product_permission_profile/get.html.erb @@ -0,0 +1,73 @@ +

8. Update user product permission profiles using an email address

+

Demonstrates how to update user product permission profiles. There may only be one permission profile assigned to a user per product.

+ +

+ API methods used: + MultiProductUserManagement:getProductPermissionProfiles, + MultiProductUserManagement:addUserProductPermissionProfilesByEmail. +

+ +

+ View source file <%= @source_file %> on GitHub. +

+ +<% if @email_ok %> +

Update user product permission profile for the following email: <%= @email %>

+ +
+
+ + <%= select_tag "product_id", options_for_select(@product_list.map { |obj| [obj['product_name'], obj['product_id']] }), { :class => 'form-control' } %> +
+ + <% if @clm_permission_profiles.present? %> +
+ + <%= select_tag "clm_permission_profile_id", options_for_select(@clm_permission_profiles.map { |obj| [obj['permission_profile_name'], obj['permission_profile_id']] }), { :class => 'form-control' } %> +
+ <% else %> +
+

Problem: Please first create a CLM permission profile. +
Thank you.

+
+ <% end %> + + <% if @esign_permission_profiles.present? %> + + <% else %> +
+

Problem: Please first create an eSignature permission profile.

+
Thank you.

+
+ <% end %> + + + + +
+ + + +<% else %> +

Problem: You do not have the user to change permissions for. Go to example 2 and create one. +
Thank you.

+ +
+ +
+<% end %> \ No newline at end of file diff --git a/app/views/admin_api/eg009_delete_user_product_permission_profile/get.html.erb b/app/views/admin_api/eg009_delete_user_product_permission_profile/get.html.erb new file mode 100644 index 0000000..e725f3a --- /dev/null +++ b/app/views/admin_api/eg009_delete_user_product_permission_profile/get.html.erb @@ -0,0 +1,37 @@ +

9. Delete user product permission profiles using an email address

+

Demonstrates how to list and delete DocuSign Admin user product permission profiles.

+ +

+ API methods used: + MultiProductUserManagement:getUserProductPermissionProfilesByEmail, + MultiProductUserManagement:removeUserProductPermission. +

+ +

+ View source file <%= @source_file %> on GitHub. +

+<% if @email_ok %> +

Delete user product permission profile for the following email: <%= @email %>

+ +
+ <% if @permission_profile_list.present? %> +
+ + <%= select_tag "product_id", options_for_select(@permission_profile_list.map { |obj| [obj['permission_name'], obj['product_id']] }), { :class => 'form-control' } %> +
+ <% else %> +
+

Problem: Please first create an eSignature permission profile. +
Thank you.

+
+ <% end %> + +
+<% else %> +

Problem: You do not have the user to change permissions for. Go to example 2 and create one. +
Thank you.

+ +
+ +
+<% end %> \ No newline at end of file diff --git a/app/views/admin_api/index.html.erb b/app/views/admin_api/index.html.erb index ffdc89a..ef9d9ff 100644 --- a/app/views/admin_api/index.html.erb +++ b/app/views/admin_api/index.html.erb @@ -99,6 +99,24 @@ href="https://developers.docusign.com/docs/admin-api/reference/usermanagement/multiproductusermanagement/getuserdsprofile/">MultiProductUserManagement:getUserDSProfile

+

8. Update user product permission profiles using an email address

+

Demonstrates how to update user product permission profiles. There may only be one permission profile assigned to a user per product.

+ +

+ API methods used: + MultiProductUserManagement:getProductPermissionProfiles, + MultiProductUserManagement:addUserProductPermissionProfilesByEmail +

+ +

9. Delete user product permission profiles using an email address

+

Demonstrates how to list and delete DocuSign Admin user product permission profiles.

+ +

+ API methods used: + MultiProductUserManagement:getUserProductPermissionProfilesByEmail, + MultiProductUserManagement:removeUserProductPermission +

+ diff --git a/config/routes.rb b/config/routes.rb index 44ccd7d..5d56220 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -81,6 +81,12 @@ get 'eg007' => 'eg007_get_user_profile_by_user_id#get' post 'eg007' => 'eg007_get_user_profile_by_user_id#create' + + get 'eg008' => 'eg008_update_user_product_permission_profile#get' + post 'eg008' => 'eg008_update_user_product_permission_profile#create' + + get 'eg009' => 'eg009_delete__user_product_permission_profile#get' + post 'eg009' => 'eg009_delete__user_product_permission_profile#create' end end constraints lambda { |req| req.session[:examples_API] == "eSignature" } do From a567cd506b83a89cdde4ca2ab172c1aac7077dd8 Mon Sep 17 00:00:00 2001 From: Aaron Wilde <52012222+AaronWDS@users.noreply.github.com> Date: Fri, 8 Jul 2022 12:16:13 -0700 Subject: [PATCH 150/363] Update eg009_delete_user_product_permission_profile_service.rb --- ...elete_user_product_permission_profile_service.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb b/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb index 12794bc..b24d858 100644 --- a/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb +++ b/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb @@ -16,14 +16,14 @@ def worker api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") # Step 2 end - # Step 3 start + # Step 4 start user_product_profile_delete_request = DocuSign_Admin::UserProductProfileDeleteRequest.new({'user_email' => args[:email], 'product_ids' => [args[:product_id]]}) - # Step 3 end + # Step 4 end - # Step 4 start + # Step 5 start product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(api_client) response = product_permission_profiles_api.remove_user_product_permission(args[:organization_id], args[:account_id], user_product_profile_delete_request) - # Step 4 end + # Step 5 end end def get_permission_profiles_by_email @@ -33,6 +33,7 @@ def get_permission_profiles_by_email api_client = DocuSign_Admin::ApiClient.new(configuration) api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + # Step 3 start product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(api_client) options = DocuSign_Admin::GetUserProductPermissionProfilesByEmailOptions.new @@ -40,6 +41,6 @@ def get_permission_profiles_by_email product_permission_profiles = product_permission_profiles_api.get_user_product_permission_profiles_by_email(args[:organization_id], args[:account_id], options) product_permission_profiles.as_json['product_permission_profiles'] - + # Step 3 end end -end \ No newline at end of file +end From 8d1da9fae6341cc1e9492ba45b2dc5f44c8baacd Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Fri, 22 Jul 2022 00:19:06 +0300 Subject: [PATCH 151/363] Quick Auth Code Grant (#80) * quick acg --- Gemfile | 4 +- Gemfile.lock | 203 ++++++------- .../eg001_embedded_signing_controller.rb | 57 ++-- quick_acg/.gitattributes | 7 + quick_acg/.gitignore | 29 ++ quick_acg/.ruby-version | 1 + quick_acg/Gemfile | 75 +++++ quick_acg/Gemfile.lock | 285 ++++++++++++++++++ quick_acg/README.md | 24 ++ quick_acg/Rakefile | 6 + quick_acg/app/assets/config/manifest.js | 3 + .../app/controllers/ds_common_controller.rb | 21 ++ quick_acg/app/views/ds_common/error.erb | 52 ++++ .../views/eg001_embedded_signing/get.html.erb | 87 ++++++ quick_acg/bin/bundle | 114 +++++++ quick_acg/bin/rails | 4 + quick_acg/bin/rake | 4 + quick_acg/bin/setup | 33 ++ quick_acg/config.ru | 7 + quick_acg/config/application.rb | 25 ++ quick_acg/config/boot.rb | 3 + quick_acg/config/credentials.yml.enc | 1 + quick_acg/config/database.yml | 25 ++ quick_acg/config/environment.rb | 5 + quick_acg/config/environments/development.rb | 63 ++++ quick_acg/config/environments/production.rb | 75 +++++ quick_acg/config/environments/test.rb | 50 +++ quick_acg/config/initializers/assets.rb | 12 + quick_acg/config/initializers/omniauth.rb | 52 ++++ quick_acg/config/puma.rb | 43 +++ quick_acg/config/routes.rb | 28 ++ quick_acg/lib/docusign.rb | 62 ++++ 32 files changed, 1318 insertions(+), 142 deletions(-) create mode 100644 quick_acg/.gitattributes create mode 100644 quick_acg/.gitignore create mode 100644 quick_acg/.ruby-version create mode 100644 quick_acg/Gemfile create mode 100644 quick_acg/Gemfile.lock create mode 100644 quick_acg/README.md create mode 100644 quick_acg/Rakefile create mode 100644 quick_acg/app/assets/config/manifest.js create mode 100644 quick_acg/app/controllers/ds_common_controller.rb create mode 100644 quick_acg/app/views/ds_common/error.erb create mode 100644 quick_acg/app/views/eg001_embedded_signing/get.html.erb create mode 100644 quick_acg/bin/bundle create mode 100644 quick_acg/bin/rails create mode 100644 quick_acg/bin/rake create mode 100644 quick_acg/bin/setup create mode 100644 quick_acg/config.ru create mode 100644 quick_acg/config/application.rb create mode 100644 quick_acg/config/boot.rb create mode 100644 quick_acg/config/credentials.yml.enc create mode 100644 quick_acg/config/database.yml create mode 100644 quick_acg/config/environment.rb create mode 100644 quick_acg/config/environments/development.rb create mode 100644 quick_acg/config/environments/production.rb create mode 100644 quick_acg/config/environments/test.rb create mode 100644 quick_acg/config/initializers/assets.rb create mode 100644 quick_acg/config/initializers/omniauth.rb create mode 100644 quick_acg/config/puma.rb create mode 100644 quick_acg/config/routes.rb create mode 100644 quick_acg/lib/docusign.rb diff --git a/Gemfile b/Gemfile index 5c550e5..b8fc89f 100644 --- a/Gemfile +++ b/Gemfile @@ -49,7 +49,7 @@ end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. - gem 'listen', '> 3.2.1' + gem 'listen', '~> 3.7.0' gem 'web-console', '~> 4.0.1' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'pry-nav', '~> 0.3.0' @@ -77,5 +77,3 @@ gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', '~> 1.2019.3', platforms: %i[mingw mswin x64_mingw jruby] gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] - -gem "webrick", "~> 1.7" diff --git a/Gemfile.lock b/Gemfile.lock index 15ce3d1..747e2c1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,56 +1,56 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.4.4) - actionpack (= 6.0.4.4) + actioncable (6.0.4.8) + actionpack (= 6.0.4.8) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.4.4) - actionpack (= 6.0.4.4) - activejob (= 6.0.4.4) - activerecord (= 6.0.4.4) - activestorage (= 6.0.4.4) - activesupport (= 6.0.4.4) + actionmailbox (6.0.4.8) + actionpack (= 6.0.4.8) + activejob (= 6.0.4.8) + activerecord (= 6.0.4.8) + activestorage (= 6.0.4.8) + activesupport (= 6.0.4.8) mail (>= 2.7.1) - actionmailer (6.0.4.4) - actionpack (= 6.0.4.4) - actionview (= 6.0.4.4) - activejob (= 6.0.4.4) + actionmailer (6.0.4.8) + actionpack (= 6.0.4.8) + actionview (= 6.0.4.8) + activejob (= 6.0.4.8) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.4.4) - actionview (= 6.0.4.4) - activesupport (= 6.0.4.4) + actionpack (6.0.4.8) + actionview (= 6.0.4.8) + activesupport (= 6.0.4.8) rack (~> 2.0, >= 2.0.8) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.4.4) - actionpack (= 6.0.4.4) - activerecord (= 6.0.4.4) - activestorage (= 6.0.4.4) - activesupport (= 6.0.4.4) + actiontext (6.0.4.8) + actionpack (= 6.0.4.8) + activerecord (= 6.0.4.8) + activestorage (= 6.0.4.8) + activesupport (= 6.0.4.8) nokogiri (>= 1.8.5) - actionview (6.0.4.4) - activesupport (= 6.0.4.4) + actionview (6.0.4.8) + activesupport (= 6.0.4.8) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.4.4) - activesupport (= 6.0.4.4) + activejob (6.0.4.8) + activesupport (= 6.0.4.8) globalid (>= 0.3.6) - activemodel (6.0.4.4) - activesupport (= 6.0.4.4) - activerecord (6.0.4.4) - activemodel (= 6.0.4.4) - activesupport (= 6.0.4.4) - activestorage (6.0.4.4) - actionpack (= 6.0.4.4) - activejob (= 6.0.4.4) - activerecord (= 6.0.4.4) + activemodel (6.0.4.8) + activesupport (= 6.0.4.8) + activerecord (6.0.4.8) + activemodel (= 6.0.4.8) + activesupport (= 6.0.4.8) + activestorage (6.0.4.8) + actionpack (= 6.0.4.8) + activejob (= 6.0.4.8) + activerecord (= 6.0.4.8) marcel (~> 1.0.0) - activesupport (6.0.4.4) + activesupport (6.0.4.8) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -85,7 +85,7 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.1.9) + concurrent-ruby (1.1.10) crass (1.0.6) docusign_admin (1.1.0) addressable (~> 2.7, >= 2.7.0) @@ -113,81 +113,56 @@ GEM jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) erubi (1.10.0) - ethon (0.14.0) + ethon (0.15.0) ffi (>= 1.15.0) execjs (2.8.1) - faraday (1.9.3) - faraday-em_http (~> 1.0) - faraday-em_synchrony (~> 1.0) - faraday-excon (~> 1.1) - faraday-httpclient (~> 1.0) - faraday-multipart (~> 1.0) - faraday-net_http (~> 1.0) - faraday-net_http_persistent (~> 1.0) - faraday-patron (~> 1.0) - faraday-rack (~> 1.0) - faraday-retry (~> 1.0) + faraday (2.3.0) + faraday-net_http (~> 2.0) ruby2_keywords (>= 0.0.4) - faraday-em_http (1.0.0) - faraday-em_synchrony (1.0.0) - faraday-excon (1.1.0) - faraday-httpclient (1.0.1) - faraday-multipart (1.0.3) - multipart-post (>= 1.2, < 3) - faraday-net_http (1.0.1) - faraday-net_http_persistent (1.2.0) - faraday-patron (1.0.0) - faraday-rack (1.0.0) - faraday-retry (1.0.3) - ffi (1.15.5) + faraday-net_http (2.0.3) ffi (1.15.5-x64-mingw32) globalid (1.0.0) activesupport (>= 5.0) hashie (5.0.0) - i18n (1.8.11) + i18n (1.11.0) concurrent-ruby (~> 1.0) io-like (0.3.1) jbuilder (2.10.2) activesupport (>= 5.0.0) - json (2.5.1) - jwt (2.2.3) - listen (3.7.0) + json (2.6.2) + jwt (2.4.1) + listen (3.7.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.13.0) + loofah (2.18.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) - marcel (1.0.1) + marcel (1.0.2) method_source (0.9.2) mini_mime (1.1.2) - minitest (5.15.0) - msgpack (1.4.2) - multi_json (1.15.0) + minitest (5.16.2) + msgpack (1.5.3) multi_xml (0.6.0) - multipart-post (2.1.1) nio4r (2.5.8) nokogiri (1.13.6-x64-mingw32) racc (~> 1.4) - nokogiri (1.13.6-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.13.6-x86_64-linux) - racc (~> 1.4) - oauth2 (1.4.7) - faraday (>= 0.8, < 2.0) + oauth2 (2.0.5) + faraday (>= 0.17.3, < 3.0) jwt (>= 1.0, < 3.0) - multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - omniauth (2.0.4) + rash_alt (>= 0.4, < 1) + version_gem (~> 1.1) + omniauth (2.1.0) hashie (>= 3.4.6) - rack (>= 1.6.2, < 3) + rack (>= 2.2.3) rack-protection - omniauth-oauth2 (1.7.1) - oauth2 (~> 1.4) + omniauth-oauth2 (1.7.3) + oauth2 (>= 1.4, < 3) omniauth (>= 1.9, < 3) - omniauth-rails_csrf_protection (1.0.0) + omniauth-rails_csrf_protection (1.0.1) actionpack (>= 4.2) omniauth (~> 2.0) pry (0.12.2) @@ -197,43 +172,45 @@ GEM pry (>= 0.9.10, < 0.13.0) pry-rails (0.3.9) pry (>= 0.10.4) - public_suffix (4.0.6) + public_suffix (4.0.7) puma (4.3.12) nio4r (~> 2.0) racc (1.6.0) - rack (2.2.3) - rack-protection (2.1.0) + rack (2.2.4) + rack-protection (2.2.0) rack - rack-test (1.1.0) - rack (>= 1.0, < 3) - rails (6.0.4.4) - actioncable (= 6.0.4.4) - actionmailbox (= 6.0.4.4) - actionmailer (= 6.0.4.4) - actionpack (= 6.0.4.4) - actiontext (= 6.0.4.4) - actionview (= 6.0.4.4) - activejob (= 6.0.4.4) - activemodel (= 6.0.4.4) - activerecord (= 6.0.4.4) - activestorage (= 6.0.4.4) - activesupport (= 6.0.4.4) + rack-test (2.0.2) + rack (>= 1.3) + rails (6.0.4.8) + actioncable (= 6.0.4.8) + actionmailbox (= 6.0.4.8) + actionmailer (= 6.0.4.8) + actionpack (= 6.0.4.8) + actiontext (= 6.0.4.8) + actionview (= 6.0.4.8) + activejob (= 6.0.4.8) + activemodel (= 6.0.4.8) + activerecord (= 6.0.4.8) + activestorage (= 6.0.4.8) + activesupport (= 6.0.4.8) bundler (>= 1.3.0) - railties (= 6.0.4.4) + railties (= 6.0.4.8) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.4.2) + rails-html-sanitizer (1.4.3) loofah (~> 2.3) - railties (6.0.4.4) - actionpack (= 6.0.4.4) - activesupport (= 6.0.4.4) + railties (6.0.4.8) + actionpack (= 6.0.4.8) + activesupport (= 6.0.4.8) method_source rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) rake (13.0.6) - rb-fsevent (0.11.0) + rash_alt (0.4.12) + hashie (>= 3.4) + rb-fsevent (0.11.1) rb-inotify (0.10.1) ffi (~> 1.0) regexp_parser (1.8.2) @@ -241,8 +218,6 @@ GEM rubyzip (2.3.2) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) - sassc (2.4.0) - ffi (~> 1.9) sassc (2.4.0-x64-mingw32) ffi (~> 1.9) sassc-rails (2.1.2) @@ -258,14 +233,14 @@ GEM spring-watcher-listen (2.0.1) listen (>= 2.7, < 4.0) spring (>= 1.2, < 3.0) - sprockets (4.0.2) + sprockets (4.1.1) concurrent-ruby (~> 1.0) rack (> 1, < 3) sprockets-rails (3.4.2) actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) - sqlite3 (1.4.2) + sqlite3 (1.4.4) thor (1.2.1) thread_safe (0.3.6) tilt (2.0.10) @@ -280,25 +255,22 @@ GEM tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) + version_gem (1.1.0) wdm (0.1.1) web-console (4.0.4) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - webrick (1.7.0) websocket-driver (0.7.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.5.3) + zeitwerk (2.6.0) PLATFORMS x64-mingw32 - x86_64-darwin-20 - x86_64-darwin-21 - x86_64-linux DEPENDENCIES bootsnap (~> 1.7.3) @@ -312,7 +284,7 @@ DEPENDENCIES docusign_monitor (~> 1.1.0) docusign_rooms (~> 1.2.0.rc1) jbuilder (~> 2.10.0) - listen (> 3.2.1) + listen (~> 3.7.0) omniauth-oauth2 (~> 1.7.1) omniauth-rails_csrf_protection pry-nav (~> 0.3.0) @@ -329,10 +301,9 @@ DEPENDENCIES uglifier (~> 4.2.0) wdm (>= 0.1.0) web-console (~> 4.0.1) - webrick (~> 1.7) RUBY VERSION ruby 3.0.2p107 BUNDLED WITH - 2.2.31 + 2.2.22 diff --git a/app/controllers/eg001_embedded_signing_controller.rb b/app/controllers/eg001_embedded_signing_controller.rb index f0b9bc2..338d86e 100644 --- a/app/controllers/eg001_embedded_signing_controller.rb +++ b/app/controllers/eg001_embedded_signing_controller.rb @@ -2,30 +2,41 @@ class Eg001EmbeddedSigningController < EgController def create - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation - # so it could be restarted automatically. - # But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after - # authentication. - redirect_to '/ds/mustAuthenticate' - end - args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - signer_email: param_gsub(params[:signerEmail]), - signer_name: param_gsub(params[:signerName]), - ds_ping_url: Rails.application.config.app_url, - signer_client_id: 1000, - pdf_filename: 'data/World_Wide_Corp_lorem.pdf' - } + begin + minimum_buffer_min = 10 + token_ok = check_token(minimum_buffer_min) + unless token_ok + flash[:messages] = 'Sorry, you need to re-authenticate.' + # We could store the parameters of the requested operation + # so it could be restarted automatically. + # But since it should be rare to have a token issue here, + # we'll make the user re-enter the form data after + # authentication. + return redirect_to '/ds/mustAuthenticate' + end + + pdf_file_path = 'data/World_Wide_Corp_lorem.pdf' + + unless File.exist?(pdf_file_path) + pdf_file_path = '../data/World_Wide_Corp_lorem.pdf' + end - redirect_url = Eg001EmbeddedSigningService.new(args).worker - redirect_to redirect_url + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + signer_email: param_gsub(params[:signerEmail]), + signer_name: param_gsub(params[:signerName]), + ds_ping_url: Rails.application.config.app_url, + signer_client_id: 1000, + pdf_filename: pdf_file_path + } + + redirect_url = Eg001EmbeddedSigningService.new(args).worker + redirect_to redirect_url + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end end def get diff --git a/quick_acg/.gitattributes b/quick_acg/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/quick_acg/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/quick_acg/.gitignore b/quick_acg/.gitignore new file mode 100644 index 0000000..4857d33 --- /dev/null +++ b/quick_acg/.gitignore @@ -0,0 +1,29 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + + +/public/assets + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/quick_acg/.ruby-version b/quick_acg/.ruby-version new file mode 100644 index 0000000..c0013a8 --- /dev/null +++ b/quick_acg/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.3 diff --git a/quick_acg/Gemfile b/quick_acg/Gemfile new file mode 100644 index 0000000..63ffc0c --- /dev/null +++ b/quick_acg/Gemfile @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby '~>3.0.2' + +# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' +gem 'rails', '~> 6.0.4.1' +# Use sqlite3 as the database for Active Record +gem 'sqlite3', '~> 1.4.2' +# Use Puma as the app server +gem 'puma', '~> 4.3.9' +# Use SCSS for stylesheets +gem 'sass-rails', '~> 6.0.0' +# Use Uglifier as compressor for JavaScript assets +gem 'uglifier', '~> 4.2.0' +# See https://github.com/rails/execjs#readme for more supported runtimes +# gem 'mini_racer', platforms: :ruby + +# Use CoffeeScript for .coffee assets and views +gem 'coffee-rails', '~> 5.0.0' +# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks +gem 'turbolinks', '~> 5.2.1' +# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder +gem 'jbuilder', '~> 2.10.0' +# Use Redis adapter to run Action Cable in production +# gem 'redis', '~> 4.0' +# Use ActiveModel has_secure_password +# gem 'bcrypt', '~> 3.1.7' + +# Use ActiveStorage variant +# gem 'mini_magick', '~> 4.8' + +# Use Capistrano for deployment +# gem 'capistrano-rails', group: :development + +# Reduces boot times through caching; required in config/boot.rb +if RUBY_PLATFORM =~ /mswin/ + gem 'bootsnap', '>= 1.1.0', '< 1.4.2', require: false +else + gem 'bootsnap', '~> 1.7.3', require: false +end + +group :development, :test do + # Call 'byebug' anywhere in the code to stop execution and get a debugger console + gem 'byebug', '~> 11.1.1', platforms: %i[mri mingw x64_mingw] +end + +group :development do + # Access an interactive console on exception pages or by calling 'console' anywhere in the code. + gem 'listen', '~> 3.7.0' + gem 'web-console', '~> 4.0.1' + # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring + gem 'pry-nav', '~> 0.3.0' + gem 'pry-rails', '~> 0.3.9' + gem 'spring', '~> 2.1.0' + gem 'spring-watcher-listen', '~> 2.0.1' +end + +group :test do + # Adds support for Capybara system testing and selenium driver + gem 'capybara', '~> 3.31.0' + gem 'selenium-webdriver', '~> 3.142.7' + # Easy installation and use of chromedriver to run system tests with Chrome + gem 'chromedriver-helper', '~> 2.1.1' +end + +gem 'docusign_esign', '~> 3.17.0' +gem 'omniauth-oauth2', '~> 1.7.1' +gem 'omniauth-rails_csrf_protection' + +# Windows does not include zoneinfo files, so bundle the tzinfo-data gem +gem 'tzinfo-data', '~> 1.2019.3', platforms: %i[mingw mswin x64_mingw jruby] +gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] diff --git a/quick_acg/Gemfile.lock b/quick_acg/Gemfile.lock new file mode 100644 index 0000000..a95a2a3 --- /dev/null +++ b/quick_acg/Gemfile.lock @@ -0,0 +1,285 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (6.0.4.8) + actionpack (= 6.0.4.8) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (6.0.4.8) + actionpack (= 6.0.4.8) + activejob (= 6.0.4.8) + activerecord (= 6.0.4.8) + activestorage (= 6.0.4.8) + activesupport (= 6.0.4.8) + mail (>= 2.7.1) + actionmailer (6.0.4.8) + actionpack (= 6.0.4.8) + actionview (= 6.0.4.8) + activejob (= 6.0.4.8) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (6.0.4.8) + actionview (= 6.0.4.8) + activesupport (= 6.0.4.8) + rack (~> 2.0, >= 2.0.8) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.0.4.8) + actionpack (= 6.0.4.8) + activerecord (= 6.0.4.8) + activestorage (= 6.0.4.8) + activesupport (= 6.0.4.8) + nokogiri (>= 1.8.5) + actionview (6.0.4.8) + activesupport (= 6.0.4.8) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (6.0.4.8) + activesupport (= 6.0.4.8) + globalid (>= 0.3.6) + activemodel (6.0.4.8) + activesupport (= 6.0.4.8) + activerecord (6.0.4.8) + activemodel (= 6.0.4.8) + activesupport (= 6.0.4.8) + activestorage (6.0.4.8) + actionpack (= 6.0.4.8) + activejob (= 6.0.4.8) + activerecord (= 6.0.4.8) + marcel (~> 1.0.0) + activesupport (6.0.4.8) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + zeitwerk (~> 2.2, >= 2.2.2) + addressable (2.8.0) + public_suffix (>= 2.0.2, < 5.0) + archive-zip (0.12.0) + io-like (~> 0.3.0) + bindex (0.8.1) + bootsnap (1.7.7) + msgpack (~> 1.0) + builder (3.2.4) + byebug (11.1.3) + capybara (3.31.0) + addressable + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (~> 1.5) + xpath (~> 3.2) + childprocess (3.0.0) + chromedriver-helper (2.1.1) + archive-zip (~> 0.10) + nokogiri (~> 1.8) + coderay (1.1.3) + coffee-rails (5.0.0) + coffee-script (>= 2.2.0) + railties (>= 5.2.0) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.12.2) + concurrent-ruby (1.1.10) + crass (1.0.6) + docusign_esign (3.17.0) + addressable (~> 2.7, >= 2.7.0) + json (~> 2.1, >= 2.1.0) + jwt (~> 2.2, >= 2.2.1) + typhoeus (~> 1.0, >= 1.0.1) + erubi (1.10.0) + ethon (0.15.0) + ffi (>= 1.15.0) + execjs (2.8.1) + faraday (2.3.0) + faraday-net_http (~> 2.0) + ruby2_keywords (>= 0.0.4) + faraday-net_http (2.0.3) + ffi (1.15.5-x64-mingw32) + globalid (1.0.0) + activesupport (>= 5.0) + hashie (5.0.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-like (0.3.1) + jbuilder (2.10.2) + activesupport (>= 5.0.0) + json (2.6.2) + jwt (2.4.1) + listen (3.7.1) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + loofah (2.18.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (0.9.2) + mini_mime (1.1.2) + minitest (5.16.2) + msgpack (1.5.3) + multi_xml (0.6.0) + nio4r (2.5.8) + nokogiri (1.13.6-x64-mingw32) + racc (~> 1.4) + oauth2 (2.0.5) + faraday (>= 0.17.3, < 3.0) + jwt (>= 1.0, < 3.0) + multi_xml (~> 0.5) + rack (>= 1.2, < 3) + rash_alt (>= 0.4, < 1) + version_gem (~> 1.1) + omniauth (2.1.0) + hashie (>= 3.4.6) + rack (>= 2.2.3) + rack-protection + omniauth-oauth2 (1.7.3) + oauth2 (>= 1.4, < 3) + omniauth (>= 1.9, < 3) + omniauth-rails_csrf_protection (1.0.1) + actionpack (>= 4.2) + omniauth (~> 2.0) + pry (0.12.2) + coderay (~> 1.1.0) + method_source (~> 0.9.0) + pry-nav (0.3.0) + pry (>= 0.9.10, < 0.13.0) + pry-rails (0.3.9) + pry (>= 0.10.4) + public_suffix (4.0.7) + puma (4.3.12) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.4) + rack-protection (2.2.0) + rack + rack-test (2.0.2) + rack (>= 1.3) + rails (6.0.4.8) + actioncable (= 6.0.4.8) + actionmailbox (= 6.0.4.8) + actionmailer (= 6.0.4.8) + actionpack (= 6.0.4.8) + actiontext (= 6.0.4.8) + actionview (= 6.0.4.8) + activejob (= 6.0.4.8) + activemodel (= 6.0.4.8) + activerecord (= 6.0.4.8) + activestorage (= 6.0.4.8) + activesupport (= 6.0.4.8) + bundler (>= 1.3.0) + railties (= 6.0.4.8) + sprockets-rails (>= 2.0.0) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.3) + loofah (~> 2.3) + railties (6.0.4.8) + actionpack (= 6.0.4.8) + activesupport (= 6.0.4.8) + method_source + rake (>= 0.8.7) + thor (>= 0.20.3, < 2.0) + rake (13.0.6) + rash_alt (0.4.12) + hashie (>= 3.4) + rb-fsevent (0.11.1) + rb-inotify (0.10.1) + ffi (~> 1.0) + regexp_parser (1.8.2) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) + sass-rails (6.0.0) + sassc-rails (~> 2.1, >= 2.1.1) + sassc (2.4.0-x64-mingw32) + ffi (~> 1.9) + sassc-rails (2.1.2) + railties (>= 4.0.0) + sassc (>= 2.0) + sprockets (> 3.0) + sprockets-rails + tilt + selenium-webdriver (3.142.7) + childprocess (>= 0.5, < 4.0) + rubyzip (>= 1.2.2) + spring (2.1.1) + spring-watcher-listen (2.0.1) + listen (>= 2.7, < 4.0) + spring (>= 1.2, < 3.0) + sprockets (4.1.1) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.4.2) + actionpack (>= 5.2) + activesupport (>= 5.2) + sprockets (>= 3.0.0) + sqlite3 (1.4.4) + thor (1.2.1) + thread_safe (0.3.6) + tilt (2.0.10) + turbolinks (5.2.1) + turbolinks-source (~> 5.2) + turbolinks-source (5.2.0) + typhoeus (1.4.0) + ethon (>= 0.9.0) + tzinfo (1.2.9) + thread_safe (~> 0.1) + tzinfo-data (1.2019.3) + tzinfo (>= 1.0.0) + uglifier (4.2.0) + execjs (>= 0.3.0, < 3) + version_gem (1.1.0) + wdm (0.1.1) + web-console (4.0.4) + actionview (>= 6.0.0) + activemodel (>= 6.0.0) + bindex (>= 0.4.0) + railties (>= 6.0.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + xpath (3.2.0) + nokogiri (~> 1.8) + zeitwerk (2.6.0) + +PLATFORMS + x64-mingw32 + +DEPENDENCIES + bootsnap (~> 1.7.3) + byebug (~> 11.1.1) + capybara (~> 3.31.0) + chromedriver-helper (~> 2.1.1) + coffee-rails (~> 5.0.0) + docusign_esign (~> 3.17.0) + jbuilder (~> 2.10.0) + listen (~> 3.7.0) + omniauth-oauth2 (~> 1.7.1) + omniauth-rails_csrf_protection + pry-nav (~> 0.3.0) + pry-rails (~> 0.3.9) + puma (~> 4.3.9) + rails (~> 6.0.4.1) + sass-rails (~> 6.0.0) + selenium-webdriver (~> 3.142.7) + spring (~> 2.1.0) + spring-watcher-listen (~> 2.0.1) + sqlite3 (~> 1.4.2) + turbolinks (~> 5.2.1) + tzinfo-data (~> 1.2019.3) + uglifier (~> 4.2.0) + wdm (>= 0.1.0) + web-console (~> 4.0.1) + +RUBY VERSION + ruby 3.0.2p107 + +BUNDLED WITH + 2.2.22 diff --git a/quick_acg/README.md b/quick_acg/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/quick_acg/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/quick_acg/Rakefile b/quick_acg/Rakefile new file mode 100644 index 0000000..9a5ea73 --- /dev/null +++ b/quick_acg/Rakefile @@ -0,0 +1,6 @@ +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require_relative "config/application" + +Rails.application.load_tasks diff --git a/quick_acg/app/assets/config/manifest.js b/quick_acg/app/assets/config/manifest.js new file mode 100644 index 0000000..5cc2c08 --- /dev/null +++ b/quick_acg/app/assets/config/manifest.js @@ -0,0 +1,3 @@ +//= link_tree ../images +//= link_directory ../javascripts .js +//= link_directory ../stylesheets .css \ No newline at end of file diff --git a/quick_acg/app/controllers/ds_common_controller.rb b/quick_acg/app/controllers/ds_common_controller.rb new file mode 100644 index 0000000..0183fdd --- /dev/null +++ b/quick_acg/app/controllers/ds_common_controller.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class DsCommonController < ApplicationController + def index + @show_doc = Rails.application.config.documentation + handle_redirects + end + Rails.configuration.file_watcher + def handle_redirects + if session[:quickstarted].nil? + session[:quickstarted] = true + redirect_to "/auth/docusign" + else + redirect_to '/eg001' + end + end + + def ds_must_authenticate + redirect_to "/auth/docusign" + end +end diff --git a/quick_acg/app/views/ds_common/error.erb b/quick_acg/app/views/ds_common/error.erb new file mode 100644 index 0000000..211d659 --- /dev/null +++ b/quick_acg/app/views/ds_common/error.erb @@ -0,0 +1,52 @@ + + + + + + + + + <% if @title %> + <%= @title %> + <% else %> + DocuSign Ruby Code Examples + <% end %> + + + + + + + + + +
+
+ <% title = "Error" %> + +

Problem: an error occurred

+

Error information:

+ + <% if @error_code %> +

<%= @error_code %>: <%= @error_message %>

+ <% if @error_information %> +

<%== @error_information %>

+ <% end %> + <% else %> +

+

<%= @err %>
+

+ <% end %> + + +

Continue

+
+
+ + \ No newline at end of file diff --git a/quick_acg/app/views/eg001_embedded_signing/get.html.erb b/quick_acg/app/views/eg001_embedded_signing/get.html.erb new file mode 100644 index 0000000..5e08a13 --- /dev/null +++ b/quick_acg/app/views/eg001_embedded_signing/get.html.erb @@ -0,0 +1,87 @@ + + + + + + + + + <% if @title %> + <%= @title %> + <% else %> + DocuSign Ruby Code Examples + <% end %> + + + + + + + + +
+
+

1. 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 + website.

+ + <% if @show_doc %> +

Documentation about this example.

+ <% end %> + +

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

+

+ View source file <%= @source_file %> on GitHub. +

+ +
+
+ + + We'll never share your email with anyone else. +
+
+ + +
+ +
+
+
+ + \ No newline at end of file diff --git a/quick_acg/bin/bundle b/quick_acg/bin/bundle new file mode 100644 index 0000000..a71368e --- /dev/null +++ b/quick_acg/bin/bundle @@ -0,0 +1,114 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'bundle' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "rubygems" + +m = Module.new do + module_function + + def invoked_as_script? + File.expand_path($0) == File.expand_path(__FILE__) + end + + def env_var_version + ENV["BUNDLER_VERSION"] + end + + def cli_arg_version + return unless invoked_as_script? # don't want to hijack other binstubs + return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` + bundler_version = nil + update_index = nil + ARGV.each_with_index do |a, i| + if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN + bundler_version = a + end + next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ + bundler_version = $1 + update_index = i + end + bundler_version + end + + def gemfile + gemfile = ENV["BUNDLE_GEMFILE"] + return gemfile if gemfile && !gemfile.empty? + + File.expand_path("../../Gemfile", __FILE__) + end + + def lockfile + lockfile = + case File.basename(gemfile) + when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) + else "#{gemfile}.lock" + end + File.expand_path(lockfile) + end + + def lockfile_version + return unless File.file?(lockfile) + lockfile_contents = File.read(lockfile) + return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ + Regexp.last_match(1) + end + + def bundler_version + @bundler_version ||= + env_var_version || cli_arg_version || + lockfile_version + end + + def bundler_requirement + return "#{Gem::Requirement.default}.a" unless bundler_version + + bundler_gem_version = Gem::Version.new(bundler_version) + + requirement = bundler_gem_version.approximate_recommendation + + return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0") + + requirement += ".a" if bundler_gem_version.prerelease? + + requirement + end + + def load_bundler! + ENV["BUNDLE_GEMFILE"] ||= gemfile + + activate_bundler + end + + def activate_bundler + gem_error = activation_error_handling do + gem "bundler", bundler_requirement + end + return if gem_error.nil? + require_error = activation_error_handling do + require "bundler/version" + end + return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) + warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" + exit 42 + end + + def activation_error_handling + yield + nil + rescue StandardError, LoadError => e + e + end +end + +m.load_bundler! + +if m.invoked_as_script? + load Gem.bin_path("bundler", "bundle") +end diff --git a/quick_acg/bin/rails b/quick_acg/bin/rails new file mode 100644 index 0000000..7bcc36e --- /dev/null +++ b/quick_acg/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby.exe +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/quick_acg/bin/rake b/quick_acg/bin/rake new file mode 100644 index 0000000..01f7fc0 --- /dev/null +++ b/quick_acg/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby.exe +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/quick_acg/bin/setup b/quick_acg/bin/setup new file mode 100644 index 0000000..5e463ee --- /dev/null +++ b/quick_acg/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby.exe +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/quick_acg/config.ru b/quick_acg/config.ru new file mode 100644 index 0000000..842bccc --- /dev/null +++ b/quick_acg/config.ru @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# This file is used by Rack-based servers to start the application. + +require_relative 'config/environment' + +run Rails.application diff --git a/quick_acg/config/application.rb b/quick_acg/config/application.rb new file mode 100644 index 0000000..f9beffa --- /dev/null +++ b/quick_acg/config/application.rb @@ -0,0 +1,25 @@ +require_relative 'boot' +require 'rails/all' +# Require the gems listed in Gemfile, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(*Rails.groups) +module CodeExamplesRuby + class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 5.2 + # Configuration for DocuSign example. + # For a production application, you will store the credentials + # in config/environments/development.rb, production.rb, test.rb, etc + config.app_url = 'http://localhost:3000' # The public url of the application. + # Init DocuSign configuration, loaded from config/appsettings.yml file + DOCUSIGN_CONFIG = YAML.load_file(File.expand_path(File.join(Rails.root.to_s, '../config/appsettings.yml')))[Rails.env] + DOCUSIGN_CONFIG.map do |k,v| + config.send("#{k}=", v) + end + + # Settings in config/environments/* take precedence over those specified here. + # Application configuration can go into files in config/initializers + # -- all .rb files in that directory are automatically loaded after loading + # the framework and any gems in your application. + end +end diff --git a/quick_acg/config/boot.rb b/quick_acg/config/boot.rb new file mode 100644 index 0000000..2820116 --- /dev/null +++ b/quick_acg/config/boot.rb @@ -0,0 +1,3 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" # Set up gems listed in the Gemfile. diff --git a/quick_acg/config/credentials.yml.enc b/quick_acg/config/credentials.yml.enc new file mode 100644 index 0000000..5dfeb60 --- /dev/null +++ b/quick_acg/config/credentials.yml.enc @@ -0,0 +1 @@ +VwFdOXZ+C/1eCY+cD7sJAKNMTTKqGujd2ae3jErSN7BCN8xJ0g2OiEDiyDKBbq7AWIHxdxzXQ1CBCG2ly0ApaZSQxaL0Kb1sPe4WcV5YZZvLw0JDJVMk7x/NPsvTjzCJs4ybfSUT/8hMs4xDGzKtxOlCYVMXrAdPyzVebV/7K5GhPTJxJTS9TopfxoCeaaGZtpM5yfUqPAKTLnxUGM3q0ul1vc+vJZNmN6clUzDBVT0K1FR9bzcRFML8QPwP3yZIRpg6+R+c+ggYAd8H5F92iFAE0QnxZQwgr2JGGJEzibIIg6Y33+Pjp4RV0WdL4OgfY43VRZp+3n9So2+SH64veB2KV+nWNAYKKXZpZCnKjuDlur6DUd1Q6VNfF5vVxGkpwza2ABJKuQMgslA6OCeYE0fBZ/AZ01oiCyue--z8P9Lw0Um2HS3bJl--JO10GQB7RkBd6Fh59SM41w== \ No newline at end of file diff --git a/quick_acg/config/database.yml b/quick_acg/config/database.yml new file mode 100644 index 0000000..fcba57f --- /dev/null +++ b/quick_acg/config/database.yml @@ -0,0 +1,25 @@ +# SQLite. Versions 3.8.0 and up are supported. +# gem install sqlite3 +# +# Ensure the SQLite 3 gem is defined in your Gemfile +# gem "sqlite3" +# +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/quick_acg/config/environment.rb b/quick_acg/config/environment.rb new file mode 100644 index 0000000..cac5315 --- /dev/null +++ b/quick_acg/config/environment.rb @@ -0,0 +1,5 @@ +# Load the Rails application. +require_relative "application" + +# Initialize the Rails application. +Rails.application.initialize! diff --git a/quick_acg/config/environments/development.rb b/quick_acg/config/environments/development.rb new file mode 100644 index 0000000..ea59bdc --- /dev/null +++ b/quick_acg/config/environments/development.rb @@ -0,0 +1,63 @@ +require "active_support/core_ext/integer/time" +require 'yaml' + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # In the development environment your application's code is reloaded any time + # it changes. This slows down response time but is perfect for development + # since you don't have to restart the web server when you make code changes. + config.cache_classes = false + + # Do not eager load code on boot. + config.eager_load = false + + # Show full error reports. + config.consider_all_requests_local = true + + # Enable server timing + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.action_controller.perform_caching = true + config.action_controller.enable_fragment_cache_logging = true + + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + + # Print deprecation notices to the Rails logger. + config.active_support.deprecation = :log + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raise an error on page load if there are pending migrations. + config.active_record.migration_error = :page_load + + # Highlight code that triggered database queries in logs. + config.active_record.verbose_query_logs = true + + # Suppress logger output for asset requests. + config.assets.quiet = true + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true + + # Uncomment if you wish to allow Action Cable access from any origin. + # config.action_cable.disable_request_forgery_protection = true +end diff --git a/quick_acg/config/environments/production.rb b/quick_acg/config/environments/production.rb new file mode 100644 index 0000000..ac46ed4 --- /dev/null +++ b/quick_acg/config/environments/production.rb @@ -0,0 +1,75 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Compress CSS using a preprocessor. + # config.assets.css_compressor = :sass + + # Do not fallback to assets pipeline if a precompiled asset is missed. + config.assets.compile = false + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/quick_acg/config/environments/test.rb b/quick_acg/config/environments/test.rb new file mode 100644 index 0000000..eb2f171 --- /dev/null +++ b/quick_acg/config/environments/test.rb @@ -0,0 +1,50 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/quick_acg/config/initializers/assets.rb b/quick_acg/config/initializers/assets.rb new file mode 100644 index 0000000..2eeef96 --- /dev/null +++ b/quick_acg/config/initializers/assets.rb @@ -0,0 +1,12 @@ +# Be sure to restart your server when you modify this file. + +# Version of your assets, change this if you want to expire all your assets. +Rails.application.config.assets.version = "1.0" + +# Add additional assets to the asset load path. +# Rails.application.config.assets.paths << Emoji.images_path + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in the app/assets +# folder are already added. +# Rails.application.config.assets.precompile += %w( admin.js admin.css ) diff --git a/quick_acg/config/initializers/omniauth.rb b/quick_acg/config/initializers/omniauth.rb new file mode 100644 index 0000000..53dd780 --- /dev/null +++ b/quick_acg/config/initializers/omniauth.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require 'docusign' + +# Defaults to STDOUT: https://github.com/omniauth/omniauth#logging +# Logs entries like: +# (docusign) Setup endpoint detected, running now. +# (docusign) Request phase initiated. +# (docusign) Callback phase initiated. +OmniAuth.config.logger = Rails.logger + +# https://github.com/omniauth/omniauth/wiki/FAQ#omniauthfailureendpoint-does-not-redirect-in-development-mode +# otherwise a callback exception like the following will not get caught: +# OmniAuth::Strategies::OAuth2::CallbackError (access_denied) +# GET "/auth/docusign/callback?error=access_denied&error_message=The%20user%20did%20not%20consent%20to%20connecting%20the%20application.&state= +# OmniAuth.config.failure_raise_out_environments = [] # defaults to: ['development'] + +OmniAuth.config.allowed_request_methods = [:post, :get] + +config = Rails.application.config +config.middleware.use OmniAuth::Builder do + # OAuth2 login request configuration + # OAuth2 login response callback message configuration is in OmniAuth::Strategies::Docusign in lib/docusign.rb + provider :docusign, config.integration_key, config.integration_secret, setup: lambda { |env| + strategy = env['omniauth.strategy'] + + # params = strategy.request.params + # examples_API = params['examples_API'] + # strategy.request.params.delete('examples_API') + + strategy.options[:client_options].site = config.app_url + strategy.options[:prompt] = 'login' + strategy.options[:oauth_base_uri] = config.authorization_server + strategy.options[:target_account_id] = config.target_account_id + strategy.options[:allow_silent_authentication] = config.allow_silent_authentication + strategy.options[:client_options].authorize_url = "#{strategy.options[:oauth_base_uri]}/oauth/auth" + strategy.options[:client_options].user_info_url = "#{strategy.options[:oauth_base_uri]}/oauth/userinfo" + strategy.options[:client_options].token_url = "#{strategy.options[:oauth_base_uri]}/oauth/token" + unless strategy.options[:allow_silent_authentication] + strategy.options[:authorize_params].prompt = strategy.options.prompt + end + session = strategy.session + + if session[:examples_API] == "Rooms" + strategy.options[:authorize_params].scope = "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" + elsif session[:examples_API] == "Click" + strategy.options[:authorize_params].scope = "signature click.manage click.send" + elsif session[:examples_API] == "Admin" + strategy.options[:authorize_params].scope = "signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" + end + } +end diff --git a/quick_acg/config/puma.rb b/quick_acg/config/puma.rb new file mode 100644 index 0000000..daaf036 --- /dev/null +++ b/quick_acg/config/puma.rb @@ -0,0 +1,43 @@ +# Puma can serve each request in a thread from an internal thread pool. +# The `threads` method setting takes two numbers: a minimum and maximum. +# Any libraries that use thread pools should be configured to match +# the maximum value specified for Puma. Default is set to 5 threads for minimum +# and maximum; this matches the default thread size of Active Record. +# +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +# Specifies the `worker_timeout` threshold that Puma will use to wait before +# terminating a worker in development environments. +# +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +# +port ENV.fetch("PORT") { 3000 } + +# Specifies the `environment` that Puma will run in. +# +environment ENV.fetch("RAILS_ENV") { "development" } + +# Specifies the `pidfile` that Puma will use. +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# Specifies the number of `workers` to boot in clustered mode. +# Workers are forked web server processes. If using threads and workers together +# the concurrency of the application would be max `threads` * `workers`. +# Workers do not work on JRuby or Windows (both of which do not support +# processes). +# +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } + +# Use the `preload_app!` method when specifying a `workers` number. +# This directive tells Puma to first boot the application and load code +# before forking the application. This takes advantage of Copy On Write +# process behavior so workers use less memory. +# +# preload_app! + +# Allow puma to be restarted by `bin/rails restart` command. +plugin :tmp_restart diff --git a/quick_acg/config/routes.rb b/quick_acg/config/routes.rb new file mode 100644 index 0000000..e78df7f --- /dev/null +++ b/quick_acg/config/routes.rb @@ -0,0 +1,28 @@ +require_relative '../../app/controllers/application_controller' +require_relative '../../app/controllers/eg_controller' +require_relative '../../app/controllers/session_controller' +require_relative '../../app/services/api_creator' +require_relative '../../app/controllers/eg001_embedded_signing_controller' +require_relative '../../app/services/eg001_embedded_signing_service' + +Rails.application.routes.draw do + root 'ds_common#index' + + get '/eg001' => 'eg001_embedded_signing#get' + post '/eg001' => 'eg001_embedded_signing#create' + + # Login starts with POST'ing to: /auth/docusign + # /auth/docusign is an internal route created by OmniAuth and the docusign strategy from: /lib/docusign.rb + # Should be POST, see: https://nvd.nist.gov/vuln/detail/CVE-2015-9284 + # get '/ds/login' => redirect('/auth/docusign') + + # Handle OmniAuth OAuth2 login callback result that includes the AuthHash + get '/auth/:provider/callback', to: 'session#create' + + get '/ds_common-return' => 'ds_common#index' + + get '/ds/mustAuthenticate' => 'ds_common#ds_must_authenticate' + post '/ds/mustAuthenticate' => 'ds_common#ds_must_authenticate' + + # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html +end diff --git a/quick_acg/lib/docusign.rb b/quick_acg/lib/docusign.rb new file mode 100644 index 0000000..807e6fe --- /dev/null +++ b/quick_acg/lib/docusign.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +# https://github.com/omniauth/omniauth-oauth2 +require 'omniauth-oauth2' + +module OmniAuth + module Strategies + class Docusign < OmniAuth::Strategies::OAuth2 + # The name of the strategy, used in config/initializer/omniauth.rb + option :name, 'docusign' + + # These are called after the OAuth2 login authentication has succeeded and are part of the DocuSign callback response message: + # transforms the DocuSign login response from the raw_info https://github.com/omniauth/omniauth/wiki/Strategy-Contribution-Guide#defining-the-callback-phase + # into the standardized schema required by OmniAuth https://github.com/omniauth/omniauth/wiki/Auth-Hash-Schema + # and gets exposed through the "request.env[omniauth.auth]" to the SessionController#create + uid { raw_info['sub'] } + + info do + { + name: raw_info['name'], + email: raw_info['email'], + first_name: raw_info['given_name'], + last_name: raw_info['family_name'] + } + end + + extra do + { + sub: raw_info['sub'], + account_id: @account['account_id'], + account_name: @account['account_name'], + base_uri: @account['base_uri'] + } + end + + private + + # @returns a Hash with the keys: + # sub, name, given_name, family_name, created, email, accounts: [account_id, is_default, account_name, base_uri] + def raw_info + return @raw_info if @raw_info + + @raw_info = access_token.get(options.client_options.user_info_url.to_s).parsed || {} + fetch_account(@raw_info['accounts']) if @raw_info.present? + @raw_info + end + + # @param items is an array of Hash'es that has the keys: account_id, is_default, account_name, base_uri + def fetch_account(items) + if options.target_account_id + @account = items.find { |item| item['account_id'] == options.target_account_id } + else + @account = items.find { |item| item['is_default'] } + end + + if @account.blank? + raise %'Could not find account information for the user in the "accounts" of raw_info: #{@raw_info}' + end + end + end + end +end From 2aaa584d9c6276c9493756702c0635e54ed013d2 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 22 Jul 2022 14:00:38 -0700 Subject: [PATCH 152/363] remove number in example --- quick_acg/app/views/eg001_embedded_signing/get.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quick_acg/app/views/eg001_embedded_signing/get.html.erb b/quick_acg/app/views/eg001_embedded_signing/get.html.erb index 5e08a13..037a8ad 100644 --- a/quick_acg/app/views/eg001_embedded_signing/get.html.erb +++ b/quick_acg/app/views/eg001_embedded_signing/get.html.erb @@ -48,7 +48,7 @@
-

1. Use embedded signing

+

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 website.

From e65f5724066859086a31c82e03642f3a42338b86 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Tue, 26 Jul 2022 02:49:46 +0300 Subject: [PATCH 153/363] Add In Person Signing code example (#82) * add In-person signing example --- .../eg039_signing_in_person_controller.rb | 36 ++++++ .../e_sign/eg039_signing_in_person_service.rb | 122 ++++++++++++++++++ app/services/e_sign/get_data_service.rb | 44 +++++++ app/views/ds_common/index.html.erb | 85 ++++++------ .../eg002_signing_via_email/get.html.erb | 2 +- .../e_sign/eg003_list_envelopes/get.html.erb | 2 +- .../e_sign/eg004_envelope_info/get.html.erb | 2 +- .../eg005_envelope_recipients/get.html.erb | 2 +- .../e_sign/eg006_envelope_docs/get.html.erb | 2 +- .../eg007_envelope_get_doc/get.html.erb | 2 +- .../e_sign/eg008_create_template/get.html.erb | 2 +- .../e_sign/eg009_use_template/get.html.erb | 2 +- .../eg010_send_binary_docs/get.html.erb | 2 +- .../eg011_embedded_sending/get.html.erb | 2 +- .../eg012_embedded_console/get.html.erb | 2 +- .../eg013_add_doc_to_template/get.html.erb | 2 +- .../e_sign/eg014_collect_payment/get.html.erb | 2 +- .../eg015_get_envelope_tab_data/get.html.erb | 2 +- .../eg016_set_envelope_tab_data/get.html.erb | 2 +- .../get.html.erb | 10 +- .../get.html.erb | 4 +- .../get.html.erb | 4 +- .../eg020_phone_authentication/get.html.erb | 2 +- .../eg022_kba_authentication/get.html.erb | 2 +- .../eg023_idv_authentication/get.html.erb | 4 +- .../eg024_permission_create/get.html.erb | 2 +- .../get.html.erb | 2 +- .../get.html.erb | 2 +- .../eg027_permissions_delete/get.html.erb | 2 +- .../e_sign/eg028_brands_creating/get.html.erb | 4 +- .../get.html.erb | 2 +- .../get.html.erb | 2 +- .../eg031_bulk_sending_envelopes/get.html.erb | 2 +- .../get.html.erb | 4 +- .../get.html.erb | 2 +- .../get.html.erb | 2 +- .../eg035_scheduled_sending/get.html.erb | 2 +- .../e_sign/eg036_delayed_routing/get.html.erb | 2 +- .../e_sign/eg037_sms_delivery/get.html.erb | 2 +- .../eg038_responsive_signing/get.html.erb | 2 +- .../eg039_signing_in_person/get.html.erb | 22 ++++ app/views/eg001_embedded_signing/get.html.erb | 2 +- config/routes.rb | 3 + .../views/eg001_embedded_signing/get.html.erb | 2 +- 44 files changed, 322 insertions(+), 84 deletions(-) create mode 100644 app/controllers/e_sign/eg039_signing_in_person_controller.rb create mode 100644 app/services/e_sign/eg039_signing_in_person_service.rb create mode 100644 app/services/e_sign/get_data_service.rb create mode 100644 app/views/e_sign/eg039_signing_in_person/get.html.erb diff --git a/app/controllers/e_sign/eg039_signing_in_person_controller.rb b/app/controllers/e_sign/eg039_signing_in_person_controller.rb new file mode 100644 index 0000000..2f862d7 --- /dev/null +++ b/app/controllers/e_sign/eg039_signing_in_person_controller.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +class ESign::Eg039SigningInPersonController < EgController + def create + minimum_buffer_min = 10 + token_ok = check_token(minimum_buffer_min) + unless token_ok + flash[:messages] = 'Sorry, you need to re-authenticate.' + # We could store the parameters of the requested operation + # so it could be restarted automatically. + # But since it should be rare to have a token issue here, + # we'll make the user re-enter the form data after + # authentication. + return redirect_to '/ds/mustAuthenticate' + end + + access_token = session[:ds_access_token] + base_path = session[:ds_base_path] + email = ESign::GetDataService.new(access_token, base_path).get_current_user_email + name = ESign::GetDataService.new(access_token, base_path).get_current_user_name + + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + host_email: param_gsub(email), + host_name: param_gsub(name), + signer_name: param_gsub(params[:signer_name]), + ds_ping_url: Rails.application.config.app_url, + pdf_filename: 'data/World_Wide_Corp_lorem.pdf' + } + + redirect_url = ESign::Eg039SigningInPersonService.new(args).worker + redirect_to redirect_url + end +end diff --git a/app/services/e_sign/eg039_signing_in_person_service.rb b/app/services/e_sign/eg039_signing_in_person_service.rb new file mode 100644 index 0000000..f8c86f0 --- /dev/null +++ b/app/services/e_sign/eg039_signing_in_person_service.rb @@ -0,0 +1,122 @@ +# frozen_string_literal: true + +class ESign::Eg039SigningInPersonService + attr_reader :args + include ApiCreator + + def initialize(args) + @args = args + end + + # ***DS.snippet.0.start + def worker + ds_ping_url = args[:ds_ping_url] + ds_return_url = "#{ds_ping_url}/ds_common-return" + pdf_filename = args[:pdf_filename] + host_email = args[:host_email] + host_name = args[:host_name] + signer_name = args[:signer_name] + + # Step 1. Create the envelope definition + envelope = make_envelope(pdf_filename, host_email, host_name, signer_name) + + # Step 2. Call DocuSign to create the envelope + envelope_api = create_envelope_api(args) + + results = envelope_api.create_envelope args[:account_id], envelope + envelope_id = results.envelope_id + + # Step 3. Create the recipient view for the embedded signing + view_request = make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_name + ) + + # Call the CreateRecipientView API + results = envelope_api.create_recipient_view args[:account_id], envelope_id, view_request + + # 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) + # Redirect to results.url + results.url + end + + private + + def make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_name) + view_request = DocuSign_eSign::RecipientViewRequest.new + # 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. + view_request.return_url = ds_return_url + '?state=123' + + # How has your app authenticated the user? In addition to your app's + # authentication, you can include authenticate steps from DocuSign; + # e.g., SMS authentication + view_request.authentication_method = 'none' + + # Recipient information must match the embedded recipient info + # that was used to create the envelope + view_request.email = host_email + view_request.user_name = host_name + + # 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 + view_request.ping_frequency = '600' # seconds + # NOTE: The pings will only be sent if the pingUrl is an HTTPS address + view_request.ping_url = ds_ping_url # Optional setting + + view_request + end + + def make_envelope(pdf_filename, host_email, host_name, signer_name) + envelope_definition = DocuSign_eSign::EnvelopeDefinition.new + envelope_definition.email_subject = 'Please sign this document sent from Ruby SDK' + + doc1 = DocuSign_eSign::Document.new + doc1.document_base64 = Base64.encode64(File.binread(pdf_filename)) + doc1.name = 'Lorem Ipsum' + doc1.file_extension = 'pdf' + doc1.document_id = '1' + + # The order in the docs array determines the order in the envelope + envelope_definition.documents = [doc1] + # Create an in person signer recipient to sign the document + # We're setting the parameters via the object creation + + in_person_signer = DocuSign_eSign::InPersonSigner.new + in_person_signer.host_email = host_email + in_person_signer.host_name = host_name + in_person_signer.signer_name = signer_name + in_person_signer.recipient_id = '1' + in_person_signer.routing_order = '1' + + # The DocuSign platform searches throughout your envelope's documents for matching + # anchor strings. + sign_here = DocuSign_eSign::SignHere.new + sign_here.anchor_string = '/sn1/' + sign_here.anchor_units = 'pixels' + sign_here.anchor_x_offset = '20' + sign_here.anchor_y_offset = '10' + # Tabs are set per recipient/signer + tabs = DocuSign_eSign::Tabs.new + tabs.sign_here_tabs = [sign_here] + in_person_signer.tabs = tabs + # Add the recipients to the envelope object + recipients = DocuSign_eSign::Recipients.new + recipients.in_person_signers = [in_person_signer] + + envelope_definition.recipients = recipients + # Request that the envelope be sent by setting status to "sent". + # To request that the envelope be created as a draft, set status to "created" + envelope_definition.status = 'sent' + envelope_definition + end + # ***DS.snippet.0.end +end \ No newline at end of file diff --git a/app/services/e_sign/get_data_service.rb b/app/services/e_sign/get_data_service.rb new file mode 100644 index 0000000..6ac178a --- /dev/null +++ b/app/services/e_sign/get_data_service.rb @@ -0,0 +1,44 @@ +class ESign::GetDataService + attr_reader :args + + def initialize(access_token, base_path) + @args = { + access_token: access_token, + base_path: base_path + } + end + + def get_current_user_email + worker + + user_info = @api_client.get_user_info(args[:access_token]) + unless user_info + raise "The user does not have access to account" + end + + user_info.email + end + + def get_current_user_name + worker + + user_info = @api_client.get_user_info(args[:access_token]) + unless user_info + raise "The user does not have access to account" + end + + user_info.name + end + + private + + def worker + configuration = DocuSign_eSign::Configuration.new + configuration.host = args[:base_path] + + @api_client = DocuSign_eSign::ApiClient.new(configuration) + @api_client.set_base_path(args[:base_path]) + @api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + + end +end \ No newline at end of file diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index 55a7ca7..8dba206 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -31,7 +31,7 @@

Basic examples

-

1. Use embedded signing

+

Use embedded signing

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

@@ -40,7 +40,7 @@ EnvelopeViews::createRecipient.

-

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

+

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

The envelope includes three documents: one each in PDF, Word, and HTML format. Anchor text (AutoPlace) is used to position the signing fields in the documents. @@ -49,14 +49,14 @@ Envelopes::create.

-

3. List envelopes whose status has changed

+

List envelopes whose status has changed

This example lists the envelopes whose status has changed within the last 30 days.

API method used: Envelopes::listStatusChanges.

-

4. Get an envelope’s basic information and status

+

Get an envelope’s basic information and status

This example lists 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, and more. @@ -65,14 +65,14 @@ Envelopes::get.

-

5. List an envelope’s recipients and their status

+

List an envelope’s recipients and their status

This example lists the envelope’s recipients, including their current status.

API method used: EnvelopeRecipients::list.

-

6. List an envelope's documents

+

List an envelope's documents

This example demonstrates how to list an envelope's documents. A Certificate of Completion document is also associated with every envelope.

@@ -80,27 +80,27 @@ EnvelopeDocuments::list.

-

7. Download a document from an envelope

+

Download a document from an envelope

This example demonstrates how to download a document from a given 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

Create a template with two roles, signer and cc.

API methods used: Templates::list and Templates::create.

-

9. Send an envelope using a template

+

Send an envelope using a template

This example demonstrates a common pattern for DocuSign integrations: envelopes will be sent programmatically, defined by a 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

+

Send an envelope using binary document transfer

The envelope includes three documents: one each in PDF, Word, and HTML format.

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 15 MB. Binary transfer is not yet supported by the SDK. @@ -109,19 +109,19 @@ Envelopes::create.

-

11. Use embedded sending

+

Use embedded sending

This example demonstrates how to embed the DocuSign sender view within your web app. An envelope will be created in draft mode. Your browser will then be redirected to the DocuSign UI, where the envelope can be (optionally) updated and then sent.

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

12. Embedded DocuSign UI

+

Embedded DocuSign UI

This example demonstrates how to embed the DocuSign UI in your app. Use this API call to open the DocuSign UI with the user already logged in.

API method used: EnvelopeViews::createConsole.

-

13. Use embedded signing from a template with an added document

+

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 @@ -131,9 +131,19 @@ EnvelopeViews::createRecipient.

+

Send an envelope to an In Person Signer

+

+ This example demonstrates how to host an In Person Signing session with embedded signing. +

+

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

+

Payments

-

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

+

Send an envelope with an order form and payment field

Anchor text (AutoPlace) is used to position the fields in the documents. @@ -143,14 +153,14 @@

Tabs

-

15. Get the tab data from an envelope

+

Get the tab data from an envelope

This example retrieves the tab (field) values from an envelope for all of the envelope’s recipients.

API method used: EnvelopeFormData::get.

-

16. Set tab values for a envelope

+

Set tab values for a envelope

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

API methods used: @@ -158,7 +168,7 @@ EnvelopeViews::createRecipient.

-

17. Set template tab values

+

Set template tab values

This example sets the tab (field) values for a template being used by an envelope. It includes setting radio button and checkbox tabs.

@@ -167,7 +177,7 @@ EnvelopeViews::createRecipient.

-

18. List envelope custom metadata field values

+

List envelope custom metadata field values

This example lists an envelope’s custom metadata field values.

API method used: @@ -176,25 +186,25 @@

Recipient authentication

-

19. Require access code authentication for a recipient

+

Require access code authentication for a recipient

This example sends an envelope requiring the recipient to enter an access code for multifactor authentication.

API method used: Envelopes::create.

-

20. Require phone authentication for a recipient

+

Require phone authentication for a recipient

Sends an envelope that requires entering a six-digit code from a text message or phone call for the purpose of multifactor authentication.

API method used: Envelopes::create.

-

22. Require knowledge based authentication (KBA) for a recipient

+

Require knowledge based authentication (KBA) for a recipient

Submit an envelope with multiple choice, public records based questions to provide multi-factor authentication.

API method used: Envelopes::create.

-

23. Require ID verification (IDV) for a recipient

+

Require ID verification (IDV) for a recipient

This is an example of an envelope utilizing ID verification authentication for a recipient.

API methods used: Accounts::getAccountIdentityVerificationsList and Envelopes::create. @@ -202,7 +212,7 @@

Permissions

-

24. Create a permission profile

+

Create a permission profile

This example creates a user group’s permission profile.

@@ -210,13 +220,13 @@ AccountPermissionProfiles::create.

-

25. Set a permission profile

+

Set a permission profile

This example updates the group name and modifies, or sets, the permission profile for the group.

API method used: Groups::update.

-

26. Update individual permission profile settings

+

Update individual permission profile settings

This example updates an individual setting on a user group’s permission profile.

@@ -224,7 +234,7 @@ AccountPermissionProfiles::update.

-

27. Delete a permission profile

+

Delete a permission profile

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

API method used: AccountPermissionProfiles::delete. @@ -232,19 +242,19 @@

Brands

-

28. Create a brand

+

Create a brand

This example creates an account brand that can be used to apply customization to your envelopes, including your own logo, colors, and text elements.

API method used: AccountBrands::create.

-

29. Apply a brand to an envelope

+

Apply a brand to an envelope

This example creates an envelope using any of the created brands on your account.

API method used: Envelopes::create.

-

30. Apply a brand and template to an envelope

+

Apply a brand and template to an envelope

This example creates an envelope from a template while applying any of the created brands on your account.

API method used: Envelopes::create. @@ -252,7 +262,7 @@

Bulk operations

-

31. Bulk send envelopes

+

Bulk send envelopes

Demonstrates how to send envelopes in bulk to multiple recipients. First, this example creates a bulk send recipients list, then creates an envelope. After that, it initiates bulk envelope sending.

@@ -271,25 +281,25 @@

Advanced recipient routing

-

32. Pause a signature workflow

+

Pause a signature workflow

This example creates an envelope where the workflow is paused before the envelope is sent to a second recipient.

API method used: Envelopes::create.

-

33. Unpause a signature workflow

+

Unpause a signature workflow

This example resumes a signature workflow for an envelope whose workflow has been paused.

API method used: Envelopes::update.

-

34. Use conditional recipients

+

Use conditional recipients

This example creates an envelope whose workflow routes it to different recipients based on the value of a transaction.

API method used: Envelopes::create.

-

35. Schedule an envelope

+

Schedule an envelope

Demonstrates how to schedule sending an envelope using the scheduled sending feature.

@@ -297,7 +307,7 @@ API method used: Envelopes:create.

-

36. Send an envelope with delayed routing

+

Send an envelope with delayed routing

Demonstrates how to delay an envelope’s delivery between recipients using the delayed routing feature. @@ -309,7 +319,7 @@

Premium features

-

37. Request a signature by SMS delivery

+

Request a signature by SMS delivery

Sends a signature request via an SMS message.

@@ -319,7 +329,7 @@ href="https://developers.docusign.com/docs/esign-rest-api/reference/envelopes/envelopes/create/">Envelopes::create.

-

38. Create a signable HTML document

+

Create a signable HTML document

Demonstrates how to create an HTML document for responsive signing.

@@ -328,6 +338,7 @@ EnvelopeViews::createRecipient.

+
diff --git a/app/views/e_sign/eg002_signing_via_email/get.html.erb b/app/views/e_sign/eg002_signing_via_email/get.html.erb index 06b733c..a0c0704 100644 --- a/app/views/e_sign/eg002_signing_via_email/get.html.erb +++ b/app/views/e_sign/eg002_signing_via_email/get.html.erb @@ -1,4 +1,4 @@ -

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

+

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. diff --git a/app/views/e_sign/eg003_list_envelopes/get.html.erb b/app/views/e_sign/eg003_list_envelopes/get.html.erb index 0466a86..6d6bfba 100644 --- a/app/views/e_sign/eg003_list_envelopes/get.html.erb +++ b/app/views/e_sign/eg003_list_envelopes/get.html.erb @@ -1,4 +1,4 @@ -

3. List envelopes in the user's account

+

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.

diff --git a/app/views/e_sign/eg004_envelope_info/get.html.erb b/app/views/e_sign/eg004_envelope_info/get.html.erb index 2a36d02..2005aae 100644 --- a/app/views/e_sign/eg004_envelope_info/get.html.erb +++ b/app/views/e_sign/eg004_envelope_info/get.html.erb @@ -1,4 +1,4 @@ -

4. Get an envelope's basic information and status

+

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.

diff --git a/app/views/e_sign/eg005_envelope_recipients/get.html.erb b/app/views/e_sign/eg005_envelope_recipients/get.html.erb index 7cf793a..e3afc17 100644 --- a/app/views/e_sign/eg005_envelope_recipients/get.html.erb +++ b/app/views/e_sign/eg005_envelope_recipients/get.html.erb @@ -1,4 +1,4 @@ -

5. List an envelope's recipients and their status

+

List an envelope's recipients and their status

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

<% if @show_doc %> diff --git a/app/views/e_sign/eg006_envelope_docs/get.html.erb b/app/views/e_sign/eg006_envelope_docs/get.html.erb index ea4a25d..33a7481 100644 --- a/app/views/e_sign/eg006_envelope_docs/get.html.erb +++ b/app/views/e_sign/eg006_envelope_docs/get.html.erb @@ -1,4 +1,4 @@ -

6. List an envelope's documents

+

List an envelope's documents

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

diff --git a/app/views/e_sign/eg007_envelope_get_doc/get.html.erb b/app/views/e_sign/eg007_envelope_get_doc/get.html.erb index 9f9381f..f1cba1e 100644 --- a/app/views/e_sign/eg007_envelope_get_doc/get.html.erb +++ b/app/views/e_sign/eg007_envelope_get_doc/get.html.erb @@ -1,5 +1,5 @@ -

7. Download a document from an envelope

+

Download a document from an envelope

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

Document download options:

    diff --git a/app/views/e_sign/eg008_create_template/get.html.erb b/app/views/e_sign/eg008_create_template/get.html.erb index 9dce1d7..d5cc859 100644 --- a/app/views/e_sign/eg008_create_template/get.html.erb +++ b/app/views/e_sign/eg008_create_template/get.html.erb @@ -1,4 +1,4 @@ -

    8. Create a template

    +

    Create a template

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

    diff --git a/app/views/e_sign/eg009_use_template/get.html.erb b/app/views/e_sign/eg009_use_template/get.html.erb index 180d9c2..627ef78 100644 --- a/app/views/e_sign/eg009_use_template/get.html.erb +++ b/app/views/e_sign/eg009_use_template/get.html.erb @@ -1,4 +1,4 @@ -

    9. Send an envelope using a template

    +

    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.

    diff --git a/app/views/e_sign/eg010_send_binary_docs/get.html.erb b/app/views/e_sign/eg010_send_binary_docs/get.html.erb index 00c7daa..78c2bb3 100644 --- a/app/views/e_sign/eg010_send_binary_docs/get.html.erb +++ b/app/views/e_sign/eg010_send_binary_docs/get.html.erb @@ -1,4 +1,4 @@ -

    10. Send an envelope using binary document transfer

    +

    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. diff --git a/app/views/e_sign/eg011_embedded_sending/get.html.erb b/app/views/e_sign/eg011_embedded_sending/get.html.erb index 932a096..c1388e5 100644 --- a/app/views/e_sign/eg011_embedded_sending/get.html.erb +++ b/app/views/e_sign/eg011_embedded_sending/get.html.erb @@ -1,4 +1,4 @@ -

    11. Use embedded sending

    +

    Use 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 diff --git a/app/views/e_sign/eg012_embedded_console/get.html.erb b/app/views/e_sign/eg012_embedded_console/get.html.erb index 2eccd5e..72d6ee2 100644 --- a/app/views/e_sign/eg012_embedded_console/get.html.erb +++ b/app/views/e_sign/eg012_embedded_console/get.html.erb @@ -1,4 +1,4 @@ -

    12. Embedded DocuSign web tool

    +

    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.

    diff --git a/app/views/e_sign/eg013_add_doc_to_template/get.html.erb b/app/views/e_sign/eg013_add_doc_to_template/get.html.erb index 788323e..1e8bd17 100644 --- a/app/views/e_sign/eg013_add_doc_to_template/get.html.erb +++ b/app/views/e_sign/eg013_add_doc_to_template/get.html.erb @@ -1,4 +1,4 @@ -

    13. Use embedded signing from a template with an added document

    +

    Use embedded signing from a template with an added document

    <% if @template_ok %>

    This example sends an envelope based on a template.

    diff --git a/app/views/e_sign/eg014_collect_payment/get.html.erb b/app/views/e_sign/eg014_collect_payment/get.html.erb index e1b9d73..0ef1523 100644 --- a/app/views/e_sign/eg014_collect_payment/get.html.erb +++ b/app/views/e_sign/eg014_collect_payment/get.html.erb @@ -1,4 +1,4 @@ -

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

    +

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

    Anchor strings (AutoPlace) diff --git a/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb b/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb index 80bf58e..3b5a3b9 100644 --- a/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb +++ b/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb @@ -1,4 +1,4 @@ -

    15. Get the tab data from an envelope

    +

    Get the tab data from an envelope

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

    diff --git a/app/views/e_sign/eg016_set_envelope_tab_data/get.html.erb b/app/views/e_sign/eg016_set_envelope_tab_data/get.html.erb index 76b49c2..d7a395e 100644 --- a/app/views/e_sign/eg016_set_envelope_tab_data/get.html.erb +++ b/app/views/e_sign/eg016_set_envelope_tab_data/get.html.erb @@ -1,5 +1,5 @@ -

    16. Set tab values for a envelope

    +

    Set tab values for a envelope

    This example creates an envelope with both read-only tabs (fields) and tabs that can be updated by the recipient. diff --git a/app/views/e_sign/eg017_set_template_tab_values/get.html.erb b/app/views/e_sign/eg017_set_template_tab_values/get.html.erb index 2007f15..06211e2 100644 --- a/app/views/e_sign/eg017_set_template_tab_values/get.html.erb +++ b/app/views/e_sign/eg017_set_template_tab_values/get.html.erb @@ -1,5 +1,5 @@ -

    17. Set template tab values

    +

    Set template tab values

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

    API method used: Envelopes::create.

    - +

    View source file <%= @source_file %> on GitHub.

    @@ -21,7 +21,7 @@ <% if @template_ok %>

    The template you created via example 8 will be used.

    - +
    @@ -48,11 +48,11 @@
    - + <% else %>

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

    - +
    diff --git a/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb b/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb index e63d71a..13f8e43 100644 --- a/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb +++ b/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb @@ -1,4 +1,4 @@ -

    18. Get the custom field data for an envelope

    +

    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 @@ -17,7 +17,7 @@

    API method used: EnvelopeCustomFields::list.

    - +

    View source file <%= @source_file %> on GitHub.

    diff --git a/app/views/e_sign/eg019_access_code_authentication/get.html.erb b/app/views/e_sign/eg019_access_code_authentication/get.html.erb index bf34e72..17a0a60 100644 --- a/app/views/e_sign/eg019_access_code_authentication/get.html.erb +++ b/app/views/e_sign/eg019_access_code_authentication/get.html.erb @@ -1,4 +1,4 @@ -

    19. Requiring an Access Code for a Recipient

    +

    Requiring an Access Code for a Recipient

    The envelope includes a pdf document. Anchor text (AutoPlace) @@ -23,7 +23,7 @@ API method used:

    - +
    20. Require Phone Authentication for a Recipient +

    Require Phone Authentication for a Recipient

    Sends an envelope that requires entering a six-digit code from a text message or phone call for the purpose of multifactor authentication. diff --git a/app/views/e_sign/eg022_kba_authentication/get.html.erb b/app/views/e_sign/eg022_kba_authentication/get.html.erb index 21cdf28..1eff5ba 100644 --- a/app/views/e_sign/eg022_kba_authentication/get.html.erb +++ b/app/views/e_sign/eg022_kba_authentication/get.html.erb @@ -1,4 +1,4 @@ -

    22. Requiring Knowledge Based Authentication (KBA) for a Recipient

    +

    Requiring Knowledge Based Authentication (KBA) for a Recipient

    The envelope includes a pdf document. Anchor text (AutoPlace) diff --git a/app/views/e_sign/eg023_idv_authentication/get.html.erb b/app/views/e_sign/eg023_idv_authentication/get.html.erb index 19666c4..94d3339 100644 --- a/app/views/e_sign/eg023_idv_authentication/get.html.erb +++ b/app/views/e_sign/eg023_idv_authentication/get.html.erb @@ -1,6 +1,6 @@ -

    23. Require ID verification (IDV) for a recipient

    +

    Require ID verification (IDV) for a recipient

    Sends an envelope that requires the recipient to upload a government-issued ID for the purpose of multifactor authentication.

    -

    Anchor text +

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

    diff --git a/app/views/e_sign/eg024_permission_create/get.html.erb b/app/views/e_sign/eg024_permission_create/get.html.erb index 436e96e..7f410c8 100644 --- a/app/views/e_sign/eg024_permission_create/get.html.erb +++ b/app/views/e_sign/eg024_permission_create/get.html.erb @@ -1,4 +1,4 @@ -

    24. Creating a permission profile

    +

    Creating a permission profile

    This code example demonstrates how to create a profile permission diff --git a/app/views/e_sign/eg025_permissions_set_user_group/get.html.erb b/app/views/e_sign/eg025_permissions_set_user_group/get.html.erb index 02ff483..82ba495 100644 --- a/app/views/e_sign/eg025_permissions_set_user_group/get.html.erb +++ b/app/views/e_sign/eg025_permissions_set_user_group/get.html.erb @@ -1,4 +1,4 @@ -

    25. Setting a permission profile

    +

    Setting a permission profile

    Updates the group name and modifies, or sets, the permission profile for the group diff --git a/app/views/e_sign/eg026_permissions_change_single_setting/get.html.erb b/app/views/e_sign/eg026_permissions_change_single_setting/get.html.erb index 5a14206..c99118a 100644 --- a/app/views/e_sign/eg026_permissions_change_single_setting/get.html.erb +++ b/app/views/e_sign/eg026_permissions_change_single_setting/get.html.erb @@ -1,4 +1,4 @@ -

    26. Updating individual permission settings

    +

    Updating individual permission settings

    This code example demonstrates how to change setting in the existion permission profile. diff --git a/app/views/e_sign/eg027_permissions_delete/get.html.erb b/app/views/e_sign/eg027_permissions_delete/get.html.erb index 0f53a9b..caca8af 100644 --- a/app/views/e_sign/eg027_permissions_delete/get.html.erb +++ b/app/views/e_sign/eg027_permissions_delete/get.html.erb @@ -1,4 +1,4 @@ -

    27. Deleting a permission profile

    +

    Deleting a permission profile

    This method deletes a permission profile from an account. diff --git a/app/views/e_sign/eg028_brands_creating/get.html.erb b/app/views/e_sign/eg028_brands_creating/get.html.erb index a148952..4c35a59 100644 --- a/app/views/e_sign/eg028_brands_creating/get.html.erb +++ b/app/views/e_sign/eg028_brands_creating/get.html.erb @@ -1,4 +1,4 @@ -

    28. Creating a brand

    +

    Creating a brand

    The brand includes a Brand Name Configure Brands.

    This is an example demonstrates how to create a brand.

    @@ -21,6 +21,6 @@ <%= select_tag "defaultBrandLanguage", options_for_select(language_list), { id: "defaultBrandLanguage", name: "defaultBrandLanguage", class: "form-control" } %>
    - + \ No newline at end of file diff --git a/app/views/e_sign/eg029_brands_apply_to_envelope/get.html.erb b/app/views/e_sign/eg029_brands_apply_to_envelope/get.html.erb index 7752aee..4e162e9 100644 --- a/app/views/e_sign/eg029_brands_apply_to_envelope/get.html.erb +++ b/app/views/e_sign/eg029_brands_apply_to_envelope/get.html.erb @@ -1,4 +1,4 @@ -

    29. Applying a Brand to an envelope

    +

    Applying a Brand to an envelope

    The envelope includes a pdf document. Anchor text diff --git a/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb b/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb index 8b31b61..9508aa3 100644 --- a/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb +++ b/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb @@ -1,4 +1,4 @@ -

    30. Applying a brand to an envelope using a template

    +

    Applying a brand to an envelope using a template

    <% if @template_ok %>

    diff --git a/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb b/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb index 8d95701..c92496e 100644 --- a/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb +++ b/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb @@ -1,4 +1,4 @@ -

    31. Bulk send envelopes

    +

    Bulk send envelopes

    Demonstrates how to send envelopes in bulk to multiple recipients. First, this example creates a bulk send recipients list, diff --git a/app/views/e_sign/eg032_pauses_signature_workflow/get.html.erb b/app/views/e_sign/eg032_pauses_signature_workflow/get.html.erb index ccd6b03..ef660f2 100644 --- a/app/views/e_sign/eg032_pauses_signature_workflow/get.html.erb +++ b/app/views/e_sign/eg032_pauses_signature_workflow/get.html.erb @@ -1,4 +1,4 @@ -

    32. Pausing a signature workflow

    +

    Pausing a signature workflow

    This example demonstrates how to create an envelope where the workflow is paused before the envelope is sent to a second recipient. @@ -44,4 +44,4 @@

    - \ No newline at end of file + \ No newline at end of file diff --git a/app/views/e_sign/eg033_unpauses_signature_workflow/get.html.erb b/app/views/e_sign/eg033_unpauses_signature_workflow/get.html.erb index 5c0bdd6..bd29685 100644 --- a/app/views/e_sign/eg033_unpauses_signature_workflow/get.html.erb +++ b/app/views/e_sign/eg033_unpauses_signature_workflow/get.html.erb @@ -1,4 +1,4 @@ -

    33. Unpausing a signature workflow

    +

    Unpausing a signature workflow

    This example demonstrates how to resume an envelope workflow that has been paused. diff --git a/app/views/e_sign/eg034_use_conditional_recipients/get.html.erb b/app/views/e_sign/eg034_use_conditional_recipients/get.html.erb index f4d0b1b..27b0be9 100644 --- a/app/views/e_sign/eg034_use_conditional_recipients/get.html.erb +++ b/app/views/e_sign/eg034_use_conditional_recipients/get.html.erb @@ -1,4 +1,4 @@ -

    33. Using conditional recipients

    +

    Using conditional recipients

    This example demonstrates how to create an envelope where the workflow is routed to different recipients based on the value of a transaction. diff --git a/app/views/e_sign/eg035_scheduled_sending/get.html.erb b/app/views/e_sign/eg035_scheduled_sending/get.html.erb index 743da75..a10fbae 100644 --- a/app/views/e_sign/eg035_scheduled_sending/get.html.erb +++ b/app/views/e_sign/eg035_scheduled_sending/get.html.erb @@ -1,4 +1,4 @@ -

    35. Schedule an envelope

    +

    Schedule an envelope

    This example demonstrates how to schedule an envelope using the scheduled sending feature.

    diff --git a/app/views/e_sign/eg036_delayed_routing/get.html.erb b/app/views/e_sign/eg036_delayed_routing/get.html.erb index 0004ddd..cc6bb22 100644 --- a/app/views/e_sign/eg036_delayed_routing/get.html.erb +++ b/app/views/e_sign/eg036_delayed_routing/get.html.erb @@ -1,4 +1,4 @@ -

    36. Send an envelope with delayed routing

    +

    Send an envelope with delayed routing

    This example demonstrates how to delay an envelope’s delivery between recipients using the delayed routing feature.

    diff --git a/app/views/e_sign/eg037_sms_delivery/get.html.erb b/app/views/e_sign/eg037_sms_delivery/get.html.erb index fc68c63..a2ed164 100644 --- a/app/views/e_sign/eg037_sms_delivery/get.html.erb +++ b/app/views/e_sign/eg037_sms_delivery/get.html.erb @@ -1,4 +1,4 @@ -

    37. Request a signature by SMS delivery

    +

    Request a signature by SMS delivery

    Sends a signature request via an SMS message.

    diff --git a/app/views/e_sign/eg038_responsive_signing/get.html.erb b/app/views/e_sign/eg038_responsive_signing/get.html.erb index 047f511..1d88925 100644 --- a/app/views/e_sign/eg038_responsive_signing/get.html.erb +++ b/app/views/e_sign/eg038_responsive_signing/get.html.erb @@ -1,4 +1,4 @@ -

    38. Create a signable HTML document

    +

    Create a signable HTML document

    Demonstrates how to create an HTML document for responsive signing.

    <% if @show_doc %> diff --git a/app/views/e_sign/eg039_signing_in_person/get.html.erb b/app/views/e_sign/eg039_signing_in_person/get.html.erb new file mode 100644 index 0000000..c895326 --- /dev/null +++ b/app/views/e_sign/eg039_signing_in_person/get.html.erb @@ -0,0 +1,22 @@ +

    Send an envelope to an In Person Signer

    +

    Demonstrates how to host an In Person Signing session with embedded signing.

    + +<% if @show_doc %> +

    Documentation about this example.

    +<% end %> + +

    API methods used: + Envelopes::create. +

    +

    + View source file <%= @source_file %> on GitHub. +

    + +
    +
    + + +
    + + +
    \ No newline at end of file diff --git a/app/views/eg001_embedded_signing/get.html.erb b/app/views/eg001_embedded_signing/get.html.erb index 1471f37..19a9a88 100644 --- a/app/views/eg001_embedded_signing/get.html.erb +++ b/app/views/eg001_embedded_signing/get.html.erb @@ -1,4 +1,4 @@ -

    1. Use embedded signing

    +

    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 website.

    diff --git a/config/routes.rb b/config/routes.rb index 5d56220..83c4822 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -202,6 +202,9 @@ get 'eg038' => 'eg038_responsive_signing#get' post 'eg038' => 'eg038_responsive_signing#create' + + get 'eg039' => 'eg039_signing_in_person#get' + post 'eg039' => 'eg039_signing_in_person#create' end end diff --git a/quick_acg/app/views/eg001_embedded_signing/get.html.erb b/quick_acg/app/views/eg001_embedded_signing/get.html.erb index 5e08a13..037a8ad 100644 --- a/quick_acg/app/views/eg001_embedded_signing/get.html.erb +++ b/quick_acg/app/views/eg001_embedded_signing/get.html.erb @@ -48,7 +48,7 @@
    -

    1. Use embedded signing

    +

    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 website.

    From 491002d8f460ab275e23ce7a5ccc01d94ac5c9a5 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Mon, 25 Jul 2022 16:59:50 -0700 Subject: [PATCH 154/363] add 2nd API method --- app/views/e_sign/eg039_signing_in_person/get.html.erb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/views/e_sign/eg039_signing_in_person/get.html.erb b/app/views/e_sign/eg039_signing_in_person/get.html.erb index c895326..411eb46 100644 --- a/app/views/e_sign/eg039_signing_in_person/get.html.erb +++ b/app/views/e_sign/eg039_signing_in_person/get.html.erb @@ -6,7 +6,8 @@ <% end %>

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

    View source file <%= @source_file %> on GitHub. @@ -19,4 +20,4 @@

    - \ No newline at end of file + From a93f16270b577389fa49bc99985db207fac8d687 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Thu, 4 Aug 2022 23:52:45 +0300 Subject: [PATCH 155/363] update gemfile (#81) Co-authored-by: Karissa Jacobsen --- Gemfile | 16 ++--- Gemfile.lock | 189 +++++++++++++++++++++++++++++---------------------- 2 files changed, 116 insertions(+), 89 deletions(-) diff --git a/Gemfile b/Gemfile index b8fc89f..402403d 100644 --- a/Gemfile +++ b/Gemfile @@ -3,14 +3,14 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '~>3.0.2' +ruby '~>3.1.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 6.0.4.1' +gem 'rails', '~> 7.0.3' # Use sqlite3 as the database for Active Record -gem 'sqlite3', '~> 1.4.2' +gem 'sqlite3', '~> 1.4.4' # Use Puma as the app server -gem 'puma', '~> 4.3.12' +gem 'puma', '~> 5.6.4' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets @@ -23,7 +23,7 @@ gem 'coffee-rails', '~> 5.0.0' # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks gem 'turbolinks', '~> 5.2.1' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder -gem 'jbuilder', '~> 2.10.0' +gem 'jbuilder', '~> 2.11.5' # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 4.0' # Use ActiveModel has_secure_password @@ -49,8 +49,8 @@ end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. - gem 'listen', '~> 3.7.0' - gem 'web-console', '~> 4.0.1' + gem 'listen', '~> 3.7.1' + gem 'web-console', '~> 4.2.0' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'pry-nav', '~> 0.3.0' gem 'pry-rails', '~> 0.3.9' @@ -75,5 +75,5 @@ gem 'omniauth-oauth2', '~> 1.7.1' gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem 'tzinfo-data', '~> 1.2019.3', platforms: %i[mingw mswin x64_mingw jruby] +gem 'tzinfo-data', '~> 1.2022.1', '>= 1.2022.1' gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] diff --git a/Gemfile.lock b/Gemfile.lock index 747e2c1..36360c9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,61 +1,71 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.4.8) - actionpack (= 6.0.4.8) + actioncable (7.0.3) + actionpack (= 7.0.3) + activesupport (= 7.0.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.4.8) - actionpack (= 6.0.4.8) - activejob (= 6.0.4.8) - activerecord (= 6.0.4.8) - activestorage (= 6.0.4.8) - activesupport (= 6.0.4.8) + actionmailbox (7.0.3) + actionpack (= 7.0.3) + activejob (= 7.0.3) + activerecord (= 7.0.3) + activestorage (= 7.0.3) + activesupport (= 7.0.3) mail (>= 2.7.1) - actionmailer (6.0.4.8) - actionpack (= 6.0.4.8) - actionview (= 6.0.4.8) - activejob (= 6.0.4.8) + net-imap + net-pop + net-smtp + actionmailer (7.0.3) + actionpack (= 7.0.3) + actionview (= 7.0.3) + activejob (= 7.0.3) + activesupport (= 7.0.3) mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp rails-dom-testing (~> 2.0) - actionpack (6.0.4.8) - actionview (= 6.0.4.8) - activesupport (= 6.0.4.8) - rack (~> 2.0, >= 2.0.8) + actionpack (7.0.3) + actionview (= 7.0.3) + activesupport (= 7.0.3) + rack (~> 2.0, >= 2.2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.4.8) - actionpack (= 6.0.4.8) - activerecord (= 6.0.4.8) - activestorage (= 6.0.4.8) - activesupport (= 6.0.4.8) + actiontext (7.0.3) + actionpack (= 7.0.3) + activerecord (= 7.0.3) + activestorage (= 7.0.3) + activesupport (= 7.0.3) + globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (6.0.4.8) - activesupport (= 6.0.4.8) + actionview (7.0.3) + activesupport (= 7.0.3) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.4.8) - activesupport (= 6.0.4.8) + activejob (7.0.3) + activesupport (= 7.0.3) globalid (>= 0.3.6) - activemodel (6.0.4.8) - activesupport (= 6.0.4.8) - activerecord (6.0.4.8) - activemodel (= 6.0.4.8) - activesupport (= 6.0.4.8) - activestorage (6.0.4.8) - actionpack (= 6.0.4.8) - activejob (= 6.0.4.8) - activerecord (= 6.0.4.8) - marcel (~> 1.0.0) - activesupport (6.0.4.8) + activemodel (7.0.3) + activesupport (= 7.0.3) + activerecord (7.0.3) + activemodel (= 7.0.3) + activesupport (= 7.0.3) + activestorage (7.0.3) + actionpack (= 7.0.3) + activejob (= 7.0.3) + activerecord (= 7.0.3) + activesupport (= 7.0.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.3) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - zeitwerk (~> 2.2, >= 2.2.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) archive-zip (0.12.0) @@ -87,6 +97,7 @@ GEM coffee-script-source (1.12.2) concurrent-ruby (1.1.10) crass (1.0.6) + digest (3.1.0) docusign_admin (1.1.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) @@ -120,14 +131,15 @@ GEM faraday-net_http (~> 2.0) ruby2_keywords (>= 0.0.4) faraday-net_http (2.0.3) - ffi (1.15.5-x64-mingw32) + ffi (1.15.5-x64-mingw-ucrt) globalid (1.0.0) activesupport (>= 5.0) hashie (5.0.0) i18n (1.11.0) concurrent-ruby (~> 1.0) io-like (0.3.1) - jbuilder (2.10.2) + jbuilder (2.11.5) + actionview (>= 5.0.0) activesupport (>= 5.0.0) json (2.6.2) jwt (2.4.1) @@ -145,8 +157,22 @@ GEM minitest (5.16.2) msgpack (1.5.3) multi_xml (0.6.0) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout nio4r (2.5.8) - nokogiri (1.13.6-x64-mingw32) + nokogiri (1.13.6-x64-mingw-ucrt) racc (~> 1.4) oauth2 (2.0.5) faraday (>= 0.17.3, < 3.0) @@ -173,7 +199,7 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.7) - puma (4.3.12) + puma (5.6.4) nio4r (~> 2.0) racc (1.6.0) rack (2.2.4) @@ -181,32 +207,32 @@ GEM rack rack-test (2.0.2) rack (>= 1.3) - rails (6.0.4.8) - actioncable (= 6.0.4.8) - actionmailbox (= 6.0.4.8) - actionmailer (= 6.0.4.8) - actionpack (= 6.0.4.8) - actiontext (= 6.0.4.8) - actionview (= 6.0.4.8) - activejob (= 6.0.4.8) - activemodel (= 6.0.4.8) - activerecord (= 6.0.4.8) - activestorage (= 6.0.4.8) - activesupport (= 6.0.4.8) - bundler (>= 1.3.0) - railties (= 6.0.4.8) - sprockets-rails (>= 2.0.0) + rails (7.0.3) + actioncable (= 7.0.3) + actionmailbox (= 7.0.3) + actionmailer (= 7.0.3) + actionpack (= 7.0.3) + actiontext (= 7.0.3) + actionview (= 7.0.3) + activejob (= 7.0.3) + activemodel (= 7.0.3) + activerecord (= 7.0.3) + activestorage (= 7.0.3) + activesupport (= 7.0.3) + bundler (>= 1.15.0) + railties (= 7.0.3) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.4.3) loofah (~> 2.3) - railties (6.0.4.8) - actionpack (= 6.0.4.8) - activesupport (= 6.0.4.8) + railties (7.0.3) + actionpack (= 7.0.3) + activesupport (= 7.0.3) method_source - rake (>= 0.8.7) - thor (>= 0.20.3, < 2.0) + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) rake (13.0.6) rash_alt (0.4.12) hashie (>= 3.4) @@ -218,7 +244,7 @@ GEM rubyzip (2.3.2) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) - sassc (2.4.0-x64-mingw32) + sassc (2.4.0) ffi (~> 1.9) sassc-rails (2.1.2) railties (>= 4.0.0) @@ -241,23 +267,23 @@ GEM activesupport (>= 5.2) sprockets (>= 3.0.0) sqlite3 (1.4.4) + strscan (3.0.3) thor (1.2.1) - thread_safe (0.3.6) tilt (2.0.10) + timeout (0.3.0) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) typhoeus (1.4.0) ethon (>= 0.9.0) - tzinfo (1.2.9) - thread_safe (~> 0.1) - tzinfo-data (1.2019.3) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + tzinfo-data (1.2022.1) tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) version_gem (1.1.0) - wdm (0.1.1) - web-console (4.0.4) + web-console (4.2.0) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) @@ -270,7 +296,7 @@ GEM zeitwerk (2.6.0) PLATFORMS - x64-mingw32 + x64-mingw-ucrt DEPENDENCIES bootsnap (~> 1.7.3) @@ -283,27 +309,28 @@ DEPENDENCIES docusign_esign (~> 3.17.0) docusign_monitor (~> 1.1.0) docusign_rooms (~> 1.2.0.rc1) - jbuilder (~> 2.10.0) - listen (~> 3.7.0) + jbuilder (~> 2.11.5) + listen (~> 3.7.1) omniauth-oauth2 (~> 1.7.1) omniauth-rails_csrf_protection pry-nav (~> 0.3.0) pry-rails (~> 0.3.9) - puma (~> 4.3.12) - rails (~> 6.0.4.1) + puma (~> 5.6.4) + rails (~> 7.0.3) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) spring (~> 2.1.0) spring-watcher-listen (~> 2.0.1) - sqlite3 (~> 1.4.2) + sqlite3 (~> 1.4.4) turbolinks (~> 5.2.1) - tzinfo-data (~> 1.2019.3) + tzinfo-data (~> 1.2022.1, >= 1.2022.1) uglifier (~> 4.2.0) wdm (>= 0.1.0) - web-console (~> 4.0.1) + web-console (~> 4.2.0) + webrick (~> 1.7) RUBY VERSION - ruby 3.0.2p107 + ruby 3.1.2p20 BUNDLED WITH - 2.2.22 + 2.3.7 From c16526bdaf78f765c9ea0a96b8680cbac0896016 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Aug 2022 20:54:13 +0000 Subject: [PATCH 156/363] Bump tzinfo from 1.2.9 to 1.2.10 in /quick_acg Bumps [tzinfo](https://github.com/tzinfo/tzinfo) from 1.2.9 to 1.2.10. - [Release notes](https://github.com/tzinfo/tzinfo/releases) - [Changelog](https://github.com/tzinfo/tzinfo/blob/master/CHANGES.md) - [Commits](https://github.com/tzinfo/tzinfo/compare/v1.2.9...v1.2.10) --- updated-dependencies: - dependency-name: tzinfo dependency-type: indirect ... Signed-off-by: dependabot[bot] --- quick_acg/Gemfile.lock | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/quick_acg/Gemfile.lock b/quick_acg/Gemfile.lock index a95a2a3..0fd69b9 100644 --- a/quick_acg/Gemfile.lock +++ b/quick_acg/Gemfile.lock @@ -100,6 +100,7 @@ GEM faraday-net_http (~> 2.0) ruby2_keywords (>= 0.0.4) faraday-net_http (2.0.3) + ffi (1.15.5) ffi (1.15.5-x64-mingw32) globalid (1.0.0) activesupport (>= 5.0) @@ -128,6 +129,8 @@ GEM nio4r (2.5.8) nokogiri (1.13.6-x64-mingw32) racc (~> 1.4) + nokogiri (1.13.6-x86_64-linux) + racc (~> 1.4) oauth2 (2.0.5) faraday (>= 0.17.3, < 3.0) jwt (>= 1.0, < 3.0) @@ -198,6 +201,8 @@ GEM rubyzip (2.3.2) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) + sassc (2.4.0) + ffi (~> 1.9) sassc (2.4.0-x64-mingw32) ffi (~> 1.9) sassc-rails (2.1.2) @@ -229,7 +234,7 @@ GEM turbolinks-source (5.2.0) typhoeus (1.4.0) ethon (>= 0.9.0) - tzinfo (1.2.9) + tzinfo (1.2.10) thread_safe (~> 0.1) tzinfo-data (1.2019.3) tzinfo (>= 1.0.0) @@ -251,6 +256,7 @@ GEM PLATFORMS x64-mingw32 + x86_64-linux DEPENDENCIES bootsnap (~> 1.7.3) From 3e4c5715c8066e4db0a584015b93be372d72e0c1 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 16 Aug 2022 15:26:59 -0700 Subject: [PATCH 157/363] DEVDOCS-8418, adding PDF Portfolio option to eSign7 --- app/controllers/e_sign/eg006_envelope_docs_controller.rb | 3 ++- app/views/e_sign/eg007_envelope_get_doc/get.html.erb | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/controllers/e_sign/eg006_envelope_docs_controller.rb b/app/controllers/e_sign/eg006_envelope_docs_controller.rb index 0a3e883..10b856c 100644 --- a/app/controllers/e_sign/eg006_envelope_docs_controller.rb +++ b/app/controllers/e_sign/eg006_envelope_docs_controller.rb @@ -17,7 +17,8 @@ def create standart_doc_items = [ { name: 'Combined', type: 'content', document_id: 'combined' }, - { name: 'Zip archive', type: 'zip', document_id: 'archive' } + { name: 'Zip archive', type: 'zip', document_id: 'archive' }, + { name: 'PDF Portfolio', type: 'content', document_id: 'portfolio' } ] results = ESign::Eg006EnvelopeDocsService.new(args).worker diff --git a/app/views/e_sign/eg007_envelope_get_doc/get.html.erb b/app/views/e_sign/eg007_envelope_get_doc/get.html.erb index f1cba1e..a08b441 100644 --- a/app/views/e_sign/eg007_envelope_get_doc/get.html.erb +++ b/app/views/e_sign/eg007_envelope_get_doc/get.html.erb @@ -7,7 +7,10 @@ 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
  • +
  • + PDF Portfolio: Retrieves the envelope documents as a PDF portfolio +
  • +
  • The envelope's individual documents
  • The envelope's Certificate of Completion
From bf76c3fb6305cb3656957ef2bb372f80457da7dc Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 16 Aug 2022 16:03:39 -0700 Subject: [PATCH 158/363] Various updates --- .../e_sign/eg006_envelope_docs_controller.rb | 3 ++- app/services/admin_api/eg001_create_user_service.rb | 4 ++-- ...elete_user_product_permission_profile_service.rb | 13 ++++++------- .../e_sign/eg020_phone_authentication_service.rb | 2 +- .../e_sign/eg007_envelope_get_doc/get.html.erb | 5 ++++- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/app/controllers/e_sign/eg006_envelope_docs_controller.rb b/app/controllers/e_sign/eg006_envelope_docs_controller.rb index 0a3e883..10b856c 100644 --- a/app/controllers/e_sign/eg006_envelope_docs_controller.rb +++ b/app/controllers/e_sign/eg006_envelope_docs_controller.rb @@ -17,7 +17,8 @@ def create standart_doc_items = [ { name: 'Combined', type: 'content', document_id: 'combined' }, - { name: 'Zip archive', type: 'zip', document_id: 'archive' } + { name: 'Zip archive', type: 'zip', document_id: 'archive' }, + { name: 'PDF Portfolio', type: 'content', document_id: 'portfolio' } ] results = ESign::Eg006EnvelopeDocsService.new(args).worker diff --git a/app/services/admin_api/eg001_create_user_service.rb b/app/services/admin_api/eg001_create_user_service.rb index 1e4024c..a951e25 100644 --- a/app/services/admin_api/eg001_create_user_service.rb +++ b/app/services/admin_api/eg001_create_user_service.rb @@ -17,9 +17,9 @@ def worker api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") # Step 2 end - # Step 6 start + # Step 4 start users_api = DocuSign_Admin::UsersApi.new(api_client) response = users_api.create_user(args[:organization_id], user_data) - # Step 6 end + # Step 4 end end end diff --git a/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb b/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb index b24d858..12794bc 100644 --- a/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb +++ b/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb @@ -16,14 +16,14 @@ def worker api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") # Step 2 end - # Step 4 start + # Step 3 start user_product_profile_delete_request = DocuSign_Admin::UserProductProfileDeleteRequest.new({'user_email' => args[:email], 'product_ids' => [args[:product_id]]}) - # Step 4 end + # Step 3 end - # Step 5 start + # Step 4 start product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(api_client) response = product_permission_profiles_api.remove_user_product_permission(args[:organization_id], args[:account_id], user_product_profile_delete_request) - # Step 5 end + # Step 4 end end def get_permission_profiles_by_email @@ -33,7 +33,6 @@ def get_permission_profiles_by_email api_client = DocuSign_Admin::ApiClient.new(configuration) api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") - # Step 3 start product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(api_client) options = DocuSign_Admin::GetUserProductPermissionProfilesByEmailOptions.new @@ -41,6 +40,6 @@ def get_permission_profiles_by_email product_permission_profiles = product_permission_profiles_api.get_user_product_permission_profiles_by_email(args[:organization_id], args[:account_id], options) product_permission_profiles.as_json['product_permission_profiles'] - # Step 3 end + end -end +end \ No newline at end of file diff --git a/app/services/e_sign/eg020_phone_authentication_service.rb b/app/services/e_sign/eg020_phone_authentication_service.rb index de0f82f..0ae4906 100644 --- a/app/services/e_sign/eg020_phone_authentication_service.rb +++ b/app/services/e_sign/eg020_phone_authentication_service.rb @@ -121,4 +121,4 @@ def get_workflow render 'ds_common/error' end end -end +end \ No newline at end of file diff --git a/app/views/e_sign/eg007_envelope_get_doc/get.html.erb b/app/views/e_sign/eg007_envelope_get_doc/get.html.erb index f1cba1e..a08b441 100644 --- a/app/views/e_sign/eg007_envelope_get_doc/get.html.erb +++ b/app/views/e_sign/eg007_envelope_get_doc/get.html.erb @@ -7,7 +7,10 @@ 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
  • +
  • + PDF Portfolio: Retrieves the envelope documents as a PDF portfolio +
  • +
  • The envelope's individual documents
  • The envelope's Certificate of Completion
  • From de7b1c7c6e316399c35218c93b4088408c919e71 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 16 Aug 2022 16:22:44 -0700 Subject: [PATCH 159/363] Updating gem files --- Gemfile | 20 ++--- Gemfile.lock | 210 +++++++++++++++++++++++++++++---------------------- 2 files changed, 130 insertions(+), 100 deletions(-) diff --git a/Gemfile b/Gemfile index b8fc89f..8edbb83 100644 --- a/Gemfile +++ b/Gemfile @@ -3,14 +3,14 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '~>3.0.2' +ruby '~>3.1.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 6.0.4.1' +gem 'rails', '~> 7.0.3' # Use sqlite3 as the database for Active Record -gem 'sqlite3', '~> 1.4.2' +gem 'sqlite3', '~> 1.4.4' # Use Puma as the app server -gem 'puma', '~> 4.3.12' +gem 'puma', '~> 5.6.4' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets @@ -23,7 +23,7 @@ gem 'coffee-rails', '~> 5.0.0' # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks gem 'turbolinks', '~> 5.2.1' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder -gem 'jbuilder', '~> 2.10.0' +gem 'jbuilder', '~> 2.11.5' # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 4.0' # Use ActiveModel has_secure_password @@ -49,8 +49,8 @@ end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. - gem 'listen', '~> 3.7.0' - gem 'web-console', '~> 4.0.1' + gem 'listen', '~> 3.7.1' + gem 'web-console', '~> 4.2.0' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'pry-nav', '~> 0.3.0' gem 'pry-rails', '~> 0.3.9' @@ -63,7 +63,7 @@ group :test do gem 'capybara', '~> 3.31.0' gem 'selenium-webdriver', '~> 3.142.7' # Easy installation and use of chromedriver to run system tests with Chrome - gem 'chromedriver-helper', '~> 2.1.1' + gem 'chromedriver-helper', '~> 1.2.0' end gem 'docusign_esign', '~> 3.17.0' @@ -75,5 +75,7 @@ gem 'omniauth-oauth2', '~> 1.7.1' gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem 'tzinfo-data', '~> 1.2019.3', platforms: %i[mingw mswin x64_mingw jruby] +gem 'tzinfo-data', '~> 1.2022.1', '>= 1.2022.1' gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] + +gem "matrix", "~> 0.4.2" diff --git a/Gemfile.lock b/Gemfile.lock index 747e2c1..a7d96d8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,61 +1,71 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.4.8) - actionpack (= 6.0.4.8) + actioncable (7.0.3.1) + actionpack (= 7.0.3.1) + activesupport (= 7.0.3.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.4.8) - actionpack (= 6.0.4.8) - activejob (= 6.0.4.8) - activerecord (= 6.0.4.8) - activestorage (= 6.0.4.8) - activesupport (= 6.0.4.8) + actionmailbox (7.0.3.1) + actionpack (= 7.0.3.1) + activejob (= 7.0.3.1) + activerecord (= 7.0.3.1) + activestorage (= 7.0.3.1) + activesupport (= 7.0.3.1) mail (>= 2.7.1) - actionmailer (6.0.4.8) - actionpack (= 6.0.4.8) - actionview (= 6.0.4.8) - activejob (= 6.0.4.8) + net-imap + net-pop + net-smtp + actionmailer (7.0.3.1) + actionpack (= 7.0.3.1) + actionview (= 7.0.3.1) + activejob (= 7.0.3.1) + activesupport (= 7.0.3.1) mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp rails-dom-testing (~> 2.0) - actionpack (6.0.4.8) - actionview (= 6.0.4.8) - activesupport (= 6.0.4.8) - rack (~> 2.0, >= 2.0.8) + actionpack (7.0.3.1) + actionview (= 7.0.3.1) + activesupport (= 7.0.3.1) + rack (~> 2.0, >= 2.2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.4.8) - actionpack (= 6.0.4.8) - activerecord (= 6.0.4.8) - activestorage (= 6.0.4.8) - activesupport (= 6.0.4.8) + actiontext (7.0.3.1) + actionpack (= 7.0.3.1) + activerecord (= 7.0.3.1) + activestorage (= 7.0.3.1) + activesupport (= 7.0.3.1) + globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (6.0.4.8) - activesupport (= 6.0.4.8) + actionview (7.0.3.1) + activesupport (= 7.0.3.1) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.4.8) - activesupport (= 6.0.4.8) + activejob (7.0.3.1) + activesupport (= 7.0.3.1) globalid (>= 0.3.6) - activemodel (6.0.4.8) - activesupport (= 6.0.4.8) - activerecord (6.0.4.8) - activemodel (= 6.0.4.8) - activesupport (= 6.0.4.8) - activestorage (6.0.4.8) - actionpack (= 6.0.4.8) - activejob (= 6.0.4.8) - activerecord (= 6.0.4.8) - marcel (~> 1.0.0) - activesupport (6.0.4.8) + activemodel (7.0.3.1) + activesupport (= 7.0.3.1) + activerecord (7.0.3.1) + activemodel (= 7.0.3.1) + activesupport (= 7.0.3.1) + activestorage (7.0.3.1) + actionpack (= 7.0.3.1) + activejob (= 7.0.3.1) + activerecord (= 7.0.3.1) + activesupport (= 7.0.3.1) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.3.1) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - zeitwerk (~> 2.2, >= 2.2.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) archive-zip (0.12.0) @@ -74,7 +84,7 @@ GEM regexp_parser (~> 1.5) xpath (~> 3.2) childprocess (3.0.0) - chromedriver-helper (2.1.1) + chromedriver-helper (1.2.0) archive-zip (~> 0.10) nokogiri (~> 1.8) coderay (1.1.3) @@ -87,6 +97,7 @@ GEM coffee-script-source (1.12.2) concurrent-ruby (1.1.10) crass (1.0.6) + digest (3.1.0) docusign_admin (1.1.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) @@ -112,22 +123,23 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - erubi (1.10.0) + erubi (1.11.0) ethon (0.15.0) ffi (>= 1.15.0) execjs (2.8.1) - faraday (2.3.0) + faraday (2.4.0) faraday-net_http (~> 2.0) ruby2_keywords (>= 0.0.4) - faraday-net_http (2.0.3) - ffi (1.15.5-x64-mingw32) + faraday-net_http (2.1.0) + ffi (1.15.5-x64-mingw-ucrt) globalid (1.0.0) activesupport (>= 5.0) hashie (5.0.0) - i18n (1.11.0) + i18n (1.12.0) concurrent-ruby (~> 1.0) io-like (0.3.1) - jbuilder (2.10.2) + jbuilder (2.11.5) + actionview (>= 5.0.0) activesupport (>= 5.0.0) json (2.6.2) jwt (2.4.1) @@ -140,15 +152,30 @@ GEM mail (2.7.1) mini_mime (>= 0.1.1) marcel (1.0.2) + matrix (0.4.2) method_source (0.9.2) mini_mime (1.1.2) minitest (5.16.2) - msgpack (1.5.3) + msgpack (1.5.4) multi_xml (0.6.0) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout nio4r (2.5.8) - nokogiri (1.13.6-x64-mingw32) + nokogiri (1.13.8-x64-mingw-ucrt) racc (~> 1.4) - oauth2 (2.0.5) + oauth2 (2.0.6) faraday (>= 0.17.3, < 3.0) jwt (>= 1.0, < 3.0) multi_xml (~> 0.5) @@ -173,40 +200,40 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.7) - puma (4.3.12) + puma (5.6.4) nio4r (~> 2.0) racc (1.6.0) rack (2.2.4) - rack-protection (2.2.0) + rack-protection (2.2.2) rack rack-test (2.0.2) rack (>= 1.3) - rails (6.0.4.8) - actioncable (= 6.0.4.8) - actionmailbox (= 6.0.4.8) - actionmailer (= 6.0.4.8) - actionpack (= 6.0.4.8) - actiontext (= 6.0.4.8) - actionview (= 6.0.4.8) - activejob (= 6.0.4.8) - activemodel (= 6.0.4.8) - activerecord (= 6.0.4.8) - activestorage (= 6.0.4.8) - activesupport (= 6.0.4.8) - bundler (>= 1.3.0) - railties (= 6.0.4.8) - sprockets-rails (>= 2.0.0) + rails (7.0.3.1) + actioncable (= 7.0.3.1) + actionmailbox (= 7.0.3.1) + actionmailer (= 7.0.3.1) + actionpack (= 7.0.3.1) + actiontext (= 7.0.3.1) + actionview (= 7.0.3.1) + activejob (= 7.0.3.1) + activemodel (= 7.0.3.1) + activerecord (= 7.0.3.1) + activestorage (= 7.0.3.1) + activesupport (= 7.0.3.1) + bundler (>= 1.15.0) + railties (= 7.0.3.1) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.4.3) loofah (~> 2.3) - railties (6.0.4.8) - actionpack (= 6.0.4.8) - activesupport (= 6.0.4.8) + railties (7.0.3.1) + actionpack (= 7.0.3.1) + activesupport (= 7.0.3.1) method_source - rake (>= 0.8.7) - thor (>= 0.20.3, < 2.0) + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) rake (13.0.6) rash_alt (0.4.12) hashie (>= 3.4) @@ -218,7 +245,7 @@ GEM rubyzip (2.3.2) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) - sassc (2.4.0-x64-mingw32) + sassc (2.4.0) ffi (~> 1.9) sassc-rails (2.1.2) railties (>= 4.0.0) @@ -241,23 +268,23 @@ GEM activesupport (>= 5.2) sprockets (>= 3.0.0) sqlite3 (1.4.4) + strscan (3.0.4) thor (1.2.1) - thread_safe (0.3.6) - tilt (2.0.10) + tilt (2.0.11) + timeout (0.3.0) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) typhoeus (1.4.0) ethon (>= 0.9.0) - tzinfo (1.2.9) - thread_safe (~> 0.1) - tzinfo-data (1.2019.3) + tzinfo (2.0.5) + concurrent-ruby (~> 1.0) + tzinfo-data (1.2022.1) tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) version_gem (1.1.0) - wdm (0.1.1) - web-console (4.0.4) + web-console (4.2.0) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) @@ -270,40 +297,41 @@ GEM zeitwerk (2.6.0) PLATFORMS - x64-mingw32 + x64-mingw-ucrt DEPENDENCIES bootsnap (~> 1.7.3) byebug (~> 11.1.1) capybara (~> 3.31.0) - chromedriver-helper (~> 2.1.1) + chromedriver-helper (~> 1.2.0) coffee-rails (~> 5.0.0) docusign_admin (~> 1.1.0) docusign_click (~> 1.0.0) docusign_esign (~> 3.17.0) docusign_monitor (~> 1.1.0) docusign_rooms (~> 1.2.0.rc1) - jbuilder (~> 2.10.0) - listen (~> 3.7.0) + jbuilder (~> 2.11.5) + listen (~> 3.7.1) + matrix (~> 0.4.2) omniauth-oauth2 (~> 1.7.1) omniauth-rails_csrf_protection pry-nav (~> 0.3.0) pry-rails (~> 0.3.9) - puma (~> 4.3.12) - rails (~> 6.0.4.1) + puma (~> 5.6.4) + rails (~> 7.0.3) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) spring (~> 2.1.0) spring-watcher-listen (~> 2.0.1) - sqlite3 (~> 1.4.2) + sqlite3 (~> 1.4.4) turbolinks (~> 5.2.1) - tzinfo-data (~> 1.2019.3) + tzinfo-data (~> 1.2022.1, >= 1.2022.1) uglifier (~> 4.2.0) wdm (>= 0.1.0) - web-console (~> 4.0.1) + web-console (~> 4.2.0) RUBY VERSION - ruby 3.0.2p107 + ruby 3.1.2p20 BUNDLED WITH - 2.2.22 + 2.3.7 From 1023684fae88a113d9bc85364b6ef918e1cdd5d9 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Wed, 17 Aug 2022 22:23:13 +0300 Subject: [PATCH 160/363] Set document visibility code example (#85) * Document visibility example --- ...g040_set_document_visibility_controller.rb | 47 +++ .../eg040_set_document_visibility_service.rb | 169 +++++++++ app/views/ds_common/index.html.erb | 342 ++++++++++-------- .../get.html.erb | 52 +++ config/routes.rb | 3 + 5 files changed, 456 insertions(+), 157 deletions(-) create mode 100644 app/controllers/e_sign/eg040_set_document_visibility_controller.rb create mode 100644 app/services/e_sign/eg040_set_document_visibility_service.rb create mode 100644 app/views/e_sign/eg040_set_document_visibility/get.html.erb diff --git a/app/controllers/e_sign/eg040_set_document_visibility_controller.rb b/app/controllers/e_sign/eg040_set_document_visibility_controller.rb new file mode 100644 index 0000000..99a67bd --- /dev/null +++ b/app/controllers/e_sign/eg040_set_document_visibility_controller.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +class ESign::Eg040SetDocumentVisibilityController < EgController + before_action :check_auth + + def create + begin + envelope_args = { + signer1_email: param_gsub(params['signer1Email']), + signer1_name: param_gsub(params['signer1Name']), + signer2_email: param_gsub(params['signer2Email']), + signer2_name: param_gsub(params['signer2Name']), + cc_email: param_gsub(params['ccEmail']), + cc_name: param_gsub(params['ccName']), + status: 'sent', + doc_docx: File.join('data', Rails.application.config.doc_docx), + doc_pdf: File.join('data', Rails.application.config.doc_pdf) + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + results = ESign::Eg040SetDocumentVisibilityService.new(args).worker + @title = 'Envelope sent' + @h1 = 'Envelope sent' + @message = "The envelope has been created and sent!
    Envelope ID #{results['envelope_id']}." + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + error = JSON.parse e.response_body + + if error['errorCode'] == "ACCOUNT_LACKS_PERMISSIONS" + @error_information = '

    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.

    ' + + @error_code = error['errorCode'] + @error_message = error['error_description'] || error['message'] + + return render 'ds_common/error' + end + + handle_error(e) + end + end +end diff --git a/app/services/e_sign/eg040_set_document_visibility_service.rb b/app/services/e_sign/eg040_set_document_visibility_service.rb new file mode 100644 index 0000000..e7340aa --- /dev/null +++ b/app/services/e_sign/eg040_set_document_visibility_service.rb @@ -0,0 +1,169 @@ +# frozen_string_literal: true + +class ESign::Eg040SetDocumentVisibilityService + attr_reader :args + include ApiCreator + + def initialize(args) + @args = args + end + + def worker + # 1. Create the envelope request object + envelope_definition = make_envelope args[:envelope_args] + # 2. Call Envelopes::create API method + # Exceptions will be caught by the calling function + envelope_api = create_envelope_api(args) + + results = envelope_api.create_envelope args[:account_id], envelope_definition + envelope_id = results.envelope_id + { 'envelope_id' => envelope_id } + end + + private + + def make_envelope(envelope_args) + # 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 1 + # recipient 2 - signer 2 + # recipient 3 - cc + # The envelope will be sent first to the signer. + # After it is signed, a copy is sent to the cc person + + # Create the envelope definition + envelope_definition = DocuSign_eSign::EnvelopeDefinition.new + + envelope_definition.email_subject = 'Please sign this document set' + + # Add the documents + doc1_b64 = Base64.encode64(create_document1(envelope_args)) + # Read files 2 and 3 from a local directory + # The reads could raise an exception if the file is not available! + doc2_b64 = Base64.encode64(File.binread(envelope_args[:doc_docx])) + doc3_b64 = Base64.encode64(File.binread(envelope_args[:doc_pdf])) + + # Create the document models + document1 = DocuSign_eSign::Document.new( + # Create the DocuSign document object + documentBase64: doc1_b64, + name: 'Order acknowledgement', # Can be different from actual file name + fileExtension: 'html', # Many different document types are accepted + documentId: '1' # A label used to reference the doc + ) + document2 = DocuSign_eSign::Document.new( + # Create the DocuSign document object + documentBase64: doc2_b64, + name: 'Battle Plan', # Can be different from actual file name + fileExtension: 'docx', # Many different document types are accepted + documentId: '2' # A label used to reference the do + ) + document3 = DocuSign_eSign::Document.new( + # Create the DocuSign document object + documentBase64: doc3_b64, + name: 'Lorem Ipsum', # Can be different from actual file name + fileExtension: 'pdf', # Many different document types are accepted + documentId: '3' # A label used to reference the doc + ) + + # The order in the docs array determines the order in the envelope + envelope_definition.documents = [document1, document2, document3] + + # Create the signer recipient model + signer1 = DocuSign_eSign::Signer.new + signer1.email = envelope_args[:signer1_email] + signer1.name = envelope_args[:signer1_name] + signer1.recipient_id = '1' + signer1.routing_order = '1' + signer1.excluded_documents = [2, 3] + + signer2 = DocuSign_eSign::Signer.new + signer2.email = envelope_args[:signer2_email] + signer2.name = envelope_args[:signer2_name] + signer2.recipient_id = '2' + signer2.routing_order = '2' + signer2.excluded_documents = [1] + ## 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 + + # Create a cc recipient to receive a copy of the documents + cc = DocuSign_eSign::CarbonCopy.new( + email: envelope_args[:cc_email], + name: envelope_args[:cc_name], + routingOrder: '3', + recipientId: '3' + ) + # Create signHere fields (also known as tabs) on the documents + # We're using anchor (autoPlace) positioning + # + # The DocuSign platform searches throughout your envelope's documents for matching + # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 + # since they use the same anchor string for their "signer 1" tabs. + sign_here1 = DocuSign_eSign::SignHere.new( + anchorString: '**signature_1**', + anchorYOffset: '10', + anchorUnits: 'pixels', + anchorXOffset: '20' + ) + + sign_here2 = DocuSign_eSign::SignHere.new( + anchorString: '/sn1/', + anchorYOffset: '10', + anchorUnits: 'pixels', + anchorXOffset: '20' + ) + # Add the tabs model (including the sign_here tabs) to the signer + # The Tabs object takes arrays of the different field/tab types + signer1_tabs = DocuSign_eSign::Tabs.new({ + signHereTabs: [sign_here1] + }) + + signer1.tabs = signer1_tabs + + signer2_tabs = DocuSign_eSign::Tabs.new({ + signHereTabs: [sign_here2] + }) + + signer2.tabs = signer2_tabs + + # Add the recipients to the envelope object + recipients = DocuSign_eSign::Recipients.new( + signers: [signer1, signer2], + carbonCopies: [cc] + ) + # Request that the envelope be sent by setting status to "sent". + # To request that the envelope be created as a draft, set status to "created" + envelope_definition.recipients = recipients + envelope_definition.status = envelope_args[:status] + envelope_definition + end + + def create_document1(args) + " + + + + + + +

    World Wide Corp

    +

    Order Processing Division

    +

    Ordered by #{args[:signer1_name]}

    +

    Email: #{args[:signer1_email]}

    +

    Copy to: #{args[:cc_name]}, #{args[: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**/

    + + " + end +end \ No newline at end of file diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index 8dba206..9c15468 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -29,7 +29,18 @@ <% end %> -

    Basic examples

    + +
    +

    Requesting a signature

    + +

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

    +

    The envelope includes three documents: one each in PDF, Word, and HTML format. Anchor text + (AutoPlace) + is used to position the signing fields in the documents. +

    +

    API method used: + Envelopes::create. +

    Use embedded signing

    This example sends an envelope and then uses embedded signing for the first signer. @@ -40,22 +51,55 @@ EnvelopeViews::createRecipient.

    -

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

    -

    The envelope includes three documents: one each in PDF, Word, and HTML format. Anchor text - (AutoPlace) - is used to position the signing fields in the documents. -

    +

    Send an envelope using a template

    +

    This example demonstrates a common pattern for DocuSign integrations: envelopes will be sent programmatically, defined by a template. The signer and cc recipient name and email are used to fill in the template’s roles.

    API method used: Envelopes::create.

    -

    List envelopes whose status has changed

    -

    This example lists the envelopes whose status has changed within the last 30 days. +

    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 + feature.

    +

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

    + +

    Request a signature by SMS delivery

    +

    + Sends a signature request via an SMS message. +

    +

    + API method used: + Envelopes::create. +

    + +

    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::listStatusChanges. + Envelopes::create. +

    + +

    Send an envelope to an In Person Signer

    +

    + This example demonstrates how to host an In Person Signing session with embedded signing. +

    +

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

    + +
    +

    Working with envelopes and templates

    +

    Get an envelope’s basic information and status

    This example lists the basic information about an envelope, including its overall status. Additional API/SDK methods may be used to get additional information about the @@ -72,6 +116,88 @@ EnvelopeRecipients::list.

    +

    List envelopes whose status has changed

    +

    This example lists the envelopes whose status has changed within the last 30 days. +

    +

    API method used: + Envelopes::listStatusChanges. +

    + +

    Create a template

    +

    Create a template with two roles, signer and cc.

    +

    API methods used: + Templates::list and + Templates::create. +

    + +

    Use embedded sending

    +

    This example demonstrates how to embed the DocuSign sender view within your web app. An envelope will be created in draft mode. Your browser will then be redirected to the DocuSign UI, where the envelope can be (optionally) updated and then sent.

    +

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

    + +

    Bulk send envelopes

    +

    Demonstrates how to send envelopes in bulk to multiple recipients. First, this example creates a bulk send recipients list, then creates an envelope. After that, + it initiates bulk envelope sending. +

    +

    API methods used: + BulkSend::createBulkSendList, + Envelopes::create, + EnvelopeCustomFields::create, + BulkSend::createBulkSendRequest, + BulkSend::getBulkSendBatchStatus +

    + + +
    +

    Working with advanced recipient routing

    + +

    Pause a signature workflow

    +

    This example creates an envelope where the workflow is paused before the envelope is sent to a second recipient.

    +

    API method used: + Envelopes::create. +

    + +

    Unpause a signature workflow

    +

    This example resumes a signature workflow for an envelope whose workflow has been paused.

    +

    API method used: + Envelopes::update. +

    + +

    Use conditional recipients

    +

    This example creates an envelope whose workflow routes it to different recipients based on the value of a transaction.

    +

    API method used: + Envelopes::create. +

    + +

    Schedule an envelope

    +

    + Demonstrates how to schedule sending an envelope using the scheduled sending feature. +

    +

    + API method used: + Envelopes:create. +

    +

    Send an envelope with delayed routing

    + +

    + Demonstrates how to delay an envelope’s delivery between recipients using the delayed routing feature. +

    +

    + API method used: + Envelopes:create. +

    + + +
    +

    Working with documents

    +

    List an envelope's documents

    This example demonstrates how to list an envelope's documents. A Certificate of Completion document is also associated with every envelope. @@ -87,19 +213,6 @@ EnvelopeDocuments::get.

    -

    Create a template

    -

    Create a template with two roles, signer and cc.

    -

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

    - -

    Send an envelope using a template

    -

    This example demonstrates a common pattern for DocuSign integrations: envelopes will be sent programmatically, defined by a template. The signer and cc recipient name and email are used to fill in the template’s roles.

    -

    API method used: - Envelopes::create. -

    -

    Send an envelope using binary document transfer

    The envelope includes three documents: one each in PDF, Word, and HTML format.

    Multipart data transfer is used to send the documents in binary format to DocuSign. @@ -109,50 +222,28 @@ Envelopes::create.

    -

    Use embedded sending

    -

    This example demonstrates how to embed the DocuSign sender view within your web app. An envelope will be created in draft mode. Your browser will then be redirected to the DocuSign UI, where the envelope can be (optionally) updated and then sent.

    -

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

    Embedded DocuSign UI

    -

    This example demonstrates how to embed the DocuSign UI in your app. Use this API call to open the DocuSign UI with the user already logged in.

    -

    API method used: - EnvelopeViews::createConsole. -

    - -

    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 - feature.

    -

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

    - -

    Send an envelope to an In Person Signer

    +

    Create a signable HTML document

    - This example demonstrates how to host an In Person Signing session with embedded signing. + Demonstrates how to create an HTML document for responsive signing.

    -

    API methods used: - Envelopes::create and + API methods used: + Envelopes::create, EnvelopeViews::createRecipient. + href="https://developers.docusign.com/docs/esign-rest-api/reference/envelopes/envelopeviews/createrecipient/">EnvelopeViews::createRecipient.

    -

    Payments

    - -

    Send an envelope with an order form and payment field

    -

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

    Set document visibility for envelope recipients

    +

    + Demonstrates how to set document visibility for envelope recipients.

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

    -

    Tabs

    + +
    +

    Working with tabs

    +

    Get the tab data from an envelope

    This example retrieves the tab (field) values from an envelope for all of the envelope’s recipients.

    @@ -184,33 +275,31 @@ EnvelopeCustomFields::list.

    -

    Recipient authentication

    -

    Require access code authentication for a recipient

    -

    This example sends an envelope requiring the recipient to enter an access code for multifactor authentication.

    -

    API method used: - Envelopes::create. -

    +
    +

    Working with brands

    -

    Require phone authentication for a recipient

    -

    Sends an envelope that requires entering a six-digit code from a text message or phone call for the purpose of multifactor authentication.

    +

    Create a brand

    +

    This example creates an account brand that can be used to apply customization to your envelopes, including your own logo, colors, and text elements.

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

    -

    Require knowledge based authentication (KBA) for a recipient

    -

    Submit an envelope with multiple choice, public records based questions to provide multi-factor authentication.

    +

    Apply a brand to an envelope

    +

    This example creates an envelope using any of the created brands on your account.

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

    -

    Require ID verification (IDV) for a recipient

    -

    This is an example of an envelope utilizing ID verification authentication for a recipient.

    -

    API methods used: - Accounts::getAccountIdentityVerificationsList and Envelopes::create. +

    Apply a brand and template to an envelope

    +

    This example creates an envelope from a template while applying any of the created brands on your account.

    +

    API method used: + Envelopes::create.

    -

    Permissions

    + +
    +

    Working with permissions

    Create a permission profile

    @@ -240,103 +329,42 @@ AccountPermissionProfiles::delete.

    -

    Brands

    -

    Create a brand

    -

    This example creates an account brand that can be used to apply customization to your envelopes, including your own logo, colors, and text elements.

    -

    API method used: - AccountBrands::create. -

    +
    +

    Implementing multi-factor recipient (signer) authentication

    -

    Apply a brand to an envelope

    -

    This example creates an envelope using any of the created brands on your account.

    -

    API method used: - Envelopes::create. -

    - -

    Apply a brand and template to an envelope

    -

    This example creates an envelope from a template while applying any of the created brands on your account.

    -

    API method used: - Envelopes::create. -

    - -

    Bulk operations

    - -

    Bulk send envelopes

    -

    Demonstrates how to send envelopes in bulk to multiple recipients. First, this example creates a bulk send recipients list, then creates an envelope. After that, - it initiates bulk envelope sending. -

    +

    Require ID verification (IDV) for a recipient

    +

    This is an example of an envelope utilizing ID verification authentication for a recipient.

    API methods used: - BulkSend::createBulkSendList, - Envelopes::create, - EnvelopeCustomFields::create, - BulkSend::createBulkSendRequest, - BulkSend::getBulkSendBatchStatus + Accounts::getAccountIdentityVerificationsList and Envelopes::create.

    -

    Advanced recipient routing

    - -

    Pause a signature workflow

    -

    This example creates an envelope where the workflow is paused before the envelope is sent to a second recipient.

    -

    API method used: - Envelopes::create. +

    Require knowledge based authentication (KBA) for a recipient

    +

    Submit an envelope with multiple choice, public records based questions to provide multi-factor authentication.

    +

    API method used: + Envelopes::create.

    -

    Unpause a signature workflow

    -

    This example resumes a signature workflow for an envelope whose workflow has been paused.

    -

    API method used: - Envelopes::update. +

    Require phone authentication for a recipient

    +

    Sends an envelope that requires entering a six-digit code from a text message or phone call for the purpose of multifactor authentication.

    +

    API method used: + Envelopes::create.

    -

    Use conditional recipients

    -

    This example creates an envelope whose workflow routes it to different recipients based on the value of a transaction.

    +

    Require access code authentication for a recipient

    +

    This example sends an envelope requiring the recipient to enter an access code for multifactor authentication.

    API method used: - Envelopes::create. -

    - -

    Schedule an envelope

    -

    - Demonstrates how to schedule sending an envelope using the scheduled sending feature. -

    -

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

    -

    Send an envelope with delayed routing

    -

    - Demonstrates how to delay an envelope’s delivery between recipients using the delayed routing feature. -

    -

    - API method used: - Envelopes:create. -

    -

    Premium features

    +
    +

    Embedded DocuSign UI

    -

    Request a signature by SMS delivery

    -

    - Sends a signature request via an SMS message. -

    -

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

    - -

    Create a signable HTML document

    -

    - Demonstrates how to create an HTML document for responsive signing. -

    - API methods used: - Envelopes::create, - EnvelopeViews::createRecipient. +

    Embedded DocuSign UI

    +

    This example demonstrates how to embed the DocuSign UI in your app. Use this API call to open the DocuSign UI with the user already logged in.

    +

    API method used: + EnvelopeViews::createConsole.

    diff --git a/app/views/e_sign/eg040_set_document_visibility/get.html.erb b/app/views/e_sign/eg040_set_document_visibility/get.html.erb new file mode 100644 index 0000000..099c2b1 --- /dev/null +++ b/app/views/e_sign/eg040_set_document_visibility/get.html.erb @@ -0,0 +1,52 @@ +

    Set document visibility for envelope recipients

    +

    Demonstrates how to set document visibility for envelope recipients.

    + +<% if @show_doc %> +

    Documentation about this example.

    +<% end %> + +

    API method used: + Envelopes::create. +

    + +

    + View source file <%= @source_file %> on GitHub. +

    + +
    +
    + + + We'll never share your email with anyone else. +
    +
    + + +
    +
    + + + We'll never share your email with anyone else. +
    +
    + + +
    +
    + + + The email for the cc recipient must be different from the signer emails. +
    +
    + + +
    + +
    diff --git a/config/routes.rb b/config/routes.rb index 83c4822..da57194 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -205,6 +205,9 @@ get 'eg039' => 'eg039_signing_in_person#get' post 'eg039' => 'eg039_signing_in_person#create' + + get 'eg040' => 'eg040_set_document_visibility#get' + post 'eg040' => 'eg040_set_document_visibility#create' end end From 24259552434cfdd8ea21cce5bbfefaa9be68c064 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Aug 2022 19:48:53 +0000 Subject: [PATCH 161/363] Bump tzinfo from 1.2.9 to 1.2.10 in /quick_acg Bumps [tzinfo](https://github.com/tzinfo/tzinfo) from 1.2.9 to 1.2.10. - [Release notes](https://github.com/tzinfo/tzinfo/releases) - [Changelog](https://github.com/tzinfo/tzinfo/blob/master/CHANGES.md) - [Commits](https://github.com/tzinfo/tzinfo/compare/v1.2.9...v1.2.10) --- updated-dependencies: - dependency-name: tzinfo dependency-type: indirect ... Signed-off-by: dependabot[bot] --- quick_acg/Gemfile.lock | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/quick_acg/Gemfile.lock b/quick_acg/Gemfile.lock index a95a2a3..0fd69b9 100644 --- a/quick_acg/Gemfile.lock +++ b/quick_acg/Gemfile.lock @@ -100,6 +100,7 @@ GEM faraday-net_http (~> 2.0) ruby2_keywords (>= 0.0.4) faraday-net_http (2.0.3) + ffi (1.15.5) ffi (1.15.5-x64-mingw32) globalid (1.0.0) activesupport (>= 5.0) @@ -128,6 +129,8 @@ GEM nio4r (2.5.8) nokogiri (1.13.6-x64-mingw32) racc (~> 1.4) + nokogiri (1.13.6-x86_64-linux) + racc (~> 1.4) oauth2 (2.0.5) faraday (>= 0.17.3, < 3.0) jwt (>= 1.0, < 3.0) @@ -198,6 +201,8 @@ GEM rubyzip (2.3.2) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) + sassc (2.4.0) + ffi (~> 1.9) sassc (2.4.0-x64-mingw32) ffi (~> 1.9) sassc-rails (2.1.2) @@ -229,7 +234,7 @@ GEM turbolinks-source (5.2.0) typhoeus (1.4.0) ethon (>= 0.9.0) - tzinfo (1.2.9) + tzinfo (1.2.10) thread_safe (~> 0.1) tzinfo-data (1.2019.3) tzinfo (>= 1.0.0) @@ -251,6 +256,7 @@ GEM PLATFORMS x64-mingw32 + x86_64-linux DEPENDENCIES bootsnap (~> 1.7.3) From c2942a106a0870ad871b26610a18d9cfe9f42be8 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Fri, 19 Aug 2022 10:40:00 -0700 Subject: [PATCH 162/363] fixing jwt project with ruby upgrade (#87) * fixing jwt project with ruby upgrade --- jwt_console_project/jwt_console.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jwt_console_project/jwt_console.rb b/jwt_console_project/jwt_console.rb index 11dd966..b5d6c95 100644 --- a/jwt_console_project/jwt_console.rb +++ b/jwt_console_project/jwt_console.rb @@ -2,7 +2,7 @@ gemfile do source 'https://rubygems.org' - gem 'docusign_esign',' ~> 3.15.0' + gem 'docusign_esign',' ~> 3.17.0' end class ESign @@ -22,10 +22,10 @@ def load_config_data begin config_file_contents = File.read(config_file_path) rescue Errno::ENOENT - $stderr.puts "missing config file" + $stderr.puts "Missing config file" raise end - YAML.load(config_file_contents) + YAML.unsafe_load(config_file_contents) end def get_consent From f04559699f8b3666f09922fcc11bd7a57b9f0efe Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Thu, 25 Aug 2022 13:18:44 -0700 Subject: [PATCH 163/363] Devdocs 8380 (#88) * remove references to example numbers --- app/views/e_sign/eg004_envelope_info/get.html.erb | 4 ++-- app/views/e_sign/eg005_envelope_recipients/get.html.erb | 4 ++-- app/views/e_sign/eg006_envelope_docs/get.html.erb | 4 ++-- app/views/e_sign/eg007_envelope_get_doc/get.html.erb | 8 ++++---- app/views/e_sign/eg009_use_template/get.html.erb | 4 ++-- app/views/e_sign/eg011_embedded_sending/get.html.erb | 2 +- app/views/e_sign/eg012_embedded_console/get.html.erb | 2 +- app/views/e_sign/eg013_add_doc_to_template/get.html.erb | 4 ++-- app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb | 4 ++-- .../e_sign/eg017_set_template_tab_values/get.html.erb | 4 ++-- .../eg018_get_envelope_custom_field_data/get.html.erb | 4 ++-- .../e_sign/eg030_brands_apply_to_template/get.html.erb | 2 +- .../e_sign/eg032_pauses_signature_workflow/get.html.erb | 2 +- .../eg032_pauses_signature_workflow/return.html.erb | 2 +- .../e_sign/eg033_unpauses_signature_workflow/get.html.erb | 2 +- config/appsettings.example.yml | 2 +- 16 files changed, 27 insertions(+), 27 deletions(-) diff --git a/app/views/e_sign/eg004_envelope_info/get.html.erb b/app/views/e_sign/eg004_envelope_info/get.html.erb index 2005aae..0cfe8d4 100644 --- a/app/views/e_sign/eg004_envelope_info/get.html.erb +++ b/app/views/e_sign/eg004_envelope_info/get.html.erb @@ -22,14 +22,14 @@

    <% if @envelope_ok %> -

    The envelope you created via example 2 will be queried.

    +

    The envelope you created via Request a signature by email (remote signing) will be queried.

    <% else %> -

    Problem: please first create an envelope using example 2.
    +

    Problem: please first create an envelope using Request a signature by email (remote signing).
    Thank you.

    diff --git a/app/views/e_sign/eg005_envelope_recipients/get.html.erb b/app/views/e_sign/eg005_envelope_recipients/get.html.erb index e3afc17..6fdc727 100644 --- a/app/views/e_sign/eg005_envelope_recipients/get.html.erb +++ b/app/views/e_sign/eg005_envelope_recipients/get.html.erb @@ -13,14 +13,14 @@

    <% if @envelope_ok %> -

    The envelope you created via example 2 will be queried.

    +

    The envelope you created via Request a signature by email (remote signing) will be queried.

    <% else %> -

    Problem: please first create an envelope using example 2.
    +

    Problem: please first create an envelope using Request a signature by email (remote signing).
    Thank you.

    diff --git a/app/views/e_sign/eg006_envelope_docs/get.html.erb b/app/views/e_sign/eg006_envelope_docs/get.html.erb index 33a7481..aee609a 100644 --- a/app/views/e_sign/eg006_envelope_docs/get.html.erb +++ b/app/views/e_sign/eg006_envelope_docs/get.html.erb @@ -19,14 +19,14 @@

    <% if @envelope_ok %> -

    The envelope you created via example 2 will be queried.

    +

    The envelope you created via Request a signature by email (remote signing) will be queried.

    <% else %> -

    Problem: please first create an envelope using example 2.
    +

    Problem: please first create an envelope using Request a signature by email (remote signing).
    Thank you.

    diff --git a/app/views/e_sign/eg007_envelope_get_doc/get.html.erb b/app/views/e_sign/eg007_envelope_get_doc/get.html.erb index a08b441..02218e2 100644 --- a/app/views/e_sign/eg007_envelope_get_doc/get.html.erb +++ b/app/views/e_sign/eg007_envelope_get_doc/get.html.erb @@ -27,8 +27,8 @@

    <% if !@envelope_ok %> -

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

    Problem: please first create an envelope using Request a signature by email (remote signing).
    + You will then need to use List envelope documents to create the list of documents.
    Thank you.

    @@ -36,7 +36,7 @@
    <% elsif !@documents_ok %>

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

    @@ -44,7 +44,7 @@
    <% else %>

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

    + The document list is from your results for List envelope documents.

    diff --git a/app/views/e_sign/eg009_use_template/get.html.erb b/app/views/e_sign/eg009_use_template/get.html.erb index 627ef78..c64de91 100644 --- a/app/views/e_sign/eg009_use_template/get.html.erb +++ b/app/views/e_sign/eg009_use_template/get.html.erb @@ -20,7 +20,7 @@

    <% if @template_ok %> -

    The template you created via example 8 will be used.

    +

    The template you created via Create a template will be used.

    @@ -50,7 +50,7 @@ <% else %> -

    Problem: please first create the template using example 8.
    +

    Problem: please first create the template using Create a template.
    Thank you.

    diff --git a/app/views/e_sign/eg011_embedded_sending/get.html.erb b/app/views/e_sign/eg011_embedded_sending/get.html.erb index c1388e5..02b946e 100644 --- a/app/views/e_sign/eg011_embedded_sending/get.html.erb +++ b/app/views/e_sign/eg011_embedded_sending/get.html.erb @@ -9,7 +9,7 @@

    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). + needed feature (see Request a signature using a composite template for adding additional documents programmatically).

    <% if @show_doc %> diff --git a/app/views/e_sign/eg012_embedded_console/get.html.erb b/app/views/e_sign/eg012_embedded_console/get.html.erb index 72d6ee2..86c8514 100644 --- a/app/views/e_sign/eg012_embedded_console/get.html.erb +++ b/app/views/e_sign/eg012_embedded_console/get.html.erb @@ -22,7 +22,7 @@ <% if !@envelope_ok %>

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

    + Request a signature by email (remote signing).

    <% end %> diff --git a/app/views/e_sign/eg013_add_doc_to_template/get.html.erb b/app/views/e_sign/eg013_add_doc_to_template/get.html.erb index 1e8bd17..96e1afc 100644 --- a/app/views/e_sign/eg013_add_doc_to_template/get.html.erb +++ b/app/views/e_sign/eg013_add_doc_to_template/get.html.erb @@ -27,7 +27,7 @@

    <% if @template_ok %> -

    The template you created via example 8 will be used.

    +

    The template you created via Create a template will be used.

    @@ -81,7 +81,7 @@ <% else %> -

    Problem: please first create the template using example 8.
    +

    Problem: please first create the template using Create a template.
    Thank you.

    diff --git a/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb b/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb index 3b5a3b9..06adfae 100644 --- a/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb +++ b/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb @@ -20,14 +20,14 @@

    <% if @envelope_ok %> -

    The envelope you created from an earlier example will be queried.

    +

    The envelope you created from Request a signature by email (remote signing) will be queried.

    <% else %> -

    Problem: please first create an envelope using example 2.
    +

    Problem: please first create an envelope using Request a signature by email (remote signing).
    Thank you.

    diff --git a/app/views/e_sign/eg017_set_template_tab_values/get.html.erb b/app/views/e_sign/eg017_set_template_tab_values/get.html.erb index 06211e2..0c2c51c 100644 --- a/app/views/e_sign/eg017_set_template_tab_values/get.html.erb +++ b/app/views/e_sign/eg017_set_template_tab_values/get.html.erb @@ -20,7 +20,7 @@ <% if @template_ok %> -

    The template you created via example 8 will be used.

    +

    The template you created via Create a template will be used.

    @@ -50,7 +50,7 @@ <% else %> -

    Problem: please first create the template using example 8.
    +

    Problem: please first create the template using Create a template.
    Thank you.

    diff --git a/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb b/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb index 13f8e43..4d08159 100644 --- a/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb +++ b/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb @@ -25,7 +25,7 @@ <% if @envelope_ok %>

    The last envelope you created with the launcher will be queried. - Recommendation: Create an envelope using example 16 then use this example in order to see an example of custom tab values. + Recommendation: Create an envelope using Set envelope tab values then use this example in order to see an example of custom tab values.

    @@ -33,7 +33,7 @@
    <% else %> -

    Problem: Please first create an envelope using example 16. +

    Problem: Please first create an envelope using Set envelope tab values.

    diff --git a/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb b/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb index 9508aa3..02af751 100644 --- a/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb +++ b/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb @@ -51,7 +51,7 @@
    <% else %> -

    Problem: please first create the template using example 8.
    +

    Problem: please first create the template using Create a template.
    Thank you.

    diff --git a/app/views/e_sign/eg032_pauses_signature_workflow/get.html.erb b/app/views/e_sign/eg032_pauses_signature_workflow/get.html.erb index ef660f2..103205e 100644 --- a/app/views/e_sign/eg032_pauses_signature_workflow/get.html.erb +++ b/app/views/e_sign/eg032_pauses_signature_workflow/get.html.erb @@ -3,7 +3,7 @@

    This example demonstrates how to create an envelope where the workflow is paused before the envelope is sent to a second recipient. The envelope includes a txt document. - For resuming workflow see example 33 + For resuming workflow see Unpause a signature workflow

    API method used: diff --git a/app/views/e_sign/eg032_pauses_signature_workflow/return.html.erb b/app/views/e_sign/eg032_pauses_signature_workflow/return.html.erb index c2c5e7a..e998339 100644 --- a/app/views/e_sign/eg032_pauses_signature_workflow/return.html.erb +++ b/app/views/e_sign/eg032_pauses_signature_workflow/return.html.erb @@ -5,7 +5,7 @@ Envelope ID: <%= @envelop_id %>

    - To resume a workflow after first recipient signs the envelope use example 33 + To resume a workflow after first recipient signs the envelope use Unpause a signature workflow

    Continue

    \ No newline at end of file diff --git a/app/views/e_sign/eg033_unpauses_signature_workflow/get.html.erb b/app/views/e_sign/eg033_unpauses_signature_workflow/get.html.erb index bd29685..fdd9803 100644 --- a/app/views/e_sign/eg033_unpauses_signature_workflow/get.html.erb +++ b/app/views/e_sign/eg033_unpauses_signature_workflow/get.html.erb @@ -17,7 +17,7 @@ <%- end -%> <% else %>

    - Problem: please first create an envelope using example 32. + Problem: please first create an envelope using Pause a signature workflow.
    Thank you.

    diff --git a/config/appsettings.example.yml b/config/appsettings.example.yml index d301dcf..9d3c687 100644 --- a/config/appsettings.example.yml +++ b/config/appsettings.example.yml @@ -26,7 +26,7 @@ default: &default allow_silent_authentication: true # A user can be silently authenticated if they have an # Active login session on another tab of the same browser # Set if you want a specific DocuSign AccountId, If false, the users default account will be used. - target_account_id: false # Payment gateway information is optional. It is only needed for example 14. + target_account_id: false # Payment gateway information is optional. It is only needed for Send a request for Accept Payments. # See the PAYMENTS_INSTALLATION.md file for instructions gateway_account_id: {DS_PAYMENT_GATEWAY_ID} # The remainder of this file is already configured. demo_doc_path: demo_documents From 04c001d394803d069f830b8231694d0f1e6ac742 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 30 Aug 2022 11:33:14 -0700 Subject: [PATCH 164/363] Fixing issue with create template code example (DEVDOCS-8573) --- app/services/e_sign/eg008_create_template_service.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/services/e_sign/eg008_create_template_service.rb b/app/services/e_sign/eg008_create_template_service.rb index 084c8c7..58f8640 100644 --- a/app/services/e_sign/eg008_create_template_service.rb +++ b/app/services/e_sign/eg008_create_template_service.rb @@ -48,6 +48,7 @@ def make_template_req # Read the PDF from the disk # Read files 2 and 3 from a local directory # The reads could raise an exception if the file is not available! + template_name = args[:template_name] doc_file = 'World_Wide_Corp_fields.pdf' base64_file_content = Base64.encode64(File.binread(File.join('data', doc_file))) From 490ffc9a500d7c0cce65c186f8b660c7e3c3112a Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 30 Aug 2022 11:44:25 -0700 Subject: [PATCH 165/363] Fixing issue with "Create a Template" code example --- Gemfile | 4 +--- Gemfile.lock | 2 +- app/services/e_sign/eg008_create_template_service.rb | 1 + 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 8edbb83..402403d 100644 --- a/Gemfile +++ b/Gemfile @@ -63,7 +63,7 @@ group :test do gem 'capybara', '~> 3.31.0' gem 'selenium-webdriver', '~> 3.142.7' # Easy installation and use of chromedriver to run system tests with Chrome - gem 'chromedriver-helper', '~> 1.2.0' + gem 'chromedriver-helper', '~> 2.1.1' end gem 'docusign_esign', '~> 3.17.0' @@ -77,5 +77,3 @@ gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', '~> 1.2022.1', '>= 1.2022.1' gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] - -gem "matrix", "~> 0.4.2" diff --git a/Gemfile.lock b/Gemfile.lock index 7e883fa..36360c9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -333,4 +333,4 @@ RUBY VERSION ruby 3.1.2p20 BUNDLED WITH - 2.3.7 \ No newline at end of file + 2.3.7 diff --git a/app/services/e_sign/eg008_create_template_service.rb b/app/services/e_sign/eg008_create_template_service.rb index 084c8c7..58f8640 100644 --- a/app/services/e_sign/eg008_create_template_service.rb +++ b/app/services/e_sign/eg008_create_template_service.rb @@ -48,6 +48,7 @@ def make_template_req # Read the PDF from the disk # Read files 2 and 3 from a local directory # The reads could raise an exception if the file is not available! + template_name = args[:template_name] doc_file = 'World_Wide_Corp_fields.pdf' base64_file_content = Base64.encode64(File.binread(File.join('data', doc_file))) From 4e5a1ba8371215bd85893b87afe24c925505efb2 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Tue, 30 Aug 2022 14:34:18 -0700 Subject: [PATCH 166/363] Add doc vis steps (#89) * add step comments --- .../e_sign/eg039_signing_in_person_service.rb | 16 +++++++++++----- .../eg040_set_document_visibility_service.rb | 10 ++++++++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/services/e_sign/eg039_signing_in_person_service.rb b/app/services/e_sign/eg039_signing_in_person_service.rb index f8c86f0..2d2971b 100644 --- a/app/services/e_sign/eg039_signing_in_person_service.rb +++ b/app/services/e_sign/eg039_signing_in_person_service.rb @@ -17,23 +17,26 @@ def worker host_name = args[:host_name] signer_name = args[:signer_name] - # Step 1. Create the envelope definition envelope = make_envelope(pdf_filename, host_email, host_name, signer_name) - # Step 2. Call DocuSign to create the envelope + # Step 3 start envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope + # Step 3 end + envelope_id = results.envelope_id - # Step 3. Create the recipient view for the embedded signing + + # Step 5 start view_request = make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_name ) # Call the CreateRecipientView API results = envelope_api.create_recipient_view args[:account_id], envelope_id, view_request + # Step 5 end - # Step 4. Redirect the user to the embedded signing + # 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) @@ -43,6 +46,7 @@ def worker private + # Step 4 start def make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_name) view_request = DocuSign_eSign::RecipientViewRequest.new # Set the URL where you want the recipient to go once they are done signing @@ -74,7 +78,9 @@ def make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_nam view_request end + # Step 4 end + # Step 2 start def make_envelope(pdf_filename, host_email, host_name, signer_name) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document sent from Ruby SDK' @@ -118,5 +124,5 @@ def make_envelope(pdf_filename, host_email, host_name, signer_name) envelope_definition.status = 'sent' envelope_definition end - # ***DS.snippet.0.end + # Step 2 end end \ No newline at end of file diff --git a/app/services/e_sign/eg040_set_document_visibility_service.rb b/app/services/e_sign/eg040_set_document_visibility_service.rb index e7340aa..21c947e 100644 --- a/app/services/e_sign/eg040_set_document_visibility_service.rb +++ b/app/services/e_sign/eg040_set_document_visibility_service.rb @@ -9,19 +9,24 @@ def initialize(args) end def worker - # 1. Create the envelope request object + # Step 3-1 start envelope_definition = make_envelope args[:envelope_args] - # 2. Call Envelopes::create API method + # Step 3-1 end + # Exceptions will be caught by the calling function + # Step 4 start envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope_definition envelope_id = results.envelope_id + # Step 4 end + { 'envelope_id' => envelope_id } end private + # Step 3-2 start def make_envelope(envelope_args) # document 1 (HTML) has tag **signature_1** # document 2 (DOCX) has tag /sn1/ @@ -141,6 +146,7 @@ def make_envelope(envelope_args) envelope_definition.status = envelope_args[:status] envelope_definition end + # Step 3-2 end def create_document1(args) " From 43ea7277c59d494914177781c856d7e20952e079 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Mon, 10 Oct 2022 14:38:41 -0700 Subject: [PATCH 167/363] DEVDOCS-8778, catching API exception when making the API calls and providing nice error message to user if Monitor not enabled --- ...eg001_get_monitoring_dataset_controller.rb | 9 +++++++-- .../eg002_post_web_query_controller.rb | 9 +++++++-- .../eg001_get_monitoring_dataset_service.rb | 19 +++++++++++------- .../eg002_post_web_query_service.rb | 20 +++++++++++-------- 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb b/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb index 4326aca..720d0ab 100644 --- a/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb +++ b/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb @@ -12,8 +12,13 @@ def create @title = "Get monitoring data" @h1 = "Get monitoring data" - @message = "Results from DataSet:getStream method:" - @json = results.to_json.to_json + + if results != "Monitor not enabled" + @message = "Results from DataSet:getStream method:" + @json = results.to_json.to_json + else + @message = "You do not have Monitor enabled for your account, follow How to enable Monitor for your account to get it enabled." + end render 'ds_common/example_done' end diff --git a/app/controllers/monitor_api/eg002_post_web_query_controller.rb b/app/controllers/monitor_api/eg002_post_web_query_controller.rb index a98e84a..beb4045 100644 --- a/app/controllers/monitor_api/eg002_post_web_query_controller.rb +++ b/app/controllers/monitor_api/eg002_post_web_query_controller.rb @@ -15,8 +15,13 @@ def create @title = "Query monitoring data with filters" @h1 = "Query monitoring data with filters" - @message = "Results from DataSet:postWebQuery method:" - @json = results.to_json.to_json + + if results != "Monitor not enabled" + @message = "Results from DataSet:postWebQuery method:" + @json = results.to_json.to_json + else + @message = "You do not have Monitor enabled for your account, follow How to enable Monitor for your account to get it enabled." + end render 'ds_common/example_done' end diff --git a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb index 378aa57..8247b6a 100644 --- a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb +++ b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb @@ -18,13 +18,18 @@ def worker # step 3 start monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) - @response = monitor_api.get_stream(args[:data_set_name], args[:version]).data + begin + @response = monitor_api.get_stream(args[:data_set_name], args[:version]).data + # step 3 end + rescue + # error, probalby no Monitor enabled + @response = "Monitor not enabled" + else + Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" + Rails.logger.info @response.inspect + ensure + return @response + end - # step 3 end - - Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" - Rails.logger.info @response.inspect - - return @response end end diff --git a/app/services/monitor_api/eg002_post_web_query_service.rb b/app/services/monitor_api/eg002_post_web_query_service.rb index 0bd370a..f605bd3 100644 --- a/app/services/monitor_api/eg002_post_web_query_service.rb +++ b/app/services/monitor_api/eg002_post_web_query_service.rb @@ -18,14 +18,18 @@ def worker # step 3 start monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) - @response = monitor_api.post_web_query(args[:data_set_name], args[:version], get_query) - - # step 3 end - - Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" - Rails.logger.info @response.inspect - - return @response + begin + @response = monitor_api.post_web_query(args[:data_set_name], args[:version], get_query) + # step 3 end + rescue + # error, probalby no Monitor enabled + @response = "Monitor not enabled" + else + Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" + Rails.logger.info @response.inspect + ensure + return @response + end end def get_query From ca12e28f86ebe08f28bf6daa3564d41e92d29668 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Mon, 17 Oct 2022 09:24:02 -0700 Subject: [PATCH 168/363] Monitor API - checking if you have this enabled As well as some comments updates --- ...eg001_get_monitoring_dataset_controller.rb | 9 +++++++-- .../eg002_post_web_query_controller.rb | 9 +++++++-- .../e_sign/eg039_signing_in_person_service.rb | 16 ++++++++++----- .../eg040_set_document_visibility_service.rb | 10 ++++++++-- .../eg001_get_monitoring_dataset_service.rb | 19 +++++++++++------- .../eg002_post_web_query_service.rb | 20 +++++++++++-------- 6 files changed, 57 insertions(+), 26 deletions(-) diff --git a/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb b/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb index 4326aca..720d0ab 100644 --- a/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb +++ b/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb @@ -12,8 +12,13 @@ def create @title = "Get monitoring data" @h1 = "Get monitoring data" - @message = "Results from DataSet:getStream method:" - @json = results.to_json.to_json + + if results != "Monitor not enabled" + @message = "Results from DataSet:getStream method:" + @json = results.to_json.to_json + else + @message = "You do not have Monitor enabled for your account, follow How to enable Monitor for your account to get it enabled." + end render 'ds_common/example_done' end diff --git a/app/controllers/monitor_api/eg002_post_web_query_controller.rb b/app/controllers/monitor_api/eg002_post_web_query_controller.rb index a98e84a..beb4045 100644 --- a/app/controllers/monitor_api/eg002_post_web_query_controller.rb +++ b/app/controllers/monitor_api/eg002_post_web_query_controller.rb @@ -15,8 +15,13 @@ def create @title = "Query monitoring data with filters" @h1 = "Query monitoring data with filters" - @message = "Results from DataSet:postWebQuery method:" - @json = results.to_json.to_json + + if results != "Monitor not enabled" + @message = "Results from DataSet:postWebQuery method:" + @json = results.to_json.to_json + else + @message = "You do not have Monitor enabled for your account, follow How to enable Monitor for your account to get it enabled." + end render 'ds_common/example_done' end diff --git a/app/services/e_sign/eg039_signing_in_person_service.rb b/app/services/e_sign/eg039_signing_in_person_service.rb index f8c86f0..2d2971b 100644 --- a/app/services/e_sign/eg039_signing_in_person_service.rb +++ b/app/services/e_sign/eg039_signing_in_person_service.rb @@ -17,23 +17,26 @@ def worker host_name = args[:host_name] signer_name = args[:signer_name] - # Step 1. Create the envelope definition envelope = make_envelope(pdf_filename, host_email, host_name, signer_name) - # Step 2. Call DocuSign to create the envelope + # Step 3 start envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope + # Step 3 end + envelope_id = results.envelope_id - # Step 3. Create the recipient view for the embedded signing + + # Step 5 start view_request = make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_name ) # Call the CreateRecipientView API results = envelope_api.create_recipient_view args[:account_id], envelope_id, view_request + # Step 5 end - # Step 4. Redirect the user to the embedded signing + # 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) @@ -43,6 +46,7 @@ def worker private + # Step 4 start def make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_name) view_request = DocuSign_eSign::RecipientViewRequest.new # Set the URL where you want the recipient to go once they are done signing @@ -74,7 +78,9 @@ def make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_nam view_request end + # Step 4 end + # Step 2 start def make_envelope(pdf_filename, host_email, host_name, signer_name) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document sent from Ruby SDK' @@ -118,5 +124,5 @@ def make_envelope(pdf_filename, host_email, host_name, signer_name) envelope_definition.status = 'sent' envelope_definition end - # ***DS.snippet.0.end + # Step 2 end end \ No newline at end of file diff --git a/app/services/e_sign/eg040_set_document_visibility_service.rb b/app/services/e_sign/eg040_set_document_visibility_service.rb index e7340aa..21c947e 100644 --- a/app/services/e_sign/eg040_set_document_visibility_service.rb +++ b/app/services/e_sign/eg040_set_document_visibility_service.rb @@ -9,19 +9,24 @@ def initialize(args) end def worker - # 1. Create the envelope request object + # Step 3-1 start envelope_definition = make_envelope args[:envelope_args] - # 2. Call Envelopes::create API method + # Step 3-1 end + # Exceptions will be caught by the calling function + # Step 4 start envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope_definition envelope_id = results.envelope_id + # Step 4 end + { 'envelope_id' => envelope_id } end private + # Step 3-2 start def make_envelope(envelope_args) # document 1 (HTML) has tag **signature_1** # document 2 (DOCX) has tag /sn1/ @@ -141,6 +146,7 @@ def make_envelope(envelope_args) envelope_definition.status = envelope_args[:status] envelope_definition end + # Step 3-2 end def create_document1(args) " diff --git a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb index 378aa57..8247b6a 100644 --- a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb +++ b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb @@ -18,13 +18,18 @@ def worker # step 3 start monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) - @response = monitor_api.get_stream(args[:data_set_name], args[:version]).data + begin + @response = monitor_api.get_stream(args[:data_set_name], args[:version]).data + # step 3 end + rescue + # error, probalby no Monitor enabled + @response = "Monitor not enabled" + else + Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" + Rails.logger.info @response.inspect + ensure + return @response + end - # step 3 end - - Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" - Rails.logger.info @response.inspect - - return @response end end diff --git a/app/services/monitor_api/eg002_post_web_query_service.rb b/app/services/monitor_api/eg002_post_web_query_service.rb index 0bd370a..f605bd3 100644 --- a/app/services/monitor_api/eg002_post_web_query_service.rb +++ b/app/services/monitor_api/eg002_post_web_query_service.rb @@ -18,14 +18,18 @@ def worker # step 3 start monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) - @response = monitor_api.post_web_query(args[:data_set_name], args[:version], get_query) - - # step 3 end - - Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" - Rails.logger.info @response.inspect - - return @response + begin + @response = monitor_api.post_web_query(args[:data_set_name], args[:version], get_query) + # step 3 end + rescue + # error, probalby no Monitor enabled + @response = "Monitor not enabled" + else + Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" + Rails.logger.info @response.inspect + ensure + return @response + end end def get_query From b74e4d28b8fd90b1dca6c4a1bed0237a0fab85f4 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Thu, 20 Oct 2022 20:19:55 +0300 Subject: [PATCH 169/363] Add manifest support (#91) * Added manifest support --- .rubocop.yml | 72 ++++ Gemfile | 7 +- Gemfile.lock | 195 +++++----- .../admin_api/eg001_create_user_controller.rb | 75 ++-- ...create_active_clm_esign_user_controller.rb | 84 ++-- .../eg003_bulk_export_user_data_controller.rb | 10 +- .../admin_api/eg004_import_user_controller.rb | 21 +- .../admin_api/eg005_audit_users_controller.rb | 40 +- ...06_get_user_profile_by_email_controller.rb | 32 +- ..._get_user_profile_by_user_id_controller.rb | 32 +- ...r_product_permission_profile_controller.rb | 128 +++---- ...r_product_permission_profile_controller.rb | 136 ++++--- .../eg001_create_clickwrap_controller.rb | 6 +- .../eg002_activate_clickwrap_controller.rb | 8 +- ...create_new_clickwrap_version_controller.rb | 6 +- .../eg004_list_clickwraps_controller.rb | 6 +- .../eg005_clickwrap_responses_controller.rb | 6 +- app/controllers/ds_common_controller.rb | 72 ++-- .../eg002_signing_via_email_controller.rb | 50 +-- .../e_sign/eg003_list_envelopes_controller.rb | 5 +- .../e_sign/eg004_envelope_info_controller.rb | 12 +- .../eg005_envelope_recipients_controller.rb | 8 +- .../e_sign/eg006_envelope_docs_controller.rb | 20 +- .../eg007_envelope_get_doc_controller.rb | 3 +- .../eg008_create_template_controller.rb | 41 +- .../e_sign/eg009_use_template_controller.rb | 12 +- .../eg010_send_binary_docs_controller.rb | 58 ++- .../eg011_embedded_sending_controller.rb | 43 +-- .../eg012_embedded_console_controller.rb | 3 +- .../eg013_add_doc_to_template_controller.rb | 5 +- .../eg014_collect_payment_controller.rb | 47 ++- .../eg015_get_envelope_tab_data_controller.rb | 3 +- .../eg016_set_envelope_tab_data_controller.rb | 1 + ...g017_set_template_tab_values_controller.rb | 3 +- ...t_envelope_custom_field_data_controller.rb | 3 +- ...9_access_code_authentication_controller.rb | 44 +-- .../eg020_phone_authentication_controller.rb | 60 ++- .../eg022_kba_authentication_controller.rb | 40 +- .../eg023_idv_authentication_controller.rb | 56 ++- .../eg024_permission_create_controller.rb | 35 +- ...5_permissions_set_user_group_controller.rb | 39 +- ...ssions_change_single_setting_controller.rb | 39 +- .../eg027_permissions_delete_controller.rb | 37 +- .../eg028_brands_creating_controller.rb | 39 +- ...029_brands_apply_to_envelope_controller.rb | 51 ++- ...030_brands_apply_to_template_controller.rb | 14 +- ...eg031_bulk_sending_envelopes_controller.rb | 55 ++- ...32_pauses_signature_workflow_controller.rb | 1 + ..._unpauses_signature_workflow_controller.rb | 1 + ...4_use_conditional_recipients_controller.rb | 59 ++- .../eg035_scheduled_sending_controller.rb | 42 +- .../eg036_delayed_routing_controller.rb | 46 ++- .../e_sign/eg037_sms_delivery_controller.rb | 48 ++- .../eg038_responsive_signing_controller.rb | 35 +- .../eg039_signing_in_person_controller.rb | 2 + ...g040_set_document_visibility_controller.rb | 66 ++-- .../eg001_embedded_signing_controller.rb | 60 ++- app/controllers/eg_controller.rb | 43 ++- ...eg001_get_monitoring_dataset_controller.rb | 6 +- .../eg002_post_web_query_controller.rb | 8 +- .../eg001_create_room_with_data_controller.rb | 12 +- ...02_create_room_with_template_controller.rb | 10 +- .../eg003_export_data_from_room_controller.rb | 6 +- .../eg004_add_forms_to_room_controller.rb | 6 +- ...eg005_get_rooms_with_filters_controller.rb | 6 +- ...n_external_form_fill_session_controller.rb | 6 +- .../eg007_create_form_group_controller.rb | 6 +- ..._office_access_to_form_group_controller.rb | 9 +- ...09_assign_form_to_form_group_controller.rb | 8 +- app/controllers/session_controller.rb | 11 +- app/helpers/application_helper.rb | 3 + app/helpers/eg024_brands_creating_helper.rb | 16 +- .../admin_api/eg001_create_user_service.rb | 4 +- ...02_create_active_clm_esign_user_service.rb | 28 +- .../eg003_bulk_export_user_data_service.rb | 6 +- .../admin_api/eg004_import_user_service.rb | 7 +- .../admin_api/eg005_audit_users_service.rb | 6 +- ...eg006_get_user_profile_by_email_service.rb | 4 +- ...007_get_user_profile_by_user_id_service.rb | 4 +- ...user_product_permission_profile_service.rb | 10 +- ...user_product_permission_profile_service.rb | 11 +- app/services/admin_api/get_data_service.rb | 111 +++--- app/services/api_creator.rb | 6 +- .../eg002_activate_clickwrap_service.rb | 2 +- .../e_sign/eg002_signing_via_email_service.rb | 7 +- .../e_sign/eg003_list_envelopes_service.rb | 5 +- .../e_sign/eg004_envelope_info_service.rb | 3 +- .../eg005_envelope_recipients_service.rb | 3 +- .../e_sign/eg006_envelope_docs_service.rb | 6 +- .../e_sign/eg007_envelope_get_doc_service.rb | 1 + .../e_sign/eg008_create_template_service.rb | 15 +- .../e_sign/eg009_use_template_service.rb | 3 +- .../e_sign/eg010_send_binary_docs_service.rb | 45 +-- .../e_sign/eg011_embedded_sending_service.rb | 9 +- .../e_sign/eg012_embedded_console_service.rb | 7 +- .../eg013_add_doc_to_template_service.rb | 7 +- .../e_sign/eg014_collect_payment_service.rb | 19 +- .../eg015_get_envelope_tab_data_service.rb | 3 +- .../eg016_set_envelope_tab_data_service.rb | 11 +- .../eg017_set_template_tab_values_service.rb | 278 +++++++------- ..._get_envelope_custom_field_data_service.rb | 3 +- ...g019_access_code_authentication_service.rb | 11 +- .../eg020_phone_authentication_service.rb | 56 ++- .../eg022_kba_authentication_service.rb | 5 +- .../eg023_idv_authentication_service.rb | 27 +- .../e_sign/eg024_permission_create_service.rb | 62 +-- ...g025_permissions_set_user_group_service.rb | 9 +- ...rmissions_change_single_setting_service.rb | 60 +-- .../eg027_permissions_delete_service.rb | 5 +- .../e_sign/eg028_brands_creating_service.rb | 9 +- .../eg029_brands_apply_to_envelope_service.rb | 15 +- .../eg030_brands_apply_to_template_service.rb | 5 +- .../eg031_bulk_sending_envelopes_service.rb | 73 ++-- ...eg032_pauses_signature_workflow_service.rb | 3 +- ...033_unpauses_signature_workflow_service.rb | 3 +- ...g034_use_conditional_recipients_service.rb | 3 +- .../e_sign/eg035_scheduled_sending_service.rb | 7 +- .../e_sign/eg036_delayed_routing_service.rb | 21 +- .../e_sign/eg037_sms_delivery_service.rb | 14 +- .../eg038_responsive_signing_service.rb | 42 +- .../e_sign/eg039_signing_in_person_service.rb | 11 +- .../eg040_set_document_visibility_service.rb | 11 +- app/services/e_sign/get_data_service.rb | 13 +- .../eg001_embedded_signing_service.rb | 18 +- app/services/jwt_auth/jwt_creator.rb | 50 +-- .../eg001_get_monitoring_dataset_service.rb | 10 +- .../eg002_post_web_query_service.rb | 20 +- .../eg001_create_room_with_data_service.rb | 37 +- ...eg002_create_room_with_template_service.rb | 41 +- .../eg003_export_data_from_room_service.rb | 6 +- .../eg004_add_forms_to_room_service.rb | 8 +- .../eg005_get_rooms_with_filters_service.rb | 4 +- ...e_an_external_form_fill_session_service.rb | 14 +- .../eg007_create_form_group_service.rb | 8 +- ...ant_office_access_to_form_group_service.rb | 6 +- ...eg009_assign_form_to_form_group_service.rb | 4 +- app/services/room_api/get_data_service.rb | 14 +- app/services/utils.rb | 17 + .../admin_api/eg001_create_user/get.html.erb | 57 +-- .../get.html.erb | 60 +-- .../eg003_bulk_export_user_data/get.html.erb | 18 +- .../admin_api/eg004_import_user/get.html.erb | 18 +- .../admin_api/eg005_audit_users/get.html.erb | 18 +- .../get.html.erb | 28 +- .../get.html.erb | 23 +- .../get.html.erb | 34 +- .../get.html.erb | 27 +- app/views/admin_api/index.html.erb | 121 ++---- .../eg001_create_clickwrap/get.html.erb | 23 +- .../eg002_activate_clickwrap/get.html.erb | 32 +- .../get.html.erb | 27 +- .../eg004_list_clickwraps/get.html.erb | 15 +- .../eg005_clickwrap_responses/get.html.erb | 56 +-- app/views/clickwrap/index.html.erb | 70 ++-- app/views/ds_common/choose_api.erb | 4 +- app/views/ds_common/ds_must_authenticate.erb | 6 +- app/views/ds_common/example_done.erb | 2 +- app/views/ds_common/index.html.erb | 362 ++---------------- .../eg002_signing_via_email/get.html.erb | 52 ++- .../e_sign/eg003_list_envelopes/get.html.erb | 17 +- .../e_sign/eg004_envelope_info/get.html.erb | 32 +- .../eg005_envelope_recipients/get.html.erb | 28 +- .../e_sign/eg006_envelope_docs/get.html.erb | 34 +- .../eg007_envelope_get_doc/get.html.erb | 54 +-- .../e_sign/eg008_create_template/get.html.erb | 26 +- .../e_sign/eg009_use_template/get.html.erb | 63 ++- .../eg010_send_binary_docs/get.html.erb | 55 ++- .../eg011_embedded_sending/get.html.erb | 64 ++-- .../eg012_embedded_console/get.html.erb | 35 +- .../eg013_add_doc_to_template/get.html.erb | 76 ++-- .../e_sign/eg014_collect_payment/get.html.erb | 56 ++- .../eg015_get_envelope_tab_data/get.html.erb | 35 +- .../eg016_set_envelope_tab_data/get.html.erb | 44 +-- .../get.html.erb | 63 ++- .../get.html.erb | 41 +- .../get.html.erb | 50 +-- .../eg020_phone_authentication/get.html.erb | 62 ++- .../eg022_kba_authentication/get.html.erb | 41 +- .../eg023_idv_authentication/get.html.erb | 39 +- .../eg024_permission_create/get.html.erb | 25 +- .../get.html.erb | 25 +- .../get.html.erb | 21 +- .../eg027_permissions_delete/get.html.erb | 22 +- .../e_sign/eg028_brands_creating/get.html.erb | 26 +- .../get.html.erb | 39 +- .../get.html.erb | 58 +-- .../eg031_bulk_sending_envelopes/get.html.erb | 92 ++--- .../get.html.erb | 57 +-- .../get.html.erb | 21 +- .../get.html.erb | 80 ++-- .../eg035_scheduled_sending/get.html.erb | 41 +- .../e_sign/eg036_delayed_routing/get.html.erb | 60 +-- .../e_sign/eg037_sms_delivery/get.html.erb | 63 +-- .../eg038_responsive_signing/get.html.erb | 52 +-- .../eg039_signing_in_person/get.html.erb | 28 +- .../get.html.erb | 63 +-- app/views/eg001_embedded_signing/get.html.erb | 38 +- .../eg001_get_monitoring_dataset/get.html.erb | 13 +- .../eg002_post_web_query/get.html.erb | 26 +- app/views/monitor_api/index.html.erb | 43 ++- app/views/partials/_continue_button.erb | 1 + .../_email_should_differ_from_signer.erb | 1 + .../partials/_email_will_not_be_shared.erb | 1 + app/views/partials/_example_info.erb | 24 ++ .../partials/_phone_will_not_be_shared.erb | 1 + app/views/partials/_submit_button.erb | 1 + .../_information.html.erb | 10 - .../eg001_create_room_with_data/get.html.erb | 16 +- .../_information.html.erb | 14 - .../get.html.erb | 27 +- .../_information.html.erb | 14 - .../eg003_export_data_from_room/get.html.erb | 22 +- .../_information.html.erb | 12 - .../eg004_add_forms_to_room/get.html.erb | 26 +- .../_information.html.erb | 14 - .../eg005_get_rooms_with_filters/get.html.erb | 16 +- .../_information.html.erb | 17 - .../get_forms.html.erb | 24 +- .../get_rooms.html.erb | 25 +- .../_information.html.erb | 11 - .../eg007_create_form_group/get.html.erb | 17 +- .../_information.html.erb | 16 - .../get.erb | 24 +- .../_information.html.erb | 18 - .../eg009_assign_form_to_form_group/get.erb | 24 +- app/views/room_api/index.html.erb | 130 ++----- config/application.rb | 12 +- config/appsettings.example.yml | 5 + config/initializers/omniauth.rb | 19 +- config/routes.rb | 12 +- db/schema.rb | 2 +- jwt_console_project/jwt_console.rb | 60 ++- lib/docusign.rb | 16 +- quick_acg/Rakefile | 2 +- .../app/controllers/ds_common_controller.rb | 4 +- quick_acg/bin/bundle | 40 +- quick_acg/bin/rails | 6 +- quick_acg/bin/rake | 4 +- quick_acg/bin/setup | 16 +- quick_acg/config/application.rb | 2 +- quick_acg/config/boot.rb | 4 +- quick_acg/config/environment.rb | 2 +- quick_acg/config/environments/development.rb | 6 +- quick_acg/config/environments/production.rb | 8 +- quick_acg/config/environments/test.rb | 6 +- quick_acg/config/initializers/assets.rb | 2 +- quick_acg/config/initializers/omniauth.rb | 19 +- quick_acg/config/puma.rb | 12 +- quick_acg/config/routes.rb | 1 + quick_acg/lib/docusign.rb | 16 +- 250 files changed, 3205 insertions(+), 4062 deletions(-) create mode 100644 .rubocop.yml create mode 100644 app/services/utils.rb create mode 100644 app/views/partials/_continue_button.erb create mode 100644 app/views/partials/_email_should_differ_from_signer.erb create mode 100644 app/views/partials/_email_will_not_be_shared.erb create mode 100644 app/views/partials/_example_info.erb create mode 100644 app/views/partials/_phone_will_not_be_shared.erb create mode 100644 app/views/partials/_submit_button.erb delete mode 100644 app/views/room_api/eg001_create_room_with_data/_information.html.erb delete mode 100644 app/views/room_api/eg002_create_room_with_template/_information.html.erb delete mode 100644 app/views/room_api/eg003_export_data_from_room/_information.html.erb delete mode 100644 app/views/room_api/eg004_add_forms_to_room/_information.html.erb delete mode 100644 app/views/room_api/eg005_get_rooms_with_filters/_information.html.erb delete mode 100644 app/views/room_api/eg006_create_an_external_form_fill_session/_information.html.erb delete mode 100644 app/views/room_api/eg007_create_form_group/_information.html.erb delete mode 100644 app/views/room_api/eg008_grant_office_access_to_form_group/_information.html.erb delete mode 100644 app/views/room_api/eg009_assign_form_to_form_group/_information.html.erb diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..97c9888 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,72 @@ +Layout/LineLength: + Enabled: false + +Style/ClassAndModuleChildren: + Enabled: false + +Style/Documentation: + Enabled: false + +Style/StringLiterals: + EnforcedStyle: single_quotes + +Lint/RescueException: + Enabled: false + +Lint/UnreachableCode: + Enabled: false + +Metrics/AbcSize: + Enabled: false + +Metrics/BlockLength: + Exclude: + - 'config/routes.rb' + +Metrics/ClassLength: + Enabled: false + +Metrics/CyclomaticComplexity: + Enabled: false + +Metrics/MethodLength: + Enabled: false + +Metrics/PerceivedComplexity: + Enabled: false + +Naming/AccessorMethodName: + Enabled: false + +Naming/MethodParameterName: + Enabled: false + +Naming/VariableName: + Enabled: false + +Naming/VariableNumber: + Enabled: false + +Style/FrozenStringLiteralComment: + Enabled: false + +Style/GlobalStdStream: + Enabled: false + +Style/GlobalVars: + Enabled: false + +Style/MixinUsage: + Exclude: + - 'bin/setup' + - 'bin/update' + +Style/RedundantFetchBlock: + Exclude: + - 'config/puma.rb' + - 'quick_acg/config/puma.rb' + +Style/SpecialGlobalVars: + Exclude: + - 'bin/bundle' + - 'quick_acg/bin/bundle' diff --git a/Gemfile b/Gemfile index 402403d..acb7ae6 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,4 @@ - # frozen_string_literal: true +# frozen_string_literal: true source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } @@ -54,6 +54,7 @@ group :development do # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'pry-nav', '~> 0.3.0' gem 'pry-rails', '~> 0.3.9' + gem 'rubocop', '~> 1.36', require: false gem 'spring', '~> 2.1.0' gem 'spring-watcher-listen', '~> 2.0.1' end @@ -66,11 +67,11 @@ group :test do gem 'chromedriver-helper', '~> 2.1.1' end +gem 'docusign_admin', '~> 1.1.0' +gem 'docusign_click', '~> 1.0.0' gem 'docusign_esign', '~> 3.17.0' gem 'docusign_monitor', '~> 1.1.0' gem 'docusign_rooms', '~> 1.2.0.rc1' -gem 'docusign_click', '~> 1.0.0' -gem 'docusign_admin', '~> 1.1.0' gem 'omniauth-oauth2', '~> 1.7.1' gem 'omniauth-rails_csrf_protection' diff --git a/Gemfile.lock b/Gemfile.lock index 36360c9..cbab39f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,75 +1,76 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.0.3) - actionpack (= 7.0.3) - activesupport (= 7.0.3) + actioncable (7.0.4) + actionpack (= 7.0.4) + activesupport (= 7.0.4) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.3) - actionpack (= 7.0.3) - activejob (= 7.0.3) - activerecord (= 7.0.3) - activestorage (= 7.0.3) - activesupport (= 7.0.3) + actionmailbox (7.0.4) + actionpack (= 7.0.4) + activejob (= 7.0.4) + activerecord (= 7.0.4) + activestorage (= 7.0.4) + activesupport (= 7.0.4) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.0.3) - actionpack (= 7.0.3) - actionview (= 7.0.3) - activejob (= 7.0.3) - activesupport (= 7.0.3) + actionmailer (7.0.4) + actionpack (= 7.0.4) + actionview (= 7.0.4) + activejob (= 7.0.4) + activesupport (= 7.0.4) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.0) - actionpack (7.0.3) - actionview (= 7.0.3) - activesupport (= 7.0.3) + actionpack (7.0.4) + actionview (= 7.0.4) + activesupport (= 7.0.4) rack (~> 2.0, >= 2.2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.3) - actionpack (= 7.0.3) - activerecord (= 7.0.3) - activestorage (= 7.0.3) - activesupport (= 7.0.3) + actiontext (7.0.4) + actionpack (= 7.0.4) + activerecord (= 7.0.4) + activestorage (= 7.0.4) + activesupport (= 7.0.4) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.3) - activesupport (= 7.0.3) + actionview (7.0.4) + activesupport (= 7.0.4) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (7.0.3) - activesupport (= 7.0.3) + activejob (7.0.4) + activesupport (= 7.0.4) globalid (>= 0.3.6) - activemodel (7.0.3) - activesupport (= 7.0.3) - activerecord (7.0.3) - activemodel (= 7.0.3) - activesupport (= 7.0.3) - activestorage (7.0.3) - actionpack (= 7.0.3) - activejob (= 7.0.3) - activerecord (= 7.0.3) - activesupport (= 7.0.3) + activemodel (7.0.4) + activesupport (= 7.0.4) + activerecord (7.0.4) + activemodel (= 7.0.4) + activesupport (= 7.0.4) + activestorage (7.0.4) + actionpack (= 7.0.4) + activejob (= 7.0.4) + activerecord (= 7.0.4) + activesupport (= 7.0.4) marcel (~> 1.0) mini_mime (>= 1.1.0) - activesupport (7.0.3) + activesupport (7.0.4) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) archive-zip (0.12.0) io-like (~> 0.3.0) + ast (2.4.2) bindex (0.8.1) bootsnap (1.7.7) msgpack (~> 1.0) @@ -97,7 +98,6 @@ GEM coffee-script-source (1.12.2) concurrent-ruby (1.1.10) crass (1.0.6) - digest (3.1.0) docusign_admin (1.1.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) @@ -123,30 +123,30 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - erubi (1.10.0) + erubi (1.11.0) ethon (0.15.0) ffi (>= 1.15.0) execjs (2.8.1) - faraday (2.3.0) - faraday-net_http (~> 2.0) + faraday (2.6.0) + faraday-net_http (>= 2.0, < 3.1) ruby2_keywords (>= 0.0.4) - faraday-net_http (2.0.3) + faraday-net_http (3.0.0) ffi (1.15.5-x64-mingw-ucrt) globalid (1.0.0) activesupport (>= 5.0) hashie (5.0.0) - i18n (1.11.0) + i18n (1.12.0) concurrent-ruby (~> 1.0) io-like (0.3.1) jbuilder (2.11.5) actionview (>= 5.0.0) activesupport (>= 5.0.0) json (2.6.2) - jwt (2.4.1) + jwt (2.5.0) listen (3.7.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.18.0) + loofah (2.19.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -154,32 +154,26 @@ GEM marcel (1.0.2) method_source (0.9.2) mini_mime (1.1.2) - minitest (5.16.2) - msgpack (1.5.3) + minitest (5.16.3) + msgpack (1.6.0) multi_xml (0.6.0) - net-imap (0.2.3) - digest + net-imap (0.3.1) net-protocol - strscan - net-pop (0.1.1) - digest + net-pop (0.1.2) net-protocol - timeout net-protocol (0.1.3) timeout - net-smtp (0.3.1) - digest + net-smtp (0.3.2) net-protocol - timeout nio4r (2.5.8) - nokogiri (1.13.6-x64-mingw-ucrt) + nokogiri (1.13.8-x64-mingw-ucrt) racc (~> 1.4) - oauth2 (2.0.5) + oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) jwt (>= 1.0, < 3.0) multi_xml (~> 0.5) - rack (>= 1.2, < 3) - rash_alt (>= 0.4, < 1) + rack (>= 1.2, < 4) + snaky_hash (~> 2.0) version_gem (~> 1.1) omniauth (2.1.0) hashie (>= 3.4.6) @@ -191,6 +185,9 @@ GEM omniauth-rails_csrf_protection (1.0.1) actionpack (>= 4.2) omniauth (~> 2.0) + parallel (1.22.1) + parser (3.1.2.1) + ast (~> 2.4.1) pry (0.12.2) coderay (~> 1.1.0) method_source (~> 0.9.0) @@ -198,48 +195,61 @@ GEM pry (>= 0.9.10, < 0.13.0) pry-rails (0.3.9) pry (>= 0.10.4) - public_suffix (4.0.7) - puma (5.6.4) + public_suffix (5.0.0) + puma (5.6.5) nio4r (~> 2.0) racc (1.6.0) rack (2.2.4) - rack-protection (2.2.0) + rack-protection (3.0.2) rack rack-test (2.0.2) rack (>= 1.3) - rails (7.0.3) - actioncable (= 7.0.3) - actionmailbox (= 7.0.3) - actionmailer (= 7.0.3) - actionpack (= 7.0.3) - actiontext (= 7.0.3) - actionview (= 7.0.3) - activejob (= 7.0.3) - activemodel (= 7.0.3) - activerecord (= 7.0.3) - activestorage (= 7.0.3) - activesupport (= 7.0.3) + rails (7.0.4) + actioncable (= 7.0.4) + actionmailbox (= 7.0.4) + actionmailer (= 7.0.4) + actionpack (= 7.0.4) + actiontext (= 7.0.4) + actionview (= 7.0.4) + activejob (= 7.0.4) + activemodel (= 7.0.4) + activerecord (= 7.0.4) + activestorage (= 7.0.4) + activesupport (= 7.0.4) bundler (>= 1.15.0) - railties (= 7.0.3) + railties (= 7.0.4) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.4.3) loofah (~> 2.3) - railties (7.0.3) - actionpack (= 7.0.3) - activesupport (= 7.0.3) + railties (7.0.4) + actionpack (= 7.0.4) + activesupport (= 7.0.4) method_source rake (>= 12.2) thor (~> 1.0) zeitwerk (~> 2.5) + rainbow (3.1.1) rake (13.0.6) - rash_alt (0.4.12) - hashie (>= 3.4) - rb-fsevent (0.11.1) + rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) regexp_parser (1.8.2) + rexml (3.2.5) + rubocop (1.36.0) + json (~> 2.3) + parallel (~> 1.10) + parser (>= 3.1.2.1) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.20.1, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 1.4.0, < 3.0) + rubocop-ast (1.21.0) + parser (>= 3.1.1.0) + ruby-progressbar (1.11.0) ruby2_keywords (0.0.5) rubyzip (2.3.2) sass-rails (6.0.0) @@ -255,6 +265,9 @@ GEM selenium-webdriver (3.142.7) childprocess (>= 0.5, < 4.0) rubyzip (>= 1.2.2) + snaky_hash (2.0.1) + hashie + version_gem (~> 1.1, >= 1.1.1) spring (2.1.1) spring-watcher-listen (2.0.1) listen (>= 2.7, < 4.0) @@ -267,22 +280,22 @@ GEM activesupport (>= 5.2) sprockets (>= 3.0.0) sqlite3 (1.4.4) - strscan (3.0.3) thor (1.2.1) - tilt (2.0.10) + tilt (2.0.11) timeout (0.3.0) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) typhoeus (1.4.0) ethon (>= 0.9.0) - tzinfo (2.0.4) + tzinfo (2.0.5) concurrent-ruby (~> 1.0) - tzinfo-data (1.2022.1) + tzinfo-data (1.2022.4) tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) - version_gem (1.1.0) + unicode-display_width (2.3.0) + version_gem (1.1.1) web-console (4.2.0) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -293,7 +306,7 @@ GEM websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.0) + zeitwerk (2.6.1) PLATFORMS x64-mingw-ucrt @@ -317,6 +330,7 @@ DEPENDENCIES pry-rails (~> 0.3.9) puma (~> 5.6.4) rails (~> 7.0.3) + rubocop (~> 1.36) sass-rails (~> 6.0.0) selenium-webdriver (~> 3.142.7) spring (~> 2.1.0) @@ -327,7 +341,6 @@ DEPENDENCIES uglifier (~> 4.2.0) wdm (>= 0.1.0) web-console (~> 4.2.0) - webrick (~> 1.7) RUBY VERSION ruby 3.1.2p20 diff --git a/app/controllers/admin_api/eg001_create_user_controller.rb b/app/controllers/admin_api/eg001_create_user_controller.rb index db516b1..e906caa 100644 --- a/app/controllers/admin_api/eg001_create_user_controller.rb +++ b/app/controllers/admin_api/eg001_create_user_controller.rb @@ -1,53 +1,49 @@ class AdminApi::Eg001CreateUserController < EgController include ApiCreator before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1) } def create - begin - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - organization_id: session['organization_id'] - } - user_data = { - user_name: param_gsub(params['user_name']), - first_name: param_gsub(params['first_name']), - last_name: param_gsub(params['last_name']), - email: param_gsub(params['email']), - auto_activate_memberships: true, - accounts: [ - { - id: args[:account_id], - permission_profile: { - id: request['permission_profile_id'] - }, - groups: [ - { - id: request['group_id'] - } - ] - } - ] - } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + organization_id: session['organization_id'] + } + user_data = { + user_name: param_gsub(params['user_name']), + first_name: param_gsub(params['first_name']), + last_name: param_gsub(params['last_name']), + email: param_gsub(params['email']), + auto_activate_memberships: true, + accounts: [ + { + id: args[:account_id], + permission_profile: { + id: request['permission_profile_id'] + }, + groups: [ + { + id: request['group_id'] + } + ] + } + ] + } - results = AdminApi::Eg001CreateUserService.new(args, user_data).worker + results = AdminApi::Eg001CreateUserService.new(args, user_data).worker - @title = 'Create a new active eSignature user' - @h1 = 'Create a new active eSignature user' - @message = "Results from eSignUserManagement:createUser method:" - @json = results.to_json.to_json - render 'ds_common/example_done' - rescue DocuSign_Admin::ApiError => e - handle_error(e) - end + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) end def get super - if session[:organization_id].nil? - session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id - end + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? args = { account_id: session['ds_account_id'], base_path: session['ds_base_path'], @@ -60,5 +56,4 @@ def get groups_api = create_group_api(args) @groups = groups_api.list_groups(args[:account_id]).groups end - end diff --git a/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb b/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb index 12e38ec..b813ddf 100644 --- a/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb +++ b/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb @@ -1,55 +1,51 @@ class AdminApi::Eg002CreateActiveClmEsignUserController < EgController - before_action :check_auth + before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2) } - def create - begin - args = { - user_name: params[:user_name], - first_name: params[:first_name], - last_name: params[:last_name], - email: params[:email], - clm_permission_profile_id: params[:clm_permission_profile_id], - esign_permission_profile_id: params[:esign_permission_profile_id], - clm_product_id: params[:clm_product_id], - esign_product_id: params[:esign_product_id], - ds_group_id: params[:ds_group_id], - account_id: session[:ds_account_id], - organization_id: session['organization_id'], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } + def create + args = { + user_name: params[:user_name], + first_name: params[:first_name], + last_name: params[:last_name], + email: params[:email], + clm_permission_profile_id: params[:clm_permission_profile_id], + esign_permission_profile_id: params[:esign_permission_profile_id], + clm_product_id: params[:clm_product_id], + esign_product_id: params[:esign_product_id], + ds_group_id: params[:ds_group_id], + account_id: session[:ds_account_id], + organization_id: session['organization_id'], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } - results = AdminApi::Eg002CreateActiveClmEsignUserService.new(args).worker + results = AdminApi::Eg002CreateActiveClmEsignUserService.new(args).worker - session[:clm_email] = params[:email] + session[:clm_email] = params[:email] - @title = "Create a new active user for CLM and eSignature" - @h1 = "Create a new active user for CLM and eSignature" - @message = "Results from MultiProductUserManagement::addOrUpdateUser method:" - @json = results.to_json.to_json + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json - render 'ds_common/example_done' - rescue DocuSign_Admin::ApiError => e - handle_error(e) - end - end + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) + end - def get - super - if session[:organization_id].nil? - session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id - end - product_permission_profiles = AdminApi::GetDataService.new(session).get_product_permission_profiles + def get + super + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? + product_permission_profiles = AdminApi::GetDataService.new(session).get_product_permission_profiles - product_permission_profiles.each do |product_permission_profile| - if product_permission_profile['product_name'] == "CLM" - @clm_permission_profiles = product_permission_profile['permission_profiles'] - @clm_product_id = product_permission_profile['product_id'] - else - @esign_permission_profiles = product_permission_profile['permission_profiles'] - @esign_product_id = product_permission_profile['product_id'] - end + product_permission_profiles.each do |product_permission_profile| + if product_permission_profile['product_name'] == 'CLM' + @clm_permission_profiles = product_permission_profile['permission_profiles'] + @clm_product_id = product_permission_profile['product_id'] + else + @esign_permission_profiles = product_permission_profile['permission_profiles'] + @esign_product_id = product_permission_profile['product_id'] end - @ds_groups = AdminApi::GetDataService.new(session).get_ds_groups end + @ds_groups = AdminApi::GetDataService.new(session).get_ds_groups end +end diff --git a/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb b/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb index e67b553..6177eda 100644 --- a/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb +++ b/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb @@ -1,10 +1,9 @@ class AdminApi::Eg003BulkExportUserDataController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 3) } def create - if session[:organization_id].nil? - session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id - end + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? file_path = File.expand_path(File.join(File.dirname(__FILE__), '../../../data/exportedUserData.csv')) @@ -23,9 +22,8 @@ def create results = AdminApi::Eg003BulkExportUserDataService.new(args).worker - @title = 'Bulk-export user data' - @h1 = 'Bulk-export user data' - @message = "User data exported to #{file_path}.
    Results from UserExport::getUserListExport method:" + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], file_path) @json = results.to_json.to_json render 'ds_common/example_done' rescue DocuSign_Admin::ApiError => e diff --git a/app/controllers/admin_api/eg004_import_user_controller.rb b/app/controllers/admin_api/eg004_import_user_controller.rb index 12598df..b1f0dcf 100644 --- a/app/controllers/admin_api/eg004_import_user_controller.rb +++ b/app/controllers/admin_api/eg004_import_user_controller.rb @@ -1,10 +1,9 @@ class AdminApi::Eg004ImportUserController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 4) } def create - if session[:organization_id].nil? - session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id - end + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? file_path = File.expand_path(File.join(File.dirname(__FILE__), '../../../data/userData.csv')) @@ -20,10 +19,9 @@ def create results = AdminApi::Eg004ImportUserService.new(args).worker session[:import_id] = results.id - @title = 'Add users via bulk import' - @h1 = 'Add users via bulk import' - @check_status=true, - @message = "Results from UserImport::addBulkUserImport method:" + @title = @example['ExampleName'] + @check_status = true, + @message = @example['ResultsPageText'] @json = results.to_json.to_json render 'ds_common/example_done' rescue DocuSign_Admin::ApiError => e @@ -32,18 +30,15 @@ def create end def check_status - if session[:organization_id].nil? - session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id - end + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? begin import_id = session[:import_id] results = AdminApi::GetDataService.new(session).check_import_status(import_id) @status = results.status - @title = 'Add users via bulk import' - @h1 = 'Add users via bulk import' - @message = "Results from UserImport::getbulkuserimportrequest method:" + @title = @example['ExampleName'] + @message = @example['AdditionalPage'][0]['ResultsPageText'] @json = results.to_json.to_json render 'admin_api/eg004_import_user/get_status.html.erb' rescue DocuSign_Admin::ApiError => e diff --git a/app/controllers/admin_api/eg005_audit_users_controller.rb b/app/controllers/admin_api/eg005_audit_users_controller.rb index e9de6bf..70c7a95 100644 --- a/app/controllers/admin_api/eg005_audit_users_controller.rb +++ b/app/controllers/admin_api/eg005_audit_users_controller.rb @@ -1,29 +1,27 @@ class AdminApi::Eg005AuditUsersController < EgController - before_action :check_auth + before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 5) } - def create - if session[:organization_id].nil? - session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id - end + def create + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? - begin - args = { - account_id: session[:ds_account_id], - organization_id: session['organization_id'], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } + begin + args = { + account_id: session[:ds_account_id], + organization_id: session['organization_id'], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } - results = AdminApi::Eg005AuditUsersService.new(args).worker + results = AdminApi::Eg005AuditUsersService.new(args).worker - @title = "Audit users" - @h1 = "Audit users" - @message = "Results from eSignUserManagement:getUserProfiles method:" - @json = results.to_json.to_json + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json - render 'ds_common/example_done' - rescue DocuSign_Admin::ApiError => e - handle_error(e) - end + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) end end +end diff --git a/app/controllers/admin_api/eg006_get_user_profile_by_email_controller.rb b/app/controllers/admin_api/eg006_get_user_profile_by_email_controller.rb index b6a4796..51858f8 100644 --- a/app/controllers/admin_api/eg006_get_user_profile_by_email_controller.rb +++ b/app/controllers/admin_api/eg006_get_user_profile_by_email_controller.rb @@ -1,28 +1,24 @@ class AdminApi::Eg006GetUserProfileByEmailController < EgController include ApiCreator before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 6) } def create - begin - if session[:organization_id].nil? - session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id - end + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? - args = { - access_token: session['ds_access_token'], - organization_id: session['organization_id'], - email: param_gsub(params['email']) - } + args = { + access_token: session['ds_access_token'], + organization_id: session['organization_id'], + email: param_gsub(params['email']) + } - results = AdminApi::Eg006GetUserProfileByEmailService.new(args).worker + results = AdminApi::Eg006GetUserProfileByEmailService.new(args).worker - @title = 'Retrieve the user’s DocuSign profile using an email address' - @h1 = 'Retrieve the user’s DocuSign profile using an email address' - @message = "Results from MultiProductUserManagement:getUserDSProfilesByEmail method:" - @json = results.to_json.to_json - render 'ds_common/example_done' - rescue DocuSign_Admin::ApiError => e - handle_error(e) - end + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) end end diff --git a/app/controllers/admin_api/eg007_get_user_profile_by_user_id_controller.rb b/app/controllers/admin_api/eg007_get_user_profile_by_user_id_controller.rb index 6f1c8ee..d3e06e0 100644 --- a/app/controllers/admin_api/eg007_get_user_profile_by_user_id_controller.rb +++ b/app/controllers/admin_api/eg007_get_user_profile_by_user_id_controller.rb @@ -1,28 +1,24 @@ class AdminApi::Eg007GetUserProfileByUserIdController < EgController include ApiCreator before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 7) } def create - begin - if session[:organization_id].nil? - session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id - end + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? - args = { - access_token: session['ds_access_token'], - organization_id: session['organization_id'], - user_id: param_gsub(params['user_id']) - } + args = { + access_token: session['ds_access_token'], + organization_id: session['organization_id'], + user_id: param_gsub(params['user_id']) + } - results = AdminApi::Eg007GetUserProfileByUserIdService.new(args).worker + results = AdminApi::Eg007GetUserProfileByUserIdService.new(args).worker - @title = 'Retrieve the user’s DocuSign profile using a User ID' - @h1 = 'Retrieve the user’s DocuSign profile using a User ID' - @message = "Results from MultiProductUserManagement:getUserDSProfile method:" - @json = results.to_json.to_json - render 'ds_common/example_done' - rescue DocuSign_Admin::ApiError => e - handle_error(e) - end + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) end end diff --git a/app/controllers/admin_api/eg008_update_user_product_permission_profile_controller.rb b/app/controllers/admin_api/eg008_update_user_product_permission_profile_controller.rb index 2847328..bbca1f0 100644 --- a/app/controllers/admin_api/eg008_update_user_product_permission_profile_controller.rb +++ b/app/controllers/admin_api/eg008_update_user_product_permission_profile_controller.rb @@ -1,84 +1,82 @@ class AdminApi::Eg008UpdateUserProductPermissionProfileController < EgController - before_action :check_auth + before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 8) } - def create - clm_email = session[:clm_email] - get_data_service = AdminApi::GetDataService.new(session) + def create + clm_email = session[:clm_email] + get_data_service = AdminApi::GetDataService.new(session) - unless clm_email && get_data_service.check_user_exists_by_email(clm_email) - @email_ok = false - return - end + unless clm_email && get_data_service.check_user_exists_by_email(clm_email) + @email_ok = false + return + end + + begin + product_permission_profiles = get_data_service.get_product_permission_profiles + product_id = params[:product_id] + permission_profile_id = nil - begin - product_permission_profiles = get_data_service.get_product_permission_profiles - product_id = params[:product_id] - permission_profile_id = nil + product_permission_profiles.each do |profile| + next unless product_id == profile['product_id'] - product_permission_profiles.each { |profile| - if product_id == profile['product_id'] - if profile['product_name'] == "CLM" - permission_profile_id = params[:clm_permission_profile_id] - else - permission_profile_id = params[:esign_permission_profile_id] - end - end - } + permission_profile_id = if profile['product_name'] == 'CLM' + params[:clm_permission_profile_id] + else + params[:esign_permission_profile_id] + end + end - args = { - email: clm_email, - permission_profile_id: permission_profile_id, - product_id: product_id, - account_id: session[:ds_account_id], - organization_id: session['organization_id'], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token] - } + args = { + email: clm_email, + permission_profile_id: permission_profile_id, + product_id: product_id, + account_id: session[:ds_account_id], + organization_id: session['organization_id'], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } - results = AdminApi::Eg008UpdateUserProductPermissionProfileService.new(args).worker + results = AdminApi::Eg008UpdateUserProductPermissionProfileService.new(args).worker - @title = "Update user product permission profiles using an email address" - @h1 = "Update user product permission profiles using an email address" - @message = "Results from MultiProductUserManagement:addUserProductPermissionProfilesByEmail method:" - @json = results.to_json.to_json + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json - render 'ds_common/example_done' - rescue DocuSign_Admin::ApiError => e - handle_error(e) - end + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) end + end - def get - super - get_data_service = AdminApi::GetDataService.new(session) + def get + super + get_data_service = AdminApi::GetDataService.new(session) - if session[:organization_id].nil? - session[:organization_id] = get_data_service.get_organization_id - end + session[:organization_id] = get_data_service.get_organization_id if session[:organization_id].nil? - clm_email = session[:clm_email] + clm_email = session[:clm_email] - unless clm_email && get_data_service.check_user_exists_by_email(clm_email) - @email_ok = false - return - end + unless clm_email && get_data_service.check_user_exists_by_email(clm_email) + @email_ok = false + return + end - product_permission_profiles = get_data_service.get_product_permission_profiles + product_permission_profiles = get_data_service.get_product_permission_profiles - product_permission_profiles.each do |product_permission_profile| - if product_permission_profile['product_name'] == "CLM" - @clm_permission_profiles = product_permission_profile['permission_profiles'] - @clm_product_id = product_permission_profile['product_id'] - else - @esign_permission_profiles = product_permission_profile['permission_profiles'] - @esign_product_id = product_permission_profile['product_id'] - end + product_permission_profiles.each do |product_permission_profile| + if product_permission_profile['product_name'] == 'CLM' + @clm_permission_profiles = product_permission_profile['permission_profiles'] + @clm_product_id = product_permission_profile['product_id'] + else + @esign_permission_profiles = product_permission_profile['permission_profiles'] + @esign_product_id = product_permission_profile['product_id'] end - product_list = [] - product_list.push({ "product_id" => @clm_product_id, "product_name" => "CLM" }) - product_list.push({ "product_id" => @esign_product_id, "product_name" => "eSignature" }) - @product_list = product_list - @email_ok = true - @email = clm_email end + product_list = [] + product_list.push({ 'product_id' => @clm_product_id, 'product_name' => 'CLM' }) + product_list.push({ 'product_id' => @esign_product_id, 'product_name' => 'eSignature' }) + @product_list = product_list + @email_ok = true + @email = clm_email end +end diff --git a/app/controllers/admin_api/eg009_delete_user_product_permission_profile_controller.rb b/app/controllers/admin_api/eg009_delete_user_product_permission_profile_controller.rb index 3248fb1..52c6183 100644 --- a/app/controllers/admin_api/eg009_delete_user_product_permission_profile_controller.rb +++ b/app/controllers/admin_api/eg009_delete_user_product_permission_profile_controller.rb @@ -1,89 +1,83 @@ class AdminApi::Eg009DeleteUserProductPermissionProfileController < EgController - before_action :check_auth + before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 9) } - def create - clm_email = session[:clm_email] - get_data_service = AdminApi::GetDataService.new(session) + def create + clm_email = session[:clm_email] + get_data_service = AdminApi::GetDataService.new(session) - unless clm_email && get_data_service.check_user_exists_by_email(clm_email) - @email_ok = false - return - end - - begin - args = { - email: clm_email, - product_id: params[:product_id], - account_id: session[:ds_account_id], - organization_id: session['organization_id'], - access_token: session[:ds_access_token] - } - - results = AdminApi::Eg009DeleteUserProductPermissionProfileService.new(args).worker - - @title = "Delete user product permission profiles using an email address" - @h1 = "Delete user product permission profiles using an email address" - @message = "Results from MultiProductUserManagement:removeUserProductPermission method:" - @json = results.to_json.to_json - - render 'ds_common/example_done' - rescue DocuSign_Admin::ApiError => e - handle_error(e) - end + unless clm_email && get_data_service.check_user_exists_by_email(clm_email) + @email_ok = false + return end - def get - super - get_data_service = AdminApi::GetDataService.new(session) - - if session[:organization_id].nil? - session[:organization_id] = get_data_service.get_organization_id - end - - clm_email = session[:clm_email] - - unless clm_email && get_data_service.check_user_exists_by_email(clm_email) - @email_ok = false - return - end - + begin args = { email: clm_email, + product_id: params[:product_id], account_id: session[:ds_account_id], organization_id: session['organization_id'], access_token: session[:ds_access_token] } - product_permission_profiles = AdminApi::Eg009DeleteUserProductPermissionProfileService.new(args).get_permission_profiles_by_email - permission_profile_list = [] - clm_product_id = nil - clm_permission_profile_name = nil - esign_product_id = nil - esign_permission_profile_name = nil - - product_permission_profiles.each do |product_permission_profile| - permission_profiles = product_permission_profile["permission_profiles"] - permission_profiles.each do |permission_profile| - if product_permission_profile['product_name'] == "CLM" - clm_permission_profile_name = permission_profile['permission_profile_name'] - clm_product_id = product_permission_profile['product_id'] - else - esign_permission_profile_name = permission_profile['permission_profile_name'] - esign_product_id = product_permission_profile['product_id'] - end + results = AdminApi::Eg009DeleteUserProductPermissionProfileService.new(args).worker + + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json + + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) + end + end + + def get + super + get_data_service = AdminApi::GetDataService.new(session) + + session[:organization_id] = get_data_service.get_organization_id if session[:organization_id].nil? + + clm_email = session[:clm_email] + + unless clm_email && get_data_service.check_user_exists_by_email(clm_email) + @email_ok = false + return + end + + args = { + email: clm_email, + account_id: session[:ds_account_id], + organization_id: session['organization_id'], + access_token: session[:ds_access_token] + } + + product_permission_profiles = AdminApi::Eg009DeleteUserProductPermissionProfileService.new(args).get_permission_profiles_by_email + permission_profile_list = [] + clm_product_id = nil + clm_permission_profile_name = nil + esign_product_id = nil + esign_permission_profile_name = nil + + product_permission_profiles.each do |product_permission_profile| + permission_profiles = product_permission_profile['permission_profiles'] + permission_profiles.each do |permission_profile| + if product_permission_profile['product_name'] == 'CLM' + clm_permission_profile_name = permission_profile['permission_profile_name'] + clm_product_id = product_permission_profile['product_id'] + else + esign_permission_profile_name = permission_profile['permission_profile_name'] + esign_product_id = product_permission_profile['product_id'] end end + end - if clm_product_id - permission_profile_list.push({"product_id" => clm_product_id, "permission_name" => "CLM - #{clm_permission_profile_name}"}) - end + permission_profile_list.push({ 'product_id' => clm_product_id, 'permission_name' => "CLM - #{clm_permission_profile_name}" }) if clm_product_id - if esign_product_id - permission_profile_list.push({"product_id" => esign_product_id, "permission_name" => "eSignature - #{esign_permission_profile_name}"}) - end + permission_profile_list.push({ 'product_id' => esign_product_id, 'permission_name' => "eSignature - #{esign_permission_profile_name}" }) if esign_product_id - @permission_profile_list = permission_profile_list - @email_ok = true - @email = clm_email - end + @permission_profile_list = permission_profile_list + @email_ok = true + @email = clm_email end +end diff --git a/app/controllers/clickwrap/eg001_create_clickwrap_controller.rb b/app/controllers/clickwrap/eg001_create_clickwrap_controller.rb index 34b2916..e6b4eb4 100644 --- a/app/controllers/clickwrap/eg001_create_clickwrap_controller.rb +++ b/app/controllers/clickwrap/eg001_create_clickwrap_controller.rb @@ -1,5 +1,6 @@ class Clickwrap::Eg001CreateClickwrapController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1) } def create args = { @@ -14,9 +15,8 @@ def create session[:clickwrap_id] = results.clickwrap_id session[:clickwrap_name] = results.clickwrap_name - @title = 'Create a clickwrap' - @h1 = 'Create a clickwrap' - @message = "The clickwrap #{results.clickwrap_name} has been created." + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results.clickwrap_name) @json = results.to_json.to_json render 'ds_common/example_done' end diff --git a/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb b/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb index 4621f57..1d89be3 100644 --- a/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb +++ b/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb @@ -1,5 +1,6 @@ class Clickwrap::Eg002ActivateClickwrapController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2) } def create args = { @@ -9,11 +10,10 @@ def create clickwrap_id: session[:clickwrap_id] } - results = Clickwrap::Eg002ActivateClickwrapService.new(args).worker + Clickwrap::Eg002ActivateClickwrapService.new(args).worker - @title = 'Activate a new clickwrap' - @h1 = 'Activate a new clickwrap' - @message = "The clickwrap #{results.clickwrap_name} has been activated." + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] render 'ds_common/example_done' end end diff --git a/app/controllers/clickwrap/eg003_create_new_clickwrap_version_controller.rb b/app/controllers/clickwrap/eg003_create_new_clickwrap_version_controller.rb index 5980d5c..a77e347 100644 --- a/app/controllers/clickwrap/eg003_create_new_clickwrap_version_controller.rb +++ b/app/controllers/clickwrap/eg003_create_new_clickwrap_version_controller.rb @@ -1,5 +1,6 @@ class Clickwrap::Eg003CreateNewClickwrapVersionController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 3) } def create args = { @@ -12,9 +13,8 @@ def create results = Clickwrap::Eg003CreateNewClickwrapVersionService.new(args).worker puts results.to_json.to_json - @title = 'Create a new clickwrap version' - @h1 = 'Create a new clickwrap version' - @message = "Version #{results.version_number} of clickwrap #{results.clickwrap_name} has been created." + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results.version_number, results.clickwrap_name) render 'ds_common/example_done' end end diff --git a/app/controllers/clickwrap/eg004_list_clickwraps_controller.rb b/app/controllers/clickwrap/eg004_list_clickwraps_controller.rb index d05e5b1..c5ce68b 100644 --- a/app/controllers/clickwrap/eg004_list_clickwraps_controller.rb +++ b/app/controllers/clickwrap/eg004_list_clickwraps_controller.rb @@ -1,5 +1,6 @@ class Clickwrap::Eg004ListClickwrapsController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 4) } def create args = { @@ -10,9 +11,8 @@ def create results = Clickwrap::Eg004ListClickwrapsService.new(args).worker - @title = 'Get a list of clickwraps' - @h1 = 'Get a list of clickwraps' - @message = "Results from the ClickWraps::getClickwraps method:" + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] @json = results.to_json.to_json render 'ds_common/example_done' end diff --git a/app/controllers/clickwrap/eg005_clickwrap_responses_controller.rb b/app/controllers/clickwrap/eg005_clickwrap_responses_controller.rb index 547abc6..e2cbaef 100644 --- a/app/controllers/clickwrap/eg005_clickwrap_responses_controller.rb +++ b/app/controllers/clickwrap/eg005_clickwrap_responses_controller.rb @@ -1,5 +1,6 @@ class Clickwrap::Eg005ClickwrapResponsesController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 5) } def create args = { @@ -12,9 +13,8 @@ def create results = Clickwrap::Eg005ClickwrapResponsesService.new(args).worker - @title = 'Get clickwrap responses' - @h1 = 'Get clickwrap responses' - @message = "Results from the ClickWraps::getClickwrapAgreements method:" + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] @json = results.to_json.to_json render 'ds_common/example_done' end diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index 033dd36..96fbfe5 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -11,10 +11,12 @@ def index def handle_redirects if Rails.configuration.quickstart + @manifest = Utils::ManifestUtils.new.get_manifest(Rails.configuration.eSignManifestUrl) + if session[:quickstarted].nil? session[:examples_API] = 'eSignature' session[:quickstarted] = true - redirect_to "/auth/docusign" + redirect_to '/auth/docusign' elsif session[:been_here].nil? redirect_to '/eg001' else @@ -26,6 +28,8 @@ def handle_redirects end def render_examples + load_corresponding_manifest + if session[:examples_API].nil? choose_api elsif session[:examples_API] == 'Rooms' @@ -42,6 +46,7 @@ def render_examples end def choose_api + load_corresponding_manifest render 'ds_common/choose_api' end @@ -61,48 +66,46 @@ def ds_return end def ds_must_authenticate - if session[:examples_API] == 'Monitor' - jwt_auth - end - if Rails.configuration.quickstart and session[:been_here].nil? and session[:examples_API] == 'eSignature' - redirect_to "/auth/docusign" - end + load_corresponding_manifest + + jwt_auth if session[:examples_API] == 'Monitor' + redirect_to '/auth/docusign' if Rails.configuration.quickstart && session[:been_here].nil? && (session[:examples_API] == 'eSignature') @title = 'Authenticate with DocuSign' @show_doc = Rails.application.config.documentation - if params[:auth] == 'grand-auth' - redirect_to "/auth/docusign" - elsif params[:auth] == 'jwt-auth' + case params[:auth] + when 'grand-auth' + redirect_to '/auth/docusign' + when 'jwt-auth' jwt_auth end end def jwt_auth if JwtAuth::JwtCreator.new(session).check_jwt_token - if session[:eg] - url = "/" + session[:eg] - else - url = root_path - end + url = if session[:eg] + "/#{session[:eg]}" + else + root_path + end else session['omniauth.state'] = SecureRandom.hex url = JwtAuth::JwtCreator.consent_url(session['omniauth.state'], session['examples_API']) - redirect_to root_path if session[:token].present? + redirect_to root_path if session[:token].present? end - if session[:examples_API] == 'Rooms' + case session[:examples_API] + when 'Rooms' configuration = DocuSign_Rooms::Configuration.new - api_client = DocuSign_Rooms::ApiClient.new(configuration) - elsif session[:examples_API] == 'Click' + DocuSign_Rooms::ApiClient.new(configuration) + when 'Click' configuration = DocuSign_Click::Configuration.new - api_client = DocuSign_Click::ApiClient.new configuration - elsif session[:examples_API] == 'Admin' + DocuSign_Click::ApiClient.new configuration + when 'Admin' configuration = DocuSign_Admin::Configuration.new - api_client = DocuSign_Admin::ApiClient.new configuration + DocuSign_Admin::ApiClient.new configuration end resp = ::JwtAuth::JwtCreator.new(session).check_jwt_token - if resp.is_a? String - redirect_to resp - end + redirect_to resp if resp.is_a? String redirect_to url end @@ -110,4 +113,23 @@ def example_done; end def error; end + private + + def load_corresponding_manifest + manifest_url = if session[:examples_API].nil? + Rails.configuration.eSignManifestUrl + elsif session[:examples_API] == 'Rooms' + Rails.configuration.roomsManifestUrl + elsif session[:examples_API] == 'Click' + Rails.configuration.clickManifestUrl + elsif session[:examples_API] == 'Monitor' + Rails.configuration.monitorManifestUrl + elsif session[:examples_API] == 'Admin' + Rails.configuration.adminManifestUrl + else + Rails.configuration.eSignManifestUrl + end + + @manifest = Utils::ManifestUtils.new.get_manifest(manifest_url) + end end diff --git a/app/controllers/e_sign/eg002_signing_via_email_controller.rb b/app/controllers/e_sign/eg002_signing_via_email_controller.rb index 124231c..f446636 100644 --- a/app/controllers/e_sign/eg002_signing_via_email_controller.rb +++ b/app/controllers/e_sign/eg002_signing_via_email_controller.rb @@ -1,33 +1,33 @@ # frozen_string_literal: true +require_relative '../../services/utils' + class ESign::Eg002SigningViaEmailController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2) } def create - begin - envelope_args = { - signer_email: param_gsub(params['signerEmail']), - signer_name: param_gsub(params['signerName']), - cc_email: param_gsub(params['ccEmail']), - cc_name: param_gsub(params['ccName']), - status: 'sent', - doc_docx: File.join('data', Rails.application.config.doc_docx), - doc_pdf: File.join('data', Rails.application.config.doc_pdf) - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } - results = ESign::Eg002SigningViaEmailService.new(args).worker - session[:envelope_id] = results['envelope_id'] - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The envelope has been created and sent!
    Envelope ID #{results['envelope_id']}." - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + cc_email: param_gsub(params['ccEmail']), + cc_name: param_gsub(params['ccName']), + status: 'sent', + doc_docx: File.join('data', Rails.application.config.doc_docx), + doc_pdf: File.join('data', Rails.application.config.doc_pdf) + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + results = ESign::Eg002SigningViaEmailService.new(args).worker + session[:envelope_id] = results['envelope_id'] + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results['envelope_id']) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end diff --git a/app/controllers/e_sign/eg003_list_envelopes_controller.rb b/app/controllers/e_sign/eg003_list_envelopes_controller.rb index 06822b1..f6d4442 100644 --- a/app/controllers/e_sign/eg003_list_envelopes_controller.rb +++ b/app/controllers/e_sign/eg003_list_envelopes_controller.rb @@ -2,6 +2,7 @@ class ESign::Eg003ListEnvelopesController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 3) } def create args = { @@ -10,8 +11,8 @@ def create access_token: session[:ds_access_token] } results = ESign::Eg003ListEnvelopesService.new(args).worker - @h1 = 'List envelopes results' - @message = 'Results from the Envelopes::listStatusChanges method:' + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] @json = results.to_json.to_json render 'ds_common/example_done' end diff --git a/app/controllers/e_sign/eg004_envelope_info_controller.rb b/app/controllers/e_sign/eg004_envelope_info_controller.rb index 3a211a1..8a96792 100644 --- a/app/controllers/e_sign/eg004_envelope_info_controller.rb +++ b/app/controllers/e_sign/eg004_envelope_info_controller.rb @@ -2,6 +2,7 @@ class ESign::Eg004EnvelopeInfoController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 4) } def create envelope_id = session[:envelope_id] @@ -16,16 +17,15 @@ def create } results = ESign::Eg004EnvelopeInfoService.new(args).worker # results is an object that implements ArrayAccess. Convert to a regular array: - @title = 'Envelope status results' - @h1 = 'Envelope status results' - @message = 'Results from the Envelopes::get method:' - @json = results.to_json.to_json + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e + rescue DocuSign_eSign::ApiError => e handle_error(e) end elsif !envelope_id - @title = 'Envelope information' + @title = @example['ExampleName'] @envelope_ok = false end end diff --git a/app/controllers/e_sign/eg005_envelope_recipients_controller.rb b/app/controllers/e_sign/eg005_envelope_recipients_controller.rb index e153a8a..a346c70 100644 --- a/app/controllers/e_sign/eg005_envelope_recipients_controller.rb +++ b/app/controllers/e_sign/eg005_envelope_recipients_controller.rb @@ -3,6 +3,7 @@ class ESign::Eg005EnvelopeRecipientsController < EgController include ApiCreator before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 5) } skip_before_action :set_meta def create @@ -19,16 +20,15 @@ def create begin results = ESign::Eg005EnvelopeRecipientsService.new(args).worker - @title = 'Envelope recipients results' - @h1 = 'List the envelope\'s recipients and their status' + @title = @example['ExampleName'] @message = 'Results from the EnvelopesRecipients::list method:' @json = results.to_json.to_json render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e + rescue DocuSign_eSign::ApiError => e handle_error(e) end elsif !envelope_id - @title = 'Envelope recipient information' + @title = @example['ExampleName'] @envelope_ok = false end end diff --git a/app/controllers/e_sign/eg006_envelope_docs_controller.rb b/app/controllers/e_sign/eg006_envelope_docs_controller.rb index 10b856c..e404cb0 100644 --- a/app/controllers/e_sign/eg006_envelope_docs_controller.rb +++ b/app/controllers/e_sign/eg006_envelope_docs_controller.rb @@ -2,6 +2,7 @@ class ESign::Eg006EnvelopeDocsController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 6) } def create envelope_id = session[:envelope_id] @@ -25,11 +26,11 @@ def create # The certificate of completion is named "summary" # We give it a better name below. envelope_doc_items = results.envelope_documents.map do |doc| - if doc.document_id == 'certificate' - new = { document_id: doc.document_id, name: 'Certificate of completion', type: doc.type } - else - new = { document_id: doc.document_id, name: doc.name, type: doc.type } - end + new = if doc.document_id == 'certificate' + { document_id: doc.document_id, name: 'Certificate of completion', type: doc.type } + else + { document_id: doc.document_id, name: doc.name, type: doc.type } + end new end @@ -37,16 +38,15 @@ def create envelope_documents = { envelope_id: args[:envelope_id], documents: documents } session[:envelope_documents] = envelope_documents - @title = 'Envelope documents list' - @h1 = 'List the envelope\'s documents' - @message = 'Results from the EnvelopeDocuments::list method:' - @json = results.to_json.to_json + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json render 'ds_common/example_done' rescue DocuSign_eSign::ApiError => e handle_error(e) end elsif !envelope_id - @title = 'Envelope recipient information' + @title = @example['ExampleName'] @envelope_ok = false end end diff --git a/app/controllers/e_sign/eg007_envelope_get_doc_controller.rb b/app/controllers/e_sign/eg007_envelope_get_doc_controller.rb index a72dff6..8363f94 100644 --- a/app/controllers/e_sign/eg007_envelope_get_doc_controller.rb +++ b/app/controllers/e_sign/eg007_envelope_get_doc_controller.rb @@ -2,6 +2,7 @@ class ESign::Eg007EnvelopeGetDocController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 7) } def create envelope_id = session[:envelope_id] @@ -25,7 +26,7 @@ def create handle_error(e) end elsif !envelope_id || !envelope_documents - @title = 'Download an envelope\'s document' + @title = @example['ExampleName'] @envelope_ok = false @documents_ok = false end diff --git a/app/controllers/e_sign/eg008_create_template_controller.rb b/app/controllers/e_sign/eg008_create_template_controller.rb index e991f1b..53bdb43 100644 --- a/app/controllers/e_sign/eg008_create_template_controller.rb +++ b/app/controllers/e_sign/eg008_create_template_controller.rb @@ -2,29 +2,26 @@ class ESign::Eg008CreateTemplateController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 8) } def create - begin - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - template_name: 'Example Signer and CC template' - } - results = ESign::Eg008CreateTemplateService.new(args).worker - session[:template_id] = results[:template_id] - msg = if results.fetch(:created_new_template) - 'The template has been created!' - else - 'Done. The template already existed in your account.' - end - @title = 'Template results' - @h1 = 'Template results' - @message = "#{msg}
    Template name: #{results[:template_name]}, - ID #{results[:template_id]}." - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + template_name: 'Example Signer and CC template' + } + results = ESign::Eg008CreateTemplateService.new(args).worker + session[:template_id] = results[:template_id] + msg = if results.fetch(:created_new_template) + 'The template has been created!' + else + 'Done. The template already existed in your account.' + end + @title = @example['ExampleName'] + @message = "#{msg} #{format_string(@example['ResultsPageText'], results[:template_name], results[:template_id])}" + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end diff --git a/app/controllers/e_sign/eg009_use_template_controller.rb b/app/controllers/e_sign/eg009_use_template_controller.rb index 1c3729d..fc98f48 100644 --- a/app/controllers/e_sign/eg009_use_template_controller.rb +++ b/app/controllers/e_sign/eg009_use_template_controller.rb @@ -2,6 +2,7 @@ class ESign::Eg009UseTemplateController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 9) } def create template_id = session[:template_id] @@ -15,7 +16,7 @@ def create cc_name: params['ccName'], template_id: template_id } - + args = { account_id: session['ds_account_id'], base_path: session['ds_base_path'], @@ -25,15 +26,14 @@ def create results = ESign::Eg009UseTemplateService.new(args).worker # results is an object that implements ArrayAccess. Convert to a regular array: - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The envelope has been created and sent!
    Envelope ID #{results[:envelope_id]}." + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results[:envelope_id]) render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e + rescue DocuSign_eSign::ApiError => e handle_error(e) end elsif !template_id - @title = 'Use a template to send an envelope' + @title = @example['ExampleName'] @template_ok = false end end diff --git a/app/controllers/e_sign/eg010_send_binary_docs_controller.rb b/app/controllers/e_sign/eg010_send_binary_docs_controller.rb index 18992f9..f0ed354 100644 --- a/app/controllers/e_sign/eg010_send_binary_docs_controller.rb +++ b/app/controllers/e_sign/eg010_send_binary_docs_controller.rb @@ -1,38 +1,36 @@ class ESign::Eg010SendBinaryDocsController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 10) } def create - begin - envelope_args = { - # Validation: Delete any non-usual characters - signer_email: param_gsub(params['signerEmail']), - signer_name: param_gsub(params['signerName']), - cc_email: param_gsub(params['ccEmail']), - cc_name: param_gsub(params['ccName']) - } - - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } + envelope_args = { + # Validation: Delete any non-usual characters + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + cc_email: param_gsub(params['ccEmail']), + cc_name: param_gsub(params['ccName']) + } - results = ESign::Eg010SendBinaryDocsService.new(args).worker - session[:envelope_id] = results['envelope_id'] - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The envelope has been created and sent!
    Envelope ID #{results['envelope_id']}." - render 'ds_common/example_done' - rescue Net::HTTPError => e - if !e.response.nil? - json_response = JSON.parse e.response - @error_code = json_response['errorCode'] - @error_message = json_response['message'] - else - @error_code = 'API request problem' - @error_message = e.to_s - end + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + + results = ESign::Eg010SendBinaryDocsService.new(args).worker + session[:envelope_id] = results['envelope_id'] + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results['envelope_id']) + render 'ds_common/example_done' + rescue Net::HTTPError => e + if !e.response.nil? + json_response = JSON.parse e.response + @error_code = json_response['errorCode'] + @error_message = json_response['message'] + else + @error_code = 'API request problem' + @error_message = e.to_s end end end diff --git a/app/controllers/e_sign/eg011_embedded_sending_controller.rb b/app/controllers/e_sign/eg011_embedded_sending_controller.rb index 8fc7d39..7e19c58 100644 --- a/app/controllers/e_sign/eg011_embedded_sending_controller.rb +++ b/app/controllers/e_sign/eg011_embedded_sending_controller.rb @@ -2,30 +2,29 @@ class ESign::Eg011EmbeddedSendingController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 11) } def create - begin - envelope_args = { - signer_email: param_gsub(params['signerEmail']), - signer_name: param_gsub(params['signerName']), - cc_email: param_gsub(params['ccEmail']), - cc_name: param_gsub(params['ccName']), - status: 'created' - } - - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - starting_view: param_gsub(params['starting_view']), - envelope_args: envelope_args, - ds_return_url: "#{Rails.application.config.app_url}/ds_common-return" - } + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + cc_email: param_gsub(params['ccEmail']), + cc_name: param_gsub(params['ccName']), + status: 'created' + } - results = ESign::Eg011EmbeddedSendingService.new(args).worker - redirect_to results['redirect_url'] - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + starting_view: param_gsub(params['starting_view']), + envelope_args: envelope_args, + ds_return_url: "#{Rails.application.config.app_url}/ds_common-return" + } + + results = ESign::Eg011EmbeddedSendingService.new(args).worker + redirect_to results['redirect_url'] + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end diff --git a/app/controllers/e_sign/eg012_embedded_console_controller.rb b/app/controllers/e_sign/eg012_embedded_console_controller.rb index 5eae80b..68e1131 100644 --- a/app/controllers/e_sign/eg012_embedded_console_controller.rb +++ b/app/controllers/e_sign/eg012_embedded_console_controller.rb @@ -2,6 +2,7 @@ class ESign::Eg012EmbeddedConsoleController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 12) } def create envelope_id = session[:envelope_id] @@ -15,7 +16,7 @@ def create starting_view: params['starting_view'], ds_return_url: "#{Rails.application.config.app_url}/ds_common-return" } - + results = ESign::Eg012EmbeddedConsoleService.new(args).worker redirect_to results['redirect_url'] rescue DocuSign_eSign::ApiError => e diff --git a/app/controllers/e_sign/eg013_add_doc_to_template_controller.rb b/app/controllers/e_sign/eg013_add_doc_to_template_controller.rb index 9ca509f..302eb47 100644 --- a/app/controllers/e_sign/eg013_add_doc_to_template_controller.rb +++ b/app/controllers/e_sign/eg013_add_doc_to_template_controller.rb @@ -2,6 +2,7 @@ class ESign::Eg013AddDocToTemplateController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 13) } def create template_id = session[:template_id] @@ -31,7 +32,7 @@ def create results = ESign::Eg013AddDocToTemplateService.new(args).worker # Save for use by other examples # which need an envelopeId - session[:envelope_id] = results[:envelope_id] + session[:envelope_id] = results[:envelope_id] # Redirect the user to the embedded signing # Don't use an iFrame! # State can be stored/recovered using the framework's session or a @@ -44,7 +45,7 @@ def create render 'ds_common/error' end elsif !template_id - @title = 'Use embedded signing from template and extra doc' + @title = @example['ExampleName'] @template_ok = false end end diff --git a/app/controllers/e_sign/eg014_collect_payment_controller.rb b/app/controllers/e_sign/eg014_collect_payment_controller.rb index fb16815..8e49d7d 100644 --- a/app/controllers/e_sign/eg014_collect_payment_controller.rb +++ b/app/controllers/e_sign/eg014_collect_payment_controller.rb @@ -2,33 +2,30 @@ class ESign::Eg014CollectPaymentController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 14) } def create - begin - envelope_args = { - signer_email: param_gsub(params['signerEmail']), - signer_name: param_gsub(params['signerName']), - cc_email: param_gsub(params['ccEmail']), - cc_name: param_gsub(params['ccName']), - gateway_account_id: Rails.application.config.gateway_account_id, - gateway_name: Rails.application.config.gateway_name, - gateway_display_name: Rails.application.config.gateway_display_name - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + cc_email: param_gsub(params['ccEmail']), + cc_name: param_gsub(params['ccName']), + gateway_account_id: Rails.application.config.gateway_account_id, + gateway_name: Rails.application.config.gateway_name, + gateway_display_name: Rails.application.config.gateway_display_name + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } - results = ESign::Eg014CollectPaymentService.new(args).worker - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The order form envelope has been created and sent!
    - Envelope ID #{results[:envelope_id]}" - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + results = ESign::Eg014CollectPaymentService.new(args).worker + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results[:envelope_id]) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end diff --git a/app/controllers/e_sign/eg015_get_envelope_tab_data_controller.rb b/app/controllers/e_sign/eg015_get_envelope_tab_data_controller.rb index a3076ef..313eaf9 100644 --- a/app/controllers/e_sign/eg015_get_envelope_tab_data_controller.rb +++ b/app/controllers/e_sign/eg015_get_envelope_tab_data_controller.rb @@ -2,6 +2,7 @@ class ESign::Eg015GetEnvelopeTabDataController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 15) } def create envelope_id = session[:envelope_id] @@ -14,7 +15,7 @@ def create } results = ESign::Eg015GetEnvelopeTabDataService.new(args).worker - @h1 = 'List envelopes results' + @title = @example['ExampleName'] @message = 'Results from the EnvelopeFormData::get method:' @json = results.to_json.to_json render 'ds_common/example_done' diff --git a/app/controllers/e_sign/eg016_set_envelope_tab_data_controller.rb b/app/controllers/e_sign/eg016_set_envelope_tab_data_controller.rb index d429321..ce0cb67 100644 --- a/app/controllers/e_sign/eg016_set_envelope_tab_data_controller.rb +++ b/app/controllers/e_sign/eg016_set_envelope_tab_data_controller.rb @@ -2,6 +2,7 @@ class ESign::Eg016SetEnvelopeTabDataController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 16) } def create args = { diff --git a/app/controllers/e_sign/eg017_set_template_tab_values_controller.rb b/app/controllers/e_sign/eg017_set_template_tab_values_controller.rb index ffd1f47..bf1ee0b 100644 --- a/app/controllers/e_sign/eg017_set_template_tab_values_controller.rb +++ b/app/controllers/e_sign/eg017_set_template_tab_values_controller.rb @@ -2,6 +2,7 @@ class ESign::Eg017SetTemplateTabValuesController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 17) } def create template_id = session[:template_id] @@ -24,7 +25,7 @@ def create redirect_url = ESign::Eg017SetTemplateTabValuesService.new(args).worker redirect_to redirect_url elsif !template_id - @title = 'Use a template to send an envelope' + @title = @example['ExampleName'] @template_ok = false end end diff --git a/app/controllers/e_sign/eg018_get_envelope_custom_field_data_controller.rb b/app/controllers/e_sign/eg018_get_envelope_custom_field_data_controller.rb index 5b2182a..d5fad90 100644 --- a/app/controllers/e_sign/eg018_get_envelope_custom_field_data_controller.rb +++ b/app/controllers/e_sign/eg018_get_envelope_custom_field_data_controller.rb @@ -2,6 +2,7 @@ class ESign::Eg018GetEnvelopeCustomFieldDataController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 18) } def create envelope_id = session[:envelope_id] @@ -14,7 +15,7 @@ def create } results = ESign::Eg018GetEnvelopeCustomFieldDataService.new(args).worker - @h1 = 'List envelopes results' + @title = @example['ExampleName'] @message = 'Results from the Envelopes::listStatusChanges method:' @json = results.to_json.to_json render 'ds_common/example_done' diff --git a/app/controllers/e_sign/eg019_access_code_authentication_controller.rb b/app/controllers/e_sign/eg019_access_code_authentication_controller.rb index 2e75eb3..2649447 100644 --- a/app/controllers/e_sign/eg019_access_code_authentication_controller.rb +++ b/app/controllers/e_sign/eg019_access_code_authentication_controller.rb @@ -2,33 +2,31 @@ class ESign::Eg019AccessCodeAuthenticationController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 19) } def create - begin - # ***DS.snippet.0.start - envelope_args = { - signer_email: param_gsub(params['signerEmail']), - signer_name: param_gsub(params['signerName']), - accessCode: params['accessCode'], - status: 'sent' - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } + # ***DS.snippet.0.start + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + accessCode: params['accessCode'], + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } - results = ESign::Eg019AccessCodeAuthenticationService.new(args).worker - session[:envelope_id] = results.envelope_id + results = ESign::Eg019AccessCodeAuthenticationService.new(args).worker + session[:envelope_id] = results.envelope_id - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The envelope has been created and sent!
    Envelope ID #{results.envelope_id}." - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results.envelope_id) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end # ***DS.snippet.0.end end diff --git a/app/controllers/e_sign/eg020_phone_authentication_controller.rb b/app/controllers/e_sign/eg020_phone_authentication_controller.rb index 95e6186..e580b73 100644 --- a/app/controllers/e_sign/eg020_phone_authentication_controller.rb +++ b/app/controllers/e_sign/eg020_phone_authentication_controller.rb @@ -2,43 +2,41 @@ class ESign::Eg020PhoneAuthenticationController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 20) } def create - begin - envelope_args = { - signer_email: param_gsub(params['signer_email']), - signer_name: param_gsub(params['signer_name']), - country_code: param_gsub(params['country_code']), - phone_number: param_gsub(params['phone_number']), - status: 'sent' - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } + envelope_args = { + signer_email: param_gsub(params['signer_email']), + signer_name: param_gsub(params['signer_name']), + country_code: param_gsub(params['country_code']), + phone_number: param_gsub(params['phone_number']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } - phone_auth_service = ESign::Eg020PhoneAuthenticationService.new(args) + phone_auth_service = ESign::Eg020PhoneAuthenticationService.new(args) - # Retrieve the workflow id - workflow_id = phone_auth_service.get_workflow - session[:workflow_id] = workflow_id + # Retrieve the workflow id + workflow_id = phone_auth_service.get_workflow + session[:workflow_id] = workflow_id - results = phone_auth_service.worker(workflow_id) + results = phone_auth_service.worker(workflow_id) - if results.to_s == "phone_auth_not_enabled" - @error_code = "IDENTITY_WORKFLOW_INVALID_ID" - @error_message = "The identity workflow ID specified is not valid." - @error_information = "Please contact Support to enable ID verification in your account." - render 'ds_common/error' - else - session[:envelope_id] = results.envelope_id - @title = 'Require Phone Authentication for a Recipient' - @h1 = 'Require Phone Authentication for a Recipient' - @message = "The envelope has been created and sent!
    Envelope ID #{results.envelope_id}." - render 'ds_common/example_done' - end + if results.to_s == 'phone_auth_not_enabled' + @error_code = 'IDENTITY_WORKFLOW_INVALID_ID' + @error_message = 'The identity workflow ID specified is not valid.' + @error_information = @example['CustomErrorTexts'][0]['ErrorMessage'] + render 'ds_common/error' + else + session[:envelope_id] = results.envelope_id + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results.envelope_id) + render 'ds_common/example_done' end end diff --git a/app/controllers/e_sign/eg022_kba_authentication_controller.rb b/app/controllers/e_sign/eg022_kba_authentication_controller.rb index e342091..3fcce4f 100644 --- a/app/controllers/e_sign/eg022_kba_authentication_controller.rb +++ b/app/controllers/e_sign/eg022_kba_authentication_controller.rb @@ -2,30 +2,28 @@ class ESign::Eg022KbaAuthenticationController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 22) } def create - begin - envelope_args = { - signer_email: param_gsub(params['signerEmail']), - signer_name: param_gsub(params['signerName']), - status: 'sent' - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } - results = ESign::Eg022KbaAuthenticationService.new(args).worker - session[:envelope_id] = results.envelope_id + results = ESign::Eg022KbaAuthenticationService.new(args).worker + session[:envelope_id] = results.envelope_id - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The envelope has been created and sent!
    Envelope ID #{results.envelope_id}." - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results.envelope_id) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end diff --git a/app/controllers/e_sign/eg023_idv_authentication_controller.rb b/app/controllers/e_sign/eg023_idv_authentication_controller.rb index 67da9eb..8c9e48f 100644 --- a/app/controllers/e_sign/eg023_idv_authentication_controller.rb +++ b/app/controllers/e_sign/eg023_idv_authentication_controller.rb @@ -2,41 +2,39 @@ class ESign::Eg023IdvAuthenticationController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 23) } def create - begin - envelope_args = { - signer_email: param_gsub(params['signerEmail']), - signer_name: param_gsub(params['signerName']), - status: 'sent' - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } - results = ESign::Eg023IdvAuthenticationService.new(args).worker + results = ESign::Eg023IdvAuthenticationService.new(args).worker - if results.to_s == "idv_not_enabled" - @error_code = "IDENTITY_WORKFLOW_INVALID_ID" - @error_message = "The identity workflow ID specified is not valid." - @error_information = "Please contact Support to enable ID verification in your account." - render 'ds_common/error' - else - session[:envelope_id] = results.envelope_id - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The envelope has been created and sent!
    Envelope ID #{results.envelope_id}." - render 'ds_common/example_done' - end - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - @error_message = error['message'] + if results.to_s == 'idv_not_enabled' + @error_code = 'IDENTITY_WORKFLOW_INVALID_ID' + @error_message = 'The identity workflow ID specified is not valid.' + @error_information = @example['CustomErrorTexts'][0]['ErrorMessage'] render 'ds_common/error' + else + session[:envelope_id] = results.envelope_id + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results.envelope_id) + render 'ds_common/example_done' end + rescue DocuSign_eSign::ApiError => e + error = JSON.parse e.response_body + @error_code = error['errorCode'] + @error_message = error['message'] + render 'ds_common/error' end # ***DS.snippet.0.end diff --git a/app/controllers/e_sign/eg024_permission_create_controller.rb b/app/controllers/e_sign/eg024_permission_create_controller.rb index 7bea1ed..d61342d 100644 --- a/app/controllers/e_sign/eg024_permission_create_controller.rb +++ b/app/controllers/e_sign/eg024_permission_create_controller.rb @@ -2,27 +2,24 @@ class ESign::Eg024PermissionCreateController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 24) } def create - begin - args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - permission_profile_name: params[:permission_profile_name] - } + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + permission_profile_name: params[:permission_profile_name] + } - results = ESign::Eg024PermissionCreateService.new(args).worker - # Step 4. a) Call the eSignature API - # b) Display the JSON response - @title = 'Creating a permission profile' - @h1 = 'Creating a permission profile' - @message = "Permission profile was created" - @json = results.to_json.to_json - render 'ds_common/example_done' - - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + results = ESign::Eg024PermissionCreateService.new(args).worker + # Step 4. a) Call the eSignature API + # b) Display the JSON response + @title = @example['ExampleName'] + @message = 'Permission profile was created' + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end diff --git a/app/controllers/e_sign/eg025_permissions_set_user_group_controller.rb b/app/controllers/e_sign/eg025_permissions_set_user_group_controller.rb index c27d1c3..0408c70 100644 --- a/app/controllers/e_sign/eg025_permissions_set_user_group_controller.rb +++ b/app/controllers/e_sign/eg025_permissions_set_user_group_controller.rb @@ -3,6 +3,7 @@ class ESign::Eg025PermissionsSetUserGroupController < EgController include ApiCreator before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 25) } def get args = { @@ -11,34 +12,30 @@ def get access_token: session['ds_access_token'] } accounts_api = create_account_api(args) - permissions = accounts_api.list_permissions(args[:account_id], options = DocuSign_eSign::ListPermissionsOptions.default) + permissions = accounts_api.list_permissions(args[:account_id], DocuSign_eSign::ListPermissionsOptions.default) @permissions_lists = permissions.permission_profiles # Get a user group group_api = create_group_api(args) - @group_lists = group_api.list_groups(args[:account_id], options = DocuSign_eSign::ListGroupsOptions.default) + @group_lists = group_api.list_groups(args[:account_id], DocuSign_eSign::ListGroupsOptions.default) super end def create - begin - args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - permission_profile_id: params[:lists], - group_id: params[:group_lists] - } - - results = ESign::Eg025PermissionsSetUserGroupService.new(args).worker - # Step 4. a) Call the eSignature API - # b) Display the JSON response - @title = 'Setting a permission profile' - @h1 = 'Setting a permission profile' - @json = results.to_json.to_json - render 'ds_common/example_done' + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + permission_profile_id: params[:lists], + group_id: params[:group_lists] + } - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + results = ESign::Eg025PermissionsSetUserGroupService.new(args).worker + # Step 4. a) Call the eSignature API + # b) Display the JSON response + @title = @example['ExampleName'] + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end diff --git a/app/controllers/e_sign/eg026_permissions_change_single_setting_controller.rb b/app/controllers/e_sign/eg026_permissions_change_single_setting_controller.rb index 2d414fd..a7f2573 100644 --- a/app/controllers/e_sign/eg026_permissions_change_single_setting_controller.rb +++ b/app/controllers/e_sign/eg026_permissions_change_single_setting_controller.rb @@ -3,39 +3,36 @@ class ESign::Eg026PermissionsChangeSingleSettingController < EgController include ApiCreator before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 26) } def get - args = { + args = { account_id: session['ds_account_id'], base_path: session['ds_base_path'], access_token: session['ds_access_token'] } accounts_api = create_account_api(args) - permissions = accounts_api.list_permissions(args[:account_id], options = DocuSign_eSign::ListPermissionsOptions.default) + permissions = accounts_api.list_permissions(args[:account_id], DocuSign_eSign::ListPermissionsOptions.default) @permissions_lists = permissions.permission_profiles super end def create - begin - args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - permission_profile_id: params[:lists] - } - - results = ESign::Eg026PermissionsChangeSingleSettingService.new(args).worker - # Step 4. a) Call the eSignature API - # b) Display the JSON response - @title = 'Updating individual permission settings' - @h1 = 'Updating individual permission settings' - @message = "Existing permission profile was changed" - @json = results.to_json.to_json - render 'ds_common/example_done' + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + permission_profile_id: params[:lists] + } - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + results = ESign::Eg026PermissionsChangeSingleSettingService.new(args).worker + # Step 4. a) Call the eSignature API + # b) Display the JSON response + @title = @example['ExampleName'] + @message = 'Existing permission profile was changed' + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end diff --git a/app/controllers/e_sign/eg027_permissions_delete_controller.rb b/app/controllers/e_sign/eg027_permissions_delete_controller.rb index 915e79d..a98f7a0 100644 --- a/app/controllers/e_sign/eg027_permissions_delete_controller.rb +++ b/app/controllers/e_sign/eg027_permissions_delete_controller.rb @@ -3,38 +3,35 @@ class ESign::Eg027PermissionsDeleteController < EgController include ApiCreator before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 27) } def get - args = { + args = { account_id: session['ds_account_id'], base_path: session['ds_base_path'], access_token: session['ds_access_token'] } accounts_api = create_account_api(args) - permissions = accounts_api.list_permissions(args[:account_id], options = DocuSign_eSign::ListPermissionsOptions.default) + permissions = accounts_api.list_permissions(args[:account_id], DocuSign_eSign::ListPermissionsOptions.default) @permissions_lists = permissions.permission_profiles super end def create - begin - args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - permission_profile_id: params[:lists] - } - - results = ESign::Eg027PermissionsDeleteService.new(args).worker - # Step 4. a) Call the eSignature API - # b) Display the JSON response - @title = 'Permission profile from an account was deleted' - @h1 = 'Permission profile from an account was deleted' - @message = "Permission profile #{params[:lists]} was deleted" - render 'ds_common/example_done' + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + permission_profile_id: params[:lists] + } - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + ESign::Eg027PermissionsDeleteService.new(args).worker + # Step 4. a) Call the eSignature API + # b) Display the JSON response + @title = @example['ExampleName'] + @message = "Permission profile #{params[:lists]} was deleted" + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end diff --git a/app/controllers/e_sign/eg028_brands_creating_controller.rb b/app/controllers/e_sign/eg028_brands_creating_controller.rb index c7cbdc3..1cf1ae2 100644 --- a/app/controllers/e_sign/eg028_brands_creating_controller.rb +++ b/app/controllers/e_sign/eg028_brands_creating_controller.rb @@ -1,28 +1,25 @@ class ESign::Eg028BrandsCreatingController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 28) } def create - begin - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - brandName: params[:brandName], - defaultBrandLanguage: params[:defaultBrandLanguage] - } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + brandName: params[:brandName], + defaultBrandLanguage: params[:defaultBrandLanguage] + } - results = ESign::Eg028BrandsCreatingService.new(args).worker - # Step 4. a) Call the eSignature API - # b) Display the JSON response - brand_id = results.brands[0].brand_id - @title = 'Brand creating' - @h1 = 'Brand creating' - @message = "The Brand has been created!
    Brand ID: #{brand_id}." - @json = results.to_json.to_json - render 'ds_common/example_done' - - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + results = ESign::Eg028BrandsCreatingService.new(args).worker + # Step 4. a) Call the eSignature API + # b) Display the JSON response + brand_id = results.brands[0].brand_id + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], brand_id) + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end diff --git a/app/controllers/e_sign/eg029_brands_apply_to_envelope_controller.rb b/app/controllers/e_sign/eg029_brands_apply_to_envelope_controller.rb index d927abd..116f45d 100644 --- a/app/controllers/e_sign/eg029_brands_apply_to_envelope_controller.rb +++ b/app/controllers/e_sign/eg029_brands_apply_to_envelope_controller.rb @@ -3,6 +3,7 @@ class ESign::Eg029BrandsApplyToEnvelopeController < EgController include ApiCreator before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 29) } def get args = { @@ -11,40 +12,36 @@ def get access_token: session['ds_access_token'] } accounts_api = create_account_api(args) - brand_lists = accounts_api.list_brands(args[:account_id], options = DocuSign_eSign::ListBrandsOptions.default) + brand_lists = accounts_api.list_brands(args[:account_id], DocuSign_eSign::ListBrandsOptions.default) @brand_names = brand_lists.brands super end def create - begin - envelope_args = { - signer_email: param_gsub(params[:signerEmail]), - signer_name: param_gsub(params[:signerName]), - brand_id: params[:brands], - status: 'sent' - - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } + envelope_args = { + signer_email: param_gsub(params[:signerEmail]), + signer_name: param_gsub(params[:signerName]), + brand_id: params[:brands], + status: 'sent' - results = ESign::Eg029BrandsApplyToEnvelopeService.new(args).worker - session[:envelope_id] = results.envelope_id + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } - # Step 4. a) Call the eSignature API - # b) Display the JSON response - @title = 'Applying a Brand to an envelope' - @h1 = 'Applying a Brand to an envelope' - @message = "The envelope has been created and sent!
    Envelope ID #{results.envelope_id}." - @json = results.to_json.to_json - render 'ds_common/example_done' + results = ESign::Eg029BrandsApplyToEnvelopeService.new(args).worker + session[:envelope_id] = results.envelope_id - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + # Step 4. a) Call the eSignature API + # b) Display the JSON response + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results.envelope_id) + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end diff --git a/app/controllers/e_sign/eg030_brands_apply_to_template_controller.rb b/app/controllers/e_sign/eg030_brands_apply_to_template_controller.rb index f86b14e..6adc75e 100644 --- a/app/controllers/e_sign/eg030_brands_apply_to_template_controller.rb +++ b/app/controllers/e_sign/eg030_brands_apply_to_template_controller.rb @@ -3,6 +3,7 @@ class ESign::Eg030BrandsApplyToTemplateController < EgController include ApiCreator before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 30) } def get args = { @@ -11,7 +12,7 @@ def get access_token: session['ds_access_token'] } accounts_api = create_account_api(args) - brand_lists = accounts_api.list_brands(args[:account_id], options = DocuSign_eSign::ListBrandsOptions.default) + brand_lists = accounts_api.list_brands(args[:account_id], DocuSign_eSign::ListBrandsOptions.default) @brand_names = brand_lists.brands super end @@ -38,22 +39,21 @@ def create envelope_args: envelope_args } - results = ESign::Eg030BrandsApplyToTemplateService.new(args).worker + results = ESign::Eg030BrandsApplyToTemplateService.new(args).worker session[:envelope_id] = results.envelope_id # Step 4. a) Call the eSignature API # b) Display the JSON response # brand_id = results.brands[0].brand_id - @title = 'Applying a brand to an envelope using a template' - @h1 = 'Applying a brand to an envelope using a template' - @message = "The envelope has been created and sent!
    Envelope ID #{results.envelope_id}." + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results.envelope_id) @json = results.to_json.to_json render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e + rescue DocuSign_eSign::ApiError => e handle_error(e) end elsif !template_id - @title = 'Use embedded signing from template and extra doc' + @title = @example['ExampleName'] @template_ok = false end end diff --git a/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb b/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb index 3e66932..cd425aa 100644 --- a/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb +++ b/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb @@ -2,39 +2,36 @@ class ESign::Eg031BulkSendingEnvelopesController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 31) } def create - begin - signers = { - signer_email: param_gsub(params['signerEmail1']), - signer_name: param_gsub(params['signerName1']), - cc_email: param_gsub(params['ccEmail1']), - cc_name: param_gsub(params['ccName1']), - status: 'created', - - signer_email1: param_gsub(params['signerEmail2']), - signer_name1: param_gsub(params['signerName2']), - cc_email1: param_gsub(params['ccEmail2']), - cc_name1: param_gsub(params['ccName2']) - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'] - } + signers = { + signer_email: param_gsub(params['signerEmail1']), + signer_name: param_gsub(params['signerName1']), + cc_email: param_gsub(params['ccEmail1']), + cc_name: param_gsub(params['ccName1']), + status: 'created', - results = ESign::Eg031BulkSendingEnvelopesService.new(args, signers).worker - # Step 4. a) Call the eSignature API - # b) Display the JSON response - @title = 'Bulk send envelopes' - @h1 = 'Bulk send envelopes' - @message = "Results from BulkSend:getBulkSendBatchStatus method:" - @json = results.to_json.to_json + signer_email1: param_gsub(params['signerEmail2']), + signer_name1: param_gsub(params['signerName2']), + cc_email1: param_gsub(params['ccEmail2']), + cc_name1: param_gsub(params['ccName2']) + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'] + } - render 'ds_common/example_done' + results = ESign::Eg031BulkSendingEnvelopesService.new(args, signers).worker + # Step 4. a) Call the eSignature API + # b) Display the JSON response + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end diff --git a/app/controllers/e_sign/eg032_pauses_signature_workflow_controller.rb b/app/controllers/e_sign/eg032_pauses_signature_workflow_controller.rb index bb11b95..57a1909 100644 --- a/app/controllers/e_sign/eg032_pauses_signature_workflow_controller.rb +++ b/app/controllers/e_sign/eg032_pauses_signature_workflow_controller.rb @@ -2,6 +2,7 @@ class ESign::Eg032PausesSignatureWorkflowController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 32) } def create signers = { diff --git a/app/controllers/e_sign/eg033_unpauses_signature_workflow_controller.rb b/app/controllers/e_sign/eg033_unpauses_signature_workflow_controller.rb index cb9d7db..2b791dc 100644 --- a/app/controllers/e_sign/eg033_unpauses_signature_workflow_controller.rb +++ b/app/controllers/e_sign/eg033_unpauses_signature_workflow_controller.rb @@ -2,6 +2,7 @@ class ESign::Eg033UnpausesSignatureWorkflowController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 33) } def update args = { diff --git a/app/controllers/e_sign/eg034_use_conditional_recipients_controller.rb b/app/controllers/e_sign/eg034_use_conditional_recipients_controller.rb index bb5f67e..d9d8383 100644 --- a/app/controllers/e_sign/eg034_use_conditional_recipients_controller.rb +++ b/app/controllers/e_sign/eg034_use_conditional_recipients_controller.rb @@ -2,39 +2,38 @@ class ESign::Eg034UseConditionalRecipientsController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 34) } def create - begin - signers = { - signerEmail1: request['signerEmail1'], - signerName1: request['signerName1'], - - signerEmailNotChecked: request['signerEmailNotChecked'], - signerNameNotChecked: request['signerNameNotChecked'], - - signerEmailChecked: request['signerEmailChecked'], - signerNameChecked: request['signerNameChecked'] - } - - args = { - accountId: session['ds_account_id'], - basePath: session['ds_base_path'], - accessToken: session['ds_access_token'] - } + signers = { + signerEmail1: request['signerEmail1'], + signerName1: request['signerName1'], - results = ESign::Eg034UseConditionalRecipientsService.new(args, signers).worker - @envelop_id = results.to_hash[:envelopeId].to_s - render 'e_sign/eg034_use_conditional_recipients/return' - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - if error['errorCode']["WORKFLOW_UPDATE_RECIPIENTROUTING_NOT_ALLOWED"] - @error_message = "Update to the workflow with recipient routing is not allowed for your account!" - @error_information = "Please contact with our support team to resolve this issue." - else - @error_message = error['message'] - end - render 'ds_common/error' + signerEmailNotChecked: request['signerEmailNotChecked'], + signerNameNotChecked: request['signerNameNotChecked'], + + signerEmailChecked: request['signerEmailChecked'], + signerNameChecked: request['signerNameChecked'] + } + + args = { + accountId: session['ds_account_id'], + basePath: session['ds_base_path'], + accessToken: session['ds_access_token'] + } + + results = ESign::Eg034UseConditionalRecipientsService.new(args, signers).worker + @envelop_id = results.to_hash[:envelopeId].to_s + render 'e_sign/eg034_use_conditional_recipients/return' + rescue DocuSign_eSign::ApiError => e + error = JSON.parse e.response_body + @error_code = error['errorCode'] + if error['errorCode']['WORKFLOW_UPDATE_RECIPIENTROUTING_NOT_ALLOWED'] + @error_message = @example['CustomErrorTexts'][0]['ErrorMessage'] + @error_information = @example['CustomErrorTexts'][0]['ErrorMessage'] + else + @error_message = error['message'] end + render 'ds_common/error' end end diff --git a/app/controllers/e_sign/eg035_scheduled_sending_controller.rb b/app/controllers/e_sign/eg035_scheduled_sending_controller.rb index 936756b..76b1ad4 100644 --- a/app/controllers/e_sign/eg035_scheduled_sending_controller.rb +++ b/app/controllers/e_sign/eg035_scheduled_sending_controller.rb @@ -2,29 +2,27 @@ class ESign::Eg035ScheduledSendingController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 35) } def create - begin - envelope_args = { - signer_email: param_gsub(params['signer_email']), - signer_name: param_gsub(params['signer_name']), - resume_date: param_gsub(params['resume_date']), - status: 'sent' - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } - results = ESign::Eg035ScheduledSendingService.new(args).worker - session[:envelope_id] = results['envelope_id'] - @title = 'Envelope scheduled' - @h1 = 'Envelope scheduled' - @message = "The envelope has been created and scheduled!
    Envelope ID #{results['envelope_id']}." - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + envelope_args = { + signer_email: param_gsub(params['signer_email']), + signer_name: param_gsub(params['signer_name']), + resume_date: param_gsub(params['resume_date']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + results = ESign::Eg035ScheduledSendingService.new(args).worker + session[:envelope_id] = results['envelope_id'] + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results['envelope_id']) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end diff --git a/app/controllers/e_sign/eg036_delayed_routing_controller.rb b/app/controllers/e_sign/eg036_delayed_routing_controller.rb index 9a0ffc3..b5c31e5 100644 --- a/app/controllers/e_sign/eg036_delayed_routing_controller.rb +++ b/app/controllers/e_sign/eg036_delayed_routing_controller.rb @@ -2,31 +2,29 @@ class ESign::Eg036DelayedRoutingController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 36) } def create - begin - envelope_args = { - signer1_email: param_gsub(params['signer1Email']), - signer1_name: param_gsub(params['signer1Name']), - signer2_email: param_gsub(params['signer2Email']), - signer2_name: param_gsub(params['signer2Name']), - delay: param_gsub(params['delay']), - status: 'sent' - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } - results = ESign::Eg036DelayedRoutingService.new(args).worker - session[:envelope_id] = results['envelope_id'] - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The envelope has been created and sent!
    Envelope ID #{results['envelope_id']}." - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + envelope_args = { + signer1_email: param_gsub(params['signer1Email']), + signer1_name: param_gsub(params['signer1Name']), + signer2_email: param_gsub(params['signer2Email']), + signer2_name: param_gsub(params['signer2Name']), + delay: param_gsub(params['delay']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + results = ESign::Eg036DelayedRoutingService.new(args).worker + session[:envelope_id] = results['envelope_id'] + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results['envelope_id']) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end diff --git a/app/controllers/e_sign/eg037_sms_delivery_controller.rb b/app/controllers/e_sign/eg037_sms_delivery_controller.rb index 53e09cb..2758fec 100644 --- a/app/controllers/e_sign/eg037_sms_delivery_controller.rb +++ b/app/controllers/e_sign/eg037_sms_delivery_controller.rb @@ -2,33 +2,31 @@ class ESign::Eg037SmsDeliveryController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 37) } def create - begin - envelope_args = { - signer_name: param_gsub(params['signer_name']), - cc_name: param_gsub(params['cc_name']), - cc_phone_number: param_gsub(params['cc_phone_number']), - cc_country_code: param_gsub(params['cc_country_code']), - phone_number: param_gsub(params['phone_number']), - country_code: param_gsub(params['country_code']), - status: 'sent' - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } + envelope_args = { + signer_name: param_gsub(params['signer_name']), + cc_name: param_gsub(params['cc_name']), + cc_phone_number: param_gsub(params['cc_phone_number']), + cc_country_code: param_gsub(params['cc_country_code']), + phone_number: param_gsub(params['phone_number']), + country_code: param_gsub(params['country_code']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } - results = ESign::Eg037SmsDeliveryService.new(args).worker - session[:envelope_id] = results['envelope_id'] - @title = 'Request a signature by SMS delivery' - @h1 = 'Request a signature by SMS delivery' - @message = "The envelope has been created and sent!
    Envelope ID #{results['envelope_id']}." - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + results = ESign::Eg037SmsDeliveryService.new(args).worker + session[:envelope_id] = results['envelope_id'] + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results['envelope_id']) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end diff --git a/app/controllers/e_sign/eg038_responsive_signing_controller.rb b/app/controllers/e_sign/eg038_responsive_signing_controller.rb index 159d3d3..3615836 100644 --- a/app/controllers/e_sign/eg038_responsive_signing_controller.rb +++ b/app/controllers/e_sign/eg038_responsive_signing_controller.rb @@ -2,26 +2,25 @@ class ESign::Eg038ResponsiveSigningController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 38) } def create - begin - args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - signer_email: param_gsub(params[:signerEmail]), - signer_name: param_gsub(params[:signerName]), - cc_email: param_gsub(params[:ccEmail]), - cc_name: param_gsub(params[:ccName]), - ds_ping_url: Rails.application.config.app_url, - signer_client_id: 1000, - doc_file: 'data/order_form.html' - } + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + signer_email: param_gsub(params[:signerEmail]), + signer_name: param_gsub(params[:signerName]), + cc_email: param_gsub(params[:ccEmail]), + cc_name: param_gsub(params[:ccName]), + ds_ping_url: Rails.application.config.app_url, + signer_client_id: 1000, + doc_file: 'data/order_form.html' + } - redirect_url = ESign::Eg038ResponsiveSigningService.new(args).worker - redirect_to redirect_url - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + redirect_url = ESign::Eg038ResponsiveSigningService.new(args).worker + redirect_to redirect_url + rescue DocuSign_eSign::ApiError => e + handle_error(e) end end diff --git a/app/controllers/e_sign/eg039_signing_in_person_controller.rb b/app/controllers/e_sign/eg039_signing_in_person_controller.rb index 2f862d7..808331a 100644 --- a/app/controllers/e_sign/eg039_signing_in_person_controller.rb +++ b/app/controllers/e_sign/eg039_signing_in_person_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class ESign::Eg039SigningInPersonController < EgController + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 39) } + def create minimum_buffer_min = 10 token_ok = check_token(minimum_buffer_min) diff --git a/app/controllers/e_sign/eg040_set_document_visibility_controller.rb b/app/controllers/e_sign/eg040_set_document_visibility_controller.rb index 99a67bd..6cf5f8c 100644 --- a/app/controllers/e_sign/eg040_set_document_visibility_controller.rb +++ b/app/controllers/e_sign/eg040_set_document_visibility_controller.rb @@ -2,46 +2,42 @@ class ESign::Eg040SetDocumentVisibilityController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 40) } def create - begin - envelope_args = { - signer1_email: param_gsub(params['signer1Email']), - signer1_name: param_gsub(params['signer1Name']), - signer2_email: param_gsub(params['signer2Email']), - signer2_name: param_gsub(params['signer2Name']), - cc_email: param_gsub(params['ccEmail']), - cc_name: param_gsub(params['ccName']), - status: 'sent', - doc_docx: File.join('data', Rails.application.config.doc_docx), - doc_pdf: File.join('data', Rails.application.config.doc_pdf) - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } - results = ESign::Eg040SetDocumentVisibilityService.new(args).worker - @title = 'Envelope sent' - @h1 = 'Envelope sent' - @message = "The envelope has been created and sent!
    Envelope ID #{results['envelope_id']}." - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body + envelope_args = { + signer1_email: param_gsub(params['signer1Email']), + signer1_name: param_gsub(params['signer1Name']), + signer2_email: param_gsub(params['signer2Email']), + signer2_name: param_gsub(params['signer2Name']), + cc_email: param_gsub(params['ccEmail']), + cc_name: param_gsub(params['ccName']), + status: 'sent', + doc_docx: File.join('data', Rails.application.config.doc_docx), + doc_pdf: File.join('data', Rails.application.config.doc_pdf) + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + results = ESign::Eg040SetDocumentVisibilityService.new(args).worker + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results['envelope_id']) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + error = JSON.parse e.response_body - if error['errorCode'] == "ACCOUNT_LACKS_PERMISSIONS" - @error_information = '

    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.

    ' + if error['errorCode'] == 'ACCOUNT_LACKS_PERMISSIONS' + @error_information = @example['CustomErrorTexts'][0]['ErrorMessage'] - @error_code = error['errorCode'] - @error_message = error['error_description'] || error['message'] + @error_code = error['errorCode'] + @error_message = error['error_description'] || error['message'] - return render 'ds_common/error' - end - - handle_error(e) + return render 'ds_common/error' end + + handle_error(e) end end diff --git a/app/controllers/eg001_embedded_signing_controller.rb b/app/controllers/eg001_embedded_signing_controller.rb index 338d86e..01aff89 100644 --- a/app/controllers/eg001_embedded_signing_controller.rb +++ b/app/controllers/eg001_embedded_signing_controller.rb @@ -1,42 +1,40 @@ # frozen_string_literal: true class Eg001EmbeddedSigningController < EgController + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1) } + def create - begin - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation - # so it could be restarted automatically. - # But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after - # authentication. - return redirect_to '/ds/mustAuthenticate' - end + minimum_buffer_min = 10 + token_ok = check_token(minimum_buffer_min) + unless token_ok + flash[:messages] = 'Sorry, you need to re-authenticate.' + # We could store the parameters of the requested operation + # so it could be restarted automatically. + # But since it should be rare to have a token issue here, + # we'll make the user re-enter the form data after + # authentication. + return redirect_to '/ds/mustAuthenticate' + end - pdf_file_path = 'data/World_Wide_Corp_lorem.pdf' + pdf_file_path = 'data/World_Wide_Corp_lorem.pdf' - unless File.exist?(pdf_file_path) - pdf_file_path = '../data/World_Wide_Corp_lorem.pdf' - end + pdf_file_path = '../data/World_Wide_Corp_lorem.pdf' unless File.exist?(pdf_file_path) - args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - signer_email: param_gsub(params[:signerEmail]), - signer_name: param_gsub(params[:signerName]), - ds_ping_url: Rails.application.config.app_url, - signer_client_id: 1000, - pdf_filename: pdf_file_path - } + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + signer_email: param_gsub(params[:signerEmail]), + signer_name: param_gsub(params[:signerName]), + ds_ping_url: Rails.application.config.app_url, + signer_client_id: 1000, + pdf_filename: pdf_file_path + } - redirect_url = Eg001EmbeddedSigningService.new(args).worker - redirect_to redirect_url - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + redirect_url = Eg001EmbeddedSigningService.new(args).worker + redirect_to redirect_url + rescue DocuSign_eSign::ApiError => e + handle_error(e) end def get diff --git a/app/controllers/eg_controller.rb b/app/controllers/eg_controller.rb index 29aabc0..1faa174 100644 --- a/app/controllers/eg_controller.rb +++ b/app/controllers/eg_controller.rb @@ -2,7 +2,7 @@ class EgController < ApplicationController skip_before_action :verify_authenticity_token - before_action :eg_name, :set_eg, :set_meta + before_action :eg_name, :set_eg, :set_meta, :ensure_manifest def file_name "#{controller_path}_service.rb" @@ -37,7 +37,6 @@ def get end def set_meta - @source_file = file_name.to_s @source_url = "#{Rails.application.config.github_example_url}#{@source_file}" end @@ -49,13 +48,13 @@ def check_token(buffer_in_min = 10) expires_at = session[:ds_expires_at] remaining_duration = expires_at.nil? ? 0 : expires_at - buffer.seconds.from_now.to_i if expires_at.nil? - Rails.logger.info "==> Token expiration is not available: fetching token" + Rails.logger.info '==> Token expiration is not available: fetching token' elsif remaining_duration.negative? Rails.logger.debug "==> Token is about to expire in #{time_in_words(remaining_duration)} at: #{Time.at(expires_at)}: fetching token" else Rails.logger.debug "==> Token is OK for #{time_in_words(remaining_duration)} at: #{Time.at(expires_at)}" end - remaining_duration > 0 + remaining_duration.positive? end def time_in_words(duration) @@ -63,18 +62,18 @@ def time_in_words(duration) end def param_gsub(parameter) - parameter.gsub(/([^\w \-\@\.\,])+/, '') + parameter.gsub(/([^\w \-@.,])+/, '') end def check_auth minimum_buffer_min = 10 token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end + return if token_ok + + flash[:messages] = 'Sorry, you need to re-authenticate.' + # We could store the parameters of the requested operation so it could be restarted automatically + # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication + redirect_to '/ds/mustAuthenticate' end def handle_error(e) @@ -87,4 +86,26 @@ def handle_error(e) def create_source_path # code here end + + def ensure_manifest + manifest_url = case session[:examples_API] + when 'Rooms' + Rails.configuration.roomsManifestUrl + when 'Click' + Rails.configuration.clickManifestUrl + when 'Monitor' + Rails.configuration.monitorManifestUrl + when 'Admin' + Rails.configuration.adminManifestUrl + else + Rails.configuration.eSignManifestUrl + end + + manifest = Utils::ManifestUtils.new.get_manifest(manifest_url) + @manifest = manifest + end + + def format_string(string, *args) + string.gsub(/\{(\d+)\}/) { |s| args[s.to_i] } + end end diff --git a/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb b/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb index 720d0ab..953dbc3 100644 --- a/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb +++ b/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb @@ -1,5 +1,6 @@ class MonitorApi::Eg001GetMonitoringDatasetController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1) } def create args = { @@ -10,11 +11,10 @@ def create results = MonitorApi::Eg001GetMonitoringDatasetService.new(args).worker - @title = "Get monitoring data" - @h1 = "Get monitoring data" + @title = @example['ExampleName'] if results != "Monitor not enabled" - @message = "Results from DataSet:getStream method:" + @message = @example['ResultsPageText'] @json = results.to_json.to_json else @message = "You do not have Monitor enabled for your account, follow How to enable Monitor for your account to get it enabled." diff --git a/app/controllers/monitor_api/eg002_post_web_query_controller.rb b/app/controllers/monitor_api/eg002_post_web_query_controller.rb index beb4045..d1270d4 100644 --- a/app/controllers/monitor_api/eg002_post_web_query_controller.rb +++ b/app/controllers/monitor_api/eg002_post_web_query_controller.rb @@ -1,5 +1,6 @@ class MonitorApi::Eg002PostWebQueryController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2) } def create args = { @@ -13,11 +14,10 @@ def create results = MonitorApi::Eg002PostWebQueryService.new(args).worker - @title = "Query monitoring data with filters" - @h1 = "Query monitoring data with filters" - + @title = @example['ExampleName'] + if results != "Monitor not enabled" - @message = "Results from DataSet:postWebQuery method:" + @message = @example['ResultsPageText'] @json = results.to_json.to_json else @message = "You do not have Monitor enabled for your account, follow How to enable Monitor for your account to get it enabled." diff --git a/app/controllers/room_api/eg001_create_room_with_data_controller.rb b/app/controllers/room_api/eg001_create_room_with_data_controller.rb index dfd3a53..e1fdacb 100644 --- a/app/controllers/room_api/eg001_create_room_with_data_controller.rb +++ b/app/controllers/room_api/eg001_create_room_with_data_controller.rb @@ -1,11 +1,12 @@ class RoomApi::Eg001CreateRoomWithDataController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1) } def create args = { - room_name: params[:roomName], - office_id: RoomApi::GetDataService.new(session).get_offices[0]['officeId'], - role_id: RoomApi::GetDataService.new(session).get_roles[2]['roleId'], + room_name: params[:roomName], + office_id: RoomApi::GetDataService.new(session).get_offices[0]['officeId'], + role_id: RoomApi::GetDataService.new(session).get_roles[2]['roleId'], account_id: session[:ds_account_id], base_path: session[:ds_base_path], access_token: session[:ds_access_token] @@ -13,9 +14,8 @@ def create results = RoomApi::Eg001CreateRoomWithDataService.new(args).worker - @title = "The room was successfully created" - @h1 = "The room was successfully created" - @message = "The room was created! Room ID: #{results.room_id}, Name: #{results.name}" + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results.room_id, results.name) @json = results.to_json.to_json render 'ds_common/example_done' diff --git a/app/controllers/room_api/eg002_create_room_with_template_controller.rb b/app/controllers/room_api/eg002_create_room_with_template_controller.rb index 5d54861..2a7048a 100644 --- a/app/controllers/room_api/eg002_create_room_with_template_controller.rb +++ b/app/controllers/room_api/eg002_create_room_with_template_controller.rb @@ -1,11 +1,12 @@ class RoomApi::Eg002CreateRoomWithTemplateController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2) } def create args = { room_name: params[:roomName], - office_id: RoomApi::GetDataService.new(session).get_offices[0]['officeId'], - role_id: RoomApi::GetDataService.new(session).get_roles[2]['roleId'], + office_id: RoomApi::GetDataService.new(session).get_offices[0]['officeId'], + role_id: RoomApi::GetDataService.new(session).get_roles[2]['roleId'], template_id: params['templateId'], account_id: session[:ds_account_id], base_path: session[:ds_base_path], @@ -14,9 +15,8 @@ def create results = RoomApi::Eg002CreateRoomWithTemplateService.new(args).worker - @title = "The room was successfully created" - @h1 = "The room was successfully created" - @message = "The room was created! Room ID: #{results.room_id}, Name: #{results.name}" + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results.room_id, results.name) @json = results.to_json.to_json render 'ds_common/example_done' diff --git a/app/controllers/room_api/eg003_export_data_from_room_controller.rb b/app/controllers/room_api/eg003_export_data_from_room_controller.rb index 99035a1..9c72229 100644 --- a/app/controllers/room_api/eg003_export_data_from_room_controller.rb +++ b/app/controllers/room_api/eg003_export_data_from_room_controller.rb @@ -1,5 +1,6 @@ class RoomApi::Eg003ExportDataFromRoomController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 3) } def create args = { @@ -11,9 +12,8 @@ def create results = RoomApi::Eg003ExportDataFromRoomService.new(args).worker - @title = "The room data was successfully exported" - @h1 = "The room data was successfully exported" - @message = "Results from the Rooms::GetRoomFieldData method:" + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] @json = results.to_json.to_json render 'ds_common/example_done' diff --git a/app/controllers/room_api/eg004_add_forms_to_room_controller.rb b/app/controllers/room_api/eg004_add_forms_to_room_controller.rb index 98d8b41..a6e08f6 100644 --- a/app/controllers/room_api/eg004_add_forms_to_room_controller.rb +++ b/app/controllers/room_api/eg004_add_forms_to_room_controller.rb @@ -1,5 +1,6 @@ class RoomApi::Eg004AddFormsToRoomController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 4) } def create args = { @@ -12,9 +13,8 @@ def create results = RoomApi::Eg004AddFormsToRoomService.new(args).worker - @title = "The form was successfully added to a room" - @h1 = "The form was successfully added to a room" - @message = "Results from the Rooms: AddFormToRoom method:" + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] @json = results.to_json.to_json render 'ds_common/example_done' diff --git a/app/controllers/room_api/eg005_get_rooms_with_filters_controller.rb b/app/controllers/room_api/eg005_get_rooms_with_filters_controller.rb index 7e39b88..729497b 100644 --- a/app/controllers/room_api/eg005_get_rooms_with_filters_controller.rb +++ b/app/controllers/room_api/eg005_get_rooms_with_filters_controller.rb @@ -1,5 +1,6 @@ class RoomApi::Eg005GetRoomsWithFiltersController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 5) } def create args = { @@ -12,9 +13,8 @@ def create results = RoomApi::Eg005GetRoomsWithFiltersService.new(args).worker - @title = "The rooms with filters were loaded" - @h1 = "The rooms with filters were loaded" - @message = "Results from the Rooms: GetRooms method:" + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] @json = results.to_json.to_json render 'ds_common/example_done' diff --git a/app/controllers/room_api/eg006_create_an_external_form_fill_session_controller.rb b/app/controllers/room_api/eg006_create_an_external_form_fill_session_controller.rb index 5134dab..5084696 100644 --- a/app/controllers/room_api/eg006_create_an_external_form_fill_session_controller.rb +++ b/app/controllers/room_api/eg006_create_an_external_form_fill_session_controller.rb @@ -1,5 +1,6 @@ class RoomApi::Eg006CreateAnExternalFormFillSessionController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 6) } def create args = { @@ -12,9 +13,8 @@ def create results = RoomApi::Eg006CreateAnExternalFormFillSessionService.new(args).worker - @title = "External form fill session was successfully created" - @h1 = "External form fill session was successfully created" - @message = "To fill the form navigate the following URL: Fill the form" + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] @json = results.to_json.to_json render 'ds_common/example_done' diff --git a/app/controllers/room_api/eg007_create_form_group_controller.rb b/app/controllers/room_api/eg007_create_form_group_controller.rb index 2791f2f..ccd6c6a 100644 --- a/app/controllers/room_api/eg007_create_form_group_controller.rb +++ b/app/controllers/room_api/eg007_create_form_group_controller.rb @@ -1,5 +1,6 @@ class RoomApi::Eg007CreateFormGroupController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 7) } def create args = { @@ -10,9 +11,8 @@ def create results = RoomApi::Eg007CreateFormGroupService.new(args).worker - @title = "The form group was successfully created" - @h1 = "The form group was successfully created" - @message = "The form group was created! form group ID: #{results.form_group_id}, Name: #{results.name}" + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results.name) @json = results.to_json.to_json render 'ds_common/example_done' diff --git a/app/controllers/room_api/eg008_grant_office_access_to_form_group_controller.rb b/app/controllers/room_api/eg008_grant_office_access_to_form_group_controller.rb index 7831296..ea9c120 100644 --- a/app/controllers/room_api/eg008_grant_office_access_to_form_group_controller.rb +++ b/app/controllers/room_api/eg008_grant_office_access_to_form_group_controller.rb @@ -1,5 +1,6 @@ class RoomApi::Eg008GrantOfficeAccessToFormGroupController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 8) } def create args = { @@ -13,15 +14,13 @@ def create result = results.to_json.to_json if result['exception'] @error_code = results[:exception] - @error_message = "Office may already have access to form group." + @error_message = 'Office may already have access to form group.' render 'ds_common/error' else - @title = "Granted office access to form group" - @h1 = "Granted office access to form group" - @message = "office access has been granted for the form group." + @title = @example['ExampleName'] + @message = 'office access has been granted for the form group.' render 'ds_common/example_done' end - end def get diff --git a/app/controllers/room_api/eg009_assign_form_to_form_group_controller.rb b/app/controllers/room_api/eg009_assign_form_to_form_group_controller.rb index e94bc94..03958e6 100644 --- a/app/controllers/room_api/eg009_assign_form_to_form_group_controller.rb +++ b/app/controllers/room_api/eg009_assign_form_to_form_group_controller.rb @@ -1,5 +1,6 @@ class RoomApi::Eg009AssignFormToFormGroupController < EgController before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 9) } def create args = { @@ -13,12 +14,11 @@ def create result = results.to_json.to_json if result['exception'] @error_code = results[:exception] - @error_message = "Form may already be assigned to form group." + @error_message = 'Form may already be assigned to form group.' render 'ds_common/error' else - @title = "Assigned form to form group" - @h1 = "Assigned form to form group" - @message = "Form has been assigned to the selected form group." + @title = @example['ExampleName'] + @message = 'Form has been assigned to the selected form group.' render 'ds_common/example_done' end diff --git a/app/controllers/session_controller.rb b/app/controllers/session_controller.rb index 7587824..b86a602 100644 --- a/app/controllers/session_controller.rb +++ b/app/controllers/session_controller.rb @@ -3,11 +3,11 @@ class SessionController < ApplicationController # GET /auth/:provider/callback def create - if session[:eg] - redirect_url = "/" + session[:eg] - else - redirect_url = root_path - end + redirect_url = if session[:eg] + "/#{session[:eg]}" + else + root_path + end # reset the session internal_destroy @@ -57,6 +57,7 @@ def internal_destroy session.delete :envelope_documents session.delete :template_id session.delete :eg + session.delete :manifest end def store_auth_hash_from_docusign_callback diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 15b06f0..edbd83e 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,4 +1,7 @@ # frozen_string_literal: true module ApplicationHelper + def format_string(string, *args) + string.gsub(/\{(\d+)\}/) { |s| args[s.to_i] } + end end diff --git a/app/helpers/eg024_brands_creating_helper.rb b/app/helpers/eg024_brands_creating_helper.rb index 8f00128..df0fc09 100644 --- a/app/helpers/eg024_brands_creating_helper.rb +++ b/app/helpers/eg024_brands_creating_helper.rb @@ -1,13 +1,13 @@ module Eg024BrandsCreatingHelper def language_list - languages = [ ['Arabic', 'ar'],[ 'Armenian', 'hy'] , ['Bahasa Indonesia', 'id' ], ['Bahasa Malay', 'ms'], ['Bulgarian', 'bg'], - ['Chinese Simplified', 'zh_CN'], ['Chinese Traditional', 'zh_TW'], ['Croatian', 'hr'], ['Czech', 'cs'], - ['Danish', 'da'], ['Dutch', 'nl'], ['English UK', 'en_GB'], ['English US', 'en' ], ['Estonian', 'et'], ['Farsi', 'fa'], - ['Hindi', 'hi'], ['Hungarian', 'hu'], ['Italian', 'it'], ['Japanese', 'ja'], ['Korean', 'ko'], ['Latvian', 'lv'], - ['Lithuanian', 'lt'], ['Norwegian', 'no'], ['Polish', 'pl'], ['Portuguese', 'pt'], ['Portuguese Brasil', 'pt_BR'], ['Romanian', 'ro'], - ['Russian', 'ru'], ['Serbian', 'sr'], ['Slovak', 'sk'], ['Slovenian', 'sl'], ['Spanish', 'es'], ['Spanish Latin America', 'es_MX'], - ['Swedish', 'sv'], ['Thai', 'th'], ['Turkish', 'tr'], ['Ukranian', 'uk'], ['Vietnamese', 'vi'] ] - array = languages.map{ |key, value| [key, value] } + languages = [%w[Arabic ar], %w[Armenian hy], ['Bahasa Indonesia', 'id'], ['Bahasa Malay', 'ms'], %w[Bulgarian bg], + ['Chinese Simplified', 'zh_CN'], ['Chinese Traditional', 'zh_TW'], %w[Croatian hr], %w[Czech cs], + %w[Danish da], %w[Dutch nl], ['English UK', 'en_GB'], ['English US', 'en'], %w[Estonian et], %w[Farsi fa], + %w[Hindi hi], %w[Hungarian hu], %w[Italian it], %w[Japanese ja], %w[Korean ko], %w[Latvian lv], + %w[Lithuanian lt], %w[Norwegian no], %w[Polish pl], %w[Portuguese pt], ['Portuguese Brasil', 'pt_BR'], %w[Romanian ro], + %w[Russian ru], %w[Serbian sr], %w[Slovak sk], %w[Slovenian sl], %w[Spanish es], ['Spanish Latin America', 'es_MX'], + %w[Swedish sv], %w[Thai th], %w[Turkish tr], %w[Ukranian uk], %w[Vietnamese vi]] + array = languages.map { |key, value| [key, value] } options_for_select(array) end end diff --git a/app/services/admin_api/eg001_create_user_service.rb b/app/services/admin_api/eg001_create_user_service.rb index a951e25..3626cec 100644 --- a/app/services/admin_api/eg001_create_user_service.rb +++ b/app/services/admin_api/eg001_create_user_service.rb @@ -14,12 +14,12 @@ def worker configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") # Step 2 end # Step 4 start users_api = DocuSign_Admin::UsersApi.new(api_client) - response = users_api.create_user(args[:organization_id], user_data) + users_api.create_user(args[:organization_id], user_data) # Step 4 end end end diff --git a/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb b/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb index 0c96d04..ebc5cc1 100644 --- a/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb +++ b/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb @@ -13,12 +13,12 @@ def worker configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") # Step 2 end # Step 6 start users_api = DocuSign_Admin::UsersApi.new(api_client) - response = users_api.add_or_update_user(args[:organization_id], args[:account_id], body(args)) + users_api.add_or_update_user(args[:organization_id], args[:account_id], body(args)) # Step 6 end end @@ -33,21 +33,21 @@ def body(args) email: args[:email], auto_activate_memberships: true, product_permission_profiles: [ - { - permission_profile_id: args[:esign_permission_profile_id], - product_id: args[:esign_product_id] - }, - { - permission_profile_id: args[:clm_permission_profile_id], - product_id: args[:clm_product_id] - } + { + permission_profile_id: args[:esign_permission_profile_id], + product_id: args[:esign_product_id] + }, + { + permission_profile_id: args[:clm_permission_profile_id], + product_id: args[:clm_product_id] + } ], ds_groups: [ - { - ds_group_id: args[:ds_group_id] - } + { + ds_group_id: args[:ds_group_id] + } ] } end # Step 5 end -end \ No newline at end of file +end diff --git a/app/services/admin_api/eg003_bulk_export_user_data_service.rb b/app/services/admin_api/eg003_bulk_export_user_data_service.rb index 66d750d..ba2652d 100644 --- a/app/services/admin_api/eg003_bulk_export_user_data_service.rb +++ b/app/services/admin_api/eg003_bulk_export_user_data_service.rb @@ -11,7 +11,7 @@ def worker configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") # Step 2 end # Step 3 start @@ -33,7 +33,7 @@ def worker end # Step 4 end - return response + response end private @@ -60,4 +60,4 @@ def get_exported_user_data(args, export_id) end end # Step 5 end -end \ No newline at end of file +end diff --git a/app/services/admin_api/eg004_import_user_service.rb b/app/services/admin_api/eg004_import_user_service.rb index 71d4b95..a6ac454 100644 --- a/app/services/admin_api/eg004_import_user_service.rb +++ b/app/services/admin_api/eg004_import_user_service.rb @@ -11,7 +11,7 @@ def worker configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") # Step 2 end # Step 3 start @@ -19,8 +19,7 @@ def worker csv_file_data = csv_file_data.gsub('{account_id}', args[:account_id]) @bulk_imports_api = DocuSign_Admin::BulkImportsApi.new(api_client) - response = @bulk_imports_api.create_bulk_import_add_users_request(args[:organization_id], csv_file_data) + @bulk_imports_api.create_bulk_import_add_users_request(args[:organization_id], csv_file_data) # Step 3 end - return response end -end \ No newline at end of file +end diff --git a/app/services/admin_api/eg005_audit_users_service.rb b/app/services/admin_api/eg005_audit_users_service.rb index dc77674..dfb8496 100644 --- a/app/services/admin_api/eg005_audit_users_service.rb +++ b/app/services/admin_api/eg005_audit_users_service.rb @@ -13,7 +13,7 @@ def worker configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") # Step 2 end # Step 3 start @@ -35,6 +35,6 @@ def worker end # Step 5 end - return results + results end -end \ No newline at end of file +end diff --git a/app/services/admin_api/eg006_get_user_profile_by_email_service.rb b/app/services/admin_api/eg006_get_user_profile_by_email_service.rb index 6ebf2e8..5dc4b7b 100644 --- a/app/services/admin_api/eg006_get_user_profile_by_email_service.rb +++ b/app/services/admin_api/eg006_get_user_profile_by_email_service.rb @@ -13,7 +13,7 @@ def worker configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") # Step 2 end # Step 3 start @@ -21,7 +21,7 @@ def worker options = DocuSign_Admin::GetUserDSProfilesByEmailOptions.new options.email = args[:email] - response = users_api.get_user_ds_profiles_by_email(args[:organization_id], options) + users_api.get_user_ds_profiles_by_email(args[:organization_id], options) # Step 3 end end end diff --git a/app/services/admin_api/eg007_get_user_profile_by_user_id_service.rb b/app/services/admin_api/eg007_get_user_profile_by_user_id_service.rb index 1a48395..09afb34 100644 --- a/app/services/admin_api/eg007_get_user_profile_by_user_id_service.rb +++ b/app/services/admin_api/eg007_get_user_profile_by_user_id_service.rb @@ -13,12 +13,12 @@ def worker configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") # Step 2 end # Step 3 start users_api = DocuSign_Admin::UsersApi.new(api_client) - response = users_api.get_user_ds_profile(args[:organization_id], args[:user_id]) + users_api.get_user_ds_profile(args[:organization_id], args[:user_id]) # Step 3 end end end diff --git a/app/services/admin_api/eg008_update_user_product_permission_profile_service.rb b/app/services/admin_api/eg008_update_user_product_permission_profile_service.rb index 2e945d1..c63b774 100644 --- a/app/services/admin_api/eg008_update_user_product_permission_profile_service.rb +++ b/app/services/admin_api/eg008_update_user_product_permission_profile_service.rb @@ -13,17 +13,17 @@ def worker configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") # Step 2 end # Step 3 start - product_permission_profile = DocuSign_Admin::ProductPermissionProfileRequest.new({'permission_profile_id' => args[:permission_profile_id], 'product_id' => args[:product_id]}) - user_product_permission_profile_request = DocuSign_Admin::UserProductPermissionProfilesRequest.new({'email' => args[:email], 'product_permission_profiles' => [product_permission_profile]}) + product_permission_profile = DocuSign_Admin::ProductPermissionProfileRequest.new({ 'permission_profile_id' => args[:permission_profile_id], 'product_id' => args[:product_id] }) + user_product_permission_profile_request = DocuSign_Admin::UserProductPermissionProfilesRequest.new({ 'email' => args[:email], 'product_permission_profiles' => [product_permission_profile] }) # Step 3 end # Step 4 start product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(api_client) - response = product_permission_profiles_api.add_user_product_permission_profiles_by_email(args[:organization_id], args[:account_id], user_product_permission_profile_request) + product_permission_profiles_api.add_user_product_permission_profiles_by_email(args[:organization_id], args[:account_id], user_product_permission_profile_request) # Step 4 end end -end \ No newline at end of file +end diff --git a/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb b/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb index 12794bc..413de64 100644 --- a/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb +++ b/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb @@ -13,16 +13,16 @@ def worker configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") # Step 2 end # Step 3 start - user_product_profile_delete_request = DocuSign_Admin::UserProductProfileDeleteRequest.new({'user_email' => args[:email], 'product_ids' => [args[:product_id]]}) + user_product_profile_delete_request = DocuSign_Admin::UserProductProfileDeleteRequest.new({ 'user_email' => args[:email], 'product_ids' => [args[:product_id]] }) # Step 3 end # Step 4 start product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(api_client) - response = product_permission_profiles_api.remove_user_product_permission(args[:organization_id], args[:account_id], user_product_profile_delete_request) + product_permission_profiles_api.remove_user_product_permission(args[:organization_id], args[:account_id], user_product_profile_delete_request) # Step 4 end end @@ -31,7 +31,7 @@ def get_permission_profiles_by_email configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(api_client) @@ -40,6 +40,5 @@ def get_permission_profiles_by_email product_permission_profiles = product_permission_profiles_api.get_user_product_permission_profiles_by_email(args[:organization_id], args[:account_id], options) product_permission_profiles.as_json['product_permission_profiles'] - end -end \ No newline at end of file +end diff --git a/app/services/admin_api/get_data_service.rb b/app/services/admin_api/get_data_service.rb index 058db0c..c6e7726 100644 --- a/app/services/admin_api/get_data_service.rb +++ b/app/services/admin_api/get_data_service.rb @@ -1,70 +1,67 @@ class AdminApi::GetDataService - attr_reader :args + attr_reader :args - def initialize(session, options = {}) - @args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - organization_id: session[:organization_id] - } - end + def initialize(session, _options = {}) + @args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + organization_id: session[:organization_id] + } + end - def get_product_permission_profiles - worker + def get_product_permission_profiles + worker - # Step 3 start - product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(@api_client) - product_permission_profiles = product_permission_profiles_api.get_product_permission_profiles(args[:organization_id], args[:account_id]) - product_permission_profiles.as_json['product_permission_profiles'] - # Step 3 end - end + # Step 3 start + product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(@api_client) + product_permission_profiles = product_permission_profiles_api.get_product_permission_profiles(args[:organization_id], args[:account_id]) + product_permission_profiles.as_json['product_permission_profiles'] + # Step 3 end + end - def get_ds_groups - worker + def get_ds_groups + worker - # Step 4 start - ds_groups_api = DocuSign_Admin::DSGroupsApi.new(@api_client) - ds_groups = ds_groups_api.get_ds_groups(args[:organization_id], args[:account_id]) - ds_groups.as_json['ds_groups'] - # Step 4 end - end + # Step 4 start + ds_groups_api = DocuSign_Admin::DSGroupsApi.new(@api_client) + ds_groups = ds_groups_api.get_ds_groups(args[:organization_id], args[:account_id]) + ds_groups.as_json['ds_groups'] + # Step 4 end + end - def get_organization_id - worker - accounts_api = DocuSign_Admin::AccountsApi.new(@api_client) - accounts_api.get_organizations().organizations[0].as_json['id'] - end + def get_organization_id + worker + accounts_api = DocuSign_Admin::AccountsApi.new(@api_client) + accounts_api.get_organizations.organizations[0].as_json['id'] + end - def check_import_status(import_id) - worker - bulk_imports_api = DocuSign_Admin::BulkImportsApi.new(@api_client) - # Step 4 start - response = bulk_imports_api.get_bulk_user_import_request(args[:organization_id], import_id); - # Step 4 end - return response - end + def check_import_status(import_id) + worker + bulk_imports_api = DocuSign_Admin::BulkImportsApi.new(@api_client) + # Step 4 start + bulk_imports_api.get_bulk_user_import_request(args[:organization_id], import_id) + # Step 4 end + end - def check_user_exists_by_email(email) - worker - users_api = DocuSign_Admin::UsersApi.new(@api_client) - options = DocuSign_Admin::GetUsersOptions.new() - options.email = email - response = users_api.get_users(args[:organization_id], options) + def check_user_exists_by_email(email) + worker + users_api = DocuSign_Admin::UsersApi.new(@api_client) + options = DocuSign_Admin::GetUsersOptions.new + options.email = email + response = users_api.get_users(args[:organization_id], options) - if response.users.length == 0 || response.users[0].user_status == "closed" - return false - end + return false if response.users.length.zero? || response.users[0].user_status == 'closed' - return true - end + true + end - private + private - def worker - configuration = DocuSign_Admin::Configuration.new - configuration.host = Rails.configuration.admin_host - @api_client = DocuSign_Admin::ApiClient.new(configuration) - @api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") - end - end \ No newline at end of file + def worker + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + @api_client = DocuSign_Admin::ApiClient.new(configuration) + @api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + end +end diff --git a/app/services/api_creator.rb b/app/services/api_creator.rb index 47694b6..4f42a63 100644 --- a/app/services/api_creator.rb +++ b/app/services/api_creator.rb @@ -19,7 +19,7 @@ def create_account_api(args) api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" # Construct your request body - accounts_api = DocuSign_eSign::AccountsApi.new api_client + DocuSign_eSign::AccountsApi.new api_client end def create_template_api(args) @@ -27,7 +27,7 @@ def create_template_api(args) configuration.host = args[:base_path] api_client = DocuSign_eSign::ApiClient.new configuration api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" - templates_api = DocuSign_eSign::TemplatesApi.new api_client + DocuSign_eSign::TemplatesApi.new api_client end def create_envelope_api(args) @@ -47,6 +47,6 @@ def create_group_api(args) configuration.host = args[:base_path] api_client = DocuSign_eSign::ApiClient.new configuration api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" - group_api = DocuSign_eSign::GroupsApi.new api_client + DocuSign_eSign::GroupsApi.new api_client end end diff --git a/app/services/clickwrap/eg002_activate_clickwrap_service.rb b/app/services/clickwrap/eg002_activate_clickwrap_service.rb index bc67256..20b9892 100644 --- a/app/services/clickwrap/eg002_activate_clickwrap_service.rb +++ b/app/services/clickwrap/eg002_activate_clickwrap_service.rb @@ -21,7 +21,7 @@ def worker # Step 4. Call the Click API accounts_api = DocuSign_Click::AccountsApi.new(api_client) - response = accounts_api.update_clickwrap_version( + accounts_api.update_clickwrap_version( args[:account_id], args[:clickwrap_id], 1, diff --git a/app/services/e_sign/eg002_signing_via_email_service.rb b/app/services/e_sign/eg002_signing_via_email_service.rb index 819a128..ed5207b 100644 --- a/app/services/e_sign/eg002_signing_via_email_service.rb +++ b/app/services/e_sign/eg002_signing_via_email_service.rb @@ -2,6 +2,7 @@ class ESign::Eg002SigningViaEmailService attr_reader :args + include ApiCreator def initialize(args) @@ -110,8 +111,8 @@ def make_envelope(envelope_args) # Add the tabs model (including the sign_here tabs) to the signer # The Tabs object takes arrays of the different field/tab types signer1_tabs = DocuSign_eSign::Tabs.new({ - signHereTabs: [sign_here1, sign_here2] - }) + signHereTabs: [sign_here1, sign_here2] + }) signer1.tabs = signer1_tabs @@ -151,4 +152,4 @@ def create_document1(args) " end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg003_list_envelopes_service.rb b/app/services/e_sign/eg003_list_envelopes_service.rb index d4f7ddf..12c36cf 100644 --- a/app/services/e_sign/eg003_list_envelopes_service.rb +++ b/app/services/e_sign/eg003_list_envelopes_service.rb @@ -2,6 +2,7 @@ class ESign::Eg003ListEnvelopesService attr_reader :args + include ApiCreator def initialize(args) @@ -20,6 +21,6 @@ def worker options = DocuSign_eSign::ListStatusChangesOptions.new options.from_date = (Date.today - 30).strftime('%Y/%m/%d') # Exceptions will be caught by the calling function - results = envelope_api.list_status_changes args[:account_id], options + envelope_api.list_status_changes args[:account_id], options end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg004_envelope_info_service.rb b/app/services/e_sign/eg004_envelope_info_service.rb index 03e6d39..aca56f3 100644 --- a/app/services/e_sign/eg004_envelope_info_service.rb +++ b/app/services/e_sign/eg004_envelope_info_service.rb @@ -2,6 +2,7 @@ class ESign::Eg004EnvelopeInfoService attr_reader :args + include ApiCreator def initialize(args) @@ -10,6 +11,6 @@ def initialize(args) def worker envelope_api = create_envelope_api(args) - results = envelope_api.get_envelope(args[:account_id], args[:envelope_id]) + envelope_api.get_envelope(args[:account_id], args[:envelope_id]) end end diff --git a/app/services/e_sign/eg005_envelope_recipients_service.rb b/app/services/e_sign/eg005_envelope_recipients_service.rb index 2309409..e78fb41 100644 --- a/app/services/e_sign/eg005_envelope_recipients_service.rb +++ b/app/services/e_sign/eg005_envelope_recipients_service.rb @@ -2,6 +2,7 @@ class ESign::Eg005EnvelopeRecipientsService attr_reader :args + include ApiCreator def initialize(args) @@ -10,6 +11,6 @@ def initialize(args) def worker envelope_api = create_envelope_api(args) - results = envelope_api.list_recipients args[:account_id], args[:envelope_id] + envelope_api.list_recipients args[:account_id], args[:envelope_id] end end diff --git a/app/services/e_sign/eg006_envelope_docs_service.rb b/app/services/e_sign/eg006_envelope_docs_service.rb index 10874c4..1708712 100644 --- a/app/services/e_sign/eg006_envelope_docs_service.rb +++ b/app/services/e_sign/eg006_envelope_docs_service.rb @@ -2,6 +2,7 @@ class ESign::Eg006EnvelopeDocsService attr_reader :args + include ApiCreator def initialize(args) @@ -11,8 +12,7 @@ def initialize(args) # ***DS.snippet.0.start def worker envelope_api = create_envelope_api(args) - results = envelope_api.list_documents args[:account_id], args[:envelope_id] - results + envelope_api.list_documents args[:account_id], args[:envelope_id] end # ***DS.snippet.0.end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg007_envelope_get_doc_service.rb b/app/services/e_sign/eg007_envelope_get_doc_service.rb index 1d3a592..4d75784 100644 --- a/app/services/e_sign/eg007_envelope_get_doc_service.rb +++ b/app/services/e_sign/eg007_envelope_get_doc_service.rb @@ -2,6 +2,7 @@ class ESign::Eg007EnvelopeGetDocService attr_reader :args + include ApiCreator def initialize(args) diff --git a/app/services/e_sign/eg008_create_template_service.rb b/app/services/e_sign/eg008_create_template_service.rb index 58f8640..b8d74f2 100644 --- a/app/services/e_sign/eg008_create_template_service.rb +++ b/app/services/e_sign/eg008_create_template_service.rb @@ -2,6 +2,7 @@ class ESign::Eg008CreateTemplateService attr_reader :args + include ApiCreator def initialize(args) @@ -17,7 +18,7 @@ def worker results = templates_api.list_templates(args[:account_id], options) created_new_template = false - if results.result_set_size.to_i > 0 + if results.result_set_size.to_i.positive? template_id = results.envelope_templates[0].template_id results_template_name = results.envelope_templates[0].name else @@ -63,9 +64,9 @@ def make_template_req # Create the signer recipient model # Since these are role definitions, no name/email: - signer = DocuSign_eSign::Signer.new ({ - 'roleName' => 'signer', 'recipientId' => '1', 'routingOrder' => '1' - }) + signer = DocuSign_eSign::Signer.new({ + 'roleName' => 'signer', 'recipientId' => '1', 'routingOrder' => '1' + }) # Create a cc recipient to receive a copy of the documents cc = DocuSign_eSign::CarbonCopy.new({ 'roleName' => 'cc', 'recipientId' => '2', 'routingOrder' => '2' @@ -158,7 +159,7 @@ def make_template_req ) # Top object: - template_request = DocuSign_eSign::EnvelopeTemplate.new( + DocuSign_eSign::EnvelopeTemplate.new( 'documents' => [document], 'name' => template_name, 'emailSubject' => 'Please sign this document', @@ -168,8 +169,6 @@ def make_template_req ), 'status' => 'created' ) - - template_request end # ***DS.snippet.0.end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg009_use_template_service.rb b/app/services/e_sign/eg009_use_template_service.rb index 0211dd2..22c4a70 100644 --- a/app/services/e_sign/eg009_use_template_service.rb +++ b/app/services/e_sign/eg009_use_template_service.rb @@ -2,6 +2,7 @@ class ESign::Eg009UseTemplateService attr_reader :args + include ApiCreator def initialize(args) @@ -65,4 +66,4 @@ def make_envelope(args) envelope_definition end # ***DS.snippet.0.end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg010_send_binary_docs_service.rb b/app/services/e_sign/eg010_send_binary_docs_service.rb index ae75f96..2057c96 100644 --- a/app/services/e_sign/eg010_send_binary_docs_service.rb +++ b/app/services/e_sign/eg010_send_binary_docs_service.rb @@ -97,14 +97,11 @@ def worker response = http.request(req) obj = JSON.parse(response.body) - if (response.code.to_i >= 200) && (response.code.to_i < 300) - envelope_id = obj['envelopeId'] - { 'envelope_id' => envelope_id } - else - raise Net::HTTPError.new(response.code, response.body) - end - end + raise Net::HTTPError.new(response.code, response.body) unless (response.code.to_i >= 200) && (response.code.to_i < 300) + envelope_id = obj['envelopeId'] + { 'envelope_id' => envelope_id } + end def make_envelope_json(envelope_args) # document 1 (HTML) has tag **signature_1** @@ -163,23 +160,23 @@ def make_envelope_json(envelope_args) # The DocuSign platform searches throughout your envelope's documents for matching # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 # since they use the same anchor string for their "signer 1" tabs. - sign_here1 = DocuSign_eSign::SignHere.new ({ - anchorString: '**signature_1**', - anchorYOffset: '10', - anchorUnits: 'pixels', - anchorXOffset: '20' - }) - - sign_here2 = DocuSign_eSign::SignHere.new ({ - anchorString: '/sn1/', - anchorYOffset: '10', - anchorUnits: 'pixels', - anchorXOffset: '20' - }) + sign_here1 = DocuSign_eSign::SignHere.new({ + anchorString: '**signature_1**', + anchorYOffset: '10', + anchorUnits: 'pixels', + anchorXOffset: '20' + }) + + sign_here2 = DocuSign_eSign::SignHere.new({ + anchorString: '/sn1/', + anchorYOffset: '10', + anchorUnits: 'pixels', + anchorXOffset: '20' + }) # Tabs are set per recipient/signer - signer1_tabs = DocuSign_eSign::Tabs.new ({ - signHereTabs: [sign_here1, sign_here2] - }) + signer1_tabs = DocuSign_eSign::Tabs.new({ + signHereTabs: [sign_here1, sign_here2] + }) signer1.tabs = signer1_tabs @@ -218,4 +215,4 @@ def create_document1(args) " end # ***DS.snippet.0.end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg011_embedded_sending_service.rb b/app/services/e_sign/eg011_embedded_sending_service.rb index cb157b8..dac2703 100644 --- a/app/services/e_sign/eg011_embedded_sending_service.rb +++ b/app/services/e_sign/eg011_embedded_sending_service.rb @@ -2,6 +2,7 @@ class ESign::Eg011EmbeddedSendingService attr_reader :args + include ApiCreator def initialize(args) @@ -125,9 +126,9 @@ def make_envelope(envelope_args) ) # Add the tabs model (including the sign_here tabs) to the signer # The Tabs object takes arrays of the different field/tab types - signer1_tabs = DocuSign_eSign::Tabs.new ({ - signHereTabs: [sign_here1, sign_here2] - }) + signer1_tabs = DocuSign_eSign::Tabs.new({ + signHereTabs: [sign_here1, sign_here2] + }) signer1.tabs = signer1_tabs @@ -167,4 +168,4 @@ def create_document1(args) " end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg012_embedded_console_service.rb b/app/services/e_sign/eg012_embedded_console_service.rb index e01344f..cca1ff1 100644 --- a/app/services/e_sign/eg012_embedded_console_service.rb +++ b/app/services/e_sign/eg012_embedded_console_service.rb @@ -2,6 +2,7 @@ class ESign::Eg012EmbeddedConsoleService attr_reader :args + include ApiCreator def initialize(args) @@ -15,13 +16,11 @@ def worker view_request = DocuSign_eSign::ConsoleViewRequest.new({ returnUrl: args[:ds_return_url] }) - if args[:starting_view] == 'envelope' && args[:envelope_id] - view_request.envelope_id = args[:envelope_id] - end + view_request.envelope_id = args[:envelope_id] if args[:starting_view] == 'envelope' && args[:envelope_id] # Step 2. Call the API method envelope_api = create_envelope_api(args) results = envelope_api.create_console_view args[:account_id], view_request { 'redirect_url' => results.url } end # ***DS.snippet.0.end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg013_add_doc_to_template_service.rb b/app/services/e_sign/eg013_add_doc_to_template_service.rb index 6af6ed0..749e4d5 100644 --- a/app/services/e_sign/eg013_add_doc_to_template_service.rb +++ b/app/services/e_sign/eg013_add_doc_to_template_service.rb @@ -2,6 +2,7 @@ class ESign::Eg013AddDocToTemplateService attr_reader :args + include ApiCreator def initialize(args) @@ -118,12 +119,10 @@ def make_envelope(args) document: doc1 ) # 8. Create the envelope definition with the composited templates - envelope_definition = DocuSign_eSign::EnvelopeDefinition.new( + DocuSign_eSign::EnvelopeDefinition.new( status: 'sent', compositeTemplates: [comp_template1, comp_template2] ) - - envelope_definition end def create_document1(args) @@ -153,4 +152,4 @@ def create_document1(args) HEREDOC end # ***DS.snippet.0.start -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg014_collect_payment_service.rb b/app/services/e_sign/eg014_collect_payment_service.rb index 76e0e88..1286139 100644 --- a/app/services/e_sign/eg014_collect_payment_service.rb +++ b/app/services/e_sign/eg014_collect_payment_service.rb @@ -2,6 +2,7 @@ class ESign::Eg014CollectPaymentService attr_reader :args + include ApiCreator def initialize(args) @@ -32,16 +33,16 @@ def make_envelope(args) # 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 + # After it is signed, a copy is sent to the cc person # # ################################################################# - # # - # # NOTA BENE: This method 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 WYSIWYG - # # form designer. - # # + # # + # # NOTA BENE: This method 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 WYSIWYG + # # form designer. + # # # ################################################################# # @@ -200,4 +201,4 @@ def make_envelope(args) envelope_definition end # ***DS.snippet.0.end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg015_get_envelope_tab_data_service.rb b/app/services/e_sign/eg015_get_envelope_tab_data_service.rb index cb0382d..4a16dff 100644 --- a/app/services/e_sign/eg015_get_envelope_tab_data_service.rb +++ b/app/services/e_sign/eg015_get_envelope_tab_data_service.rb @@ -2,6 +2,7 @@ class ESign::Eg015GetEnvelopeTabDataService attr_reader :args + include ApiCreator def initialize(args) @@ -16,7 +17,7 @@ def worker # The get form data call requires an account ID and an envelope ID # Exceptions will be caught by the calling function - results = create_envelope_api(args).get_form_data args[:account_id], args[:envelope_id] + create_envelope_api(args).get_form_data args[:account_id], args[:envelope_id] end # ***DS.snippet.0.end end diff --git a/app/services/e_sign/eg016_set_envelope_tab_data_service.rb b/app/services/e_sign/eg016_set_envelope_tab_data_service.rb index 8394581..f52b701 100644 --- a/app/services/e_sign/eg016_set_envelope_tab_data_service.rb +++ b/app/services/e_sign/eg016_set_envelope_tab_data_service.rb @@ -2,6 +2,7 @@ class ESign::Eg016SetEnvelopeTabDataService attr_reader :args + include ApiCreator def initialize(args) @@ -43,7 +44,7 @@ def make_recipient_view_request(signer_email, signer_name, signer_client_id, ds_ # 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 - view_request.return_url = ds_return_url + '?state=123' + view_request.return_url = "#{ds_return_url}?state=123" # How has your app authenticated the user? In addition to your app's authentication, # you can include authenticate steps from DocuSign; e.g., SMS authentication @@ -79,10 +80,10 @@ def make_envelope(signer_email, signer_name, signer_client_id, pdf_filename) envelope_definition.documents = [doc1] # Create a signer recipient to sign the document, identified by name and email # We're setting the parameters via the object creation - signer1 = DocuSign_eSign::Signer.new ({ - email: signer_email, name: signer_name, - clientUserId: signer_client_id, recipientId: 1 - }) + signer1 = DocuSign_eSign::Signer.new({ + email: signer_email, name: signer_name, + clientUserId: signer_client_id, recipientId: 1 + }) # Step 3. Create Tabs and CustomFields salary = '$123,000' diff --git a/app/services/e_sign/eg017_set_template_tab_values_service.rb b/app/services/e_sign/eg017_set_template_tab_values_service.rb index d45da1c..a444a7a 100644 --- a/app/services/e_sign/eg017_set_template_tab_values_service.rb +++ b/app/services/e_sign/eg017_set_template_tab_values_service.rb @@ -2,151 +2,151 @@ class ESign::Eg017SetTemplateTabValuesService attr_reader :args + include ApiCreator def initialize(args) @args = args end -# ***DS.snippet.0.start -def worker - ds_ping_url = Rails.application.config.app_url - ds_return_url = "#{ds_ping_url}/ds_common-return" - signer_client_id = 1000 - envelope_args = args[:envelope_args] - - # Step 4. Construct the request body - envelope_definition = make_envelope(envelope_args) - - # Step 5. Call the eSignature REST API - envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope args[:account_id], envelope_definition - envelope_id = results.envelope_id - - # Step 6. Create the View Request - view_request = make_recipient_view_request(envelope_args[:signer_email], envelope_args[:signer_name], signer_client_id, ds_return_url, ds_ping_url) - - # Call the CreateRecipientView API - results = create_envelope_api(args).create_recipient_view args[:account_id], envelope_id, view_request - - # 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 return URL (see the makeRecipientViewRequest method) - # Redirect to results.url - results.url -end - -private - -def make_envelope(args) - # Create the envelope definition with the template_id - envelope_definition = DocuSign_eSign::EnvelopeDefinition.new({ - status: 'sent', - templateId: args[:template_id] - }) - # Create the template role elements to connect the signer and cc recipients - # to the template - signer = DocuSign_eSign::TemplateRole.new({ - clientUserId: 1000, - email: args[:signer_email], - name: args[:signer_name], - roleName: 'signer' - }) - # Create a cc template role. - cc = DocuSign_eSign::TemplateRole.new({ - email: args[:cc_email], - name: args[:cc_name], - roleName: 'cc' - }) - - # Step 3. Create Tabs and CustomFields - - # List item - list1 = DocuSign_eSign::List.new - list1.value = 'Green' - list1.document_id = '1' - list1.page_number = '1' - list1.tab_label = 'list' - - # Checkboxes - check1 = DocuSign_eSign::Checkbox.new - check1.tab_label = 'ckAuthorization' - check1.selected = 'true' - - check3 = DocuSign_eSign::Checkbox.new - check3.tab_label = 'ckAgreement' - check3.selected = 'true' - - radioGroup = DocuSign_eSign::RadioGroup.new - radioGroup.group_name = 'radio1' - radio = DocuSign_eSign::Radio.new - radio.value = 'white' - radio.selected = 'true' - radioGroup.radios = [radio] - - text = DocuSign_eSign::Text.new - text.tab_label = 'text' - text.value = 'Jabberwocky!' - - # We can also add a new tab (field) to the ones already in the template - textExtra = DocuSign_eSign::Text.new - textExtra.document_id = '1' - textExtra.page_number = '1' - textExtra.x_position = '280' - textExtra.y_position = '172' - textExtra.font = 'helvetica' - textExtra.font_size = 'size14' - textExtra.tab_label = 'added text field' - textExtra.height = '23' - textExtra.width = '84' - textExtra.required = 'false' - textExtra.bold = 'true' - textExtra.value = args[:signer_name] - textExtra.locked = 'false' - textExtra.tab_id = 'name' - - # Pull together the existing and new tabs in a Tabs object - tabs = DocuSign_eSign::Tabs.new - tabs.list_tabs = [list1] - tabs.checkbox_tabs = [check1, check3] - tabs.radio_group_tabs = [radioGroup] - tabs.text_tabs = [text, textExtra] - signer.tabs = tabs - - # Add the TemplateRole objects to the envelope object - envelope_definition.template_roles = [signer, cc] - envelope_definition -end + # ***DS.snippet.0.start + def worker + ds_ping_url = Rails.application.config.app_url + ds_return_url = "#{ds_ping_url}/ds_common-return" + signer_client_id = 1000 + envelope_args = args[:envelope_args] + + # Step 4. Construct the request body + envelope_definition = make_envelope(envelope_args) + + # Step 5. Call the eSignature REST API + envelope_api = create_envelope_api(args) + results = envelope_api.create_envelope args[:account_id], envelope_definition + envelope_id = results.envelope_id + + # Step 6. Create the View Request + view_request = make_recipient_view_request(envelope_args[:signer_email], envelope_args[:signer_name], signer_client_id, ds_return_url, ds_ping_url) + + # Call the CreateRecipientView API + results = create_envelope_api(args).create_recipient_view args[:account_id], envelope_id, view_request + + # 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 return URL (see the makeRecipientViewRequest method) + # Redirect to results.url + results.url + end + private + + def make_envelope(args) + # Create the envelope definition with the template_id + envelope_definition = DocuSign_eSign::EnvelopeDefinition.new({ + status: 'sent', + templateId: args[:template_id] + }) + # Create the template role elements to connect the signer and cc recipients + # to the template + signer = DocuSign_eSign::TemplateRole.new({ + clientUserId: 1000, + email: args[:signer_email], + name: args[:signer_name], + roleName: 'signer' + }) + # Create a cc template role. + cc = DocuSign_eSign::TemplateRole.new({ + email: args[:cc_email], + name: args[:cc_name], + roleName: 'cc' + }) + + # Step 3. Create Tabs and CustomFields + + # List item + list1 = DocuSign_eSign::List.new + list1.value = 'Green' + list1.document_id = '1' + list1.page_number = '1' + list1.tab_label = 'list' + + # Checkboxes + check1 = DocuSign_eSign::Checkbox.new + check1.tab_label = 'ckAuthorization' + check1.selected = 'true' + + check3 = DocuSign_eSign::Checkbox.new + check3.tab_label = 'ckAgreement' + check3.selected = 'true' + + radioGroup = DocuSign_eSign::RadioGroup.new + radioGroup.group_name = 'radio1' + radio = DocuSign_eSign::Radio.new + radio.value = 'white' + radio.selected = 'true' + radioGroup.radios = [radio] + + text = DocuSign_eSign::Text.new + text.tab_label = 'text' + text.value = 'Jabberwocky!' + + # We can also add a new tab (field) to the ones already in the template + textExtra = DocuSign_eSign::Text.new + textExtra.document_id = '1' + textExtra.page_number = '1' + textExtra.x_position = '280' + textExtra.y_position = '172' + textExtra.font = 'helvetica' + textExtra.font_size = 'size14' + textExtra.tab_label = 'added text field' + textExtra.height = '23' + textExtra.width = '84' + textExtra.required = 'false' + textExtra.bold = 'true' + textExtra.value = args[:signer_name] + textExtra.locked = 'false' + textExtra.tab_id = 'name' + + # Pull together the existing and new tabs in a Tabs object + tabs = DocuSign_eSign::Tabs.new + tabs.list_tabs = [list1] + tabs.checkbox_tabs = [check1, check3] + tabs.radio_group_tabs = [radioGroup] + tabs.text_tabs = [text, textExtra] + signer.tabs = tabs + + # Add the TemplateRole objects to the envelope object + envelope_definition.template_roles = [signer, cc] + envelope_definition + end -def make_recipient_view_request(signer_email, signer_name, signer_client_id, ds_return_url, ds_ping_url) - view_request = DocuSign_eSign::RecipientViewRequest.new - # Set the URL where you want the recipient to go once they are done signing; this - # 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 - view_request.return_url = ds_return_url + '?state=123' - - # How has your app authenticated the user? In addition to your app's authentication, - # you can include authenticate steps from DocuSign; e.g., SMS authentication - view_request.authentication_method = 'none' - - # Recipient information must match embedded recipient info we used to create the envelope - view_request.email = signer_email - view_request.user_name = signer_name - view_request.client_user_id = 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 - view_request.ping_frequency = '600' # seconds - # NOTE: The pings will only be sent if the pingUrl is an HTTPS address - view_request.ping_url = ds_ping_url # optional setting - - view_request + def make_recipient_view_request(signer_email, signer_name, signer_client_id, ds_return_url, ds_ping_url) + view_request = DocuSign_eSign::RecipientViewRequest.new + # Set the URL where you want the recipient to go once they are done signing; this + # 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 + view_request.return_url = "#{ds_return_url}?state=123" + + # How has your app authenticated the user? In addition to your app's authentication, + # you can include authenticate steps from DocuSign; e.g., SMS authentication + view_request.authentication_method = 'none' + + # Recipient information must match embedded recipient info we used to create the envelope + view_request.email = signer_email + view_request.user_name = signer_name + view_request.client_user_id = 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 + view_request.ping_frequency = '600' # seconds + # NOTE: The pings will only be sent if the pingUrl is an HTTPS address + view_request.ping_url = ds_ping_url # optional setting + + view_request + end + # ***DS.snippet.0.end end -# ***DS.snippet.0.end -end \ No newline at end of file diff --git a/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb b/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb index fb0156e..e7accc6 100644 --- a/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb +++ b/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb @@ -2,6 +2,7 @@ class ESign::Eg018GetEnvelopeCustomFieldDataService attr_reader :args + include ApiCreator def initialize(args) @@ -10,6 +11,6 @@ def initialize(args) def worker # Step 3. Call the eSignature REST API - results = create_envelope_api(args).list_custom_fields args[:account_id], args[:envelope_id] + create_envelope_api(args).list_custom_fields args[:account_id], args[:envelope_id] end end diff --git a/app/services/e_sign/eg019_access_code_authentication_service.rb b/app/services/e_sign/eg019_access_code_authentication_service.rb index 89d3522..364b717 100644 --- a/app/services/e_sign/eg019_access_code_authentication_service.rb +++ b/app/services/e_sign/eg019_access_code_authentication_service.rb @@ -2,6 +2,7 @@ class ESign::Eg019AccessCodeAuthenticationService attr_reader :args + include ApiCreator def initialize(args) @@ -45,9 +46,9 @@ def worker # Add the tabs model (including the sign_here tabs) to the signer # The Tabs object takes arrays of the different field/tab types - signer1_tabs = DocuSign_eSign::Tabs.new ({ - signHereTabs: [sign_here1] - }) + signer1_tabs = DocuSign_eSign::Tabs.new({ + signHereTabs: [sign_here1] + }) signer1.tabs = signer1_tabs # Add the recipients to the Envelope object @@ -59,7 +60,7 @@ def worker envelope_definition.recipients = recipients envelope_definition.status = envelope_args[:status] # Step 4. Call the eSignature REST API - results = envelope_api.create_envelope(args[:account_id], envelope_definition) + envelope_api.create_envelope(args[:account_id], envelope_definition) # ***DS.snippet.0.end end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg020_phone_authentication_service.rb b/app/services/e_sign/eg020_phone_authentication_service.rb index 0ae4906..613fecb 100644 --- a/app/services/e_sign/eg020_phone_authentication_service.rb +++ b/app/services/e_sign/eg020_phone_authentication_service.rb @@ -2,6 +2,7 @@ class ESign::Eg020PhoneAuthenticationService attr_reader :args + include ApiCreator def initialize(args) @@ -12,11 +13,7 @@ def worker(workflow_id) # ***DS.snippet.0.start envelope_args = args[:envelope_args] - if workflow_id.blank? - return "phone_auth_not_enabled" - end - - envelope_api = create_envelope_api(args) + return 'phone_auth_not_enabled' if workflow_id.blank? # Construct your envelope JSON body # Step 4 start @@ -72,8 +69,8 @@ def worker(workflow_id) # Add the tabs model (including the sign_here tabs) to the signer # The Tabs object wants arrays of the different field/tab types signer1_tabs = DocuSign_eSign::Tabs.new({ - signHereTabs: [sign_here1] - }) + signHereTabs: [sign_here1] + }) signer1.tabs = signer1_tabs # Add the recipients to the Envelope object @@ -94,31 +91,28 @@ def worker(workflow_id) end def get_workflow - #Retrieve the workflow id - - begin - # Step 3 start - workflow_details = create_account_api(args) - workflow_response = workflow_details.get_account_identity_verification(args[:account_id]) - - # Check that idv authentication is enabled - if workflow_response.identity_verification - phone_auth_workflow = workflow_response.identity_verification.find{ |item| item.default_name == "Phone Authentication" } - if phone_auth_workflow - phone_auth_workflow.workflow_id - else - return "" - end + # Retrieve the workflow id + + # Step 3 start + workflow_details = create_account_api(args) + workflow_response = workflow_details.get_account_identity_verification(args[:account_id]) + + # Check that idv authentication is enabled + if workflow_response.identity_verification + phone_auth_workflow = workflow_response.identity_verification.find { |item| item.default_name == 'Phone Authentication' } + if phone_auth_workflow + phone_auth_workflow.workflow_id else - return "" + '' end - # Step 3 end - - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = e.code - @error_message = error['error_description'] - render 'ds_common/error' + else + '' end + # Step 3 end + rescue DocuSign_eSign::ApiError => e + error = JSON.parse e.response_body + @error_code = e.code + @error_message = error['error_description'] + render 'ds_common/error' end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg022_kba_authentication_service.rb b/app/services/e_sign/eg022_kba_authentication_service.rb index ed11917..6d6a881 100644 --- a/app/services/e_sign/eg022_kba_authentication_service.rb +++ b/app/services/e_sign/eg022_kba_authentication_service.rb @@ -2,6 +2,7 @@ class ESign::Eg022KbaAuthenticationService attr_reader :args + include ApiCreator def initialize(args) @@ -58,7 +59,7 @@ def worker envelope_definition.status = envelope_args[:status] # Step 4. Call the eSignature REST API - results = envelope_api.create_envelope args[:account_id], envelope_definition + envelope_api.create_envelope args[:account_id], envelope_definition # ***DS.snippet.0.end end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg023_idv_authentication_service.rb b/app/services/e_sign/eg023_idv_authentication_service.rb index 7d0a52d..45547b8 100644 --- a/app/services/e_sign/eg023_idv_authentication_service.rb +++ b/app/services/e_sign/eg023_idv_authentication_service.rb @@ -2,6 +2,7 @@ class ESign::Eg023IdvAuthenticationService attr_reader :args + include ApiCreator def initialize(args) @@ -15,18 +16,14 @@ def worker accounts_api = create_account_api(args) workflow_response = accounts_api.get_account_identity_verification args[:account_id] if workflow_response.identity_verification - idv_workflow = workflow_response.identity_verification.find{ |item| item.default_name == "DocuSign ID Verification" } - if idv_workflow - workflow_id = idv_workflow.workflow_id - end + idv_workflow = workflow_response.identity_verification.find { |item| item.default_name == 'DocuSign ID Verification' } + workflow_id = idv_workflow.workflow_id if idv_workflow end # Step 3 end - if workflow_id.blank? - return "idv_not_enabled" - end + return 'idv_not_enabled' if workflow_id.blank? - puts "WORKFLOW ID: " + puts 'WORKFLOW ID: ' puts workflow_id # Construct your envelope JSON body @@ -35,7 +32,7 @@ def worker envelope_definition.email_subject = 'Please sign this document set' # Add the documents - pdf_filename = "World_Wide_Corp_lorem.pdf" + pdf_filename = 'World_Wide_Corp_lorem.pdf' # Create the document models document1 = DocuSign_eSign::Document.new( @@ -63,9 +60,9 @@ def worker # Add the tabs model (including the sign_here tabs) to the signer # The Tabs object takes arrays of the different field/tab types - signer1_tabs = DocuSign_eSign::Tabs.new ({ - signHereTabs: [sign_here1] - }) + signer1_tabs = DocuSign_eSign::Tabs.new({ + signHereTabs: [sign_here1] + }) signer1.tabs = signer1_tabs wf = DocuSign_eSign::RecipientIdentityVerification.new @@ -85,9 +82,7 @@ def worker # Call the eSignature REST API # Step 5 start envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope args[:account_id], envelope_definition + envelope_api.create_envelope args[:account_id], envelope_definition # Step 5 end - - results end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg024_permission_create_service.rb b/app/services/e_sign/eg024_permission_create_service.rb index b4e2a1a..a12b8ef 100644 --- a/app/services/e_sign/eg024_permission_create_service.rb +++ b/app/services/e_sign/eg024_permission_create_service.rb @@ -2,6 +2,7 @@ class ESign::Eg024PermissionCreateService attr_reader :args + include ApiCreator def initialize(args) @@ -12,42 +13,43 @@ def worker accounts_api = create_account_api(args) permission_profile_name = args[:permission_profile_name] permission_profile_settings = make_permission_profile_settings - create_permission_account = accounts_api.create_permission_profile(args[:account_id], { permissionProfileName: permission_profile_name, - settings: permission_profile_settings}, - options = DocuSign_eSign::CreatePermissionProfileOptions.default) + accounts_api.create_permission_profile(args[:account_id], { permissionProfileName: permission_profile_name, + settings: permission_profile_settings }, + DocuSign_eSign::CreatePermissionProfileOptions.default) end private def make_permission_profile_settings permission_profile = DocuSign_eSign::PermissionProfile.new - pr_settings = ({ + pr_settings = { useNewDocuSignExperienceInterface: 0, - allowBulkSending: "true", - allowEnvelopeSending: "true", - allowSignerAttachments: "true", - allowTaggingInSendAndCorrect:"true", - allowWetSigningOverride:"true", - allowedAddressBookAccess:"personalAndShared", - allowedTemplateAccess: "share", - enableRecipientViewingNotifications:"true", - enableSequentialSigningInterface:"true", - receiveCompletedSelfSignedDocumentsAsEmailLinks:"false", - signingUiVersion:"v2", - useNewSendingInterface:"true", - allowApiAccess:"true", - allowApiAccessToAccount:"true", - allowApiSendingOnBehalfOfOthers:"true", - allowApiSequentialSigning:"true", - enableApiRequestLogging:"true", - allowDocuSignDesktopClient:"false", - allowSendersToSetRecipientEmailLanguage:"true", - allowVaulting:"false", - allowedToBeEnvelopeTransferRecipient: "true", - enableTransactionPointIntegration: "false", - powerFormRole: "admin", - vaultingMode: "none" - }) + allowBulkSending: 'true', + allowEnvelopeSending: 'true', + allowSignerAttachments: 'true', + allowTaggingInSendAndCorrect: 'true', + allowWetSigningOverride: 'true', + allowedAddressBookAccess: 'personalAndShared', + allowedTemplateAccess: 'share', + enableRecipientViewingNotifications: 'true', + enableSequentialSigningInterface: 'true', + receiveCompletedSelfSignedDocumentsAsEmailLinks: 'false', + signingUiVersion: 'v2', + useNewSendingInterface: 'true', + allowApiAccess: 'true', + allowApiAccessToAccount: 'true', + allowApiSendingOnBehalfOfOthers: 'true', + allowApiSequentialSigning: 'true', + enableApiRequestLogging: 'true', + allowDocuSignDesktopClient: 'false', + allowSendersToSetRecipientEmailLanguage: 'true', + allowVaulting: 'false', + allowedToBeEnvelopeTransferRecipient: 'true', + enableTransactionPointIntegration: 'false', + powerFormRole: 'admin', + vaultingMode: 'none' + } permission_profile.settings = pr_settings + permission_profile end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg025_permissions_set_user_group_service.rb b/app/services/e_sign/eg025_permissions_set_user_group_service.rb index 171a3bb..a18a84a 100644 --- a/app/services/e_sign/eg025_permissions_set_user_group_service.rb +++ b/app/services/e_sign/eg025_permissions_set_user_group_service.rb @@ -2,6 +2,7 @@ class ESign::Eg025PermissionsSetUserGroupService attr_reader :args + include ApiCreator def initialize(args) @@ -12,9 +13,9 @@ def worker group_api = create_group_api(args) # Step 3: Construct the request body - params = {groups: [{permissionProfileId: args[:permission_profile_id], groupId: args[:group_id]}]} - + params = { groups: [{ permissionProfileId: args[:permission_profile_id], groupId: args[:group_id] }] } + # Step 4: Call the eSignature REST API - result = group_api.update_groups(args[:account_id], params) + group_api.update_groups(args[:account_id], params) end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg026_permissions_change_single_setting_service.rb b/app/services/e_sign/eg026_permissions_change_single_setting_service.rb index 52ed413..cf97f2c 100644 --- a/app/services/e_sign/eg026_permissions_change_single_setting_service.rb +++ b/app/services/e_sign/eg026_permissions_change_single_setting_service.rb @@ -2,6 +2,7 @@ class ESign::Eg026PermissionsChangeSingleSettingService attr_reader :args + include ApiCreator def initialize(args) @@ -12,41 +13,42 @@ def worker accounts_api = create_account_api(args) permission_profile_settings = make_permission_profile_settings permission_profile_id = args[:permission_profile_id] - update_permission_profile = accounts_api.update_permission_profile(args[:account_id], permission_profile_id, - permission_profile_settings, options = DocuSign_eSign::UpdatePermissionProfileOptions.default) + accounts_api.update_permission_profile(args[:account_id], permission_profile_id, + permission_profile_settings, DocuSign_eSign::UpdatePermissionProfileOptions.default) end private def make_permission_profile_settings permission_profile = DocuSign_eSign::PermissionProfile.new - pr_settings = ({ + pr_settings = { useNewDocuSignExperienceInterface: 0, - allowBulkSending: "true", - allowEnvelopeSending: "true", - allowSignerAttachments: "true", - allowTaggingInSendAndCorrect:"true", - allowWetSigningOverride:"true", - allowedAddressBookAccess:"personalAndShared", - allowedTemplateAccess: "share", - enableRecipientViewingNotifications:"true", - enableSequentialSigningInterface:"true", - receiveCompletedSelfSignedDocumentsAsEmailLinks:"false", - signingUiVersion:"v2", - useNewSendingInterface:"true", - allowApiAccess:"true", - allowApiAccessToAccount:"true", - allowApiSendingOnBehalfOfOthers:"true", - allowApiSequentialSigning:"true", - enableApiRequestLogging:"true", - allowDocuSignDesktopClient:"false", - allowSendersToSetRecipientEmailLanguage:"true", - allowVaulting:"false", - allowedToBeEnvelopeTransferRecipient: "true", - enableTransactionPointIntegration: "false", - powerFormRole: "admin", - vaultingMode: "none" - }) + allowBulkSending: 'true', + allowEnvelopeSending: 'true', + allowSignerAttachments: 'true', + allowTaggingInSendAndCorrect: 'true', + allowWetSigningOverride: 'true', + allowedAddressBookAccess: 'personalAndShared', + allowedTemplateAccess: 'share', + enableRecipientViewingNotifications: 'true', + enableSequentialSigningInterface: 'true', + receiveCompletedSelfSignedDocumentsAsEmailLinks: 'false', + signingUiVersion: 'v2', + useNewSendingInterface: 'true', + allowApiAccess: 'true', + allowApiAccessToAccount: 'true', + allowApiSendingOnBehalfOfOthers: 'true', + allowApiSequentialSigning: 'true', + enableApiRequestLogging: 'true', + allowDocuSignDesktopClient: 'false', + allowSendersToSetRecipientEmailLanguage: 'true', + allowVaulting: 'false', + allowedToBeEnvelopeTransferRecipient: 'true', + enableTransactionPointIntegration: 'false', + powerFormRole: 'admin', + vaultingMode: 'none' + } permission_profile.settings = pr_settings + permission_profile end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg027_permissions_delete_service.rb b/app/services/e_sign/eg027_permissions_delete_service.rb index 16d581c..f1498d9 100644 --- a/app/services/e_sign/eg027_permissions_delete_service.rb +++ b/app/services/e_sign/eg027_permissions_delete_service.rb @@ -2,6 +2,7 @@ class ESign::Eg027PermissionsDeleteService attr_reader :args + include ApiCreator def initialize(args) @@ -11,6 +12,6 @@ def initialize(args) def worker # Step 3: Call the eSignature REST API accounts_api = create_account_api(args) - delete_permission_profile = accounts_api.delete_permission_profile(args[:account_id], args[:permission_profile_id]) + accounts_api.delete_permission_profile(args[:account_id], args[:permission_profile_id]) end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg028_brands_creating_service.rb b/app/services/e_sign/eg028_brands_creating_service.rb index 48327eb..944b4c5 100644 --- a/app/services/e_sign/eg028_brands_creating_service.rb +++ b/app/services/e_sign/eg028_brands_creating_service.rb @@ -2,6 +2,7 @@ class ESign::Eg028BrandsCreatingService attr_reader :args + include ApiCreator def initialize(args) @@ -19,9 +20,9 @@ def worker # Step 3: Construct your request body accounts_api = DocuSign_eSign::AccountsApi.new api_client - params = { brandName: args[:brandName], defaultBrandLanguage: args[:defaultBrandLanguage] } - + params = { brandName: args[:brandName], defaultBrandLanguage: args[:defaultBrandLanguage] } + # Step 4: Call the eSignature API - results = accounts_api.create_brand(args[:account_id], params) + accounts_api.create_brand(args[:account_id], params) end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb b/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb index 2d2d90a..fada571 100644 --- a/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb +++ b/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb @@ -2,6 +2,7 @@ class ESign::Eg029BrandsApplyToEnvelopeService attr_reader :args + include ApiCreator def initialize(args) @@ -16,7 +17,7 @@ def worker # Step 3: Construct your envelope JSON body envelope_definition = make_envelope(args[:envelope_args]) # Step 4. Call the eSignature REST API - results = envelope_api.create_envelope args[:account_id], envelope_definition + envelope_api.create_envelope args[:account_id], envelope_definition # ***DS.snippet.0.end end @@ -45,7 +46,7 @@ def make_envelope(envelope_args) signer1 = DocuSign_eSign::Signer.new signer1.name = envelope_args[:signer_name] signer1.email = envelope_args[:signer_email] - signer1.role_name = 'signer' + signer1.role_name = 'signer' signer1.note = '' signer1.routing_order = '1' signer1.status = envelope_args[:status] @@ -54,7 +55,7 @@ def make_envelope(envelope_args) sign_here1 = DocuSign_eSign::SignHere.new sign_here1.document_id = '1' - sign_here1.name ='SignHereTab' + sign_here1.name = 'SignHereTab' sign_here1.page_number = '1' sign_here1.recipient_id = '1' sign_here1.tab_label = 'SignHereTab' @@ -63,9 +64,9 @@ def make_envelope(envelope_args) # Add the tabs model (including the sign_here tabs) to the signer # The Tabs object wants arrays of the different field/tab types - signer1_tabs = DocuSign_eSign::Tabs.new ({ - signHereTabs: [sign_here1] - }) + signer1_tabs = DocuSign_eSign::Tabs.new({ + signHereTabs: [sign_here1] + }) signer1.tabs = signer1_tabs # Add the recipients to the envelope object @@ -79,4 +80,4 @@ def make_envelope(envelope_args) envelope_definition.status = envelope_args[:status] envelope_definition end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg030_brands_apply_to_template_service.rb b/app/services/e_sign/eg030_brands_apply_to_template_service.rb index 9eb5aba..ea0e162 100644 --- a/app/services/e_sign/eg030_brands_apply_to_template_service.rb +++ b/app/services/e_sign/eg030_brands_apply_to_template_service.rb @@ -2,6 +2,7 @@ class ESign::Eg030BrandsApplyToTemplateService attr_reader :args + include ApiCreator def initialize(args) @@ -16,7 +17,7 @@ def worker # Step 3. Construct your envelope JSON body envelope_definition = make_envelope(args[:envelope_args]) # Step 4. Call the eSignature REST API - results = envelope_api.create_envelope args[:account_id], envelope_definition + envelope_api.create_envelope args[:account_id], envelope_definition # ***DS.snippet.0.end end @@ -46,4 +47,4 @@ def make_envelope(envelope_args) envelope_definition.template_roles = [signer, cc] envelope_definition end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb index 297b652..bf796e5 100644 --- a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb +++ b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb @@ -2,6 +2,7 @@ class ESign::Eg031BulkSendingEnvelopesService attr_reader :args, :signers + include ApiCreator def initialize(args, signers) @@ -23,14 +24,14 @@ def worker bulk_envelopes_api = DocuSign_eSign::BulkEnvelopesApi.new api_client bulk_sending_list = create_bulk_sending_list(signers) bulk_list = bulk_envelopes_api.create_bulk_send_list(args[:account_id], bulk_sending_list) - bulk_list_id = bulk_list.list_id + bulk_list_id = bulk_list.list_id # Step 3-1 end # Create the draft envelope # Step 4-1 start envelope_api = create_envelope_api(args) envelope_definition = make_envelope - envelope = envelope_api.create_envelope(args[:account_id], envelope_definition, options = DocuSign_eSign::CreateEnvelopeOptions.default) + envelope = envelope_api.create_envelope(args[:account_id], envelope_definition, DocuSign_eSign::CreateEnvelopeOptions.default) envelope_id = envelope.envelope_id # Step 4-1 end @@ -56,10 +57,10 @@ def worker def construct_api_headers(api_client, args) api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" - api_client.default_headers['Content-Type'] = "application/json;charset=UTF-8" - api_client.default_headers['Accept'] = "application/json, text/plain, */*" - api_client.default_headers['Accept-Encoding'] = "gzip, deflate, br" - api_client.default_headers['Accept-Language'] = "en-US,en;q=0.9" + api_client.default_headers['Content-Type'] = 'application/json;charset=UTF-8' + api_client.default_headers['Accept'] = 'application/json, text/plain, */*' + api_client.default_headers['Accept-Encoding'] = 'gzip, deflate, br' + api_client.default_headers['Accept-Language'] = 'en-US,en;q=0.9' end # Step 3-2 start @@ -69,7 +70,7 @@ def create_bulk_sending_list(signers) roleName: 'signer', tabs: [], name: signers[:signer_name], - email: signers[:signer_email], + email: signers[:signer_email] ) # Create a cc recipient to receive a copy of the documents @@ -77,21 +78,21 @@ def create_bulk_sending_list(signers) roleName: 'cc', tabs: [], name: signers[:cc_name], - email: signers[:cc_email], + email: signers[:cc_email] ) recipient3 = DocuSign_eSign::BulkSendingCopyRecipient.new( roleName: 'signer', tabs: [], name: signers[:signer_name1], - email: signers[:signer_email1], + email: signers[:signer_email1] ) recipient4 = DocuSign_eSign::BulkSendingCopyRecipient.new( roleName: 'cc', tabs: [], name: signers[:cc_name1], - email: signers[:cc_email1], + email: signers[:cc_email1] ) # Add the recipients to the envelope object @@ -104,24 +105,23 @@ def create_bulk_sending_list(signers) recipients: [recipient3, recipient4], custom_fields: [] ) - bulk_copies.append(bulk_copy1, bulk_copy2) - bulk_sending_list = DocuSign_eSign::BulkSendingList.new( - name: "sample.csv", + bulk_copies.append(bulk_copy1, bulk_copy2) + DocuSign_eSign::BulkSendingList.new( + name: 'sample.csv', bulkCopies: bulk_copies ) - bulk_sending_list end # Step 3-2 end # Step 5-2 start def custom_fields(bulk_list_id) text_custom_fields = DocuSign_eSign::TextCustomField.new( - name:'mailingListId', + name: 'mailingListId', required: 'false', show: 'false', value: bulk_list_id ) - custom_fields = DocuSign_eSign::CustomFields.new( + DocuSign_eSign::CustomFields.new( listCustomFields: [], textCustomFields: [text_custom_fields] ) @@ -142,28 +142,28 @@ def make_envelope doc.document_id = '2' signer = DocuSign_eSign::Signer.new( - name: "Multi Bulk Recipient::signer", - email: "multiBulkRecipients-signer@docusign.com", - roleName: "signer", - note: "", + name: 'Multi Bulk Recipient::signer', + email: 'multiBulkRecipients-signer@docusign.com', + roleName: 'signer', + note: '', routingOrder: 1, - status: "created", - templateAccessCodeRequired: "null", - deliveryMethod: "email", - recipientId: "1", - recipientType: "signer" + status: 'created', + templateAccessCodeRequired: 'null', + deliveryMethod: 'email', + recipientId: '1', + recipientType: 'signer' ) cc = DocuSign_eSign::CarbonCopy.new( - name: "Multi Bulk Recipient::cc", - email: "multiBulkRecipients-cc@docusign.com", - roleName: "cc", - note: "", + name: 'Multi Bulk Recipient::cc', + email: 'multiBulkRecipients-cc@docusign.com', + roleName: 'cc', + note: '', routingOrder: 2, - status: "created", - deliveryMethod: "email", - recipientId: "2", - recipientType: "cc" + status: 'created', + deliveryMethod: 'email', + recipientId: '2', + recipientType: 'cc' ) # The DocuSign platform searches throughout your envelope's documents for matching @@ -188,10 +188,9 @@ def make_envelope envelope_definition.recipients = recipients # The order in the docs array determines the order in the envelope envelope_definition.documents = [doc] - envelope_definition.envelope_id_stamping = "true" - envelope_definition.status = "created" + envelope_definition.envelope_id_stamping = 'true' + envelope_definition.status = 'created' envelope_definition end # Step 4-2 end - -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg032_pauses_signature_workflow_service.rb b/app/services/e_sign/eg032_pauses_signature_workflow_service.rb index 5c4571a..98cd8e6 100644 --- a/app/services/e_sign/eg032_pauses_signature_workflow_service.rb +++ b/app/services/e_sign/eg032_pauses_signature_workflow_service.rb @@ -2,6 +2,7 @@ class ESign::Eg032PausesSignatureWorkflowService attr_reader :args, :signers + include ApiCreator def initialize(args, signers) @@ -92,7 +93,7 @@ def worker # Step 4. Call the eSignature API envelopes_api = DocuSign_eSign::EnvelopesApi.new(api_client) - results = envelopes_api.create_envelope( + envelopes_api.create_envelope( args[:accountId], envelope_definition ) diff --git a/app/services/e_sign/eg033_unpauses_signature_workflow_service.rb b/app/services/e_sign/eg033_unpauses_signature_workflow_service.rb index 2b30b9a..9cdc21d 100644 --- a/app/services/e_sign/eg033_unpauses_signature_workflow_service.rb +++ b/app/services/e_sign/eg033_unpauses_signature_workflow_service.rb @@ -2,6 +2,7 @@ class ESign::Eg033UnpausesSignatureWorkflowService attr_reader :args + include ApiCreator def initialize(args) @@ -27,7 +28,7 @@ def worker update_options = DocuSign_eSign::UpdateOptions.new update_options.resend_envelope = true - result = envelopes_api.update( + envelopes_api.update( args[:accountId], args[:envelopeId], envelope_definition, diff --git a/app/services/e_sign/eg034_use_conditional_recipients_service.rb b/app/services/e_sign/eg034_use_conditional_recipients_service.rb index 6d8669e..1edc054 100644 --- a/app/services/e_sign/eg034_use_conditional_recipients_service.rb +++ b/app/services/e_sign/eg034_use_conditional_recipients_service.rb @@ -2,6 +2,7 @@ class ESign::Eg034UseConditionalRecipientsService attr_reader :args, :signers + include ApiCreator def initialize(args, signers) @@ -177,7 +178,7 @@ def worker # Step 4. Call the eSignature API envelopes_api = DocuSign_eSign::EnvelopesApi.new(api_client) - results = envelopes_api.create_envelope( + envelopes_api.create_envelope( args[:accountId], envelope_definition ) diff --git a/app/services/e_sign/eg035_scheduled_sending_service.rb b/app/services/e_sign/eg035_scheduled_sending_service.rb index b2e6a7c..c7e3789 100644 --- a/app/services/e_sign/eg035_scheduled_sending_service.rb +++ b/app/services/e_sign/eg035_scheduled_sending_service.rb @@ -2,6 +2,7 @@ class ESign::Eg035ScheduledSendingService attr_reader :args + include ApiCreator def initialize(args) @@ -77,8 +78,8 @@ def make_envelope(envelope_args) # Add the tabs model (including the sign_here tabs) to the signer # The Tabs object takes arrays of the different field/tab types signer1_tabs = DocuSign_eSign::Tabs.new({ - signHereTabs: [sign_here] - }) + signHereTabs: [sign_here] + }) signer1.tabs = signer1_tabs @@ -107,4 +108,4 @@ def make_envelope(envelope_args) # Step 2 end envelope_definition end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg036_delayed_routing_service.rb b/app/services/e_sign/eg036_delayed_routing_service.rb index a18e8b6..6146392 100644 --- a/app/services/e_sign/eg036_delayed_routing_service.rb +++ b/app/services/e_sign/eg036_delayed_routing_service.rb @@ -2,6 +2,7 @@ class ESign::Eg036DelayedRoutingService attr_reader :args + include ApiCreator def initialize(args) @@ -79,21 +80,21 @@ def make_envelope(envelope_args) ) sign_here2 = DocuSign_eSign::SignHere.new( - xPosition: "320", - yPosition: "175", - pageNumber: "1", - documentId: "1" + xPosition: '320', + yPosition: '175', + pageNumber: '1', + documentId: '1' ) # Add the tabs model (including the sign_here tabs) to the signer # The Tabs object takes arrays of the different field/tab types signer1_tabs = DocuSign_eSign::Tabs.new({ - signHereTabs: [sign_here1] - }) + signHereTabs: [sign_here1] + }) signer2_tabs = DocuSign_eSign::Tabs.new({ - signHereTabs: [sign_here2] - }) + signHereTabs: [sign_here2] + }) signer1.tabs = signer1_tabs signer2.tabs = signer2_tabs @@ -106,7 +107,7 @@ def make_envelope(envelope_args) envelope_definition.recipients = recipients # Create recipientRules model - delay_time = "0." + envelope_args[:delay].to_s + ":00:00"; + delay_time = "0.#{envelope_args[:delay]}:00:00" rule = DocuSign_eSign::EnvelopeDelayRule.new(delay: delay_time) delayed_routing = DocuSign_eSign::DelayedRouting.new(rules: [rule]) @@ -128,4 +129,4 @@ def make_envelope(envelope_args) # Step 2 end envelope_definition end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg037_sms_delivery_service.rb b/app/services/e_sign/eg037_sms_delivery_service.rb index cbe5f0c..e2b6a9f 100644 --- a/app/services/e_sign/eg037_sms_delivery_service.rb +++ b/app/services/e_sign/eg037_sms_delivery_service.rb @@ -2,6 +2,7 @@ class ESign::Eg037SmsDeliveryService attr_reader :args + include ApiCreator def initialize(args) @@ -24,6 +25,7 @@ def worker end private + # Step 2 start def make_envelope(envelope_args) # document 1 (HTML) has tag **signature_1** @@ -77,8 +79,8 @@ def make_envelope(envelope_args) envelope_definition.documents = [document1, document2, document3] signer_phone_number = DocuSign_eSign::RecipientPhoneNumber.new - signer_phone_number.country_code=envelope_args[:country_code] - signer_phone_number.number=envelope_args[:phone_number] + signer_phone_number.country_code = envelope_args[:country_code] + signer_phone_number.number = envelope_args[:phone_number] # Create the signer recipient model signer1 = DocuSign_eSign::Signer.new @@ -91,8 +93,8 @@ def make_envelope(envelope_args) # same integer as the order for two or more recipients cc_phone_number = DocuSign_eSign::RecipientPhoneNumber.new - cc_phone_number.country_code=envelope_args[:cc_country_code] - cc_phone_number.number=envelope_args[:cc_phone_number] + cc_phone_number.country_code = envelope_args[:cc_country_code] + cc_phone_number.number = envelope_args[:cc_phone_number] # Create a cc recipient to receive a copy of the documents cc1 = DocuSign_eSign::CarbonCopy.new @@ -123,8 +125,8 @@ def make_envelope(envelope_args) # Add the tabs model (including the sign_here tabs) to the signer # The Tabs object takes arrays of the different field/tab types signer1_tabs = DocuSign_eSign::Tabs.new({ - signHereTabs: [sign_here1, sign_here2] - }) + signHereTabs: [sign_here1, sign_here2] + }) signer1.tabs = signer1_tabs diff --git a/app/services/e_sign/eg038_responsive_signing_service.rb b/app/services/e_sign/eg038_responsive_signing_service.rb index 6223f8b..e0c5714 100644 --- a/app/services/e_sign/eg038_responsive_signing_service.rb +++ b/app/services/e_sign/eg038_responsive_signing_service.rb @@ -2,6 +2,7 @@ class ESign::Eg038ResponsiveSigningService attr_reader :args + include ApiCreator def initialize(args) @@ -48,7 +49,7 @@ def make_recipient_view_request(args, ds_return_url) # the DocuSign signing. It's usually better to use # the session mechanism of your web framework. Query parameters # can be changed/spoofed very easily. - view_request.return_url = ds_return_url + '?state=123' + view_request.return_url = "#{ds_return_url}?state=123" # How has your app authenticated the user? In addition to your app's # authentication, you can include authenticate steps from DocuSign; @@ -90,17 +91,17 @@ def make_envelope(args) envelope_definition.documents = [doc] # Create a signer recipient to sign the document, identified by name and email # We're setting the parameters via the object creation - signer = DocuSign_eSign::Signer.new ({ - email: args[:signer_email], - name: args[:signer_name], - clientUserId: args[:signer_client_id], - recipientId: 1, - role_name: "Signer" - }) - - cc = DocuSign_eSign::CarbonCopy.new ({ - email: args[:cc_email], name: args[:cc_name], recipientId: 2 - }) + signer = DocuSign_eSign::Signer.new({ + email: args[:signer_email], + name: args[:signer_name], + clientUserId: args[:signer_client_id], + recipientId: 1, + role_name: 'Signer' + }) + + cc = DocuSign_eSign::CarbonCopy.new({ + email: args[:cc_email], name: args[:cc_name], recipientId: 2 + }) # Add the recipients to the envelope object recipients = DocuSign_eSign::Recipients.new @@ -118,14 +119,13 @@ def get_html_content(args) doc_html = File.open(args[:doc_file]).read # Substitute values into the HTML # Substitute for: {signerName}, {signerEmail}, {ccName}, {ccEmail} - return doc_html.gsub('{signerName}', args[:signer_name]) \ - .gsub('{signerEmail}', args[:signer_email]) \ - .gsub('{ccName}', args[:cc_name]) \ - .gsub('{ccEmail}', args[:cc_email]) \ - .gsub("/sn1/", "") \ - .gsub("/l1q/", "") \ - .gsub("/l2q/", "") - + doc_html.gsub('{signerName}', args[:signer_name]) \ + .gsub('{signerEmail}', args[:signer_email]) \ + .gsub('{ccName}', args[:cc_name]) \ + .gsub('{ccEmail}', args[:cc_email]) \ + .gsub('/sn1/', '') \ + .gsub('/l1q/', '') \ + .gsub('/l2q/', '') end # Step 2 end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg039_signing_in_person_service.rb b/app/services/e_sign/eg039_signing_in_person_service.rb index 2d2971b..072f01d 100644 --- a/app/services/e_sign/eg039_signing_in_person_service.rb +++ b/app/services/e_sign/eg039_signing_in_person_service.rb @@ -2,6 +2,7 @@ class ESign::Eg039SigningInPersonService attr_reader :args + include ApiCreator def initialize(args) @@ -19,7 +20,7 @@ def worker envelope = make_envelope(pdf_filename, host_email, host_name, signer_name) - # Step 3 start + # Step 3 start envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope @@ -27,10 +28,8 @@ def worker envelope_id = results.envelope_id - # Step 5 start - view_request = make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_name - ) + view_request = make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_name) # Call the CreateRecipientView API results = envelope_api.create_recipient_view args[:account_id], envelope_id, view_request @@ -56,7 +55,7 @@ def make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_nam # the DocuSign signing. It's usually better to use # the session mechanism of your web framework. Query parameters # can be changed/spoofed very easily. - view_request.return_url = ds_return_url + '?state=123' + view_request.return_url = "#{ds_return_url}?state=123" # How has your app authenticated the user? In addition to your app's # authentication, you can include authenticate steps from DocuSign; @@ -125,4 +124,4 @@ def make_envelope(pdf_filename, host_email, host_name, signer_name) envelope_definition end # Step 2 end -end \ No newline at end of file +end diff --git a/app/services/e_sign/eg040_set_document_visibility_service.rb b/app/services/e_sign/eg040_set_document_visibility_service.rb index 21c947e..fa9acad 100644 --- a/app/services/e_sign/eg040_set_document_visibility_service.rb +++ b/app/services/e_sign/eg040_set_document_visibility_service.rb @@ -2,6 +2,7 @@ class ESign::Eg040SetDocumentVisibilityService attr_reader :args + include ApiCreator def initialize(args) @@ -124,14 +125,14 @@ def make_envelope(envelope_args) # Add the tabs model (including the sign_here tabs) to the signer # The Tabs object takes arrays of the different field/tab types signer1_tabs = DocuSign_eSign::Tabs.new({ - signHereTabs: [sign_here1] - }) + signHereTabs: [sign_here1] + }) signer1.tabs = signer1_tabs signer2_tabs = DocuSign_eSign::Tabs.new({ - signHereTabs: [sign_here2] - }) + signHereTabs: [sign_here2] + }) signer2.tabs = signer2_tabs @@ -172,4 +173,4 @@ def create_document1(args) " end -end \ No newline at end of file +end diff --git a/app/services/e_sign/get_data_service.rb b/app/services/e_sign/get_data_service.rb index 6ac178a..58cbc70 100644 --- a/app/services/e_sign/get_data_service.rb +++ b/app/services/e_sign/get_data_service.rb @@ -12,9 +12,7 @@ def get_current_user_email worker user_info = @api_client.get_user_info(args[:access_token]) - unless user_info - raise "The user does not have access to account" - end + raise 'The user does not have access to account' unless user_info user_info.email end @@ -23,9 +21,7 @@ def get_current_user_name worker user_info = @api_client.get_user_info(args[:access_token]) - unless user_info - raise "The user does not have access to account" - end + raise 'The user does not have access to account' unless user_info user_info.name end @@ -38,7 +34,6 @@ def worker @api_client = DocuSign_eSign::ApiClient.new(configuration) @api_client.set_base_path(args[:base_path]) - @api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") - + @api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") end -end \ No newline at end of file +end diff --git a/app/services/eg001_embedded_signing_service.rb b/app/services/eg001_embedded_signing_service.rb index 0bfebc7..f9ce8a6 100644 --- a/app/services/eg001_embedded_signing_service.rb +++ b/app/services/eg001_embedded_signing_service.rb @@ -2,6 +2,7 @@ class Eg001EmbeddedSigningService attr_reader :args + include ApiCreator def initialize(args) @@ -29,8 +30,7 @@ def worker # session[:envelope_id] = envelope_id # Step 3. Create the recipient view for the embedded signing - view_request = make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, signer_email, signer_name - ) + view_request = make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, signer_email, signer_name) # Call the CreateRecipientView API results = envelope_api.create_recipient_view args[:account_id], envelope_id, view_request @@ -54,10 +54,10 @@ def make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, si # the DocuSign signing. It's usually better to use # the session mechanism of your web framework. Query parameters # can be changed/spoofed very easily. - view_request.return_url = ds_return_url + '?state=123' + view_request.return_url = "#{ds_return_url}?state=123" # How has your app authenticated the user? In addition to your app's - # authentication, you can include authenticate steps from DocuSign; + # authentication, you can include authenticate steps from DocuSign; # e.g., SMS authentication view_request.authentication_method = 'none' @@ -92,10 +92,10 @@ def make_envelope(signer_client_id, pdf_filename, signer_email, signer_name) envelope_definition.documents = [doc1] # Create a signer recipient to sign the document, identified by name and email # We're setting the parameters via the object creation - signer1 = DocuSign_eSign::Signer.new ({ - email: signer_email, name: signer_name, - clientUserId: signer_client_id, recipientId: 1 - }) + signer1 = DocuSign_eSign::Signer.new({ + email: signer_email, name: signer_name, + clientUserId: signer_client_id, recipientId: 1 + }) # The DocuSign platform searches throughout your envelope's documents for matching # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 # since they use the same anchor string for their "signer 1" tabs. @@ -119,4 +119,4 @@ def make_envelope(signer_client_id, pdf_filename, signer_email, signer_name) envelope_definition end # ***DS.snippet.0.end -end \ No newline at end of file +end diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index 6cf1da2..d67d689 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -13,19 +13,13 @@ def self.consent_url(state, examples_API) # GET /oauth/auth # This endpoint is used to obtain consent and is the first step in several authentication flows. # https://developers.docusign.com/platform/auth/reference/obtain-consent - scope = "signature impersonation" - if examples_API == 'Rooms' - scope = "#{scope} 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" - end - if examples_API == 'Click' - scope = "#{scope} click.manage click.send" - end - if examples_API == 'Admin' - scope = "#{scope} organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" - end + scope = 'signature impersonation' + scope = "#{scope} 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" if examples_API == 'Rooms' + scope = "#{scope} click.manage click.send" if examples_API == 'Click' + scope = "#{scope} organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" if examples_API == 'Admin' base_uri = "#{Rails.configuration.authorization_server}/oauth/auth" - response_type = "code" + response_type = 'code' scopes = ERB::Util.url_encode(scope) # https://developers.docusign.com/platform/auth/reference/scopes/ client_id = Rails.configuration.jwt_integration_key redirect_uri = "#{Rails.configuration.app_url}/auth/docusign/callback" @@ -36,7 +30,7 @@ def self.consent_url(state, examples_API) def initialize(session) @session = session - scope = "signature impersonation" + scope = 'signature impersonation' @client_module = DocuSign_eSign if session[:examples_API] == 'Rooms' scope = "#{scope} 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" @@ -46,9 +40,7 @@ def initialize(session) scope = "#{scope} click.manage click.send" @client_module = DocuSign_Click end - if session[:examples_API] == 'Monitor' - @client_module = DocuSign_Monitor - end + @client_module = DocuSign_Monitor if session[:examples_API] == 'Monitor' if session[:examples_API] == 'Admin' scope = "#{scope} organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" @client_module = DocuSign_Admin @@ -65,24 +57,20 @@ def check_jwt_token # docusign_esign: POST /oauth/token # This endpoint enables you to exchange an authorization code or JWT token for an access token. # https://developers.docusign.com/platform/auth/reference/obtain-access-token - token = api_client.request_jwt_user_token(Rails.configuration.jwt_integration_key, Rails.configuration.impersonated_user_guid, rsa_pk, expires_in=3600, @scope) - rescue OpenSSL::PKey::RSAError => exception - Rails.logger.error exception.inspect - if File.read(rsa_pk).starts_with? '{RSA_PRIVATE_KEY}' - fail "Please add your private RSA key to: #{rsa_pk}" - else - raise - end - rescue @client_module::ApiError => exception - Rails.logger.warn exception.inspect + token = api_client.request_jwt_user_token(Rails.configuration.jwt_integration_key, Rails.configuration.impersonated_user_guid, rsa_pk, 3600, @scope) + rescue OpenSSL::PKey::RSAError => e + Rails.logger.error e.inspect + raise "Please add your private RSA key to: #{rsa_pk}" if File.read(rsa_pk).starts_with? '{RSA_PRIVATE_KEY}' - if exception.response_body == nil - return false - end + raise + rescue @client_module::ApiError => e + Rails.logger.warn e.inspect + + return false if e.response_body.nil? - body = JSON.parse(exception.response_body) + body = JSON.parse(e.response_body) - if body['error'] == "consent_required" + if body['error'] == 'consent_required' false else details = <<~TXT @@ -90,7 +78,7 @@ def check_jwt_token or https://developers.docusign.com/esign-rest-api/guides/authentication/oauth2-code-grant#troubleshooting-errors or try enabling `configuration.debugging = true` in the initialize method above for more logging output TXT - fail "JWT response error: `#{body}`. #{details}" + raise "JWT response error: `#{body}`. #{details}" end else update_account_info(token) diff --git a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb index 8247b6a..5766882 100644 --- a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb +++ b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb @@ -18,18 +18,18 @@ def worker # step 3 start monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) - begin + begin @response = monitor_api.get_stream(args[:data_set_name], args[:version]).data - # step 3 end + # step 3 end rescue # error, probalby no Monitor enabled @response = "Monitor not enabled" - else + else Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" Rails.logger.info @response.inspect - ensure + ensure return @response end - + end end diff --git a/app/services/monitor_api/eg002_post_web_query_service.rb b/app/services/monitor_api/eg002_post_web_query_service.rb index f605bd3..d93d240 100644 --- a/app/services/monitor_api/eg002_post_web_query_service.rb +++ b/app/services/monitor_api/eg002_post_web_query_service.rb @@ -18,40 +18,40 @@ def worker # step 3 start monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) - begin + begin @response = monitor_api.post_web_query(args[:data_set_name], args[:version], get_query) # step 3 end rescue # error, probalby no Monitor enabled @response = "Monitor not enabled" - else + else Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" Rails.logger.info @response.inspect - ensure + ensure return @response end end def get_query - return { + { "filters": [ { - "FilterName": "Time", + "FilterName": 'Time', "BeginTime": args[:start_date], "EndTime": args[:end_date] }, { - "FilterName": "Has", - "ColumnName": "AccountId", + "FilterName": 'Has', + "ColumnName": 'AccountId', "Value": args[:account_id] } ], "aggregations": [ { - "aggregationName": "Raw", - "limit": "100", + "aggregationName": 'Raw', + "limit": '100', "orderby": [ - "Timestamp, desc" + 'Timestamp, desc' ] } ] diff --git a/app/services/room_api/eg001_create_room_with_data_service.rb b/app/services/room_api/eg001_create_room_with_data_service.rb index f6cf4cc..4f77533 100644 --- a/app/services/room_api/eg001_create_room_with_data_service.rb +++ b/app/services/room_api/eg001_create_room_with_data_service.rb @@ -12,32 +12,33 @@ def worker configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) - response = rooms_api.create_room(args[:account_id], body(args)) + rooms_api.create_room(args[:account_id], body(args)) end private def body(args) DocuSign_Rooms::RoomForCreate.new( - { - name: args[:room_name], - roleId: args[:role_id], - transactionSideId: "buy", - fieldData: DocuSign_Rooms::FieldDataForCreate.new( - data:{ - address1: '123 EZ Street', - address2: 'unit 10', - city: 'Galaxian', - state: 'US-HI', - postalCode: '88888', - companyRoomStatus: '5', - comments: 'Lorem ipsum dolor sit amet, consectetur adipiscin' - }) - } + { + name: args[:room_name], + roleId: args[:role_id], + transactionSideId: 'buy', + fieldData: DocuSign_Rooms::FieldDataForCreate.new( + data: { + address1: '123 EZ Street', + address2: 'unit 10', + city: 'Galaxian', + state: 'US-HI', + postalCode: '88888', + companyRoomStatus: '5', + comments: 'Lorem ipsum dolor sit amet, consectetur adipiscin' + } + ) + } ) end -end \ No newline at end of file +end diff --git a/app/services/room_api/eg002_create_room_with_template_service.rb b/app/services/room_api/eg002_create_room_with_template_service.rb index fcbe052..2842654 100644 --- a/app/services/room_api/eg002_create_room_with_template_service.rb +++ b/app/services/room_api/eg002_create_room_with_template_service.rb @@ -12,33 +12,34 @@ def worker configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) - response = rooms_api.create_room(args[:account_id], body(args)) + rooms_api.create_room(args[:account_id], body(args)) end private def body(args) DocuSign_Rooms::RoomForCreate.new( - { - name: args[:room_name], - roleId: args[:role_id], - transactionSideId: "listbuy", - roomTemplateId: args[:template_id], - officeId: args[:office_id], - fieldData: DocuSign_Rooms::FieldDataForCreate.new( - data:{ - address1: '123 EZ Street', - address2: 'unit 10', - city: 'Galaxian', - state: 'US-HI', - postalCode: '88888', - companyRoomStatus: '5', - comments: 'Lorem ipsum dolor sit amet, consectetur adipiscin' - }) - } + { + name: args[:room_name], + roleId: args[:role_id], + transactionSideId: 'listbuy', + roomTemplateId: args[:template_id], + officeId: args[:office_id], + fieldData: DocuSign_Rooms::FieldDataForCreate.new( + data: { + address1: '123 EZ Street', + address2: 'unit 10', + city: 'Galaxian', + state: 'US-HI', + postalCode: '88888', + companyRoomStatus: '5', + comments: 'Lorem ipsum dolor sit amet, consectetur adipiscin' + } + ) + } ) end -end \ No newline at end of file +end diff --git a/app/services/room_api/eg003_export_data_from_room_service.rb b/app/services/room_api/eg003_export_data_from_room_service.rb index 1242096..a7c36f5 100644 --- a/app/services/room_api/eg003_export_data_from_room_service.rb +++ b/app/services/room_api/eg003_export_data_from_room_service.rb @@ -12,9 +12,9 @@ def worker configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) - response = rooms_api.get_room_field_data(args[:room_id],args[:account_id]) + rooms_api.get_room_field_data(args[:room_id], args[:account_id]) end -end \ No newline at end of file +end diff --git a/app/services/room_api/eg004_add_forms_to_room_service.rb b/app/services/room_api/eg004_add_forms_to_room_service.rb index 28235e5..0709c4f 100644 --- a/app/services/room_api/eg004_add_forms_to_room_service.rb +++ b/app/services/room_api/eg004_add_forms_to_room_service.rb @@ -12,7 +12,7 @@ def worker configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) @@ -21,7 +21,7 @@ def worker def body(form_id) DocuSign_Rooms::FormForAdd.new({ - formId: form_id - }) + formId: form_id + }) end -end \ No newline at end of file +end diff --git a/app/services/room_api/eg005_get_rooms_with_filters_service.rb b/app/services/room_api/eg005_get_rooms_with_filters_service.rb index daf5217..efaf106 100644 --- a/app/services/room_api/eg005_get_rooms_with_filters_service.rb +++ b/app/services/room_api/eg005_get_rooms_with_filters_service.rb @@ -12,13 +12,13 @@ def worker configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") filters = DocuSign_Rooms::GetRoomsOptions.new filters.field_data_changed_start_date = args[:date_from] filters.field_data_changed_end_date = args[:date_to] rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) - response = rooms_api.get_rooms(args[:account_id], filters) + rooms_api.get_rooms(args[:account_id], filters) end end diff --git a/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb b/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb index 21efb67..1841406 100644 --- a/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb +++ b/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb @@ -12,14 +12,14 @@ def worker configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") rooms_api = DocuSign_Rooms::ExternalFormFillSessionsApi.new(api_client) begin rooms_api.create_external_form_fill_session(args[:account_id], body(args)) - rescue Exception => e - return + rescue Exception + nil end end @@ -27,8 +27,8 @@ def worker def body(args) DocuSign_Rooms::ExternalFormFillSessionForCreate.new({ - formId: args[:form_id], - roomId: args[:room_id] - }) + formId: args[:form_id], + roomId: args[:room_id] + }) end -end \ No newline at end of file +end diff --git a/app/services/room_api/eg007_create_form_group_service.rb b/app/services/room_api/eg007_create_form_group_service.rb index 26e999f..0d5dc5a 100644 --- a/app/services/room_api/eg007_create_form_group_service.rb +++ b/app/services/room_api/eg007_create_form_group_service.rb @@ -13,7 +13,7 @@ def worker configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") # Step 2 end # Step 4 start @@ -27,9 +27,9 @@ def worker def body(args) # Step 3 start DocuSign_Rooms::RoomForCreate.new( - { - name: args[:group_name] - } + { + name: args[:group_name] + } ) # Step 3 end end diff --git a/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb b/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb index 9620517..f2d4fe3 100644 --- a/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb +++ b/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb @@ -13,15 +13,15 @@ def worker configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") # Step 2 end # Step 5 start form_groups_api = DocuSign_Rooms::FormGroupsApi.new(api_client) begin response = form_groups_api.grant_office_access_to_form_group(args[:form_group_id], args[:office_id], args[:account_id]) - rescue Exception => e - return {exception: 'Failed to grant office access to a form group'} + rescue Exception + return { exception: 'Failed to grant office access to a form group' } end # Step 5 end response diff --git a/app/services/room_api/eg009_assign_form_to_form_group_service.rb b/app/services/room_api/eg009_assign_form_to_form_group_service.rb index 9694835..0248436 100644 --- a/app/services/room_api/eg009_assign_form_to_form_group_service.rb +++ b/app/services/room_api/eg009_assign_form_to_form_group_service.rb @@ -13,14 +13,14 @@ def worker configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) - api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") # Step 2 end # Step 6 start form_groups_api = DocuSign_Rooms::FormGroupsApi.new(api_client) begin response = form_groups_api.assign_form_group_form(args[:form_group_id], args[:account_id], body(args)) - rescue Exception => e + rescue Exception return { exception: 'Failed to assign a form to a form group' } end # Step 6 end diff --git a/app/services/room_api/get_data_service.rb b/app/services/room_api/get_data_service.rb index 3be2df4..0384c3b 100644 --- a/app/services/room_api/get_data_service.rb +++ b/app/services/room_api/get_data_service.rb @@ -5,10 +5,10 @@ class RoomApi::GetDataService def initialize(session, options = {}) @args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - room_id: options + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + room_id: options } end @@ -50,7 +50,7 @@ def get_form_libraries form_libraries_api = DocuSign_Rooms::FormLibrariesApi.new(@api_client) begin form_libraries = form_libraries_api.get_form_libraries(args[:account_id]) - rescue Exception => e + rescue Exception return end @@ -81,8 +81,8 @@ def get_form_groups def worker configuration = DocuSign_Rooms::Configuration.new - configuration.host = "https://demo.rooms.docusign.com/restapi" + configuration.host = 'https://demo.rooms.docusign.com/restapi' @api_client = DocuSign_Rooms::ApiClient.new(configuration) - @api_client.set_default_header("Authorization", "Bearer #{args[:access_token]}") + @api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") end end diff --git a/app/services/utils.rb b/app/services/utils.rb new file mode 100644 index 0000000..6f2d4e7 --- /dev/null +++ b/app/services/utils.rb @@ -0,0 +1,17 @@ +module Utils + class ManifestUtils + def get_manifest(manifest_url) + uri = URI(manifest_url) + res = Net::HTTP.get_response(uri) + JSON.parse(res.body) + end + + def get_example(manifest, number) + manifest['Groups'].each do |group| + group['Examples'].each do |example| + return example if example['ExampleNumber'] == number + end + end + end + end +end diff --git a/app/views/admin_api/eg001_create_user/get.html.erb b/app/views/admin_api/eg001_create_user/get.html.erb index 723fb7d..abd0081 100644 --- a/app/views/admin_api/eg001_create_user/get.html.erb +++ b/app/views/admin_api/eg001_create_user/get.html.erb @@ -1,42 +1,43 @@ -

    1. Create a new eSignature user with active status

    -

    Demonstrates how to create a new eSignature user and activate their account automatically.

    +<%= render('partials/example_info') %> -

    - API methods used: - AccountPermissionProfiles:list, - Groups:list, - eSignUserManagement:createUser. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% user_name_index = 0 %> +<% first_name_index = 1 %> +<% last_name_index = 2 %> +<% email_index = 3 %> +<% permission_index = 4 %> +<% group_index = 5 %> -
    - - + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + ">
    - - + + ">
    - - + + ">
    - + - We will never share your email with anyone else. + aria-describedby="emailHelp" required + placeholder="<%= @example["Forms"][form_index]["Inputs"][email_index]["InputPlaceholder"] %>"> + <%= render('partials/email_will_not_be_shared') %>
    <% if @permission_profiles.present? %>
    - + <%= select_tag "permission_profile_id", options_for_select(@permission_profiles.map { |obj| [obj.permission_profile_name, obj.permission_profile_id] }), { :class => 'form-control' } %>
    <% else %> @@ -47,7 +48,7 @@ <% end %> <% if @groups.present? %>
    - + <%= select_tag "group_id", options_for_select(@groups.map { |obj| [obj.group_name, obj.group_id] }), { :class => 'form-control' } %>
    <% else %> @@ -56,5 +57,5 @@
    Thank you.

    <% end %> - + <%= render('partials/submit_button') %> diff --git a/app/views/admin_api/eg002_create_active_clm_esign_user/get.html.erb b/app/views/admin_api/eg002_create_active_clm_esign_user/get.html.erb index 83c9d69..efbf319 100644 --- a/app/views/admin_api/eg002_create_active_clm_esign_user/get.html.erb +++ b/app/views/admin_api/eg002_create_active_clm_esign_user/get.html.erb @@ -1,42 +1,44 @@ -

    2. Create a new active user for CLM and eSignature

    -

    Demonstrates how to create a new DocuSign user (valid for both CLM and eSignature) and activate their account automatically.

    +<%= render('partials/example_info') %> -

    - API methods used: - MultiProductUserManagement:getProductPermissionProfiles, - MultiProductUserManagement:getDsGroups, - MultiProductUserManagement:addOrUpdateUser. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% user_name_index = 0 %> +<% first_name_index = 1 %> +<% last_name_index = 2 %> +<% user_email_index = 3 %> +<% esign_profile_index = 4 %> +<% clm_profile_index = 5 %> +<% group_index = 6 %>
    -
    - - + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + ">
    - - + + ">
    - - + + ">
    - + - We will never share your email with anyone else. + aria-describedby="emailHelp" required + placeholder="<%= @example["Forms"][form_index]["Inputs"][user_email_index]["InputPlaceholder"] %>"> + <%= render('partials/email_will_not_be_shared') %>
    <% if @esign_permission_profiles.present? %>
    - + <%= select_tag "esign_permission_profile_id", options_for_select(@esign_permission_profiles.map { |obj| [obj['permission_profile_name'], obj['permission_profile_id']] }), { :class => 'form-control' } %>
    <% else %> @@ -47,7 +49,7 @@ <% end %> <% if @clm_permission_profiles.present? %>
    - + <%= select_tag "clm_permission_profile_id", options_for_select(@clm_permission_profiles.map { |obj| [obj['permission_profile_name'], obj['permission_profile_id']] }), { :class => 'form-control' } %>
    <% else %> @@ -58,7 +60,7 @@ <% end %> <% if @ds_groups.present? %>
    - + <%= select_tag "ds_group_id", options_for_select(@ds_groups.map { |obj| [obj['group_name'], obj['ds_group_id']] }), { :class => 'form-control' } %>
    <% else %> @@ -69,5 +71,5 @@ <% end %> - + <%= render('partials/submit_button') %> diff --git a/app/views/admin_api/eg003_bulk_export_user_data/get.html.erb b/app/views/admin_api/eg003_bulk_export_user_data/get.html.erb index 87c7988..ce45f3c 100644 --- a/app/views/admin_api/eg003_bulk_export_user_data/get.html.erb +++ b/app/views/admin_api/eg003_bulk_export_user_data/get.html.erb @@ -1,19 +1,5 @@ -

    3. Bulk-export user data

    -

    - Demonstrates how to bulk-export user accounts within an organization into a CSV (comma-separated value) file. -

    - -

    API methods used: - UserExport:createUserListExport, - UserExport:getUserListExport. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<%= render('partials/example_info') %>
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/admin_api/eg004_import_user/get.html.erb b/app/views/admin_api/eg004_import_user/get.html.erb index 9c4c768..ce45f3c 100644 --- a/app/views/admin_api/eg004_import_user/get.html.erb +++ b/app/views/admin_api/eg004_import_user/get.html.erb @@ -1,19 +1,5 @@ -

    4. Add users via bulk import

    -

    - Demonstrates how to bulk-import users and add user data from an example CSV (comma-separated value) file into a DocuSign Admin organization. -

    - -

    API methods used: - UserImport:addBulkUserImport, - UserImport:getBulkUserImportRequest. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<%= render('partials/example_info') %>
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/admin_api/eg005_audit_users/get.html.erb b/app/views/admin_api/eg005_audit_users/get.html.erb index 552db48..5117b86 100644 --- a/app/views/admin_api/eg005_audit_users/get.html.erb +++ b/app/views/admin_api/eg005_audit_users/get.html.erb @@ -1,19 +1,5 @@ -

    5. Audit users

    -

    - Demonstrates how to audit the users in your account by retrieving the profiles of users that were modified after a specified date. -

    - -

    API methods used: - Users:getUsers, - eSignUserManagement:getUserProfiles. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<%= render('partials/example_info') %>
    - + <%= render('partials/submit_button') %>
    diff --git a/app/views/admin_api/eg006_get_user_profile_by_email/get.html.erb b/app/views/admin_api/eg006_get_user_profile_by_email/get.html.erb index d240550..71083d4 100644 --- a/app/views/admin_api/eg006_get_user_profile_by_email/get.html.erb +++ b/app/views/admin_api/eg006_get_user_profile_by_email/get.html.erb @@ -1,21 +1,19 @@ -

    6. Retrieve the user's DocuSign profile using an email address

    -

    Demonstrates how to obtain the user’s DocuSign profile information across all DocuSign accounts by specifying the user’s email address.

    +<%= render('partials/example_info') %> -

    API method used: - MultiProductUserManagement:getUserDSProfilesByEmail. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% email_index = 0 %>
    -
    - + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + - We will never share your email with anyone else. + aria-describedby="emailHelp" required + placeholder="<%= @example["Forms"][form_index]["Inputs"][email_index]["InputPlaceholder"] %>"> + <%= render('partials/email_will_not_be_shared') %>
    - + <%= render('partials/submit_button') %> diff --git a/app/views/admin_api/eg007_get_user_profile_by_user_id/get.html.erb b/app/views/admin_api/eg007_get_user_profile_by_user_id/get.html.erb index fe00a18..632ceef 100644 --- a/app/views/admin_api/eg007_get_user_profile_by_user_id/get.html.erb +++ b/app/views/admin_api/eg007_get_user_profile_by_user_id/get.html.erb @@ -1,17 +1,18 @@ -

    7. Retrieve the user's DocuSign profile using a User ID

    -

    Demonstrates how to obtain the user’s DocuSign profile information across all DocuSign accounts by specifying the user’s User ID.

    +<%= render('partials/example_info') %> -

    API method used: - MultiProductUserManagement:getUserDSProfile. -

    +<% form_index = 0 %> +<% user_id_index = 0 %>
    -
    - + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + placeholder="<%= @example["Forms"][form_index]["Inputs"][user_id_index]["InputPlaceholder"] %>" + required pattern="[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}">
    - + <%= render('partials/submit_button') %> diff --git a/app/views/admin_api/eg008_update_user_product_permission_profile/get.html.erb b/app/views/admin_api/eg008_update_user_product_permission_profile/get.html.erb index 95fe66b..ea6b984 100644 --- a/app/views/admin_api/eg008_update_user_product_permission_profile/get.html.erb +++ b/app/views/admin_api/eg008_update_user_product_permission_profile/get.html.erb @@ -1,28 +1,25 @@ -

    8. Update user product permission profiles using an email address

    -

    Demonstrates how to update user product permission profiles. There may only be one permission profile assigned to a user per product.

    +<%= render('partials/example_info') %> -

    - API methods used: - MultiProductUserManagement:getProductPermissionProfiles, - MultiProductUserManagement:addUserProductPermissionProfilesByEmail. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% product_index = 0 %> +<% esign_permission_index = 1 %> +<% clm_permission_index = 2 %> +<% redirect_to2_index = 0 %> <% if @email_ok %> -

    Update user product permission profile for the following email: <%= @email %>

    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize format_string(@example["Forms"][form_index]["FormName"], @email) %> + <% end %>
    - + <%= select_tag "product_id", options_for_select(@product_list.map { |obj| [obj['product_name'], obj['product_id']] }), { :class => 'form-control' } %>
    <% if @clm_permission_profiles.present? %>
    - + <%= select_tag "clm_permission_profile_id", options_for_select(@clm_permission_profiles.map { |obj| [obj['permission_profile_name'], obj['permission_profile_id']] }), { :class => 'form-control' } %>
    <% else %> @@ -34,7 +31,7 @@ <% if @esign_permission_profiles.present? %> <% else %> @@ -46,7 +43,7 @@ - + <%= render('partials/submit_button') %>
    @@ -64,10 +61,9 @@ }); <% else %> -

    Problem: You do not have the user to change permissions for. Go to example 2 and create one. -
    Thank you.

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %>
    - + <%= render('partials/continue_button') %>
    <% end %> \ No newline at end of file diff --git a/app/views/admin_api/eg009_delete_user_product_permission_profile/get.html.erb b/app/views/admin_api/eg009_delete_user_product_permission_profile/get.html.erb index e725f3a..6e76b0e 100644 --- a/app/views/admin_api/eg009_delete_user_product_permission_profile/get.html.erb +++ b/app/views/admin_api/eg009_delete_user_product_permission_profile/get.html.erb @@ -1,22 +1,18 @@ -

    9. Delete user product permission profiles using an email address

    -

    Demonstrates how to list and delete DocuSign Admin user product permission profiles.

    +<%= render('partials/example_info') %> -

    - API methods used: - MultiProductUserManagement:getUserProductPermissionProfilesByEmail, - MultiProductUserManagement:removeUserProductPermission. -

    +<% form_index = 0 %> +<% product_index = 0 %> +<% redirect_to2_index = 0 %> -

    - View source file <%= @source_file %> on GitHub. -

    <% if @email_ok %> -

    Delete user product permission profile for the following email: <%= @email %>

    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize format_string(@example["Forms"][form_index]["FormName"], @email) %> + <% end %>
    <% if @permission_profile_list.present? %>
    - + <%= select_tag "product_id", options_for_select(@permission_profile_list.map { |obj| [obj['permission_name'], obj['product_id']] }), { :class => 'form-control' } %>
    <% else %> @@ -25,13 +21,12 @@
    Thank you.

    <% end %> - + <%= render('partials/submit_button') %> <% else %> -

    Problem: You do not have the user to change permissions for. Go to example 2 and create one. -
    Thank you.

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %>
    - + <%= render('partials/continue_button') %>
    <% end %> \ No newline at end of file diff --git a/app/views/admin_api/index.html.erb b/app/views/admin_api/index.html.erb index ef9d9ff..be500ad 100644 --- a/app/views/admin_api/index.html.erb +++ b/app/views/admin_api/index.html.erb @@ -21,101 +21,32 @@

    Documentation on using JWT Grant or Authorization Code Grant from a Ruby on Rails application.

    <% end %> -

    1. Create a new active eSignature user

    -

    - Demonstrates how to create a new eSignature user and activate their account automatically.

    -

    - API method used: - AccountPermissionProfiles:list, - Groups:list, - eSignUserManagement:createUser -

    - -

    2. Create a new active user for CLM and eSignature

    -

    - Demonstrates how to create a new DocuSign user (valid for both CLM and eSignature) and activate their account automatically. -

    -

    - API methods used: - MultiProductUserManagement:getProductPermissionProfiles, - MultiProductUserManagement:getDsGroups, - MultiProductUserManagement:addOrUpdateUser -

    - -

    3. Bulk-export user data

    -

    - Demonstrates how to bulk-export user accounts within an organization into a CSV (comma-separated value) file.

    -

    - API methods used: - UserExport:createUserListExport, - UserExport:getUserListExport -

    - -

    4. Add users via bulk import

    -

    - Demonstrates how to bulk import users and add user data from an example CSV (comma-separated value) file into a DocuSign Admin organization.

    -

    - API method used: - UserImport:addBulkUserImport, - UserImport:getBulkUserImportRequest - -

    - -

    5. Audit users

    -

    - Demonstrates how to audit the users in your account by retrieving the profiles of users that were modified after a specified date. -

    -

    - API methods used: - Users:getUsers, - eSignUserManagement:getUserProfiles -

    - -

    6. Retrieve the user's DocuSign profile using an email address

    -

    Demonstrates how to obtain the user’s DocuSign profile information across all DocuSign accounts by specifying the user’s email address.

    - -

    API method used: - MultiProductUserManagement:getUserDSProfilesByEmail -

    - -

    7. Retrieve the user's DocuSign profile using a User ID

    -

    Demonstrates how to obtain the user’s DocuSign profile information across all DocuSign accounts by specifying the user’s User ID.

    - -

    API method used: - MultiProductUserManagement:getUserDSProfile -

    - -

    8. Update user product permission profiles using an email address

    -

    Demonstrates how to update user product permission profiles. There may only be one permission profile assigned to a user per product.

    - -

    - API methods used: - MultiProductUserManagement:getProductPermissionProfiles, - MultiProductUserManagement:addUserProductPermissionProfilesByEmail -

    - -

    9. Delete user product permission profiles using an email address

    -

    Demonstrates how to list and delete DocuSign Admin user product permission profiles.

    - -

    - API methods used: - MultiProductUserManagement:getUserProductPermissionProfilesByEmail, - MultiProductUserManagement:removeUserProductPermission -

    + <% @manifest["Groups"].each { |group| %> +

    <%= group["Name"] %>

    + + <% group["Examples"].each { |example| %> + <% if not example["SkipLanguages"] or not example["SkipLanguages"].include? "ruby" %> +

    "> + "> + <%= example["ExampleName"] %> + +

    + +

    <%= sanitize example["ExampleDescription"] %>

    + + <% if example["LinksToAPIMethod"].length > 1 %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsedPlural"] %> + <% else %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsed"] %> + <% end %> + + <% example["LinksToAPIMethod"].each do |link| %> + "><%= link["PathName"] %> + <% end %> + <% end %> +

    + <% } %> + <% } %>
    diff --git a/app/views/clickwrap/eg001_create_clickwrap/get.html.erb b/app/views/clickwrap/eg001_create_clickwrap/get.html.erb index 9571832..e8c9605 100644 --- a/app/views/clickwrap/eg001_create_clickwrap/get.html.erb +++ b/app/views/clickwrap/eg001_create_clickwrap/get.html.erb @@ -1,19 +1,18 @@ -

    1. Create a clickwrap

    -

    Creates a clickwrap that you can embed in your website or app.

    +<%= render('partials/example_info') %> -

    API method used: - ClickWraps::createClickwrap -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% click_name_index = 0 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + + name="clickwrapName" required + placeholder="<%= @example["Forms"][form_index]["Inputs"][click_name_index]["InputPlaceholder"] %>">
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/clickwrap/eg002_activate_clickwrap/get.html.erb b/app/views/clickwrap/eg002_activate_clickwrap/get.html.erb index 4b4e2a7..e6249c8 100644 --- a/app/views/clickwrap/eg002_activate_clickwrap/get.html.erb +++ b/app/views/clickwrap/eg002_activate_clickwrap/get.html.erb @@ -1,34 +1,18 @@ -

    2. Activate a clickwrap

    -

    - Activates a new clickwrap that you have already created. By default, new clickwraps are - inactive. You must activate your clickwrap before you can use it. -

    +<%= render('partials/example_info') %> -

    API method used: - ClickWraps::updateClickwrapVersion -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% redirect_to1_index = 0 %> <% if session[:clickwrap_id] %> -

    - The clickwrap you created via example 1 will be queried. -

    -
    - + <% if @example["Forms"][0]["FormName"] %> + <%= sanitize @example["Forms"][0]["FormName"] %> + <% end %> + + <%= render('partials/submit_button') %>
    <% else %> - -

    - Problem: please first create a clickwrap using - example 1. -
    - Thank you. -

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="eg001"') %> <% end %> \ No newline at end of file diff --git a/app/views/clickwrap/eg003_create_new_clickwrap_version/get.html.erb b/app/views/clickwrap/eg003_create_new_clickwrap_version/get.html.erb index 6ecbfdb..bb8575d 100644 --- a/app/views/clickwrap/eg003_create_new_clickwrap_version/get.html.erb +++ b/app/views/clickwrap/eg003_create_new_clickwrap_version/get.html.erb @@ -1,35 +1,16 @@ -

    3. Create a new clickwrap version

    -

    - Creates a new version of a clickwrap. -

    -

    - You can specify whether you require users who have previously accepted the clickwrap - to accept the new version when they return to your website. -

    +<%= render('partials/example_info') %> -

    API method used: - ClickWraps::createClickwrapVersion -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% redirect_to1_index = 0 %> <% if session[:clickwrap_id] %>

    The clickwrap you created via example 1 will be queried.

    - + <%= render('partials/submit_button') %>
    <% else %> - -

    - Problem: please first create a clickwrap using - example 1. -
    - Thank you. -

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="eg001"') %> <% end %> \ No newline at end of file diff --git a/app/views/clickwrap/eg004_list_clickwraps/get.html.erb b/app/views/clickwrap/eg004_list_clickwraps/get.html.erb index 1444ff4..7766e2d 100644 --- a/app/views/clickwrap/eg004_list_clickwraps/get.html.erb +++ b/app/views/clickwrap/eg004_list_clickwraps/get.html.erb @@ -1,17 +1,6 @@ -

    4. Get a list of clickwraps

    -

    - Gets a list of clickwraps associated with a specific DocuSign user. -

    - -

    API method used: - ClickWraps::getClickwraps -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<%= render('partials/example_info') %>
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/clickwrap/eg005_clickwrap_responses/get.html.erb b/app/views/clickwrap/eg005_clickwrap_responses/get.html.erb index 70d276c..ab1e10c 100644 --- a/app/views/clickwrap/eg005_clickwrap_responses/get.html.erb +++ b/app/views/clickwrap/eg005_clickwrap_responses/get.html.erb @@ -1,54 +1,24 @@ -

    5. Get clickwrap responses

    -

    - Gets user responses to your clickwrap agreements. -

    +<%= render('partials/example_info') %> -

    API method used: - ClickWraps::getClickwrapAgreements -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% click_id_index = 0 %> +<% redirect_to1_index = 0 %> <% if session[:clickwrap_id] %> - -

    - First, test your clickwrap: -

    - -
      -
    • Log in to your developer account and select the Manage page. -
    • Select the Clickwraps tab. -
    • - In the list of active clickwraps, locate the one you want to test, then click - the dropdown arrow to the right of COPY CODE and select Test Clickwrap. -
    • -
    • In the Test Clickwrap dialog box, click TEST CLICKWRAP. -
    • In the Test Your Clickwrap browser page, in the Unique ID field, enter any string, then click Test Clickwrap. -
    • Review your displayed clickwrap and click I AGREE (or the equivalent button you configured) to complete the test. -
    - -

    - Then enter the same string you used to test your clickwrap in the field below. -

    -
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - - + + ">
    - + <%= render('partials/submit_button') %>
    <% else %> - -

    - Problem: please first create a clickwrap using - example 1. -
    - Thank you. -

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="eg001"') %> <% end %> \ No newline at end of file diff --git a/app/views/clickwrap/index.html.erb b/app/views/clickwrap/index.html.erb index 1886c12..643d0a4 100644 --- a/app/views/clickwrap/index.html.erb +++ b/app/views/clickwrap/index.html.erb @@ -24,50 +24,32 @@

    Documentation on using JWT or OAuth Authorization Code Grant from a Ruby Rails application.

    <% end %> -

    1. Create a clickwrap

    -

    - Creates a clickwrap that you can embed in your website or app. -

    -

    - API methods used: - ClickWraps::createClickwrap -

    - -

    2. Activate a clickwrap

    -

    - Activates a new clickwrap that you have already created. -

    -

    - API methods used: - ClickWraps::updateClickwrapVersion -

    - -

    3. Create a new clickwrap version

    -

    - Creates a new version of a clickwrap. -

    -

    - API methods used: - ClickWraps::createClickwrapVersion -

    - -

    4. Get a list of clickwraps

    -

    - Gets a list of clickwraps associated with a specific DocuSign user. -

    -

    - API methods used: - ClickWraps::getClickwraps -

    - -

    5. Get clickwrap responses

    -

    - Gets user responses to your clickwrap agreements. -

    -

    - API methods used: - ClickWraps::getClickwrapAgreements -

    + <% @manifest["Groups"].each { |group| %> +

    <%= group["Name"] %>

    + + <% group["Examples"].each { |example| %> + <% if not example["SkipLanguages"] or not example["SkipLanguages"].include? "ruby" %> +

    "> + "> + <%= example["ExampleName"] %> + +

    + +

    <%= sanitize example["ExampleDescription"] %>

    + + <% if example["LinksToAPIMethod"].length > 1 %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsedPlural"] %> + <% else %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsed"] %> + <% end %> + + <% example["LinksToAPIMethod"].each do |link| %> + "><%= link["PathName"] %> + <% end %> + <% end %> +

    + <% } %> + <% } %>
    diff --git a/app/views/ds_common/choose_api.erb b/app/views/ds_common/choose_api.erb index 27d3a6c..ff11754 100644 --- a/app/views/ds_common/choose_api.erb +++ b/app/views/ds_common/choose_api.erb @@ -1,5 +1,5 @@
    -

    Please Choose an API

    + <%= sanitize @manifest["SupportingTexts"]["SelectAPIPage"]["SelectAPIHeader"] %>

    <%= hidden_field_tag :authenticity_token, form_authenticity_token %> @@ -11,7 +11,7 @@
    - +

    diff --git a/app/views/ds_common/ds_must_authenticate.erb b/app/views/ds_common/ds_must_authenticate.erb index 844cc22..9e77ef6 100644 --- a/app/views/ds_common/ds_must_authenticate.erb +++ b/app/views/ds_common/ds_must_authenticate.erb @@ -1,5 +1,5 @@
    -

    Please Authenticate with DocuSign

    + <%= sanitize @manifest["SupportingTexts"]["LoginPage"]["LoginHeader"] %>

    <%= hidden_field_tag :authenticity_token, form_authenticity_token %> @@ -10,10 +10,10 @@ <% end %>
    - +


    -

    You need to authenticate with DocuSign to continue your request.

    +

    <%= @manifest["SupportingTexts"]["LoginPage"]["LoginHelperText"] %>

    diff --git a/app/views/ds_common/example_done.erb b/app/views/ds_common/example_done.erb index 64d63f7..75df06b 100644 --- a/app/views/ds_common/example_done.erb +++ b/app/views/ds_common/example_done.erb @@ -1,4 +1,4 @@ -

    <%= @h1 %>

    +

    <%= @title %>

    <% if !@message.nil? %>

    <%= @message.html_safe %>

    <% end %> diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index 9c15468..157e227 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -28,344 +28,34 @@

    Documentation on using JWT or OAuth Authorization Code Grant from a Ruby on Rails application.

    <% end %> - - -
    -

    Requesting a signature

    - -

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

    -

    The envelope includes three documents: one each in PDF, Word, and HTML format. Anchor text - (AutoPlace) - is used to position the signing fields in the documents. -

    -

    API method used: - Envelopes::create. -

    - -

    Use embedded signing

    -

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

    -

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

    - -

    Send an envelope using a template

    -

    This example demonstrates a common pattern for DocuSign integrations: envelopes will be sent programmatically, defined by a template. The signer and cc recipient name and email are used to fill in the template’s roles.

    -

    API method used: - Envelopes::create. -

    - -

    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 - feature.

    -

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

    - -

    Request a signature by SMS delivery

    -

    - Sends a signature request via an SMS message. -

    -

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

    - -

    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. -

    - -

    Send an envelope to an In Person Signer

    -

    - This example demonstrates how to host an In Person Signing session with embedded signing. -

    -

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

    - - -
    -

    Working with envelopes and templates

    - -

    Get an envelope’s basic information and status

    -

    This example lists 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, and more. -

    -

    API method used: - Envelopes::get. -

    - -

    List an envelope’s recipients and their status

    -

    This example lists the envelope’s recipients, including their current status. -

    -

    API method used: - EnvelopeRecipients::list. -

    - -

    List envelopes whose status has changed

    -

    This example lists the envelopes whose status has changed within the last 30 days. -

    -

    API method used: - Envelopes::listStatusChanges. -

    - -

    Create a template

    -

    Create a template with two roles, signer and cc.

    -

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

    - -

    Use embedded sending

    -

    This example demonstrates how to embed the DocuSign sender view within your web app. An envelope will be created in draft mode. Your browser will then be redirected to the DocuSign UI, where the envelope can be (optionally) updated and then sent.

    -

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

    - -

    Bulk send envelopes

    -

    Demonstrates how to send envelopes in bulk to multiple recipients. First, this example creates a bulk send recipients list, then creates an envelope. After that, - it initiates bulk envelope sending. -

    -

    API methods used: - BulkSend::createBulkSendList, - Envelopes::create, - EnvelopeCustomFields::create, - BulkSend::createBulkSendRequest, - BulkSend::getBulkSendBatchStatus -

    - - -
    -

    Working with advanced recipient routing

    - -

    Pause a signature workflow

    -

    This example creates an envelope where the workflow is paused before the envelope is sent to a second recipient.

    -

    API method used: - Envelopes::create. -

    - -

    Unpause a signature workflow

    -

    This example resumes a signature workflow for an envelope whose workflow has been paused.

    -

    API method used: - Envelopes::update. -

    - -

    Use conditional recipients

    -

    This example creates an envelope whose workflow routes it to different recipients based on the value of a transaction.

    -

    API method used: - Envelopes::create. -

    - -

    Schedule an envelope

    -

    - Demonstrates how to schedule sending an envelope using the scheduled sending feature. -

    -

    - API method used: - Envelopes:create. -

    -

    Send an envelope with delayed routing

    - -

    - Demonstrates how to delay an envelope’s delivery between recipients using the delayed routing feature. -

    -

    - API method used: - Envelopes:create. -

    - - -
    -

    Working with documents

    - -

    List an envelope's documents

    -

    This example demonstrates how to list an envelope's documents. A Certificate of Completion document - is also associated with every envelope. -

    -

    API method used: - EnvelopeDocuments::list. -

    - -

    Download a document from an envelope

    -

    This example demonstrates how to download a document from a given envelope. An envelope’s documents can be downloaded one by one or as a complete set. -

    -

    API method used: - EnvelopeDocuments::get. -

    - -

    Send an envelope using binary document transfer

    -

    The envelope includes three documents: one each in PDF, Word, and HTML format.

    -

    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 15 MB. Binary transfer is not yet supported by the SDK. -

    -

    API method used: - Envelopes::create. -

    - -

    Create a signable HTML document

    -

    - Demonstrates how to create an HTML document for responsive signing. -

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

    - -

    Set document visibility for envelope recipients

    -

    - Demonstrates how to set document visibility for envelope recipients. -

    -

    API method used: - Envelopes::create. -

    - - -
    -

    Working with tabs

    - -

    Get the tab data from an envelope

    -

    This example retrieves the tab (field) values from an envelope for all of the envelope’s recipients.

    -

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

    - -

    Set tab values for a envelope

    -

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

    -

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

    - -

    Set template tab values

    -

    This example sets the tab (field) values for a template being used by an envelope. It includes setting radio button and checkbox tabs.

    -

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

    - -

    List envelope custom metadata field values

    -

    This example lists an envelope’s custom metadata field values.

    -

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

    - - -
    -

    Working with brands

    - -

    Create a brand

    -

    This example creates an account brand that can be used to apply customization to your envelopes, including your own logo, colors, and text elements.

    -

    API method used: - AccountBrands::create. -

    - -

    Apply a brand to an envelope

    -

    This example creates an envelope using any of the created brands on your account.

    -

    API method used: - Envelopes::create. -

    - -

    Apply a brand and template to an envelope

    -

    This example creates an envelope from a template while applying any of the created brands on your account.

    -

    API method used: - Envelopes::create. -

    - - -
    -

    Working with permissions

    - -

    Create a permission profile

    -

    - This example creates a user group’s permission profile. -

    -

    API method used: - AccountPermissionProfiles::create. -

    - -

    Set a permission profile

    -

    This example updates the group name and modifies, or sets, the permission profile for the group.

    -

    API method used: - Groups::update. -

    - -

    Update individual permission profile settings

    -

    - This example updates an individual setting on a user group’s permission profile. -

    -

    API method used: - AccountPermissionProfiles::update. -

    - -

    Delete a permission profile

    -

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

    -

    API method used: - AccountPermissionProfiles::delete. -

    - - -
    -

    Implementing multi-factor recipient (signer) authentication

    - -

    Require ID verification (IDV) for a recipient

    -

    This is an example of an envelope utilizing ID verification authentication for a recipient.

    -

    API methods used: - Accounts::getAccountIdentityVerificationsList and Envelopes::create. -

    - -

    Require knowledge based authentication (KBA) for a recipient

    -

    Submit an envelope with multiple choice, public records based questions to provide multi-factor authentication.

    -

    API method used: - Envelopes::create. -

    - -

    Require phone authentication for a recipient

    -

    Sends an envelope that requires entering a six-digit code from a text message or phone call for the purpose of multifactor authentication.

    -

    API method used: - Envelopes::create. -

    - -

    Require access code authentication for a recipient

    -

    This example sends an envelope requiring the recipient to enter an access code for multifactor authentication.

    -

    API method used: - Envelopes::create. -

    - -
    -

    Embedded DocuSign UI

    -

    Embedded DocuSign UI

    -

    This example demonstrates how to embed the DocuSign UI in your app. Use this API call to open the DocuSign UI with the user already logged in.

    -

    API method used: - EnvelopeViews::createConsole. -

    + <% @manifest["Groups"].each { |group| %> +

    <%= group["Name"] %>

    + + <% group["Examples"].each { |example| %> + <% if not example["SkipLanguages"] or not example["SkipLanguages"].include? "ruby" %> +

    "> + "> + <%= example["ExampleName"] %> + +

    + +

    <%= sanitize example["ExampleDescription"] %>

    + + <% if example["LinksToAPIMethod"].length > 1 %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsedPlural"] %> + <% else %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsed"] %> + <% end %> + + <% example["LinksToAPIMethod"].each do |link| %> + "><%= link["PathName"] %> + <% end %> + <% end %> +

    + <% } %> + <% } %>
    diff --git a/app/views/e_sign/eg002_signing_via_email/get.html.erb b/app/views/e_sign/eg002_signing_via_email/get.html.erb index a0c0704..740b325 100644 --- a/app/views/e_sign/eg002_signing_via_email/get.html.erb +++ b/app/views/e_sign/eg002_signing_via_email/get.html.erb @@ -1,46 +1,40 @@ -

    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.

    +<%= render('partials/example_info') %> -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - Envelopes::create. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %> +<% cc_email_index = 2 %> +<% cc_name_index = 3 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - <%= @example["Forms"][form_index]["Inputs"][signer_name_index]["InputName"] %> + " name="signerName" value="<%= @config.signer_name %>" required>
    - + - The email for the cc recipient must be different from the signer's email. + aria-describedby="emailHelp" placeholder="<%= @example["Forms"][form_index]["Inputs"][cc_email_index]["InputPlaceholder"] %>" required /> + <%= render('partials/email_should_differ_from_signer') %>
    - - <%= @example["Forms"][form_index]["Inputs"][cc_name_index]["InputName"] %> + " name="ccName" required>
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/e_sign/eg003_list_envelopes/get.html.erb b/app/views/e_sign/eg003_list_envelopes/get.html.erb index 6d6bfba..4bf9d9e 100644 --- a/app/views/e_sign/eg003_list_envelopes/get.html.erb +++ b/app/views/e_sign/eg003_list_envelopes/get.html.erb @@ -1,18 +1,5 @@ -

    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.

    - -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - Envelopes::listStatusChanges. -

    -

    - View source file <%= @source_file %> on GitHub. -

    +<%= render('partials/example_info') %>
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/e_sign/eg004_envelope_info/get.html.erb b/app/views/e_sign/eg004_envelope_info/get.html.erb index 0cfe8d4..69c11dd 100644 --- a/app/views/e_sign/eg004_envelope_info/get.html.erb +++ b/app/views/e_sign/eg004_envelope_info/get.html.erb @@ -1,38 +1,16 @@ -

    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.

    +<%= render('partials/example_info') %> -

    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. -

    - -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - Envelopes::get. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% redirect_to2_index = 0 %> <% if @envelope_ok %> -

    The envelope you created via Request a signature by email (remote signing) will be queried.

    -
    - + <%= render('partials/submit_button') %>
    <% else %> -

    Problem: please first create an envelope using Request a signature by email (remote signing).
    - Thank you.

    +<%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %>
    - + <%= render('partials/continue_button') %>
    <% end %> diff --git a/app/views/e_sign/eg005_envelope_recipients/get.html.erb b/app/views/e_sign/eg005_envelope_recipients/get.html.erb index 6fdc727..302f88e 100644 --- a/app/views/e_sign/eg005_envelope_recipients/get.html.erb +++ b/app/views/e_sign/eg005_envelope_recipients/get.html.erb @@ -1,29 +1,21 @@ -

    List an envelope's recipients and their status

    -

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

    +<%= render('partials/example_info') %> -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - EnvelopeRecipients::list. -

    -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% redirect_to2_index = 0 %> <% if @envelope_ok %> -

    The envelope you created via Request a signature by email (remote signing) will be queried.

    -
    - + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + + <%= render('partials/submit_button') %>
    <% else %> -

    Problem: please first create an envelope using Request a signature by email (remote signing).
    - Thank you.

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %>
    - + <%= render('partials/continue_button') %>
    <% end %> diff --git a/app/views/e_sign/eg006_envelope_docs/get.html.erb b/app/views/e_sign/eg006_envelope_docs/get.html.erb index aee609a..0feb105 100644 --- a/app/views/e_sign/eg006_envelope_docs/get.html.erb +++ b/app/views/e_sign/eg006_envelope_docs/get.html.erb @@ -1,35 +1,21 @@ -

    List an envelope's documents

    -

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

    +<%= render('partials/example_info') %> -

    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.

    - -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - EnvelopeDocuments::list. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% redirect_to2_index = 0 %> <% if @envelope_ok %> -

    The envelope you created via Request a signature by email (remote signing) will be queried.

    -
    - + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + + <%= render('partials/submit_button') %>
    <% else %> -

    Problem: please first create an envelope using Request a signature by email (remote signing).
    - Thank you.

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %>
    - + <%= render('partials/continue_button') %>
    <% end %> diff --git a/app/views/e_sign/eg007_envelope_get_doc/get.html.erb b/app/views/e_sign/eg007_envelope_get_doc/get.html.erb index 02218e2..1717f34 100644 --- a/app/views/e_sign/eg007_envelope_get_doc/get.html.erb +++ b/app/views/e_sign/eg007_envelope_get_doc/get.html.erb @@ -1,54 +1,30 @@ +<%= render('partials/example_info') %> -

    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.
    • -
    • - PDF Portfolio: Retrieves the envelope documents as a PDF portfolio -
    • -
    • The envelope's individual documents
    • -
    • The envelope's Certificate of Completion
    • -
    - -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - EnvelopeDocuments::get. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% doc_index = 0 %> +<% redirect_to2_index = 0 %> +<% redirect_to6_index = 1 %> <% if !@envelope_ok %> -

    Problem: please first create an envelope using Request a signature by email (remote signing).
    - You will then need to use List envelope documents to create the list of documents.
    - Thank you.

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %>
    - + <%= render('partials/continue_button') %>
    <% elsif !@documents_ok %> -

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

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to6_index]["RedirectText"], 'href="eg006"') %>
    - + <%= render('partials/continue_button') %>
    <% else %> -

    Please choose a document.
    - The document list is from your results for List envelope documents.

    -
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - +
    - + <%= render('partials/submit_button') %>
    <% end %> diff --git a/app/views/e_sign/eg008_create_template/get.html.erb b/app/views/e_sign/eg008_create_template/get.html.erb index d5cc859..ebf2e7e 100644 --- a/app/views/e_sign/eg008_create_template/get.html.erb +++ b/app/views/e_sign/eg008_create_template/get.html.erb @@ -1,27 +1,5 @@ -

    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. -

    - -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

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

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<%= render('partials/example_info') %>
    - + <%= render('partials/submit_button') %>
    diff --git a/app/views/e_sign/eg009_use_template/get.html.erb b/app/views/e_sign/eg009_use_template/get.html.erb index c64de91..11825a7 100644 --- a/app/views/e_sign/eg009_use_template/get.html.erb +++ b/app/views/e_sign/eg009_use_template/get.html.erb @@ -1,59 +1,52 @@ -

    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.

    +<%= render('partials/example_info') %> -

    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. -

    - -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - Envelopes::create. -

    -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %> +<% cc_email_index = 2 %> +<% cc_name_index = 3 %> +<% redirect_to8_index = 0 %> <% if @template_ok %> -

    The template you created via Create a template will be used.

    -
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - <%= @example["Forms"][form_index]["Inputs"][signer_name_index]["InputName"] %> + " name="signerName" value="<%= @config.signer_name %>" required>
    - + - The email for the cc recipient must be different from the signer's email. + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][cc_email_index]["InputPlaceholder"] %>" required /> + <%= render('partials/email_should_differ_from_signer') %>
    - - <%= @example["Forms"][form_index]["Inputs"][cc_name_index]["InputName"] %> + " name="ccName" required>
    - + <%= render('partials/submit_button') %>
    <% else %> -

    Problem: please first create the template using Create a template.
    - Thank you.

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to8_index]["RedirectText"], 'href="eg008"') %>
    - + <%= render('partials/continue_button') %>
    <% end %> diff --git a/app/views/e_sign/eg010_send_binary_docs/get.html.erb b/app/views/e_sign/eg010_send_binary_docs/get.html.erb index 78c2bb3..61befd6 100644 --- a/app/views/e_sign/eg010_send_binary_docs/get.html.erb +++ b/app/views/e_sign/eg010_send_binary_docs/get.html.erb @@ -1,47 +1,42 @@ -

    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. -

    +<%= render('partials/example_info') %> -

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

    - -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - Envelopes::create. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %> +<% cc_email_index = 2 %> +<% cc_name_index = 3 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - <%= @example["Forms"][form_index]["Inputs"][signer_name_index]["InputName"] %> + " name="signerName" value="<%= @config.signer_name %>" required>
    - + - The email for the cc recipient must be different from the signer's email. + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][cc_email_index]["InputPlaceholder"] %>" required> + <%= render('partials/email_should_differ_from_signer') %>
    - - <%= @example["Forms"][form_index]["Inputs"][cc_name_index]["InputName"] %> + " name="ccName" required>
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/e_sign/eg011_embedded_sending/get.html.erb b/app/views/e_sign/eg011_embedded_sending/get.html.erb index 02b946e..0bb3890 100644 --- a/app/views/e_sign/eg011_embedded_sending/get.html.erb +++ b/app/views/e_sign/eg011_embedded_sending/get.html.erb @@ -1,60 +1,50 @@ -

    Use 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 Request a signature using a composite template for adding additional documents programmatically). -

    +<%= render('partials/example_info') %> -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

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

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% view_index = 0 %> +<% signer_email_index = 1 %> +<% signer_name_index = 2 %> +<% cc_email_index = 3 %> +<% cc_name_index = 4 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - +
    - + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - <%= @example["Forms"][form_index]["Inputs"][signer_name_index]["InputName"] %> + " name="signerName" value="<%= @config.signer_name %>" required>
    - + - The email for the cc recipient must be different from the signer's email. + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][cc_email_index]["InputPlaceholder"] %>" required /> + <%= render('partials/email_should_differ_from_signer') %>
    - - <%= @example["Forms"][form_index]["Inputs"][cc_name_index]["InputName"] %> + " name="ccName" required>
    - + <%= render('partials/submit_button') %>
    diff --git a/app/views/e_sign/eg012_embedded_console/get.html.erb b/app/views/e_sign/eg012_embedded_console/get.html.erb index 86c8514..5d7fb5d 100644 --- a/app/views/e_sign/eg012_embedded_console/get.html.erb +++ b/app/views/e_sign/eg012_embedded_console/get.html.erb @@ -1,38 +1,25 @@ -

    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. -

    +<%= render('partials/example_info') %> -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - EnvelopeViews::createConsole. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% view_index = 0 %> +<% redirect_to2_index = 0 %> <% if !@envelope_ok %> -

    Optional: to use the Envelope's document view please first create an envelope using - Request a signature by email (remote signing).

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %> <% end %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - +
    - + <%= render('partials/submit_button') %>
    diff --git a/app/views/e_sign/eg013_add_doc_to_template/get.html.erb b/app/views/e_sign/eg013_add_doc_to_template/get.html.erb index 96e1afc..34a6f5e 100644 --- a/app/views/e_sign/eg013_add_doc_to_template/get.html.erb +++ b/app/views/e_sign/eg013_add_doc_to_template/get.html.erb @@ -1,61 +1,50 @@ -

    Use embedded signing from a template with an added document

    +<%= render('partials/example_info') %> -<% if @template_ok %> -

    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 is initiated from your website.

    -<% end %> - - <% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

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

    -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %> +<% cc_email_index = 2 %> +<% cc_name_index = 3 %> +<% item_index = 4 %> +<% quantity_index = 5 %> +<% redirect_to8_index = 0 %> <% if @template_ok %> -

    The template you created via Create a template will be used.

    -
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - <%= @example["Forms"][form_index]["Inputs"][signer_name_index]["InputName"] %> + " name="signerName" value="<%= @config.signer_name %>" required>
    - + - The email for the cc recipient must be different from the signer's email. + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][cc_email_index]["InputPlaceholder"] %>" required /> + <%= render('partials/email_should_differ_from_signer') %>
    - - <%= @example["Forms"][form_index]["Inputs"][cc_name_index]["InputName"] %> + " name="ccName" required>


    - +
    - +
    - + <%= render('partials/submit_button') %>
    <% else %> -

    Problem: please first create the template using Create a template.
    - Thank you.

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to8_index]["RedirectText"], 'href="eg008"') %>
    - + <%= render('partials/continue_button') %>
    <% end %> \ No newline at end of file diff --git a/app/views/e_sign/eg014_collect_payment/get.html.erb b/app/views/e_sign/eg014_collect_payment/get.html.erb index 0ef1523..111e84a 100644 --- a/app/views/e_sign/eg014_collect_payment/get.html.erb +++ b/app/views/e_sign/eg014_collect_payment/get.html.erb @@ -1,51 +1,49 @@ -

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

    +<%= render('partials/example_info') %> -

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

    - -<% if @showDoc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - Envelopes::create. -

    - -

    -View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %> +<% cc_email_index = 2 %> +<% cc_name_index = 3 %> +<% set_getaway_index = 0 %> <% if @gateway_ok %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - <%= @example["Forms"][form_index]["Inputs"][signer_name_index]["InputName"] %> + " name="signerName" value="<%= @config.signer_name %>" required>
    - + - The email for the cc recipient must be different from the signer's email. + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][cc_email_index]["InputPlaceholder"] %>" required /> + <%= render('partials/email_should_differ_from_signer') %>
    - - <%= @example["Forms"][form_index]["Inputs"][cc_name_index]["InputName"] %> + " name="ccName" required>
    - + <%= render('partials/submit_button') %>
    <% else %> -

    Problem: please set the gateway_account_id value in the config/application.rb configuration file.

    + <%= sanitize @example["RedirectsToOtherCodeExamples"][set_getaway_index]["RedirectText"] %> <% end %> \ No newline at end of file diff --git a/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb b/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb index 06adfae..302f88e 100644 --- a/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb +++ b/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb @@ -1,36 +1,21 @@ -

    Get the tab data from an envelope

    -

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

    +<%= render('partials/example_info') %> -

    - 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. -

    - -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - EnvelopeFormData::get. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% redirect_to2_index = 0 %> <% if @envelope_ok %> -

    The envelope you created from Request a signature by email (remote signing) will be queried.

    -
    - + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + + <%= render('partials/submit_button') %>
    <% else %> -

    Problem: please first create an envelope using Request a signature by email (remote signing).
    - Thank you.

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %>
    - + <%= render('partials/continue_button') %>
    <% end %> diff --git a/app/views/e_sign/eg016_set_envelope_tab_data/get.html.erb b/app/views/e_sign/eg016_set_envelope_tab_data/get.html.erb index d7a395e..2fdf193 100644 --- a/app/views/e_sign/eg016_set_envelope_tab_data/get.html.erb +++ b/app/views/e_sign/eg016_set_envelope_tab_data/get.html.erb @@ -1,39 +1,27 @@ +<%= render('partials/example_info') %> -

    Set tab values for a envelope

    -

    - This example creates an envelope 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.

    - - -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

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

    - - -

    - View source file <%= @source_file %> on GitHub. -

    - +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - <%= @example["Forms"][form_index]["Inputs"][signer_name_index]["InputName"] %> + " name="signerName" value="<%= @config.signer_name %>" required>
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/e_sign/eg017_set_template_tab_values/get.html.erb b/app/views/e_sign/eg017_set_template_tab_values/get.html.erb index 0c2c51c..1164469 100644 --- a/app/views/e_sign/eg017_set_template_tab_values/get.html.erb +++ b/app/views/e_sign/eg017_set_template_tab_values/get.html.erb @@ -1,59 +1,52 @@ +<%= render('partials/example_info') %> -

    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.

    - -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - Envelopes::create. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    - +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %> +<% cc_email_index = 2 %> +<% cc_name_index = 3 %> +<% redirect_to8_index = 0 %> <% if @template_ok %> -

    The template you created via Create a template will be used.

    -
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - <%= @example["Forms"][form_index]["Inputs"][signer_name_index]["InputName"] %> + " name="signerName" value="<%= @config.signer_name %>" required>
    - + - The email for the cc recipient must be different from the signer's email. + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][cc_email_index]["InputPlaceholder"] %>" required /> + <%= render('partials/email_should_differ_from_signer') %>
    - - <%= @example["Forms"][form_index]["Inputs"][cc_name_index]["InputName"] %> + " name="ccName" required>
    - + <%= render('partials/submit_button') %>
    <% else %> -

    Problem: please first create the template using Create a template.
    - Thank you.

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to8_index]["RedirectText"], 'href="eg008"') %>
    - + <%= render('partials/continue_button') %>
    <% end %> \ No newline at end of file diff --git a/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb b/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb index 4d08159..a334c07 100644 --- a/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb +++ b/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb @@ -1,42 +1,21 @@ -

    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. -

    +<%= render('partials/example_info') %> -

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

    -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - EnvelopeCustomFields::list. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% redirect_to16_index = 0 %> <% if @envelope_ok %> -

    - The last envelope you created with the launcher will be queried. - Recommendation: Create an envelope using Set envelope tab values then use this example in order to see an example of custom tab values. -

    -
    - + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + + <%= render('partials/submit_button') %>
    <% else %> -

    Problem: Please first create an envelope using Set envelope tab values. -

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to16_index]["RedirectText"], 'href="eg016"') %>
    - + <%= render('partials/continue_button') %>
    <% end %> diff --git a/app/views/e_sign/eg019_access_code_authentication/get.html.erb b/app/views/e_sign/eg019_access_code_authentication/get.html.erb index 17a0a60..433cd4b 100644 --- a/app/views/e_sign/eg019_access_code_authentication/get.html.erb +++ b/app/views/e_sign/eg019_access_code_authentication/get.html.erb @@ -1,45 +1,35 @@ -

    Requiring an Access Code 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 An Access Code for Recipient Authentication. -

    -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> +<%= render('partials/example_info') %> - -

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

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% code_index = 0 %> +<% signer_email_index = 1 %> +<% signer_name_index = 2 %>
    -
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %>
    - + + aria-describedby="acText" + placeholder="<%= @example["Forms"][form_index]["Inputs"][code_index]["InputPlaceholder"] %>" required> Provide this string to a recipient that is different such as in person or by mail or via different email.
    - +
    + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - <%= @example["Forms"][form_index]["Inputs"][signer_name_index]["InputName"] %> + " name="signerName" value="<%= @config.signer_name %>" required>
    - + <%= render('partials/submit_button') %> \ No newline at end of file diff --git a/app/views/e_sign/eg020_phone_authentication/get.html.erb b/app/views/e_sign/eg020_phone_authentication/get.html.erb index f2d6ada..05f636b 100644 --- a/app/views/e_sign/eg020_phone_authentication/get.html.erb +++ b/app/views/e_sign/eg020_phone_authentication/get.html.erb @@ -1,52 +1,44 @@ -

    Require Phone Authentication for a Recipient

    +<%= render('partials/example_info') %> -

    - Sends an envelope that requires entering a six-digit code from a text message or phone call for the purpose of multifactor authentication. -

    - -

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

    - -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - Envelopes:create. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% code_index = 0 %> +<% phone_index = 1 %> +<% signer_email_index = 2 %> +<% signer_name_index = 3 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + + aria-describedby="accessHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][code_index]["InputPlaceholder"] %>" required> The country code for the phone number below.
    - + - This phone number will receive a notification. We'll never share your phone number with anyone else. + aria-describedby="accessHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][phone_index]["InputPlaceholder"] %>" required> + <%= render('partials/phone_will_not_be_shared') %>
    - + - We'll never share your email with anyone else. + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][signer_email_index]["InputPlaceholder"] %>" required + value="<%= @config.signer_email %>" required> + <%= render('partials/email_will_not_be_shared') %>
    - - + + " name="signer_name" + value="<%= @config.signer_name %>" required>
    - + <%= render('partials/submit_button') %>
    diff --git a/app/views/e_sign/eg022_kba_authentication/get.html.erb b/app/views/e_sign/eg022_kba_authentication/get.html.erb index 1eff5ba..2fdf193 100644 --- a/app/views/e_sign/eg022_kba_authentication/get.html.erb +++ b/app/views/e_sign/eg022_kba_authentication/get.html.erb @@ -1,36 +1,27 @@ -

    Requiring Knowledge Based Authentication (KBA) 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 KBA for Recipient Authentication. -

    -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> +<%= render('partials/example_info') %> -

    API method used: - Envelopes::create. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - <%= @example["Forms"][form_index]["Inputs"][signer_name_index]["InputName"] %> + " name="signerName" value="<%= @config.signer_name %>" required>
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/e_sign/eg023_idv_authentication/get.html.erb b/app/views/e_sign/eg023_idv_authentication/get.html.erb index 94d3339..51ef8c1 100644 --- a/app/views/e_sign/eg023_idv_authentication/get.html.erb +++ b/app/views/e_sign/eg023_idv_authentication/get.html.erb @@ -1,34 +1,27 @@ -

    Require ID verification (IDV) for a recipient

    -

    Sends an envelope that requires the recipient to upload a government-issued ID for the purpose of multifactor authentication.

    -

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

    +<%= render('partials/example_info') %> -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - Envelopes::create. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - <%= @example["Forms"][form_index]["Inputs"][signer_name_index]["InputName"] %> + " name="signerName" value="<%= @config.signer_name %>" required>
    - + <%= render('partials/submit_button') %>
    diff --git a/app/views/e_sign/eg024_permission_create/get.html.erb b/app/views/e_sign/eg024_permission_create/get.html.erb index 7f410c8..e77dafd 100644 --- a/app/views/e_sign/eg024_permission_create/get.html.erb +++ b/app/views/e_sign/eg024_permission_create/get.html.erb @@ -1,20 +1,17 @@ -

    Creating a permission profile

    +<%= render('partials/example_info') %> -

    - This code example demonstrates how to create a profile permission -

    - -

    API method used: - AccountPermissionProfiles::create. - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% profile_index = 0 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - - + + " required />
    - + <%= render('partials/submit_button') %>
    diff --git a/app/views/e_sign/eg025_permissions_set_user_group/get.html.erb b/app/views/e_sign/eg025_permissions_set_user_group/get.html.erb index 82ba495..f7d3fce 100644 --- a/app/views/e_sign/eg025_permissions_set_user_group/get.html.erb +++ b/app/views/e_sign/eg025_permissions_set_user_group/get.html.erb @@ -1,19 +1,16 @@ -

    Setting a permission profile

    +<%= render('partials/example_info') %> -

    - Updates the group name and modifies, or sets, the permission profile for the group -

    +<% form_index = 0 %> +<% profile_index = 0 %> +<% group_index = 1 %> -

    API method used: - Groups::update. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - +
    - +
    - + <%= render('partials/submit_button') %>
    diff --git a/app/views/e_sign/eg026_permissions_change_single_setting/get.html.erb b/app/views/e_sign/eg026_permissions_change_single_setting/get.html.erb index c99118a..c4f83e7 100644 --- a/app/views/e_sign/eg026_permissions_change_single_setting/get.html.erb +++ b/app/views/e_sign/eg026_permissions_change_single_setting/get.html.erb @@ -1,23 +1,20 @@ -

    Updating individual permission settings

    +<%= render('partials/example_info') %> -

    - This code example demonstrates how to change setting in the existion permission profile. -

    +<% form_index = 0 %> +<% profile_index = 0 %> -

    API method used: - AccountPermissionProfiles::update. -

    -

    - View source file <%= @source_file %> on GitHub. -

    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - +
    - + <%= render('partials/submit_button') %>
    diff --git a/app/views/e_sign/eg027_permissions_delete/get.html.erb b/app/views/e_sign/eg027_permissions_delete/get.html.erb index caca8af..c4f83e7 100644 --- a/app/views/e_sign/eg027_permissions_delete/get.html.erb +++ b/app/views/e_sign/eg027_permissions_delete/get.html.erb @@ -1,24 +1,20 @@ -

    Deleting a permission profile

    +<%= render('partials/example_info') %> -

    - This method deletes a permission profile from an account. -

    +<% form_index = 0 %> +<% profile_index = 0 %> -

    API method used: - AccountPermissionProfiles::delete. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - +
    - + <%= render('partials/submit_button') %>
    diff --git a/app/views/e_sign/eg028_brands_creating/get.html.erb b/app/views/e_sign/eg028_brands_creating/get.html.erb index 4c35a59..eac0438 100644 --- a/app/views/e_sign/eg028_brands_creating/get.html.erb +++ b/app/views/e_sign/eg028_brands_creating/get.html.erb @@ -1,26 +1,24 @@ -

    Creating a brand

    -

    The brand includes a Brand Name Configure Brands.

    -

    This is an example demonstrates how to create a brand.

    +<%= render('partials/example_info') %> -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - AccountsBrands::create. -

    +<% form_index = 0 %> +<% brand_name_index = 0 %> +<% language_index = 1 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %>
    - - + + " required />
    - + <%= select_tag "defaultBrandLanguage", options_for_select(language_list), { id: "defaultBrandLanguage", name: "defaultBrandLanguage", class: "form-control" } %>
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/e_sign/eg029_brands_apply_to_envelope/get.html.erb b/app/views/e_sign/eg029_brands_apply_to_envelope/get.html.erb index 4e162e9..a5b564a 100644 --- a/app/views/e_sign/eg029_brands_apply_to_envelope/get.html.erb +++ b/app/views/e_sign/eg029_brands_apply_to_envelope/get.html.erb @@ -1,39 +1,36 @@ -

    Applying a Brand to an envelope

    +<%= render('partials/example_info') %> -

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

    - -

    API method used: - Envelopes::create. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %> +<% brand_index = 2 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - <%= @example["Forms"][form_index]["Inputs"][signer_name_index]["InputName"] %> + " name="signerName" value="<%= @config.signer_name %>" required>
    - +
    - + <%= render('partials/submit_button') %>
    diff --git a/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb b/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb index 02af751..d4afe48 100644 --- a/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb +++ b/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb @@ -1,60 +1,60 @@ -

    Applying a brand to an envelope using a template

    +<%= render('partials/example_info') %> -<% if @template_ok %> -

    - This code example demonstrates how to apply a brand to a template -

    -<% end %> - -

    API method used: - Envelopes::create. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %> +<% cc_email_index = 2 %> +<% cc_name_index = 3 %> +<% brand_index = 4 %> +<% redirect_to8_index = 1 %> <% if @template_ok %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - <%= @example["Forms"][form_index]["Inputs"][signer_name_index]["InputName"] %> + " name="signerName" value="<%= @config.signer_name %>" required>
    - + - The email for the cc recipient must be different from the signer's email. + aria-describedby="emailHelp" placeholder="<%= @example["Forms"][form_index]["Inputs"][cc_email_index]["InputPlaceholder"] %>" required> + <%= render('partials/email_should_differ_from_signer') %>
    - - <%= @example["Forms"][form_index]["Inputs"][cc_name_index]["InputName"] %> + " name="ccName" required>
    - +
    - + <%= render('partials/submit_button') %>
    <% else %> -

    Problem: please first create the template using Create a template.
    - Thank you.

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to8_index]["RedirectText"], 'href="eg008"') %>
    - + <%= render('partials/continue_button') %>
    <% end %> \ No newline at end of file diff --git a/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb b/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb index c92496e..52a3acf 100644 --- a/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb +++ b/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb @@ -1,70 +1,76 @@ -

    Bulk send envelopes

    +<%= render('partials/example_info') %> -

    - Demonstrates how to send envelopes in bulk to multiple recipients. First, this example creates a bulk send recipients list, - then creates an envelope. After that, it initiates bulk envelope sending. -

    - -

    API methods used: - BulkSend::createBulkSendList, - Envelopes::create, - EnvelopeCustomFields::create, - BulkSend::createBulkSendRequest, - BulkSend::getBulkSendBatchStatus -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% bulk1_form_index = 0 %> +<% bulk2_form_index = 1 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %> +<% cc_email_index = 2 %> +<% cc_name_index = 3 %>
    - -
    +
    -
    Bulk copy #1
    + <% if @example["Forms"][bulk1_form_index]["FormName"] %> +
    <%= sanitize @example["Forms"][bulk1_form_index]["FormName"] %>
    + <% end %> +
    - - + + " + required class='form-control'/>
    - - + + " + required class='form-control'/>
    - - + + " + required class='form-control'/>
    - - + + " + required class='form-control'/>
    -
    Bulk copy #2
    + <% if @example["Forms"][bulk2_form_index]["FormName"] %> +
    <%= sanitize @example["Forms"][bulk2_form_index]["FormName"] %>
    + <% end %> +
    - - + + " + required class='form-control'/>
    - - + + " + required class='form-control'/>
    - - + + " + required class='form-control'/>
    - - + + " + required class='form-control'/>
    - + <%= render('partials/submit_button') %> \ No newline at end of file diff --git a/app/views/e_sign/eg032_pauses_signature_workflow/get.html.erb b/app/views/e_sign/eg032_pauses_signature_workflow/get.html.erb index 103205e..a6f99bc 100644 --- a/app/views/e_sign/eg032_pauses_signature_workflow/get.html.erb +++ b/app/views/e_sign/eg032_pauses_signature_workflow/get.html.erb @@ -1,47 +1,50 @@ -

    Pausing a signature workflow

    +<%= render('partials/example_info') %> -

    - This example demonstrates how to create an envelope where the workflow is paused before the envelope is sent to a second recipient. - The envelope includes a txt document. - For resuming workflow see Unpause a signature workflow -

    - -

    API method used: - Envelopes::create, -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% signer1_form_index = 0 %> +<% signer2_form_index = 1 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %>
    -

    Signed #1

    + <% if @example["Forms"][signer1_form_index]["FormName"] %> +

    <%= sanitize @example["Forms"][signer1_form_index]["FormName"] %>

    + <% end %> +
    - + " required value="<%= @config.signer_email %>">
    - - + + " + name="signerName1" value="<%= @config.signer_name %>" required>
    -

    Signed #2

    + + <% if @example["Forms"][signer2_form_index]["FormName"] %> +

    <%= sanitize @example["Forms"][signer2_form_index]["FormName"] %>

    + <% end %> +
    - + + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][signer2_form_index]["Inputs"][signer_email_index]["InputPlaceholder"] %>" + value="pat@example.com"/>
    - - + + " + name="signerName2" value="Pat Johnson">
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/e_sign/eg033_unpauses_signature_workflow/get.html.erb b/app/views/e_sign/eg033_unpauses_signature_workflow/get.html.erb index fdd9803..116d5ed 100644 --- a/app/views/e_sign/eg033_unpauses_signature_workflow/get.html.erb +++ b/app/views/e_sign/eg033_unpauses_signature_workflow/get.html.erb @@ -1,24 +1,13 @@ -

    Unpausing a signature workflow

    +<%= render('partials/example_info') %> -

    - This example demonstrates how to resume an envelope workflow that has been paused. -

    +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% redirect_to32_index = 0 %> -

    API method used: - Envelopes::update, -

    - -

    - View source file <%= @source_file %> on GitHub. -

    <% if session[:envelope_id] %> <%= form_tag eg033_path, method: :put do -%> <%= submit_tag 'Submit', class: 'btn btn-docu'%> <%- end -%> <% else %> -

    - Problem: please first create an envelope using Pause a signature workflow. -
    - Thank you. -

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to32_index]["RedirectText"], 'href="eg032"') %> <% end %> \ No newline at end of file diff --git a/app/views/e_sign/eg034_use_conditional_recipients/get.html.erb b/app/views/e_sign/eg034_use_conditional_recipients/get.html.erb index 27b0be9..f47f0db 100644 --- a/app/views/e_sign/eg034_use_conditional_recipients/get.html.erb +++ b/app/views/e_sign/eg034_use_conditional_recipients/get.html.erb @@ -1,64 +1,72 @@ -

    Using conditional recipients

    +<%= render('partials/example_info') %> -

    - This example demonstrates how to create an envelope where the workflow is routed to different recipients based on the value of a transaction. -

    - -

    - The envelope includes a txt document. -

    - -

    API method used: - Envelopes::create, -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% signer1_form_index = 0 %> +<% signer2_unchecked_form_index = 1 %> +<% signer2_checked_form_index = 2 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %>
    -

    Signed #1

    + <% if @example["Forms"][signer1_form_index]["FormName"] %> +

    <%= sanitize @example["Forms"][signer1_form_index]["FormName"] %>

    + <% end %> +
    - + + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][signer1_form_index]["Inputs"][signer_email_index]["InputPlaceholder"] %>" + required value="<%= @config.signer_email %>">
    - - + + " + name="signerName1" value="<%= @config.signer_name %>" required>
    -

    Conditional signer #2 (when not checked)

    + + <% if @example["Forms"][signer2_unchecked_form_index]["FormName"] %> +

    <%= sanitize @example["Forms"][signer2_unchecked_form_index]["FormName"] %>

    + <% end %> +
    - + + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][signer2_unchecked_form_index]["Inputs"][signer_email_index]["InputPlaceholder"] %>" + value="pat@example.com"/>
    - - + + " + name="signerNameNotChecked" value="Pat Johnson">
    -

    Conditional signer #2 (when checked)

    + <% if @example["Forms"][signer2_checked_form_index]["FormName"] %> +

    <%= sanitize @example["Forms"][signer2_checked_form_index]["FormName"] %>

    + <% end %> +
    - + + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][signer2_checked_form_index]["Inputs"][signer_email_index]["InputPlaceholder"] %>" + value="mat@example.com"/>
    - - + + " + name="signerNameChecked" value="Mat Johnson">
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/e_sign/eg035_scheduled_sending/get.html.erb b/app/views/e_sign/eg035_scheduled_sending/get.html.erb index a10fbae..59198a9 100644 --- a/app/views/e_sign/eg035_scheduled_sending/get.html.erb +++ b/app/views/e_sign/eg035_scheduled_sending/get.html.erb @@ -1,34 +1,33 @@ -

    Schedule an envelope

    -

    - This example demonstrates how to schedule an envelope using the scheduled sending feature. -

    +<%= render('partials/example_info') %> -

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

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %> +<% date_index = 2 %>
    -
    - + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - + + " + name="signer_name" value="<%= @config.signer_name %>" required />
    - + Please choose a date in the future.
    - + <%= render('partials/submit_button') %> \ No newline at end of file diff --git a/app/views/e_sign/eg036_delayed_routing/get.html.erb b/app/views/e_sign/eg036_delayed_routing/get.html.erb index cc6bb22..741096c 100644 --- a/app/views/e_sign/eg036_delayed_routing/get.html.erb +++ b/app/views/e_sign/eg036_delayed_routing/get.html.erb @@ -1,44 +1,46 @@ -

    Send an envelope with delayed routing

    -

    - This example demonstrates how to delay an envelope’s delivery between recipients using the delayed routing feature. -

    +<%= render('partials/example_info') %> -

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

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% signer1_email_index = 0 %> +<% signer1_name_index = 1 %> +<% signer2_email_index = 2 %> +<% signer2_name_index = 3 %> +<% delay_index = 4 %>
    -
    - + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + - We'll never share your email with anyone else. + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][signer1_email_index]["InputPlaceholder"] %>" + required value="<%= @config.signer_email %>" /> + <%= render('partials/email_will_not_be_shared') %>
    - - + + " + name="signer1Name" value="<%= @config.signer_name %>" required />
    - + + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][signer2_email_index]["InputPlaceholder"] %>" required />
    - - + + " + name="signer2Name" required />
    - - + +
    - + <%= render('partials/submit_button') %> \ No newline at end of file diff --git a/app/views/e_sign/eg037_sms_delivery/get.html.erb b/app/views/e_sign/eg037_sms_delivery/get.html.erb index a2ed164..59c8c9b 100644 --- a/app/views/e_sign/eg037_sms_delivery/get.html.erb +++ b/app/views/e_sign/eg037_sms_delivery/get.html.erb @@ -1,50 +1,57 @@ -

    Request a signature by SMS delivery

    -

    -Sends a signature request via an SMS message. -

    +<%= render('partials/example_info') %> -

    API method used: - Envelopes::create. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% signer_code_index = 0 %> +<% signer_phone_index = 1 %> +<% signer_name_index = 2 %> +<% cc_code_index = 3 %> +<% cc_phone_index = 4 %> +<% cc_name_index = 5 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + + aria-describedby="accessHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][signer_code_index]["InputPlaceholder"] %>" required /> The country code for the phone number below.
    - + - This phone number will receive a notification. We'll never share your phone number. + aria-describedby="accessHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][signer_phone_index]["InputPlaceholder"] %>" required /> + <%= render('partials/phone_will_not_be_shared') %>
    - - + + " name="signer_name" + value="<%= @config.signer_name %>" required />
    - + + aria-describedby="accessHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][cc_code_index]["InputPlaceholder"] %>" required /> The country code for the phone number below.
    - + - This phone number will receive a notification. We'll never share your phone number. + aria-describedby="accessHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][cc_phone_index]["InputPlaceholder"] %>" required /> + <%= render('partials/phone_will_not_be_shared') %>
    - - + + " name="cc_name" + required />
    - + <%= render('partials/submit_button') %>
    diff --git a/app/views/e_sign/eg038_responsive_signing/get.html.erb b/app/views/e_sign/eg038_responsive_signing/get.html.erb index 1d88925..4f51f85 100644 --- a/app/views/e_sign/eg038_responsive_signing/get.html.erb +++ b/app/views/e_sign/eg038_responsive_signing/get.html.erb @@ -1,42 +1,42 @@ -

    Create a signable HTML document

    -

    Demonstrates how to create an HTML document for responsive signing.

    +<%= render('partials/example_info') %> -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

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

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %> +<% cc_email_index = 2 %> +<% cc_name_index = 3 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - + + " + name="signerName" value="<%= @config.signer_name %>" required>
    - + - The email for the cc recipient must be different from the signer's email. + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][cc_email_index]["InputPlaceholder"] %>" required /> + <%= render('partials/email_should_differ_from_signer') %>
    - - <%= @example["Forms"][form_index]["Inputs"][cc_name_index]["InputName"] %> + " name="ccName" required>
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/e_sign/eg039_signing_in_person/get.html.erb b/app/views/e_sign/eg039_signing_in_person/get.html.erb index 411eb46..7eede7a 100644 --- a/app/views/e_sign/eg039_signing_in_person/get.html.erb +++ b/app/views/e_sign/eg039_signing_in_person/get.html.erb @@ -1,23 +1,19 @@ -

    Send an envelope to an In Person Signer

    -

    Demonstrates how to host an In Person Signing session with embedded signing.

    +<%= render('partials/example_info') %> -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

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

    -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% signer_name_index = 0 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - - + + " + name="signer_name" required>
    - + <%= render('partials/submit_button') %>
    diff --git a/app/views/e_sign/eg040_set_document_visibility/get.html.erb b/app/views/e_sign/eg040_set_document_visibility/get.html.erb index 099c2b1..0912f7e 100644 --- a/app/views/e_sign/eg040_set_document_visibility/get.html.erb +++ b/app/views/e_sign/eg040_set_document_visibility/get.html.erb @@ -1,52 +1,57 @@ -

    Set document visibility for envelope recipients

    -

    Demonstrates how to set document visibility for envelope recipients.

    +<%= render('partials/example_info') %> -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

    API method used: - Envelopes::create. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% signer1_email_index = 0 %> +<% signer1_name_index = 1 %> +<% signer2_email_index = 2 %> +<% signer2_name_index = 3 %> +<% cc_email_index = 4 %> +<% cc_name_index = 5 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - <%= @example["Forms"][form_index]["Inputs"][signer1_name_index]["InputName"] %> + " name="signer1Name" value="<%= @config.signer_name %>" required>
    - + - We'll never share your email with anyone else. + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][signer2_email_index]["InputPlaceholder"] %>" required> + <%= render('partials/email_will_not_be_shared') %>
    - - <%= @example["Forms"][form_index]["Inputs"][signer2_name_index]["InputName"] %> + " name="signer2Name" required>
    - + - The email for the cc recipient must be different from the signer emails. + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][cc_email_index]["InputPlaceholder"] %>" required /> + <%= render('partials/email_should_differ_from_signer') %>
    - - <%= @example["Forms"][form_index]["Inputs"][cc_name_index]["InputName"] %> + " name="ccName" required>
    - + <%= render('partials/submit_button') %>
    diff --git a/app/views/eg001_embedded_signing/get.html.erb b/app/views/eg001_embedded_signing/get.html.erb index 19a9a88..94bca70 100644 --- a/app/views/eg001_embedded_signing/get.html.erb +++ b/app/views/eg001_embedded_signing/get.html.erb @@ -1,31 +1,27 @@ -

    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 website.

    +<%= render('partials/example_info') %> -<% if @show_doc %> -

    Documentation about this example.

    -<% end %> - -

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

    -

    - View source file <%= @source_file %> on GitHub. -

    +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + " required value="<%= @config.signer_email %>"> - We'll never share your email with anyone else. + <%= render('partials/email_will_not_be_shared') %>
    - - + + " + name="signerName" value="<%= @config.signer_name %>" required>
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/monitor_api/eg001_get_monitoring_dataset/get.html.erb b/app/views/monitor_api/eg001_get_monitoring_dataset/get.html.erb index c8838fa..ce45f3c 100644 --- a/app/views/monitor_api/eg001_get_monitoring_dataset/get.html.erb +++ b/app/views/monitor_api/eg001_get_monitoring_dataset/get.html.erb @@ -1,14 +1,5 @@ -

    1. Get monitoring data

    -

    Demonstrates how to get and display all of your organization’s monitoring data.

    - -

    API method used: - DataSet:GetStream -

    - -

    - View source file <%= @source_file %> on GitHub. -

    +<%= render('partials/example_info') %>
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/monitor_api/eg002_post_web_query/get.html.erb b/app/views/monitor_api/eg002_post_web_query/get.html.erb index 0f758c9..178593c 100644 --- a/app/views/monitor_api/eg002_post_web_query/get.html.erb +++ b/app/views/monitor_api/eg002_post_web_query/get.html.erb @@ -1,25 +1,21 @@ -

    2. Query monitoring data with filters

    -

    Demonstrates how to query an organization's data based on specified filters and aggregations.

    +<%= render('partials/example_info') %> -

    API method used: - DataSet:postWebQuery. -

    +<% form_index = 0 %> +<% start_index = 0 %> +<% end_name_index = 1 %> -

    - View source file <%= @source_file %> on GitHub. -

    - -

    - Please select start and end dates. -

    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + max=<%= Time.now %>>
    - + max=<%= Time.now %>>
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/monitor_api/index.html.erb b/app/views/monitor_api/index.html.erb index 32d3f54..0f6c745 100644 --- a/app/views/monitor_api/index.html.erb +++ b/app/views/monitor_api/index.html.erb @@ -22,23 +22,32 @@

    Documentation on using JWT Authorization from a Ruby Rails application.

    <% end %> -

    1. Get monitoring data

    -

    - Demonstrates how to get and display all of your organization’s monitoring data. -

    -

    - API method used: - DataSet:GetStream -

    - -

    2. Query monitoring data with filters

    -

    - Demonstrates how to query an organization's data based on specified filters and aggregations. -

    -

    - API method used: - DataSet:postWebQuery. -

    + <% @manifest["Groups"].each { |group| %> +

    <%= group["Name"] %>

    + + <% group["Examples"].each { |example| %> + <% if not example["SkipLanguages"] or not example["SkipLanguages"].include? "ruby" %> +

    "> + "> + <%= example["ExampleName"] %> + +

    + +

    <%= sanitize example["ExampleDescription"] %>

    + + <% if example["LinksToAPIMethod"].length > 1 %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsedPlural"] %> + <% else %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsed"] %> + <% end %> + + <% example["LinksToAPIMethod"].each do |link| %> + "><%= link["PathName"] %> + <% end %> + <% end %> +

    + <% } %> + <% } %>
    diff --git a/app/views/partials/_continue_button.erb b/app/views/partials/_continue_button.erb new file mode 100644 index 0000000..c811c29 --- /dev/null +++ b/app/views/partials/_continue_button.erb @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/views/partials/_email_should_differ_from_signer.erb b/app/views/partials/_email_should_differ_from_signer.erb new file mode 100644 index 0000000..2ed2e20 --- /dev/null +++ b/app/views/partials/_email_should_differ_from_signer.erb @@ -0,0 +1 @@ +<%= @manifest["SupportingTexts"]["HelpingTexts"]["CCEmailShouldDifferFromSigner"] %> \ No newline at end of file diff --git a/app/views/partials/_email_will_not_be_shared.erb b/app/views/partials/_email_will_not_be_shared.erb new file mode 100644 index 0000000..33b098d --- /dev/null +++ b/app/views/partials/_email_will_not_be_shared.erb @@ -0,0 +1 @@ +<%= @manifest["SupportingTexts"]["HelpingTexts"]["EmailWontBeShared"] %> \ No newline at end of file diff --git a/app/views/partials/_example_info.erb b/app/views/partials/_example_info.erb new file mode 100644 index 0000000..5d4a307 --- /dev/null +++ b/app/views/partials/_example_info.erb @@ -0,0 +1,24 @@ +

    <%= @example["ExampleName"] %>

    +

    <%= sanitize @example["ExampleDescription"] %>

    + +<% if @show_doc %> +

    Documentation about this example.

    +<% end %> + +<% if @example["Note"] %> + <%= sanitize @example["Note"] %> +<% end %> + +<% if @example["LinksToAPIMethod"].length > 1 %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsedPlural"] %> +<% else %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsed"] %> +<% end %> + +<% @example["LinksToAPIMethod"].each do |link| %> + "><%= link["PathName"] %> +<% end %> + +

    + <%= sanitize format_string(@manifest["SupportingTexts"]["ViewSourceFile"], format_string('{1}', @source_url, @source_file)) %> +

    \ No newline at end of file diff --git a/app/views/partials/_phone_will_not_be_shared.erb b/app/views/partials/_phone_will_not_be_shared.erb new file mode 100644 index 0000000..63439ef --- /dev/null +++ b/app/views/partials/_phone_will_not_be_shared.erb @@ -0,0 +1 @@ +<%= "#{@manifest["SupportingTexts"]["HelpingTexts"]["PhoneNumberWillBeNotified"]} #{@manifest["SupportingTexts"]["HelpingTexts"]["PhoneNumberWontBeShared"]}" %> \ No newline at end of file diff --git a/app/views/partials/_submit_button.erb b/app/views/partials/_submit_button.erb new file mode 100644 index 0000000..2aceab4 --- /dev/null +++ b/app/views/partials/_submit_button.erb @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/views/room_api/eg001_create_room_with_data/_information.html.erb b/app/views/room_api/eg001_create_room_with_data/_information.html.erb deleted file mode 100644 index d9d9a51..0000000 --- a/app/views/room_api/eg001_create_room_with_data/_information.html.erb +++ /dev/null @@ -1,10 +0,0 @@ -

    1. Create a new room

    -

    This is a general example of creating a room.

    - -

    API methods used: - Roles::GetRoles and - Rooms::CreateRoom. -

    -

    - View source file <%= @source_file %> on GitHub. -

    \ No newline at end of file diff --git a/app/views/room_api/eg001_create_room_with_data/get.html.erb b/app/views/room_api/eg001_create_room_with_data/get.html.erb index e477c6a..5b973e8 100644 --- a/app/views/room_api/eg001_create_room_with_data/get.html.erb +++ b/app/views/room_api/eg001_create_room_with_data/get.html.erb @@ -1,9 +1,17 @@ -<%=render 'room_api/eg001_create_room_with_data/information' %> +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% room_name_index = 0 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - - + + ">
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/room_api/eg002_create_room_with_template/_information.html.erb b/app/views/room_api/eg002_create_room_with_template/_information.html.erb deleted file mode 100644 index 1f54f28..0000000 --- a/app/views/room_api/eg002_create_room_with_template/_information.html.erb +++ /dev/null @@ -1,14 +0,0 @@ -

    2. Create room with a template

    -

    - This code example demonstrates creating a DocuSign room using a predefined template. If you've created a template for your organization in either Rooms for Mortgage or Rooms for Real Estate, you can create rooms based on this template using the Rooms API. -

    - -

    API methods used: - Roles::GetRoles and - Rooms::CreateRoom and - RoomTemplates::GetRoomTemplates. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    \ No newline at end of file diff --git a/app/views/room_api/eg002_create_room_with_template/get.html.erb b/app/views/room_api/eg002_create_room_with_template/get.html.erb index 5580622..01dbdba 100644 --- a/app/views/room_api/eg002_create_room_with_template/get.html.erb +++ b/app/views/room_api/eg002_create_room_with_template/get.html.erb @@ -1,26 +1,31 @@ -<%=render 'room_api/eg002_create_room_with_template/information' %> +<%= render('partials/example_info') %> +<% form_index = 0 %> +<% room_name_index = 0 %> +<% template_index = 1 %> +<% create_room_redirect_index = 0 %> <% unless @templates.blank? %> - +<% %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - - + + "> - + <%= select_tag "templateId", options_for_select(@templates.map { |obj| [obj['name'], obj['templateId']] }), {:class => 'form-control'} %>
    - + <%= render('partials/submit_button') %>
    <% else %> -

    - Problem: you don't have any templates. Please first create a form template using - DociSign::Admin - Thank you. -

    + <%= sanitize @example["RedirectsToOtherCodeExamples"][create_room_redirect_index]["RedirectText"] %> <% end %> diff --git a/app/views/room_api/eg003_export_data_from_room/_information.html.erb b/app/views/room_api/eg003_export_data_from_room/_information.html.erb deleted file mode 100644 index 9afa218..0000000 --- a/app/views/room_api/eg003_export_data_from_room/_information.html.erb +++ /dev/null @@ -1,14 +0,0 @@ -

    3. Export data from a room

    -

    - This code example demonstrates how to export rooms data from a - DocuSign room.. -

    - -

    - API methods used: - Rooms::GetRooms. -

    - -

    - View source file <%= @source_file %> on GitHub. -

    \ No newline at end of file diff --git a/app/views/room_api/eg003_export_data_from_room/get.html.erb b/app/views/room_api/eg003_export_data_from_room/get.html.erb index d15d810..2e61356 100644 --- a/app/views/room_api/eg003_export_data_from_room/get.html.erb +++ b/app/views/room_api/eg003_export_data_from_room/get.html.erb @@ -1,24 +1,24 @@ -<%=render 'room_api/eg003_export_data_from_room/information' %> +<%= render('partials/example_info') %> +<% form_index = 0 %> +<% room_id_index = 0 %> +<% redirect_to1_index = 0 %> <% if @rooms.count.positive? %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + <%= select_tag "roomId", options_for_select(@rooms.map { |obj| [obj['name'], obj['roomId']] }), {:class => 'form-control'} %>
    - + <%= render('partials/submit_button') %>
    <% else %> -

    - Problem: you don't have any rooms. Please first create a room using - Create a new room - or - Create room with a template. -
    - Thank you. -

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="eg001"') %> <% end %> diff --git a/app/views/room_api/eg004_add_forms_to_room/_information.html.erb b/app/views/room_api/eg004_add_forms_to_room/_information.html.erb deleted file mode 100644 index 07071b0..0000000 --- a/app/views/room_api/eg004_add_forms_to_room/_information.html.erb +++ /dev/null @@ -1,12 +0,0 @@ -

    4. Adding forms to a room

    -

    - This code example demonstrates how to attach forms to a room using the Rooms API. -

    -

    - API methods used: - Rooms::GetRooms and - FormLibraries::GetFormLibraryForms. -

    -

    - View source file <%= @source_file %> on GitHub. -

    \ No newline at end of file diff --git a/app/views/room_api/eg004_add_forms_to_room/get.html.erb b/app/views/room_api/eg004_add_forms_to_room/get.html.erb index f1f9982..9e7d9e2 100644 --- a/app/views/room_api/eg004_add_forms_to_room/get.html.erb +++ b/app/views/room_api/eg004_add_forms_to_room/get.html.erb @@ -1,31 +1,33 @@ -<%=render 'room_api/eg004_add_forms_to_room/information' %> +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% room_id_index = 0 %> +<% form_id_index = 1 %> +<% redirect_to1_index = 0 %> <% unless @form_libraries.blank? %> <% if @form_libraries.count.positive? && @rooms.count.positive? %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + <%= select_tag "roomId", options_for_select(@rooms.map { |obj| [obj['name'], obj['roomId']] }), {:class => 'form-control'} %> - + <%= select_tag "formId", options_for_select(@form_libraries.map { |obj| [obj['name'], obj['libraryFormId']] }), {:class => 'form-control'} %>
    - + <%= render('partials/submit_button') %>
    <% elsif @rooms.count.zero? %>
    -

    - Problem: you don't have any rooms. Please first create a room using - Create a new room - or - Create room with a template. -
    - Thank you. -

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="eg001"') %>
    <% end %> diff --git a/app/views/room_api/eg005_get_rooms_with_filters/_information.html.erb b/app/views/room_api/eg005_get_rooms_with_filters/_information.html.erb deleted file mode 100644 index 70d65d2..0000000 --- a/app/views/room_api/eg005_get_rooms_with_filters/_information.html.erb +++ /dev/null @@ -1,14 +0,0 @@ -

    5. Get Rooms with filters

    -

    - This code example demonstrates how to return rooms filtered by your parameters using the - Rooms API. - This specific code example filters for all rooms that have had their field data updated within the last 10 days, as shown on the Details tab in the UI. -

    -

    - API methods used: - Rooms::GetRooms and - Rooms::CreateRoom. -

    -

    - View source file <%= @source_file %> on GitHub. -

    diff --git a/app/views/room_api/eg005_get_rooms_with_filters/get.html.erb b/app/views/room_api/eg005_get_rooms_with_filters/get.html.erb index ac2da11..1c0601d 100644 --- a/app/views/room_api/eg005_get_rooms_with_filters/get.html.erb +++ b/app/views/room_api/eg005_get_rooms_with_filters/get.html.erb @@ -1,16 +1,24 @@ -<%=render 'room_api/eg005_get_rooms_with_filters/information' %> +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% start_index = 0 %> +<% end_index = 1 %> <% if @rooms.count.positive? %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + max=<%= Time.now %>>
    - + max=<%= Time.now %>>
    - + <%= render('partials/submit_button') %>
    <% else %> diff --git a/app/views/room_api/eg006_create_an_external_form_fill_session/_information.html.erb b/app/views/room_api/eg006_create_an_external_form_fill_session/_information.html.erb deleted file mode 100644 index 91096a7..0000000 --- a/app/views/room_api/eg006_create_an_external_form_fill_session/_information.html.erb +++ /dev/null @@ -1,17 +0,0 @@ -

    6. Creating an external form fill session

    -

    - The DocuSign Rooms API offers developers the option to have users fill out forms without logging in to the Rooms UI through the use of an - external form fill session. - This code example demonstrates how to create an external form fill session using the - Rooms API. - The result of this code example is the URL for the form fill session, which you can embed in your integration or send to the user. -

    -

    - API methods used: - Rooms::GetRooms and - FormLibraries: GetFormLibraries and - FormLibraries::GetFormLibraryForms. -

    -

    - View source file <%= @source_file %> on GitHub. -

    \ No newline at end of file diff --git a/app/views/room_api/eg006_create_an_external_form_fill_session/get_forms.html.erb b/app/views/room_api/eg006_create_an_external_form_fill_session/get_forms.html.erb index fe00bb8..55203ef 100644 --- a/app/views/room_api/eg006_create_an_external_form_fill_session/get_forms.html.erb +++ b/app/views/room_api/eg006_create_an_external_form_fill_session/get_forms.html.erb @@ -1,26 +1,28 @@ -<%= render 'room_api/eg006_create_an_external_form_fill_session/information' %> +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% form_id_index = 0 %> +<% redirect_to4_index = 0 %> <% unless @form_libraries.blank? %>
    -
    - + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + > <%= select_tag "formId", options_for_select(@form_libraries.map { |obj| [obj['name'], obj['docuSignFormId']] }), {:class => 'form-control'} %>
    - + <%= render('partials/submit_button') %> <% else %>
    -

    - Problem: DocuSign Forms is not enabled for this company. Please contact - DocuSign Rooms Support - to enable Forms. -
    - Thank you. -

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to4_index]["RedirectText"], 'href="eg004"') %>
    <% end %> \ No newline at end of file diff --git a/app/views/room_api/eg006_create_an_external_form_fill_session/get_rooms.html.erb b/app/views/room_api/eg006_create_an_external_form_fill_session/get_rooms.html.erb index 42ad1f9..4d1f5df 100644 --- a/app/views/room_api/eg006_create_an_external_form_fill_session/get_rooms.html.erb +++ b/app/views/room_api/eg006_create_an_external_form_fill_session/get_rooms.html.erb @@ -1,26 +1,27 @@ -<%= render 'room_api/eg006_create_an_external_form_fill_session/information' %> +<%= render('partials/example_info') %> + +<% form_index = 1 %> +<% room_index = 0 %> +<% redirect_to1_index = 1 %> <% if @rooms.count.positive? %>
    -
    - + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + <%= select_tag "roomId", options_for_select(@rooms.map { |obj| [obj['name'], obj['roomId']] }), {:class => 'form-control'} %>
    - + <%= render('partials/submit_button') %> <% else %>
    -

    - Problem: you don't have any rooms. Please first create a room using - Create a new room - or - Create room with a template. -
    - Thank you. -

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="eg001"') %>
    <% end %> \ No newline at end of file diff --git a/app/views/room_api/eg007_create_form_group/_information.html.erb b/app/views/room_api/eg007_create_form_group/_information.html.erb deleted file mode 100644 index 16c26cd..0000000 --- a/app/views/room_api/eg007_create_form_group/_information.html.erb +++ /dev/null @@ -1,11 +0,0 @@ -

    7. How to create a form group

    -

    - This example demonstrates how to create a form group - for your DocuSign Rooms for Real Estate account. -

    -

    API methods used: - FormGroups::CreateFormGroup -

    -

    - View source file <%= @source_file %> on GitHub. -

    \ No newline at end of file diff --git a/app/views/room_api/eg007_create_form_group/get.html.erb b/app/views/room_api/eg007_create_form_group/get.html.erb index 17ab797..7276b98 100644 --- a/app/views/room_api/eg007_create_form_group/get.html.erb +++ b/app/views/room_api/eg007_create_form_group/get.html.erb @@ -1,9 +1,18 @@ -<%=render 'room_api/eg007_create_form_group/information' %> +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% form_group_index = 0 %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - - > + + " + value=<%="RubyFormGroup##{rand(100)}"%>>
    - + <%= render('partials/submit_button') %>
    \ No newline at end of file diff --git a/app/views/room_api/eg008_grant_office_access_to_form_group/_information.html.erb b/app/views/room_api/eg008_grant_office_access_to_form_group/_information.html.erb deleted file mode 100644 index 07c5031..0000000 --- a/app/views/room_api/eg008_grant_office_access_to_form_group/_information.html.erb +++ /dev/null @@ -1,16 +0,0 @@ -

    8. Grant office access to a form group

    -

    - This example demonstrates how to assign an office to a - form group - for your DocuSign Rooms for Real Estate account. Granting office access to a form group will enable you to filter - which form groups are available based on that office. -

    -

    - API methods used: - FormGroups:GetFormGroups - and - Offices:GetOffices -

    -

    - View source file <%= @source_file %> on GitHub. -

    \ No newline at end of file diff --git a/app/views/room_api/eg008_grant_office_access_to_form_group/get.erb b/app/views/room_api/eg008_grant_office_access_to_form_group/get.erb index 6178c4f..04a3037 100644 --- a/app/views/room_api/eg008_grant_office_access_to_form_group/get.erb +++ b/app/views/room_api/eg008_grant_office_access_to_form_group/get.erb @@ -1,24 +1,28 @@ -<%= render 'room_api/eg008_grant_office_access_to_form_group/information' %> +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% office_index = 0 %> +<% form_group_index = 1 %> +<% redirect_to7_index = 0 %> <% if @form_groups.present? %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + <%= select_tag "form_group_id", options_for_select(@form_groups.map { |obj| [obj['name'], obj['formGroupId']] }), { :class => 'form-control' } %>
    - + <%= select_tag "office_id", options_for_select(@offices.map { |obj| [obj['name'], obj['officeId']] }), { :class => 'form-control' } %>
    - + <%= render('partials/submit_button') %>
    <% else %>
    -

    - Problem: you don't have any form groups. Please first create a them using - Create form group -
    - Thank you. -

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to7_index]["RedirectText"], 'href="eg007"') %>
    <% end %> \ No newline at end of file diff --git a/app/views/room_api/eg009_assign_form_to_form_group/_information.html.erb b/app/views/room_api/eg009_assign_form_to_form_group/_information.html.erb deleted file mode 100644 index 933e52d..0000000 --- a/app/views/room_api/eg009_assign_form_to_form_group/_information.html.erb +++ /dev/null @@ -1,18 +0,0 @@ -

    9. Assign a form to a form group

    -

    - This example demonstrates how to assign a form to a - form group - for your DocuSign Rooms for Real Estate account. As a prerequisite, ensure that you have - created a form group - and set the office ID on this form group - before proceeding. -

    -

    - API methods used: - FormGroups:GetFormGroups - and - FormLibraries::GetFormLibraryForms. -

    -

    - View source file <%= @source_file %> on GitHub. -

    \ No newline at end of file diff --git a/app/views/room_api/eg009_assign_form_to_form_group/get.erb b/app/views/room_api/eg009_assign_form_to_form_group/get.erb index ab192db..9fbe685 100644 --- a/app/views/room_api/eg009_assign_form_to_form_group/get.erb +++ b/app/views/room_api/eg009_assign_form_to_form_group/get.erb @@ -1,24 +1,28 @@ -<%= render 'room_api/eg009_assign_form_to_form_group/information' %> +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% form_id_index = 0 %> +<% form_group_id_index = 1 %> +<% redirect_to7_index = 0 %> <% if @form_groups.present? %>
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + <%= select_tag "form_group_id", options_for_select(@form_groups.map { |obj| [obj['name'], obj['formGroupId']] }), { :class => 'form-control' } %>
    - + <%= select_tag "form_id", options_for_select(@forms.map { |obj| [obj['name'], obj['libraryFormId']] }), { :class => 'form-control' } %>
    - + <%= render('partials/submit_button') %>
    <% else %>
    -

    - Problem: you don't have any form groups. Please first create a them using - Create form group -
    - Thank you. -

    + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to7_index]["RedirectText"], 'href="eg007"') %>
    <% end %> \ No newline at end of file diff --git a/app/views/room_api/index.html.erb b/app/views/room_api/index.html.erb index 314f759..02aa3e0 100644 --- a/app/views/room_api/index.html.erb +++ b/app/views/room_api/index.html.erb @@ -28,119 +28,33 @@ from a Ruby Rails application.

    <% end %> -

    Basic examples

    + <% @manifest["Groups"].each { |group| %> +

    <%= group["Name"] %>

    -

    1. Create room with data

    -

    - This example creates a room. -

    -

    - API methods used: - Roles::GetRoles - and - Rooms::CreateRoom. -

    + <% group["Examples"].each { |example| %> + <% if not example["SkipLanguages"] or not example["SkipLanguages"].include? "ruby" %> +

    "> + "> + <%= example["ExampleName"] %> + +

    -

    2. Create room with a template

    -

    - This code example demonstrates creating a DocuSign Room using a predefined template. If you've created a template - for your organization in either Rooms for Mortgage or Rooms for Real Estate, you can create rooms based on this - template using the Rooms API. -

    -

    - API methods used: - Roles::GetRoles - and - Rooms::CreateRoom - and - RoomTemplates::GetRoomTemplates. -

    +

    <%= sanitize example["ExampleDescription"] %>

    -

    3. Export data from a room

    -

    - This code example demonstrates how to export rooms data from a - DocuSign Room.. -

    -

    - API methods used: - Rooms::GetRooms. -

    + <% if example["LinksToAPIMethod"].length > 1 %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsedPlural"] %> + <% else %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsed"] %> + <% end %> -

    4. Adding forms to a room

    -

    - This code example demonstrates how to attach forms to a room using the Rooms API. -

    -

    - API methods used: - Rooms::GetRooms - and - FormLibraries::GetFormLibraryForms. -

    + <% example["LinksToAPIMethod"].each do |link| %> + "><%= link["PathName"] %> + <% end %> + <% end %> +

    + <% } %> + <% } %> -

    5. Get Rooms with filters

    -

    - This code example demonstrates how to return rooms filtered by your parameters using the - Rooms API. - This specific code example filters for all rooms that have had their field data updated within the last 10 days, as - shown on the Details tab in the UI. -

    -

    - API methods used: - Rooms::GetRooms - and - Rooms::CreateRoom. -

    - -

    6. Creating an external form fill session

    -

    - The DocuSign Rooms API offers developers the option to have users fill out forms without logging in to the Rooms UI - through the use of an - external form fill session. - This code example demonstrates how to create an external form fill session using the - Rooms API: - the result of this code example is the URL for the form fill session, which you can embed in your integration or - send to the user. -

    -

    - API methods used: - Rooms::GetRooms - and - FormLibraries: - GetFormLibraries and - FormLibraries::GetFormLibraryForms. -

    - -

    7. Creating a form group

    -

    - Creates a new form group with the name given in the name property of the request body. -

    -

    - API methods used: - FormGroups::CreateFormGroup. -

    - -

    8. Grant office access to a form group

    -

    - This example demonstrates how to assign an office to a form group for your DocuSign Rooms for Real Estate account. - Granting office access to a form group will enable you to filter which form groups are available based on that office. -

    -

    - API methods used: - FormGroups:GetFormGroups - and - Offices:GetOffices -

    - -

    9. Assign a form to a form group

    -

    - How to assign a form to a form group for your DocuSign Rooms for Real Estate account. -

    -

    - API methods used: - FormGroups:GetFormGroups - and - FormLibraries::GetFormLibraryForms. -

    diff --git a/config/application.rb b/config/application.rb index 7592639..4a2b8ba 100644 --- a/config/application.rb +++ b/config/application.rb @@ -11,12 +11,12 @@ class Application < Rails::Application # For a production application, you will store the credentials # in config/environments/development.rb, production.rb, test.rb, etc config.app_url = 'http://localhost:3000' # The public url of the application. - # Init DocuSign configuration, loaded from config/appsettings.yml file - DOCUSIGN_CONFIG = YAML.load_file("#{Rails.root.to_s}/config/appsettings.yml")[Rails.env] - DOCUSIGN_CONFIG.map do |k,v| - config.send("#{k}=", v) - end - + # Init DocuSign configuration, loaded from config/appsettings.yml file + DOCUSIGN_CONFIG = YAML.load_file("#{Rails.root}/config/appsettings.yml")[Rails.env] + DOCUSIGN_CONFIG.map do |k, v| + config.send("#{k}=", v) + end + # Settings in config/environments/* take precedence over those specified here. # Application configuration can go into files in config/initializers # -- all .rb files in that directory are automatically loaded after loading diff --git a/config/appsettings.example.yml b/config/appsettings.example.yml index 9d3c687..29a45b5 100644 --- a/config/appsettings.example.yml +++ b/config/appsettings.example.yml @@ -36,6 +36,11 @@ default: &default gateway_name: "stripe" gateway_display_name: "Stripe" github_example_url: https://github.com/docusign/code-examples-ruby/tree/master/app/services/ + eSignManifestUrl: "https://raw.githubusercontent.com/docusign/code-examples-csharp/master/manifest/eSignatureManifest.json" + clickManifestUrl: "https://raw.githubusercontent.com/docusign/code-examples-csharp/master/manifest/ClickManifest.json" + roomsManifestUrl: "https://raw.githubusercontent.com/docusign/code-examples-csharp/master/manifest/RoomsManifest.json" + adminManifestUrl: "https://raw.githubusercontent.com/docusign/code-examples-csharp/master/manifest/AdminManifest.json" + monitorManifestUrl: "https://raw.githubusercontent.com/docusign/code-examples-csharp/master/manifest/MonitorManifest.json" documentation: false api_only: false diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 53dd780..7bc52f7 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -15,7 +15,7 @@ # GET "/auth/docusign/callback?error=access_denied&error_message=The%20user%20did%20not%20consent%20to%20connecting%20the%20application.&state= # OmniAuth.config.failure_raise_out_environments = [] # defaults to: ['development'] -OmniAuth.config.allowed_request_methods = [:post, :get] +OmniAuth.config.allowed_request_methods = %i[post get] config = Rails.application.config config.middleware.use OmniAuth::Builder do @@ -36,17 +36,16 @@ strategy.options[:client_options].authorize_url = "#{strategy.options[:oauth_base_uri]}/oauth/auth" strategy.options[:client_options].user_info_url = "#{strategy.options[:oauth_base_uri]}/oauth/userinfo" strategy.options[:client_options].token_url = "#{strategy.options[:oauth_base_uri]}/oauth/token" - unless strategy.options[:allow_silent_authentication] - strategy.options[:authorize_params].prompt = strategy.options.prompt - end + strategy.options[:authorize_params].prompt = strategy.options.prompt unless strategy.options[:allow_silent_authentication] session = strategy.session - if session[:examples_API] == "Rooms" - strategy.options[:authorize_params].scope = "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" - elsif session[:examples_API] == "Click" - strategy.options[:authorize_params].scope = "signature click.manage click.send" - elsif session[:examples_API] == "Admin" - strategy.options[:authorize_params].scope = "signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" + case session[:examples_API] + when 'Rooms' + strategy.options[:authorize_params].scope = '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' + when 'Click' + strategy.options[:authorize_params].scope = 'signature click.manage click.send' + when 'Admin' + strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' end } end diff --git a/config/routes.rb b/config/routes.rb index da57194..2620982 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true Rails.application.routes.draw do - constraints lambda { |req| req.session[:examples_API] == "Rooms" } do + constraints ->(req) { req.session[:examples_API] == 'Rooms' } do scope module: 'room_api' do get 'eg001' => 'eg001_create_room_with_data#get' post 'eg001' => 'eg001_create_room_with_data#create' @@ -32,7 +32,7 @@ post 'eg009' => 'eg009_assign_form_to_form_group#create' end end - constraints lambda { |req| req.session[:examples_API] == "Click" } do + constraints ->(req) { req.session[:examples_API] == 'Click' } do scope module: 'clickwrap' do get 'eg001' => 'eg001_create_clickwrap#get' post 'eg001' => 'eg001_create_clickwrap#create' @@ -50,7 +50,7 @@ post 'eg005' => 'eg005_clickwrap_responses#create' end end - constraints lambda { |req| req.session[:examples_API] == "Monitor" } do + constraints ->(req) { req.session[:examples_API] == 'Monitor' } do scope module: 'monitor_api' do get 'eg001' => 'eg001_get_monitoring_dataset#get' post 'eg001' => 'eg001_get_monitoring_dataset#create' @@ -58,7 +58,7 @@ post 'eg002' => 'eg002_post_web_query#create' end end - constraints lambda { |req| req.session[:examples_API] == "Admin" } do + constraints ->(req) { req.session[:examples_API] == 'Admin' } do scope module: 'admin_api' do get 'eg001' => 'eg001_create_user#get' post 'eg001' => 'eg001_create_user#create' @@ -81,7 +81,7 @@ get 'eg007' => 'eg007_get_user_profile_by_user_id#get' post 'eg007' => 'eg007_get_user_profile_by_user_id#create' - + get 'eg008' => 'eg008_update_user_product_permission_profile#get' post 'eg008' => 'eg008_update_user_product_permission_profile#create' @@ -89,7 +89,7 @@ post 'eg009' => 'eg009_delete__user_product_permission_profile#create' end end - constraints lambda { |req| req.session[:examples_API] == "eSignature" } do + constraints ->(req) { req.session[:examples_API] == 'eSignature' } do get '/eg001' => 'eg001_embedded_signing#get' post '/eg001' => 'eg001_embedded_signing#create' diff --git a/db/schema.rb b/db/schema.rb index 3c0c23d..eb3a310 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -12,7 +12,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2018_12_03_073200) do +ActiveRecord::Schema.define(version: 20_181_203_073_200) do create_table 'sessions', force: :cascade do |t| t.datetime 'created_at', null: false t.datetime 'updated_at', null: false diff --git a/jwt_console_project/jwt_console.rb b/jwt_console_project/jwt_console.rb index b5d6c95..68e912d 100644 --- a/jwt_console_project/jwt_console.rb +++ b/jwt_console_project/jwt_console.rb @@ -2,7 +2,7 @@ gemfile do source 'https://rubygems.org' - gem 'docusign_esign',' ~> 3.17.0' + gem 'docusign_esign', ' ~> 3.17.0' end class ESign @@ -10,11 +10,11 @@ class ESign require 'docusign_esign' require_relative '../app/services/api_creator' -require_relative '../app/services/e_sign/eg002_signing_via_email_service.rb' +require_relative '../app/services/e_sign/eg002_signing_via_email_service' require 'yaml' -$SCOPES = [ - "signature", "impersonation" +$SCOPES = %w[ + signature impersonation ] def load_config_data @@ -22,28 +22,28 @@ def load_config_data begin config_file_contents = File.read(config_file_path) rescue Errno::ENOENT - $stderr.puts "Missing config file" + warn 'Missing config file' raise end YAML.unsafe_load(config_file_contents) end def get_consent - url_scopes = $SCOPES.join('+'); + url_scopes = $SCOPES.join('+') # Construct consent URL - redirect_uri = "https://developers.docusign.com/platform/auth/consent"; - consent_url = "https://#{CONFIG["authorization_server"]}/oauth/auth?response_type=code&" + - "scope=#{url_scopes}&client_id=#{CONFIG["jwt_integration_key"]}&" + + redirect_uri = 'https://developers.docusign.com/platform/auth/consent' + consent_url = "https://#{CONFIG['authorization_server']}/oauth/auth?response_type=code&" \ + "scope=#{url_scopes}&client_id=#{CONFIG['jwt_integration_key']}&" \ "redirect_uri=#{redirect_uri}" - puts "Open the following URL in your browser to grant consent to the application:" + puts 'Open the following URL in your browser to grant consent to the application:' puts consent_url puts "Consent granted? \n 1)Yes \n 2)No" - continue = gets; - if continue.chomp == "1" - return true; + continue = gets + if continue.chomp == '1' + true else - puts "Please grant consent" + puts 'Please grant consent' exit end end @@ -52,33 +52,31 @@ def authenticate configuration = DocuSign_eSign::Configuration.new configuration.debugging = true api_client = DocuSign_eSign::ApiClient.new(configuration) - api_client.set_oauth_base_path(CONFIG["authorization_server"]) + api_client.set_oauth_base_path(CONFIG['authorization_server']) rsa_pk = 'docusign_private_key.txt' begin - token = api_client.request_jwt_user_token(CONFIG["jwt_integration_key"], CONFIG["impersonated_user_guid"], rsa_pk, expires_in=3600, $SCOPES) + token = api_client.request_jwt_user_token(CONFIG['jwt_integration_key'], CONFIG['impersonated_user_guid'], rsa_pk, 3600, $SCOPES) user_info_response = api_client.get_user_info(token.access_token) account = user_info_response.accounts.find(&:is_default) - account_info = { + { access_token: token.access_token, account_id: account.account_id, base_path: account.base_uri } - account_info - rescue OpenSSL::PKey::RSAError => exception - Rails.logger.error exception.inspect - if File.read(rsa_pk).starts_with? '{RSA_PRIVATE_KEY}' - fail "Please add your private RSA key to: #{rsa_pk}" - else - raise - end - rescue DocuSign_eSign::ApiError => exception - body = JSON.parse(exception.response_body) - if body['error'] == "consent_required" + rescue OpenSSL::PKey::RSAError => e + Rails.logger.error e.inspect + + raise "Please add your private RSA key to: #{rsa_pk}" if File.read(rsa_pk).starts_with? '{RSA_PRIVATE_KEY}' + + raise + rescue DocuSign_eSign::ApiError => e + body = JSON.parse(e.response_body) + if body['error'] == 'consent_required' authenticate if get_consent else - puts "API Error" + puts 'API Error' puts body['error'] puts body['message'] exit @@ -105,14 +103,12 @@ def get_args(apiAccountId, accessToken, basePath) doc_docx: '../data/World_Wide_Corp_Battle_Plan_Trafalgar.docx', doc_pdf: '../data/World_Wide_Corp_lorem.pdf' } - args = { + { account_id: apiAccountId, base_path: basePath, access_token: accessToken, envelope_args: envelope_args } - - return args end def main diff --git a/lib/docusign.rb b/lib/docusign.rb index 807e6fe..b37d692 100644 --- a/lib/docusign.rb +++ b/lib/docusign.rb @@ -47,15 +47,13 @@ def raw_info # @param items is an array of Hash'es that has the keys: account_id, is_default, account_name, base_uri def fetch_account(items) - if options.target_account_id - @account = items.find { |item| item['account_id'] == options.target_account_id } - else - @account = items.find { |item| item['is_default'] } - end - - if @account.blank? - raise %'Could not find account information for the user in the "accounts" of raw_info: #{@raw_info}' - end + @account = if options.target_account_id + items.find { |item| item['account_id'] == options.target_account_id } + else + items.find { |item| item['is_default'] } + end + + raise %(Could not find account information for the user in the "accounts" of raw_info: #{@raw_info}) if @account.blank? end end end diff --git a/quick_acg/Rakefile b/quick_acg/Rakefile index 9a5ea73..e85f913 100644 --- a/quick_acg/Rakefile +++ b/quick_acg/Rakefile @@ -1,6 +1,6 @@ # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. -require_relative "config/application" +require_relative 'config/application' Rails.application.load_tasks diff --git a/quick_acg/app/controllers/ds_common_controller.rb b/quick_acg/app/controllers/ds_common_controller.rb index 0183fdd..3a05d4b 100644 --- a/quick_acg/app/controllers/ds_common_controller.rb +++ b/quick_acg/app/controllers/ds_common_controller.rb @@ -9,13 +9,13 @@ def index def handle_redirects if session[:quickstarted].nil? session[:quickstarted] = true - redirect_to "/auth/docusign" + redirect_to '/auth/docusign' else redirect_to '/eg001' end end def ds_must_authenticate - redirect_to "/auth/docusign" + redirect_to '/auth/docusign' end end diff --git a/quick_acg/bin/bundle b/quick_acg/bin/bundle index a71368e..d34d131 100644 --- a/quick_acg/bin/bundle +++ b/quick_acg/bin/bundle @@ -8,7 +8,7 @@ # this file is here to facilitate running it. # -require "rubygems" +require 'rubygems' m = Module.new do module_function @@ -18,36 +18,36 @@ m = Module.new do end def env_var_version - ENV["BUNDLER_VERSION"] + ENV['BUNDLER_VERSION'] end def cli_arg_version return unless invoked_as_script? # don't want to hijack other binstubs - return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` + return unless 'update'.start_with?(ARGV.first || ' ') # must be running `bundle update` + bundler_version = nil update_index = nil ARGV.each_with_index do |a, i| - if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN - bundler_version = a - end + bundler_version = a if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ - bundler_version = $1 + + bundler_version = Regexp.last_match(1) update_index = i end bundler_version end def gemfile - gemfile = ENV["BUNDLE_GEMFILE"] + gemfile = ENV['BUNDLE_GEMFILE'] return gemfile if gemfile && !gemfile.empty? - File.expand_path("../../Gemfile", __FILE__) + File.expand_path('../Gemfile', __dir__) end def lockfile lockfile = case File.basename(gemfile) - when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) + when 'gems.rb' then gemfile.sub(/\.rb$/, gemfile) else "#{gemfile}.lock" end File.expand_path(lockfile) @@ -55,15 +55,17 @@ m = Module.new do def lockfile_version return unless File.file?(lockfile) + lockfile_contents = File.read(lockfile) return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ + Regexp.last_match(1) end def bundler_version @bundler_version ||= env_var_version || cli_arg_version || - lockfile_version + lockfile_version end def bundler_requirement @@ -73,28 +75,30 @@ m = Module.new do requirement = bundler_gem_version.approximate_recommendation - return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0") + return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new('2.7.0') - requirement += ".a" if bundler_gem_version.prerelease? + requirement += '.a' if bundler_gem_version.prerelease? requirement end def load_bundler! - ENV["BUNDLE_GEMFILE"] ||= gemfile + ENV['BUNDLE_GEMFILE'] ||= gemfile activate_bundler end def activate_bundler gem_error = activation_error_handling do - gem "bundler", bundler_requirement + gem 'bundler', bundler_requirement end return if gem_error.nil? + require_error = activation_error_handling do - require "bundler/version" + require 'bundler/version' end return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) + warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" exit 42 end @@ -109,6 +113,4 @@ end m.load_bundler! -if m.invoked_as_script? - load Gem.bin_path("bundler", "bundle") -end +load Gem.bin_path('bundler', 'bundle') if m.invoked_as_script? diff --git a/quick_acg/bin/rails b/quick_acg/bin/rails index 7bcc36e..bec72ac 100644 --- a/quick_acg/bin/rails +++ b/quick_acg/bin/rails @@ -1,4 +1,4 @@ #!/usr/bin/env ruby.exe -APP_PATH = File.expand_path("../config/application", __dir__) -require_relative "../config/boot" -require "rails/commands" +APP_PATH = File.expand_path('../config/application', __dir__) +require_relative '../config/boot' +require 'rails/commands' diff --git a/quick_acg/bin/rake b/quick_acg/bin/rake index 01f7fc0..f6ed5a2 100644 --- a/quick_acg/bin/rake +++ b/quick_acg/bin/rake @@ -1,4 +1,4 @@ #!/usr/bin/env ruby.exe -require_relative "../config/boot" -require "rake" +require_relative '../config/boot' +require 'rake' Rake.application.run diff --git a/quick_acg/bin/setup b/quick_acg/bin/setup index 5e463ee..b6c604a 100644 --- a/quick_acg/bin/setup +++ b/quick_acg/bin/setup @@ -1,8 +1,8 @@ #!/usr/bin/env ruby.exe -require "fileutils" +require 'fileutils' # path to your application root. -APP_ROOT = File.expand_path("..", __dir__) +APP_ROOT = File.expand_path('..', __dir__) def system!(*args) system(*args) || abort("\n== Command #{args} failed ==") @@ -13,9 +13,9 @@ FileUtils.chdir APP_ROOT do # This script is idempotent, so that you can run it at any time and get an expectable outcome. # Add necessary setup steps to this file. - puts "== Installing dependencies ==" - system! "gem install bundler --conservative" - system("bundle check") || system!("bundle install") + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') # puts "\n== Copying sample files ==" # unless File.exist?("config/database.yml") @@ -23,11 +23,11 @@ FileUtils.chdir APP_ROOT do # end puts "\n== Preparing database ==" - system! "bin/rails db:prepare" + system! 'bin/rails db:prepare' puts "\n== Removing old logs and tempfiles ==" - system! "bin/rails log:clear tmp:clear" + system! 'bin/rails log:clear tmp:clear' puts "\n== Restarting application server ==" - system! "bin/rails restart" + system! 'bin/rails restart' end diff --git a/quick_acg/config/application.rb b/quick_acg/config/application.rb index f9beffa..bc611cc 100644 --- a/quick_acg/config/application.rb +++ b/quick_acg/config/application.rb @@ -13,7 +13,7 @@ class Application < Rails::Application config.app_url = 'http://localhost:3000' # The public url of the application. # Init DocuSign configuration, loaded from config/appsettings.yml file DOCUSIGN_CONFIG = YAML.load_file(File.expand_path(File.join(Rails.root.to_s, '../config/appsettings.yml')))[Rails.env] - DOCUSIGN_CONFIG.map do |k,v| + DOCUSIGN_CONFIG.map do |k, v| config.send("#{k}=", v) end diff --git a/quick_acg/config/boot.rb b/quick_acg/config/boot.rb index 2820116..30f5120 100644 --- a/quick_acg/config/boot.rb +++ b/quick_acg/config/boot.rb @@ -1,3 +1,3 @@ -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) -require "bundler/setup" # Set up gems listed in the Gemfile. +require 'bundler/setup' # Set up gems listed in the Gemfile. diff --git a/quick_acg/config/environment.rb b/quick_acg/config/environment.rb index cac5315..426333b 100644 --- a/quick_acg/config/environment.rb +++ b/quick_acg/config/environment.rb @@ -1,5 +1,5 @@ # Load the Rails application. -require_relative "application" +require_relative 'application' # Initialize the Rails application. Rails.application.initialize! diff --git a/quick_acg/config/environments/development.rb b/quick_acg/config/environments/development.rb index ea59bdc..3566bec 100644 --- a/quick_acg/config/environments/development.rb +++ b/quick_acg/config/environments/development.rb @@ -1,4 +1,4 @@ -require "active_support/core_ext/integer/time" +require 'active_support/core_ext/integer/time' require 'yaml' Rails.application.configure do @@ -20,13 +20,13 @@ # Enable/disable caching. By default caching is disabled. # Run rails dev:cache to toggle caching. - if Rails.root.join("tmp/caching-dev.txt").exist? + if Rails.root.join('tmp/caching-dev.txt').exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { - "Cache-Control" => "public, max-age=#{2.days.to_i}" + 'Cache-Control' => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false diff --git a/quick_acg/config/environments/production.rb b/quick_acg/config/environments/production.rb index ac46ed4..f174ab7 100644 --- a/quick_acg/config/environments/production.rb +++ b/quick_acg/config/environments/production.rb @@ -1,4 +1,4 @@ -require "active_support/core_ext/integer/time" +require 'active_support/core_ext/integer/time' Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -22,7 +22,7 @@ # Disable serving static files from the `/public` folder by default since # Apache or NGINX already handles this. - config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? # Compress CSS using a preprocessor. # config.assets.css_compressor = :sass @@ -45,7 +45,7 @@ config.log_level = :info # Prepend all log lines with the following tags. - config.log_tags = [ :request_id ] + config.log_tags = [:request_id] # Use a different cache store in production. # config.cache_store = :mem_cache_store @@ -64,7 +64,7 @@ # require "syslog/logger" # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") - if ENV["RAILS_LOG_TO_STDOUT"].present? + if ENV['RAILS_LOG_TO_STDOUT'].present? logger = ActiveSupport::Logger.new(STDOUT) logger.formatter = config.log_formatter config.logger = ActiveSupport::TaggedLogging.new(logger) diff --git a/quick_acg/config/environments/test.rb b/quick_acg/config/environments/test.rb index eb2f171..16b3759 100644 --- a/quick_acg/config/environments/test.rb +++ b/quick_acg/config/environments/test.rb @@ -1,4 +1,4 @@ -require "active_support/core_ext/integer/time" +require 'active_support/core_ext/integer/time' # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that @@ -14,12 +14,12 @@ # Eager loading loads your whole application. When running a single test locally, # this probably isn't necessary. It's a good idea to do in a continuous integration # system, or in some way before deploying your code. - config.eager_load = ENV["CI"].present? + config.eager_load = ENV['CI'].present? # Configure public file server for tests with Cache-Control for performance. config.public_file_server.enabled = true config.public_file_server.headers = { - "Cache-Control" => "public, max-age=#{1.hour.to_i}" + 'Cache-Control' => "public, max-age=#{1.hour.to_i}" } # Show full error reports and disable caching. diff --git a/quick_acg/config/initializers/assets.rb b/quick_acg/config/initializers/assets.rb index 2eeef96..fe48fc3 100644 --- a/quick_acg/config/initializers/assets.rb +++ b/quick_acg/config/initializers/assets.rb @@ -1,7 +1,7 @@ # Be sure to restart your server when you modify this file. # Version of your assets, change this if you want to expire all your assets. -Rails.application.config.assets.version = "1.0" +Rails.application.config.assets.version = '1.0' # Add additional assets to the asset load path. # Rails.application.config.assets.paths << Emoji.images_path diff --git a/quick_acg/config/initializers/omniauth.rb b/quick_acg/config/initializers/omniauth.rb index 53dd780..7bc52f7 100644 --- a/quick_acg/config/initializers/omniauth.rb +++ b/quick_acg/config/initializers/omniauth.rb @@ -15,7 +15,7 @@ # GET "/auth/docusign/callback?error=access_denied&error_message=The%20user%20did%20not%20consent%20to%20connecting%20the%20application.&state= # OmniAuth.config.failure_raise_out_environments = [] # defaults to: ['development'] -OmniAuth.config.allowed_request_methods = [:post, :get] +OmniAuth.config.allowed_request_methods = %i[post get] config = Rails.application.config config.middleware.use OmniAuth::Builder do @@ -36,17 +36,16 @@ strategy.options[:client_options].authorize_url = "#{strategy.options[:oauth_base_uri]}/oauth/auth" strategy.options[:client_options].user_info_url = "#{strategy.options[:oauth_base_uri]}/oauth/userinfo" strategy.options[:client_options].token_url = "#{strategy.options[:oauth_base_uri]}/oauth/token" - unless strategy.options[:allow_silent_authentication] - strategy.options[:authorize_params].prompt = strategy.options.prompt - end + strategy.options[:authorize_params].prompt = strategy.options.prompt unless strategy.options[:allow_silent_authentication] session = strategy.session - if session[:examples_API] == "Rooms" - strategy.options[:authorize_params].scope = "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" - elsif session[:examples_API] == "Click" - strategy.options[:authorize_params].scope = "signature click.manage click.send" - elsif session[:examples_API] == "Admin" - strategy.options[:authorize_params].scope = "signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" + case session[:examples_API] + when 'Rooms' + strategy.options[:authorize_params].scope = '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' + when 'Click' + strategy.options[:authorize_params].scope = 'signature click.manage click.send' + when 'Admin' + strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' end } end diff --git a/quick_acg/config/puma.rb b/quick_acg/config/puma.rb index daaf036..e9dc159 100644 --- a/quick_acg/config/puma.rb +++ b/quick_acg/config/puma.rb @@ -4,25 +4,25 @@ # the maximum value specified for Puma. Default is set to 5 threads for minimum # and maximum; this matches the default thread size of Active Record. # -max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } -min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +max_threads_count = ENV.fetch('RAILS_MAX_THREADS') { 5 } +min_threads_count = ENV.fetch('RAILS_MIN_THREADS') { max_threads_count } threads min_threads_count, max_threads_count # Specifies the `worker_timeout` threshold that Puma will use to wait before # terminating a worker in development environments. # -worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" +worker_timeout 3600 if ENV.fetch('RAILS_ENV', 'development') == 'development' # Specifies the `port` that Puma will listen on to receive requests; default is 3000. # -port ENV.fetch("PORT") { 3000 } +port ENV.fetch('PORT') { 3000 } # Specifies the `environment` that Puma will run in. # -environment ENV.fetch("RAILS_ENV") { "development" } +environment ENV.fetch('RAILS_ENV') { 'development' } # Specifies the `pidfile` that Puma will use. -pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } +pidfile ENV.fetch('PIDFILE') { 'tmp/pids/server.pid' } # Specifies the number of `workers` to boot in clustered mode. # Workers are forked web server processes. If using threads and workers together diff --git a/quick_acg/config/routes.rb b/quick_acg/config/routes.rb index e78df7f..ed81788 100644 --- a/quick_acg/config/routes.rb +++ b/quick_acg/config/routes.rb @@ -4,6 +4,7 @@ require_relative '../../app/services/api_creator' require_relative '../../app/controllers/eg001_embedded_signing_controller' require_relative '../../app/services/eg001_embedded_signing_service' +require_relative '../../app/services/utils.rb' Rails.application.routes.draw do root 'ds_common#index' diff --git a/quick_acg/lib/docusign.rb b/quick_acg/lib/docusign.rb index 807e6fe..b37d692 100644 --- a/quick_acg/lib/docusign.rb +++ b/quick_acg/lib/docusign.rb @@ -47,15 +47,13 @@ def raw_info # @param items is an array of Hash'es that has the keys: account_id, is_default, account_name, base_uri def fetch_account(items) - if options.target_account_id - @account = items.find { |item| item['account_id'] == options.target_account_id } - else - @account = items.find { |item| item['is_default'] } - end - - if @account.blank? - raise %'Could not find account information for the user in the "accounts" of raw_info: #{@raw_info}' - end + @account = if options.target_account_id + items.find { |item| item['account_id'] == options.target_account_id } + else + items.find { |item| item['is_default'] } + end + + raise %(Could not find account information for the user in the "accounts" of raw_info: #{@raw_info}) if @account.blank? end end end From e21fdd29cd2b8d343d7f1626c8b5f6efe1027fcd Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Fri, 21 Oct 2022 13:56:24 -0700 Subject: [PATCH 170/363] Updating README --- README.md | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 27152f9..29382e1 100644 --- a/README.md +++ b/README.md @@ -17,37 +17,41 @@ When the token expires, it updates automatically. ## 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 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, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/esign-rest-api/how-to/code-launchers#examples-and-languages) on the DocuSign Developer Center. +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. -## Rooms API -**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/). +## Rooms API -For a list of code examples that use the Rooms API, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/rooms-api/how-to/code-launchers#examples-and-languages) on the DocuSign Developer Center. +**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/). -## Click API +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. -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). -For a list of code examples that use the Click API, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/click-api/how-to/code-launchers#examples-and-languages) on the DocuSign Developer Center. +## 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) + +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. + ## Monitor API -**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/). -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/). +**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/). + +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/). + +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. -For a list of code examples that use the Monitor API, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/monitor-api/how-to/code-launchers/#examples-and-languages) on the DocuSign Developer Center. ## Admin API **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). -For more 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/). +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/). -For a list of code examples that use the Admin API, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/admin-api/how-to/code-launchers/#examples-and-languages) on the DocuSign Developer Center. +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. ## Installation From e6b953ce52f0ce42bd78328dfa7cc8a231d9aeba Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Fri, 21 Oct 2022 14:31:22 -0700 Subject: [PATCH 171/363] README.md updates --- README.md | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 27152f9..29382e1 100644 --- a/README.md +++ b/README.md @@ -17,37 +17,41 @@ When the token expires, it updates automatically. ## 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 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, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/esign-rest-api/how-to/code-launchers#examples-and-languages) on the DocuSign Developer Center. +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. -## Rooms API -**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/). +## Rooms API -For a list of code examples that use the Rooms API, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/rooms-api/how-to/code-launchers#examples-and-languages) on the DocuSign Developer Center. +**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/). -## Click API +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. -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). -For a list of code examples that use the Click API, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/click-api/how-to/code-launchers#examples-and-languages) on the DocuSign Developer Center. +## 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) + +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. + ## Monitor API -**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/). -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/). +**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/). + +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/). + +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. -For a list of code examples that use the Monitor API, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/monitor-api/how-to/code-launchers/#examples-and-languages) on the DocuSign Developer Center. ## Admin API **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). -For more 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/). +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/). -For a list of code examples that use the Admin API, select the Ruby tab under [Examples and languages](https://developers.docusign.com/docs/admin-api/how-to/code-launchers/#examples-and-languages) on the DocuSign Developer Center. +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. ## Installation From 8bf31f6fc6003bfb71f2053d32cd76204339048d Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Wed, 26 Oct 2022 13:38:27 -0700 Subject: [PATCH 172/363] add code to test HMAC message validation (#95) --- connect_test.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 connect_test.rb diff --git a/connect_test.rb b/connect_test.rb new file mode 100644 index 0000000..267a44c --- /dev/null +++ b/connect_test.rb @@ -0,0 +1,19 @@ +def ComputeHash(secret, payload) + require 'openssl' + require 'base64' + + digest = OpenSSL::Digest.new('sha256') + hashBytes = OpenSSL::HMAC.digest(digest, secret, payload) + base64Hash = Base64.encode64(hashBytes) + return base64Hash; +end + +def HashIsValid(secret, payload, signature) + ver = ComputeHash(secret, payload) + OpenSSL.secure_compare(ver.chomp, signature) +end + +secret = 'xxoxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGE=' # Replace this value with your own secret +signature = 'c60xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxew=' # Replace this value with your own signature +payload = File.read('payload.txt') # Read the payload from a file named payload.txt +puts HashIsValid(secret, payload, signature) # should return true for valid \ No newline at end of file From a9386f5d0b063f64622a196b94b54e2894834f18 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Mon, 14 Nov 2022 16:01:04 -0800 Subject: [PATCH 173/363] CFR part 11 example (#98) * CFR part 11 example --- Gemfile | 2 +- Gemfile.lock | 8 +- app/controllers/ds_common_controller.rb | 17 ++- .../eg014_collect_payment_controller.rb | 55 +++++---- .../eg020_phone_authentication_controller.rb | 11 +- ...32_pauses_signature_workflow_controller.rb | 11 ++ ..._unpauses_signature_workflow_controller.rb | 11 ++ ...4_use_conditional_recipients_controller.rb | 63 ++++++---- .../eg036_delayed_routing_controller.rb | 55 +++++---- .../e_sign/eg037_sms_delivery_controller.rb | 59 +++++---- .../eg039_signing_in_person_controller.rb | 11 ++ ...g040_set_document_visibility_controller.rb | 11 ++ .../eg041_cfr_embedded_signing_controller.rb | 52 ++++++++ .../eg001_embedded_signing_controller.rb | 21 ++-- app/controllers/session_controller.rb | 1 + .../eg041_cfr_embedded_signing_service.rb | 110 +++++++++++++++++ app/services/e_sign/get_data_service.rb | 7 ++ app/views/ds_common/error.erb | 3 +- app/views/ds_common/index.html.erb | 51 ++++++-- .../eg041_cfr_embedded_signing/get.html.erb | 43 +++++++ app/views/partials/_example_info.erb | 2 +- config/routes.rb | 3 + quick_acg/Gemfile | 2 +- quick_acg/Gemfile.lock | 9 +- .../app/controllers/ds_common_controller.rb | 8 +- quick_acg/app/views/ds_common/error.erb | 9 +- .../eg041_cfr_embedded_signing/get.html.erb | 113 ++++++++++++++++++ .../views/eg001_embedded_signing/get.html.erb | 24 ++-- quick_acg/config/routes.rb | 11 ++ 29 files changed, 645 insertions(+), 138 deletions(-) create mode 100644 app/controllers/e_sign/eg041_cfr_embedded_signing_controller.rb create mode 100644 app/services/e_sign/eg041_cfr_embedded_signing_service.rb create mode 100644 app/views/e_sign/eg041_cfr_embedded_signing/get.html.erb create mode 100644 quick_acg/app/views/e_sign/eg041_cfr_embedded_signing/get.html.erb diff --git a/Gemfile b/Gemfile index acb7ae6..fe0c968 100644 --- a/Gemfile +++ b/Gemfile @@ -69,7 +69,7 @@ end gem 'docusign_admin', '~> 1.1.0' gem 'docusign_click', '~> 1.0.0' -gem 'docusign_esign', '~> 3.17.0' +gem 'docusign_esign', '~> 3.19.0' gem 'docusign_monitor', '~> 1.1.0' gem 'docusign_rooms', '~> 1.2.0.rc1' gem 'omniauth-oauth2', '~> 1.7.1' diff --git a/Gemfile.lock b/Gemfile.lock index cbab39f..25d14d2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -108,7 +108,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.17.0) + docusign_esign (3.19.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -131,6 +131,7 @@ GEM faraday-net_http (>= 2.0, < 3.1) ruby2_keywords (>= 0.0.4) faraday-net_http (3.0.0) + ffi (1.15.5) ffi (1.15.5-x64-mingw-ucrt) globalid (1.0.0) activesupport (>= 5.0) @@ -168,6 +169,8 @@ GEM nio4r (2.5.8) nokogiri (1.13.8-x64-mingw-ucrt) racc (~> 1.4) + nokogiri (1.13.8-x86_64-darwin) + racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) jwt (>= 1.0, < 3.0) @@ -310,6 +313,7 @@ GEM PLATFORMS x64-mingw-ucrt + x86_64-darwin-21 DEPENDENCIES bootsnap (~> 1.7.3) @@ -319,7 +323,7 @@ DEPENDENCIES coffee-rails (~> 5.0.0) docusign_admin (~> 1.1.0) docusign_click (~> 1.0.0) - docusign_esign (~> 3.17.0) + docusign_esign (~> 3.19.0) docusign_monitor (~> 1.1.0) docusign_rooms (~> 1.2.0.rc1) jbuilder (~> 2.11.5) diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index 96fbfe5..b9d8ea5 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -10,6 +10,7 @@ def index end def handle_redirects + minimum_buffer_min = 10 if Rails.configuration.quickstart @manifest = Utils::ManifestUtils.new.get_manifest(Rails.configuration.eSignManifestUrl) @@ -18,10 +19,22 @@ def handle_redirects session[:quickstarted] = true redirect_to '/auth/docusign' elsif session[:been_here].nil? - redirect_to '/eg001' + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) + if enableCFR == "enabled" + session[:status_cfr] = "enabled" + redirect_to '/eg041' + else + redirect_to '/eg001' + end else render_examples end + elsif session[:ds_access_token].present? + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) + if enableCFR == "enabled" + session[:status_cfr] = "enabled" + end + render_examples else render_examples end @@ -41,7 +54,9 @@ def render_examples elsif session[:examples_API] == 'Admin' render 'admin_api/index' else + @status_cfr = session[:status_cfr] session[:examples_API] = 'eSignature' + render 'ds_common/index' end end diff --git a/app/controllers/e_sign/eg014_collect_payment_controller.rb b/app/controllers/e_sign/eg014_collect_payment_controller.rb index 8e49d7d..ef10847 100644 --- a/app/controllers/e_sign/eg014_collect_payment_controller.rb +++ b/app/controllers/e_sign/eg014_collect_payment_controller.rb @@ -5,27 +5,40 @@ class ESign::Eg014CollectPaymentController < EgController before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 14) } def create - envelope_args = { - signer_email: param_gsub(params['signerEmail']), - signer_name: param_gsub(params['signerName']), - cc_email: param_gsub(params['ccEmail']), - cc_name: param_gsub(params['ccName']), - gateway_account_id: Rails.application.config.gateway_account_id, - gateway_name: Rails.application.config.gateway_name, - gateway_display_name: Rails.application.config.gateway_display_name - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } + begin + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + cc_email: param_gsub(params['ccEmail']), + cc_name: param_gsub(params['ccName']), + gateway_account_id: Rails.application.config.gateway_account_id, + gateway_name: Rails.application.config.gateway_name, + gateway_display_name: Rails.application.config.gateway_display_name + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } - results = ESign::Eg014CollectPaymentService.new(args).worker - @title = @example['ExampleName'] - @message = format_string(@example['ResultsPageText'], results[:envelope_id]) - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - handle_error(e) + results = ESign::Eg014CollectPaymentService.new(args).worker + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results[:envelope_id]) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end + end + + def get + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) + if enableCFR == "enabled" + session[:status_cfr] = "enabled" + @title = "Not CFR Part 11 compatible" + @error_information = @manifest['SupportingTexts']['CFRError'] + render 'ds_common/error' + end + super end end diff --git a/app/controllers/e_sign/eg020_phone_authentication_controller.rb b/app/controllers/e_sign/eg020_phone_authentication_controller.rb index e580b73..8ac3505 100644 --- a/app/controllers/e_sign/eg020_phone_authentication_controller.rb +++ b/app/controllers/e_sign/eg020_phone_authentication_controller.rb @@ -40,5 +40,14 @@ def create end end - # ***DS.snippet.0.end + def get + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) + if enableCFR == "enabled" + session[:status_cfr] = "enabled" + @title = "Not CFR Part 11 compatible" + @error_information = @manifest['SupportingTexts']['CFRError'] + render 'ds_common/error' + end + super + end end diff --git a/app/controllers/e_sign/eg032_pauses_signature_workflow_controller.rb b/app/controllers/e_sign/eg032_pauses_signature_workflow_controller.rb index 57a1909..66c009e 100644 --- a/app/controllers/e_sign/eg032_pauses_signature_workflow_controller.rb +++ b/app/controllers/e_sign/eg032_pauses_signature_workflow_controller.rb @@ -25,4 +25,15 @@ def create render 'e_sign/eg032_pauses_signature_workflow/return' end + + def get + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) + if enableCFR == "enabled" + session[:status_cfr] = "enabled" + @title = "Not CFR Part 11 compatible" + @error_information = @manifest['SupportingTexts']['CFRError'] + render 'ds_common/error' + end + super + end end diff --git a/app/controllers/e_sign/eg033_unpauses_signature_workflow_controller.rb b/app/controllers/e_sign/eg033_unpauses_signature_workflow_controller.rb index 2b791dc..6b65217 100644 --- a/app/controllers/e_sign/eg033_unpauses_signature_workflow_controller.rb +++ b/app/controllers/e_sign/eg033_unpauses_signature_workflow_controller.rb @@ -18,4 +18,15 @@ def update @envelop_id = results.to_hash[:envelopeId].to_s render 'e_sign/eg033_unpauses_signature_workflow/return' end + + def get + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) + if enableCFR == "enabled" + session[:status_cfr] = "enabled" + @title = "Not CFR Part 11 compatible" + @error_information = @manifest['SupportingTexts']['CFRError'] + render 'ds_common/error' + end + super + end end diff --git a/app/controllers/e_sign/eg034_use_conditional_recipients_controller.rb b/app/controllers/e_sign/eg034_use_conditional_recipients_controller.rb index d9d8383..d5ce4a5 100644 --- a/app/controllers/e_sign/eg034_use_conditional_recipients_controller.rb +++ b/app/controllers/e_sign/eg034_use_conditional_recipients_controller.rb @@ -5,35 +5,48 @@ class ESign::Eg034UseConditionalRecipientsController < EgController before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 34) } def create - signers = { - signerEmail1: request['signerEmail1'], - signerName1: request['signerName1'], + begin + signers = { + signerEmail1: request['signerEmail1'], + signerName1: request['signerName1'], - signerEmailNotChecked: request['signerEmailNotChecked'], - signerNameNotChecked: request['signerNameNotChecked'], + signerEmailNotChecked: request['signerEmailNotChecked'], + signerNameNotChecked: request['signerNameNotChecked'], - signerEmailChecked: request['signerEmailChecked'], - signerNameChecked: request['signerNameChecked'] - } + signerEmailChecked: request['signerEmailChecked'], + signerNameChecked: request['signerNameChecked'] + } - args = { - accountId: session['ds_account_id'], - basePath: session['ds_base_path'], - accessToken: session['ds_access_token'] - } + args = { + accountId: session['ds_account_id'], + basePath: session['ds_base_path'], + accessToken: session['ds_access_token'] + } - results = ESign::Eg034UseConditionalRecipientsService.new(args, signers).worker - @envelop_id = results.to_hash[:envelopeId].to_s - render 'e_sign/eg034_use_conditional_recipients/return' - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - if error['errorCode']['WORKFLOW_UPDATE_RECIPIENTROUTING_NOT_ALLOWED'] - @error_message = @example['CustomErrorTexts'][0]['ErrorMessage'] - @error_information = @example['CustomErrorTexts'][0]['ErrorMessage'] - else - @error_message = error['message'] + results = ESign::Eg034UseConditionalRecipientsService.new(args, signers).worker + @envelop_id = results.to_hash[:envelopeId].to_s + render 'e_sign/eg034_use_conditional_recipients/return' + rescue DocuSign_eSign::ApiError => e + error = JSON.parse e.response_body + @error_code = error['errorCode'] + if error['errorCode']['WORKFLOW_UPDATE_RECIPIENTROUTING_NOT_ALLOWED'] + @error_message = @example['CustomErrorTexts'][0]['ErrorMessage'] + @error_information = @example['CustomErrorTexts'][0]['ErrorMessage'] + else + @error_message = error['message'] + end + render 'ds_common/error' end - render 'ds_common/error' + end + + def get + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) + if enableCFR == "enabled" + session[:status_cfr] = "enabled" + @title = "Not CFR Part 11 compatible" + @error_information = @manifest['SupportingTexts']['CFRError'] + render 'ds_common/error' + end + super end end diff --git a/app/controllers/e_sign/eg036_delayed_routing_controller.rb b/app/controllers/e_sign/eg036_delayed_routing_controller.rb index b5c31e5..2c3b5e5 100644 --- a/app/controllers/e_sign/eg036_delayed_routing_controller.rb +++ b/app/controllers/e_sign/eg036_delayed_routing_controller.rb @@ -5,26 +5,39 @@ class ESign::Eg036DelayedRoutingController < EgController before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 36) } def create - envelope_args = { - signer1_email: param_gsub(params['signer1Email']), - signer1_name: param_gsub(params['signer1Name']), - signer2_email: param_gsub(params['signer2Email']), - signer2_name: param_gsub(params['signer2Name']), - delay: param_gsub(params['delay']), - status: 'sent' - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } - results = ESign::Eg036DelayedRoutingService.new(args).worker - session[:envelope_id] = results['envelope_id'] - @title = @example['ExampleName'] - @message = format_string(@example['ResultsPageText'], results['envelope_id']) - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - handle_error(e) + begin + envelope_args = { + signer1_email: param_gsub(params['signer1Email']), + signer1_name: param_gsub(params['signer1Name']), + signer2_email: param_gsub(params['signer2Email']), + signer2_name: param_gsub(params['signer2Name']), + delay: param_gsub(params['delay']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + results = ESign::Eg036DelayedRoutingService.new(args).worker + session[:envelope_id] = results['envelope_id'] + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results['envelope_id']) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end + end + + def get + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) + if enableCFR == "enabled" + session[:status_cfr] = "enabled" + @title = "Not CFR Part 11 compatible" + @error_information = @manifest['SupportingTexts']['CFRError'] + render 'ds_common/error' + end + super end end diff --git a/app/controllers/e_sign/eg037_sms_delivery_controller.rb b/app/controllers/e_sign/eg037_sms_delivery_controller.rb index 2758fec..b3efa8c 100644 --- a/app/controllers/e_sign/eg037_sms_delivery_controller.rb +++ b/app/controllers/e_sign/eg037_sms_delivery_controller.rb @@ -5,28 +5,41 @@ class ESign::Eg037SmsDeliveryController < EgController before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 37) } def create - envelope_args = { - signer_name: param_gsub(params['signer_name']), - cc_name: param_gsub(params['cc_name']), - cc_phone_number: param_gsub(params['cc_phone_number']), - cc_country_code: param_gsub(params['cc_country_code']), - phone_number: param_gsub(params['phone_number']), - country_code: param_gsub(params['country_code']), - status: 'sent' - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } + begin + envelope_args = { + signer_name: param_gsub(params['signer_name']), + cc_name: param_gsub(params['cc_name']), + cc_phone_number: param_gsub(params['cc_phone_number']), + cc_country_code: param_gsub(params['cc_country_code']), + phone_number: param_gsub(params['phone_number']), + country_code: param_gsub(params['country_code']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } - results = ESign::Eg037SmsDeliveryService.new(args).worker - session[:envelope_id] = results['envelope_id'] - @title = @example['ExampleName'] - @message = format_string(@example['ResultsPageText'], results['envelope_id']) - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - handle_error(e) + results = ESign::Eg037SmsDeliveryService.new(args).worker + session[:envelope_id] = results['envelope_id'] + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results['envelope_id']) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end end -end + + def get + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) + if enableCFR == "enabled" + session[:status_cfr] = "enabled" + @title = "Not CFR Part 11 compatible" + @error_information = @manifest['SupportingTexts']['CFRError'] + render 'ds_common/error' + end + super + end +end \ No newline at end of file diff --git a/app/controllers/e_sign/eg039_signing_in_person_controller.rb b/app/controllers/e_sign/eg039_signing_in_person_controller.rb index 808331a..84f3659 100644 --- a/app/controllers/e_sign/eg039_signing_in_person_controller.rb +++ b/app/controllers/e_sign/eg039_signing_in_person_controller.rb @@ -35,4 +35,15 @@ def create redirect_url = ESign::Eg039SigningInPersonService.new(args).worker redirect_to redirect_url end + + def get + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) + if enableCFR == "enabled" + session[:status_cfr] = "enabled" + @title = "Not CFR Part 11 compatible" + @error_information = @manifest['SupportingTexts']['CFRError'] + render 'ds_common/error' + end + super + end end diff --git a/app/controllers/e_sign/eg040_set_document_visibility_controller.rb b/app/controllers/e_sign/eg040_set_document_visibility_controller.rb index 6cf5f8c..8d7eeec 100644 --- a/app/controllers/e_sign/eg040_set_document_visibility_controller.rb +++ b/app/controllers/e_sign/eg040_set_document_visibility_controller.rb @@ -40,4 +40,15 @@ def create handle_error(e) end + + def get + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) + if enableCFR == "enabled" + session[:status_cfr] = "enabled" + @title = "Not CFR Part 11 compatible" + @error_information = @manifest['SupportingTexts']['CFRError'] + render 'ds_common/error' + end + super + end end diff --git a/app/controllers/e_sign/eg041_cfr_embedded_signing_controller.rb b/app/controllers/e_sign/eg041_cfr_embedded_signing_controller.rb new file mode 100644 index 0000000..bb10f88 --- /dev/null +++ b/app/controllers/e_sign/eg041_cfr_embedded_signing_controller.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require_relative '../../services/utils' + +class ESign::Eg041CfrEmbeddedSigningController < EgController + before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 41) } + + def create + pdf_file_path = 'data/World_Wide_Corp_lorem.pdf' + + pdf_file_path = '../data/World_Wide_Corp_lorem.pdf' unless File.exist?(pdf_file_path) + + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + country_code: param_gsub(params['countryCode']), + phone_number: param_gsub(params['phoneNumber']), + signer_client_id: 1000, + ds_return_url: "#{Rails.application.config.app_url}/ds_common-return", + ds_ping_url: "#{Rails.application.config.app_url}/", + pdf_filename: pdf_file_path + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + redirect_url = ESign::Eg041CfrEmbeddedSigningService.new(args).worker + + if redirect_url.to_s == 'invalid_workflow_id' + @error_code = 'IDENTITY_WORKFLOW_INVALID_ID' + @error_message = 'The identity workflow ID specified is not valid.' + render 'ds_common/error' + else + redirect_to redirect_url + end + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end + + def get + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) + if enableCFR != "enabled" + @title = "Must use a CFR Part 11 enabled account" + @error_information = "This example requires a CFR Part 11 account. Please return to the homepage to run one of the examples that is compatible or authenticate with a different account." + render 'ds_common/error' + end + super + end +end diff --git a/app/controllers/eg001_embedded_signing_controller.rb b/app/controllers/eg001_embedded_signing_controller.rb index 01aff89..0de17e9 100644 --- a/app/controllers/eg001_embedded_signing_controller.rb +++ b/app/controllers/eg001_embedded_signing_controller.rb @@ -1,21 +1,11 @@ # frozen_string_literal: true class Eg001EmbeddedSigningController < EgController + before_action :check_auth + # before_action -> { @manifest = Utils::ManifestUtils.new.get_manifest(Rails.configuration.eSignManifestUrl)} before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1) } def create - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - unless token_ok - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation - # so it could be restarted automatically. - # But since it should be rare to have a token issue here, - # we'll make the user re-enter the form data after - # authentication. - return redirect_to '/ds/mustAuthenticate' - end - pdf_file_path = 'data/World_Wide_Corp_lorem.pdf' pdf_file_path = '../data/World_Wide_Corp_lorem.pdf' unless File.exist?(pdf_file_path) @@ -38,6 +28,13 @@ def create end def get + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) + if enableCFR == "enabled" + session[:status_cfr] = "enabled" + @title = "Not CFR Part 11 compatible" + @error_information = @manifest['SupportingTexts']['CFRError'] + render 'ds_common/error' + end session[:been_here] = true super end diff --git a/app/controllers/session_controller.rb b/app/controllers/session_controller.rb index b86a602..97a70eb 100644 --- a/app/controllers/session_controller.rb +++ b/app/controllers/session_controller.rb @@ -58,6 +58,7 @@ def internal_destroy session.delete :template_id session.delete :eg session.delete :manifest + session.delete :status_cfr end def store_auth_hash_from_docusign_callback diff --git a/app/services/e_sign/eg041_cfr_embedded_signing_service.rb b/app/services/e_sign/eg041_cfr_embedded_signing_service.rb new file mode 100644 index 0000000..f7cb0d7 --- /dev/null +++ b/app/services/e_sign/eg041_cfr_embedded_signing_service.rb @@ -0,0 +1,110 @@ +# frozen_string_literal: true + +class ESign::Eg041CfrEmbeddedSigningService + attr_reader :args + + include ApiCreator + + def initialize(args) + @args = args + end + + # ***DS.snippet.0.start + def worker + envelope_args = args[:envelope_args] + accounts_api = create_account_api(args) + + #Obtain your workflow_id + workflow_results = accounts_api.get_account_identity_verification(args[:account_id]) + + if workflow_results.identity_verification + workflow = workflow_results.identity_verification.find { |item| item.default_name == 'SMS for access & signatures' } + workflow_id = workflow.workflow_id if workflow + end + + return 'invalid_workflow_id' if workflow_id.blank? + + envelope_api = create_envelope_api(args) + envelope_definition = make_envelope(args[:envelope_args], workflow_id) + + envelope = envelope_api.create_envelope(args[:account_id], envelope_definition) + + envelope_id = envelope.envelope_id + + view_request = DocuSign_eSign::RecipientViewRequest.new({ + returnUrl: "#{envelope_args[:ds_return_url]}?state=123", + authenticationMethod: "none", + email: envelope_args[:signer_email], + userName: "#{envelope_args[:signer_name]}", + clientUserId: envelope_args[:signer_client_id], + pingFrequency: 600, + pingUrl: envelope_args[:ds_ping_url] + }) + + results = envelope_api.create_recipient_view(args[:account_id], envelope_id, view_request) + + results.url + end + + private + def make_envelope(args, workflow_id) + envelope_definition = DocuSign_eSign::EnvelopeDefinition.new + envelope_definition.email_subject = 'Please sign this document sent from Ruby SDK' + + doc1 = DocuSign_eSign::Document.new + doc1.document_base64 = Base64.encode64(File.binread(args[:pdf_filename])) + doc1.name = 'Lorem Ipsum' + doc1.file_extension = 'pdf' + doc1.document_id = '1' + + # The order in the docs array determines the order in the envelope + envelope_definition.documents = [doc1] + + phone_number = DocuSign_eSign::RecipientIdentityPhoneNumber.new + phone_number.country_code = args[:country_code] + phone_number.number = args[:phone_number] + + input_option = DocuSign_eSign::RecipientIdentityInputOption.new + input_option.name = 'phone_number_list' + input_option.value_type = 'PhoneNumberList' + input_option.phone_number_list = [phone_number] + + identity_verification = DocuSign_eSign::RecipientIdentityVerification.new + + identity_verification.workflow_id = workflow_id + identity_verification.input_options = [input_option] + + + # Create a signer recipient to sign the document, identified by name and email + # We're setting the parameters via the object creation + signer1 = DocuSign_eSign::Signer.new({ + email: args[:signer_email], + name: args[:signer_name], + clientUserId: args[:signer_client_id], + recipientId: 1, + identityVerification: identity_verification + }) + # The DocuSign platform searches throughout your envelope's documents for matching + # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 + # since they use the same anchor string for their "signer 1" tabs. + sign_here = DocuSign_eSign::SignHere.new + sign_here.anchor_string = '/sn1/' + sign_here.anchor_units = 'pixels' + sign_here.anchor_x_offset = '20' + sign_here.anchor_y_offset = '-30' + # Tabs are set per recipient/signer + tabs = DocuSign_eSign::Tabs.new + tabs.sign_here_tabs = [sign_here] + signer1.tabs = tabs + # Add the recipients to the envelope object + recipients = DocuSign_eSign::Recipients.new + recipients.signers = [signer1] + + envelope_definition.recipients = recipients + # Request that the envelope be sent by setting status to "sent". + # To request that the envelope be created as a draft, set status to "created" + envelope_definition.status = 'sent' + envelope_definition + end + # ***DS.snippet.0.end +end diff --git a/app/services/e_sign/get_data_service.rb b/app/services/e_sign/get_data_service.rb index 58cbc70..2769df5 100644 --- a/app/services/e_sign/get_data_service.rb +++ b/app/services/e_sign/get_data_service.rb @@ -26,6 +26,13 @@ def get_current_user_name user_info.name end + def is_cfr(account_id) + worker + accounts_api = DocuSign_eSign::AccountsApi.new @api_client + account_details = accounts_api.get_account_information(account_id) + account_details.status21_cfr_part11 + end + private def worker diff --git a/app/views/ds_common/error.erb b/app/views/ds_common/error.erb index f3260d9..6794a71 100644 --- a/app/views/ds_common/error.erb +++ b/app/views/ds_common/error.erb @@ -5,10 +5,11 @@ <% if @error_code %>

    <%= @error_code %>: <%= @error_message %>

    +<% end %> <% if @error_information %>

    <%== @error_information %>

    <% end %> -<% else %> +<% if @err %>

    <%= @err %>

    <% end %> diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index 157e227..a10bfc7 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -35,25 +35,50 @@ <% group["Examples"].each { |example| %> <% if not example["SkipLanguages"] or not example["SkipLanguages"].include? "ruby" %> -

    "> - "> - <%= example["ExampleName"] %> - -

    + <% if @status_cfr && @status_cfr == "enabled" %> + <% if example["CFREnabled"] == "AllAccounts" || example["CFREnabled"] == "CFROnly" %> +

    "> + "> + <%= example["ExampleName"] %> + +

    -

    <%= sanitize example["ExampleDescription"] %>

    +

    <%= sanitize example["ExampleDescription"] %>

    - <% if example["LinksToAPIMethod"].length > 1 %> - <%= sanitize @manifest["SupportingTexts"]["APIMethodUsedPlural"] %> + <% if example["LinksToAPIMethod"].length > 1 %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsedPlural"] %> + <% else %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsed"] %> + <% end %> + + <% example["LinksToAPIMethod"].each do |link| %> + "><%= link["PathName"] %> + <% end %> +

    + <% end %> <% else %> - <%= sanitize @manifest["SupportingTexts"]["APIMethodUsed"] %> - <% end %> + <% if example["CFREnabled"] == "AllAccounts" || example["CFREnabled"] == "NonCFR" %> +

    "> + "> + <%= example["ExampleName"] %> + +

    + +

    <%= sanitize example["ExampleDescription"] %>

    + + <% if example["LinksToAPIMethod"].length > 1 %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsedPlural"] %> + <% else %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsed"] %> + <% end %> - <% example["LinksToAPIMethod"].each do |link| %> - "><%= link["PathName"] %> + <% example["LinksToAPIMethod"].each do |link| %> + "><%= link["PathName"] %> + <% end %> +

    + <% end %> <% end %> <% end %> -

    <% } %> <% } %> diff --git a/app/views/e_sign/eg041_cfr_embedded_signing/get.html.erb b/app/views/e_sign/eg041_cfr_embedded_signing/get.html.erb new file mode 100644 index 0000000..16b9af2 --- /dev/null +++ b/app/views/e_sign/eg041_cfr_embedded_signing/get.html.erb @@ -0,0 +1,43 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %> +<% country_code_index = 2 %> +<% phone_number_index = 3 %> + +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + " required + value="<%= @config.signer_email %>"> + <%= render('partials/email_will_not_be_shared') %> +
    +
    + + " name="signerName" + value="<%= @config.signer_name %>" required> +
    +
    + + " required /> + The country code for the phone number below. +
    +
    + + " required /> + <%= render('partials/phone_will_not_be_shared') %> +
    + <%= render('partials/submit_button') %> +
    \ No newline at end of file diff --git a/app/views/partials/_example_info.erb b/app/views/partials/_example_info.erb index 5d4a307..4328ea9 100644 --- a/app/views/partials/_example_info.erb +++ b/app/views/partials/_example_info.erb @@ -20,5 +20,5 @@ <% end %>

    - <%= sanitize format_string(@manifest["SupportingTexts"]["ViewSourceFile"], format_string('{1}', @source_url, @source_file)) %> + <%= sanitize format_string(@manifest["SupportingTexts"]["ViewSourceFile"], "#{@source_file}" ) %>

    \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 2620982..249f9eb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -208,6 +208,9 @@ get 'eg040' => 'eg040_set_document_visibility#get' post 'eg040' => 'eg040_set_document_visibility#create' + + get 'eg041' => 'eg041_cfr_embedded_signing#get' + post 'eg041' => 'eg041_cfr_embedded_signing#create' end end diff --git a/quick_acg/Gemfile b/quick_acg/Gemfile index 63ffc0c..09d66d9 100644 --- a/quick_acg/Gemfile +++ b/quick_acg/Gemfile @@ -66,7 +66,7 @@ group :test do gem 'chromedriver-helper', '~> 2.1.1' end -gem 'docusign_esign', '~> 3.17.0' +gem 'docusign_esign', '~> 3.19.0' gem 'omniauth-oauth2', '~> 1.7.1' gem 'omniauth-rails_csrf_protection' diff --git a/quick_acg/Gemfile.lock b/quick_acg/Gemfile.lock index 0fd69b9..0cdb2b7 100644 --- a/quick_acg/Gemfile.lock +++ b/quick_acg/Gemfile.lock @@ -87,13 +87,13 @@ GEM coffee-script-source (1.12.2) concurrent-ruby (1.1.10) crass (1.0.6) - docusign_esign (3.17.0) + docusign_esign (3.19.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) erubi (1.10.0) - ethon (0.15.0) + ethon (0.16.0) ffi (>= 1.15.0) execjs (2.8.1) faraday (2.3.0) @@ -129,6 +129,8 @@ GEM nio4r (2.5.8) nokogiri (1.13.6-x64-mingw32) racc (~> 1.4) + nokogiri (1.13.6-x86_64-darwin) + racc (~> 1.4) nokogiri (1.13.6-x86_64-linux) racc (~> 1.4) oauth2 (2.0.5) @@ -256,6 +258,7 @@ GEM PLATFORMS x64-mingw32 + x86_64-darwin-21 x86_64-linux DEPENDENCIES @@ -264,7 +267,7 @@ DEPENDENCIES capybara (~> 3.31.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_esign (~> 3.17.0) + docusign_esign (~> 3.19.0) jbuilder (~> 2.10.0) listen (~> 3.7.0) omniauth-oauth2 (~> 1.7.1) diff --git a/quick_acg/app/controllers/ds_common_controller.rb b/quick_acg/app/controllers/ds_common_controller.rb index 3a05d4b..1e00524 100644 --- a/quick_acg/app/controllers/ds_common_controller.rb +++ b/quick_acg/app/controllers/ds_common_controller.rb @@ -11,7 +11,13 @@ def handle_redirects session[:quickstarted] = true redirect_to '/auth/docusign' else - redirect_to '/eg001' + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) + if enableCFR == "enabled" + session[:status_cfr] = "enabled" + redirect_to '/eg041' + else + redirect_to '/eg001' + end end end diff --git a/quick_acg/app/views/ds_common/error.erb b/quick_acg/app/views/ds_common/error.erb index 211d659..9eae50e 100644 --- a/quick_acg/app/views/ds_common/error.erb +++ b/quick_acg/app/views/ds_common/error.erb @@ -35,10 +35,11 @@ <% if @error_code %>

    <%= @error_code %>: <%= @error_message %>

    - <% if @error_information %> -

    <%== @error_information %>

    - <% end %> - <% else %> + <% end %> + <% if @error_information %> +

    <%== @error_information %>

    + <% end %> + <% if @err %>

    <%= @err %>

    diff --git a/quick_acg/app/views/e_sign/eg041_cfr_embedded_signing/get.html.erb b/quick_acg/app/views/e_sign/eg041_cfr_embedded_signing/get.html.erb new file mode 100644 index 0000000..7507806 --- /dev/null +++ b/quick_acg/app/views/e_sign/eg041_cfr_embedded_signing/get.html.erb @@ -0,0 +1,113 @@ + + + + + + + + + <% if @title %> + <%= @title %> + <% else %> + DocuSign Ruby Code Examples + <% end %> + + + + + + + + +
    +
    +

    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 + website.

    + + <% if @show_doc %> +

    Documentation about this example.

    + <% end %> + +

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

    +

    + View source file <%= @source_file %> on GitHub. +

    + + <% form_index = 0 %> + <% signer_email_index = 0 %> + <% signer_name_index = 1 %> + <% country_code_index = 2 %> + <% phone_number_index = 3 %> + +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + " required + value="<%= @config.signer_email %>"> + <%= @manifest["SupportingTexts"]["HelpingTexts"]["EmailWontBeShared"] %> +
    +
    + + " name="signerName" + value="<%= @config.signer_name %>" required> +
    +
    + + " required /> + The country code for the phone number below. +
    +
    + + " required /> + <%= "#{@manifest["SupportingTexts"]["HelpingTexts"]["PhoneNumberWillBeNotified"]} #{@manifest["SupportingTexts"]["HelpingTexts"]["PhoneNumberWontBeShared"]}" %> +
    + +
    +
    +
    + + \ No newline at end of file diff --git a/quick_acg/app/views/eg001_embedded_signing/get.html.erb b/quick_acg/app/views/eg001_embedded_signing/get.html.erb index 037a8ad..230e534 100644 --- a/quick_acg/app/views/eg001_embedded_signing/get.html.erb +++ b/quick_acg/app/views/eg001_embedded_signing/get.html.erb @@ -66,18 +66,28 @@ View source file <%= @source_file %> on GitHub.

    + <% form_index = 0 %> + <% signer_email_index = 0 %> + <% signer_name_index = 1 %> +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> +
    - + - We'll never share your email with anyone else. + aria-describedby="emailHelp" + placeholder="<%= @example["Forms"][form_index]["Inputs"][signer_email_index]["InputPlaceholder"] %>" required + value="<%= @config.signer_email %>"> + <%= @manifest["SupportingTexts"]["HelpingTexts"]["EmailWontBeShared"] %>
    - - + + " + name="signerName" value="<%= @config.signer_name %>" required>
    diff --git a/quick_acg/config/routes.rb b/quick_acg/config/routes.rb index ed81788..fe2c640 100644 --- a/quick_acg/config/routes.rb +++ b/quick_acg/config/routes.rb @@ -6,12 +6,23 @@ require_relative '../../app/services/eg001_embedded_signing_service' require_relative '../../app/services/utils.rb' +class ESign +end + +require_relative '../../app/controllers/e_sign/eg041_cfr_embedded_signing_controller' +require_relative '../../app/services/e_sign/eg041_cfr_embedded_signing_service' +require_relative '../../app/services/e_sign/get_data_service' + Rails.application.routes.draw do root 'ds_common#index' get '/eg001' => 'eg001_embedded_signing#get' post '/eg001' => 'eg001_embedded_signing#create' + scope module: 'e_sign' do + get 'eg041' => 'eg041_cfr_embedded_signing#get' + post 'eg041' => 'eg041_cfr_embedded_signing#create' + end # Login starts with POST'ing to: /auth/docusign # /auth/docusign is an internal route created by OmniAuth and the docusign strategy from: /lib/docusign.rb # Should be POST, see: https://nvd.nist.gov/vuln/detail/CVE-2015-9284 From fc85943d3073126d510f25d89b8aa3eeba3e2928 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Fri, 18 Nov 2022 08:51:29 -0800 Subject: [PATCH 174/363] add createHasAgreed example (#97) * add createHasAgreed example --- Gemfile | 2 +- Gemfile.lock | 4 +- .../eg002_activate_clickwrap_controller.rb | 6 +- .../eg006_embed_clickwrap_controller.rb | 40 +++++++++ .../eg002_activate_clickwrap_service.rb | 20 +++++ .../eg006_embed_clickwrap_service.rb | 86 +++++++++++++++++++ app/views/admin_api/index.html.erb | 2 +- .../eg002_activate_clickwrap/get.html.erb | 9 +- .../eg006_embed_clickwrap/get.html.erb | 63 ++++++++++++++ .../eg006_embed_clickwrap/results.html.erb | 28 ++++++ app/views/clickwrap/index.html.erb | 2 +- app/views/ds_common/index.html.erb | 2 +- app/views/monitor_api/index.html.erb | 2 +- app/views/room_api/index.html.erb | 2 +- config/routes.rb | 3 + 15 files changed, 261 insertions(+), 10 deletions(-) create mode 100644 app/controllers/clickwrap/eg006_embed_clickwrap_controller.rb create mode 100644 app/services/clickwrap/eg006_embed_clickwrap_service.rb create mode 100644 app/views/clickwrap/eg006_embed_clickwrap/get.html.erb create mode 100644 app/views/clickwrap/eg006_embed_clickwrap/results.html.erb diff --git a/Gemfile b/Gemfile index fe0c968..9df5ac4 100644 --- a/Gemfile +++ b/Gemfile @@ -68,7 +68,7 @@ group :test do end gem 'docusign_admin', '~> 1.1.0' -gem 'docusign_click', '~> 1.0.0' +gem 'docusign_click', '~> 1.2.2' gem 'docusign_esign', '~> 3.19.0' gem 'docusign_monitor', '~> 1.1.0' gem 'docusign_rooms', '~> 1.2.0.rc1' diff --git a/Gemfile.lock b/Gemfile.lock index 25d14d2..3571ccb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -103,7 +103,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_click (1.0.0) + docusign_click (1.2.2) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -322,7 +322,7 @@ DEPENDENCIES chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) docusign_admin (~> 1.1.0) - docusign_click (~> 1.0.0) + docusign_click (~> 1.2.0) docusign_esign (~> 3.19.0) docusign_monitor (~> 1.1.0) docusign_rooms (~> 1.2.0.rc1) diff --git a/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb b/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb index 1d89be3..d6c8782 100644 --- a/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb +++ b/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb @@ -7,7 +7,7 @@ def create account_id: session[:ds_account_id], base_path: session[:ds_base_path], access_token: session[:ds_access_token], - clickwrap_id: session[:clickwrap_id] + clickwrap_id: params[:clickwrapId] } Clickwrap::Eg002ActivateClickwrapService.new(args).worker @@ -16,4 +16,8 @@ def create @message = @example['ResultsPageText'] render 'ds_common/example_done' end + + def get + @clickwraps = Clickwrap::Eg002ActivateClickwrapService.new(session).get_inactive_clickwraps + end end diff --git a/app/controllers/clickwrap/eg006_embed_clickwrap_controller.rb b/app/controllers/clickwrap/eg006_embed_clickwrap_controller.rb new file mode 100644 index 0000000..df57dfd --- /dev/null +++ b/app/controllers/clickwrap/eg006_embed_clickwrap_controller.rb @@ -0,0 +1,40 @@ +class Clickwrap::Eg006EmbedClickwrapController < EgController + before_action :check_auth + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 6) } + + def create + begin + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + clickwrap_id: params[:clickwrapId], + full_name: params[:fullName], + email: params[:email], + company: params[:company], + title: params[:title], + date: params[:date] + } + + results = Clickwrap::Eg006EmbedClickwrapService.new(args).worker + + if results == nil + @error_code = '200' + @error_message = '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.' + render 'ds_common/error' + else + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText']) + @agreementUrl = results["agreementUrl"] + render 'clickwrap/eg006_embed_clickwrap/results' + end + rescue DocuSign_Click::ApiError => e + handle_error(e) + end + end + + def get + @clickwraps = Clickwrap::Eg006EmbedClickwrapService.new(session).get_active_clickwraps + @inactive_clickwraps = Clickwrap::Eg006EmbedClickwrapService.new(session).get_inactive_clickwraps + end +end diff --git a/app/services/clickwrap/eg002_activate_clickwrap_service.rb b/app/services/clickwrap/eg002_activate_clickwrap_service.rb index 20b9892..26867e1 100644 --- a/app/services/clickwrap/eg002_activate_clickwrap_service.rb +++ b/app/services/clickwrap/eg002_activate_clickwrap_service.rb @@ -28,4 +28,24 @@ def worker clickwrap_request ) end + + def get_inactive_clickwraps + configuration = DocuSign_Click::Configuration.new + configuration.host = args[:ds_base_path] + + api_client = DocuSign_Click::ApiClient.new configuration + api_client.set_default_header('Authorization', "Bearer #{args[:ds_access_token]}") + + accounts_api = DocuSign_Click::AccountsApi.new(api_client) + + options = DocuSign_Click::GetClickwrapsOptions.new + options.status = 'inactive' + + results = accounts_api.get_clickwraps( + args[:ds_account_id], + options + ) + puts results.as_json['clickwraps'] + results.as_json['clickwraps'] + end end diff --git a/app/services/clickwrap/eg006_embed_clickwrap_service.rb b/app/services/clickwrap/eg006_embed_clickwrap_service.rb new file mode 100644 index 0000000..9792fd7 --- /dev/null +++ b/app/services/clickwrap/eg006_embed_clickwrap_service.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +class Clickwrap::Eg006EmbedClickwrapService + attr_reader :args + + def initialize(args) + @args = args + end + + def worker + # Step 2. Construct your API headers + configuration = DocuSign_Click::Configuration.new + configuration.host = args[:base_path] + + api_client = DocuSign_Click::ApiClient.new configuration + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + api_client.config.debugging = true; + + # document_data = DocuSign_Click::DocumentData.new({ + # full_name: args[:full_name], + # email: args[:email], + # company: args[:company], + # title: args[:title], + # date: args[:date] + # }) + + document_data = { + "fullName" => args[:full_name], + "email" => args[:email], + "company" => args[:company], + "title" => args[:title], + "date" => args[:date] + } + + + userAgreementRequest = DocuSign_Click::UserAgreementRequest.new({ + clientUserId: args[:email], + documentData: document_data + }) + + accounts_api = DocuSign_Click::AccountsApi.new(api_client) + + response = accounts_api.create_has_agreed(args[:account_id], args[:clickwrap_id], userAgreementRequest) + + response.as_json + end + + def get_active_clickwraps + configuration = DocuSign_Click::Configuration.new + configuration.host = args[:ds_base_path] + + api_client = DocuSign_Click::ApiClient.new configuration + api_client.set_default_header('Authorization', "Bearer #{args[:ds_access_token]}") + + accounts_api = DocuSign_Click::AccountsApi.new(api_client) + + options = DocuSign_Click::GetClickwrapsOptions.new + options.status = 'active' + + results = accounts_api.get_clickwraps( + args[:ds_account_id], + options + ) + puts results.as_json['clickwraps'] + results.as_json['clickwraps'] + end + + def get_inactive_clickwraps + configuration = DocuSign_Click::Configuration.new + configuration.host = args[:ds_base_path] + + api_client = DocuSign_Click::ApiClient.new configuration + api_client.set_default_header('Authorization', "Bearer #{args[:ds_access_token]}") + + accounts_api = DocuSign_Click::AccountsApi.new(api_client) + + options = DocuSign_Click::GetClickwrapsOptions.new + options.status = 'inactive' + + results = accounts_api.get_clickwraps( + args[:ds_account_id], + options + ) + results.as_json['clickwraps'] + end +end diff --git a/app/views/admin_api/index.html.erb b/app/views/admin_api/index.html.erb index be500ad..f7c8a5e 100644 --- a/app/views/admin_api/index.html.erb +++ b/app/views/admin_api/index.html.erb @@ -25,7 +25,7 @@

    <%= group["Name"] %>

    <% group["Examples"].each { |example| %> - <% if not example["SkipLanguages"] or not example["SkipLanguages"].include? "ruby" %> + <% if not example["SkipForLanguages"] or not example["SkipForLanguages"].include? "ruby" %>

    "> "> <%= example["ExampleName"] %> diff --git a/app/views/clickwrap/eg002_activate_clickwrap/get.html.erb b/app/views/clickwrap/eg002_activate_clickwrap/get.html.erb index e6249c8..88faa14 100644 --- a/app/views/clickwrap/eg002_activate_clickwrap/get.html.erb +++ b/app/views/clickwrap/eg002_activate_clickwrap/get.html.erb @@ -1,14 +1,21 @@ <%= render('partials/example_info') %> <% redirect_to1_index = 0 %> +<% clickwrap_id_index = 0 %> +<% form_index = 0 %> -<% if session[:clickwrap_id] %> +<% if @clickwraps.count.positive? %>
    <% if @example["Forms"][0]["FormName"] %> <%= sanitize @example["Forms"][0]["FormName"] %> <% end %> +
    + + <%= select_tag "clickwrapId", options_for_select(@clickwraps.map { |obj| [obj['clickwrapName'], obj['clickwrapId']] }), {:class => 'form-control'} %> +
    + <%= render('partials/submit_button') %>
    diff --git a/app/views/clickwrap/eg006_embed_clickwrap/get.html.erb b/app/views/clickwrap/eg006_embed_clickwrap/get.html.erb new file mode 100644 index 0000000..2142fe0 --- /dev/null +++ b/app/views/clickwrap/eg006_embed_clickwrap/get.html.erb @@ -0,0 +1,63 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% clickwrap_id_index = 0 %> +<% full_name_index = 1 %> +<% email_index = 2 %> +<% company_index = 3 %> +<% title_index = 4 %> +<% date_index = 5 %> +<% redirect_to1_index = 0 %> +<% redirect_to2_index = 1 %> + +<% if @clickwraps.count.positive? %> +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + <%= select_tag "clickwrapId", options_for_select(@clickwraps.map { |obj| [obj['clickwrapName'], obj['clickwrapId']] }), {:class => 'form-control'} %> +
    +

    + <%= sanitize @manifest["SupportingTexts"]["HelpingTexts"]["DynamicContentValue"] %> +

    +

    + <%= sanitize @manifest["SupportingTexts"]["HelpingTexts"]["DynamicContentNote"] %> +

    +
    + + " required /> +
    +
    + + " required + <%= render('partials/email_will_not_be_shared') %> +
    +
    + + " required> +
    +
    + + " required> +
    +
    + + " required> +
    + <%= render('partials/submit_button') %> +
    + +<% elsif @inactive_clickwraps.count.positive? %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %> +<% else %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="eg001"') %> +<% end %> diff --git a/app/views/clickwrap/eg006_embed_clickwrap/results.html.erb b/app/views/clickwrap/eg006_embed_clickwrap/results.html.erb new file mode 100644 index 0000000..6b6f6eb --- /dev/null +++ b/app/views/clickwrap/eg006_embed_clickwrap/results.html.erb @@ -0,0 +1,28 @@ +

    <%= @title %>

    +<% if !@message.nil? %> +

    <%= @message.html_safe %>

    +<% end %> + +<% if !@agreementUrl.nil? %> +

    + <%= sanitize @manifest["SupportingTexts"]["HelpingTexts"]["EmbedClickwrapURL"] %> <%= @agreementUrl.html_safe %> +

    +<% end %> + +

    + <%= sanitize @manifest["SupportingTexts"]["HelpingTexts"]["NOTAGREED"] %> +

    + +

    Continue

    + +
    + +<%= javascript_tag do %> + docuSignClick.Clickwrap.render({ + agreementUrl: "<%= @agreementUrl.html_safe %>", + onAgreed: function () { + // Triggered if the user has just agreed + document.getElementById("agreementStatus").innerHTML = "<%= sanitize @manifest["SupportingTexts"]["HelpingTexts"]["AGREED"] %>"; + } + }, "#ds-terms-of-service"); +<% end %> diff --git a/app/views/clickwrap/index.html.erb b/app/views/clickwrap/index.html.erb index 643d0a4..2e8574f 100644 --- a/app/views/clickwrap/index.html.erb +++ b/app/views/clickwrap/index.html.erb @@ -28,7 +28,7 @@

    <%= group["Name"] %>

    <% group["Examples"].each { |example| %> - <% if not example["SkipLanguages"] or not example["SkipLanguages"].include? "ruby" %> + <% if not example["SkipForLanguages"] or not example["SkipForLanguages"].include? "ruby" %>

    "> "> <%= example["ExampleName"] %> diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index a10bfc7..3efc745 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -34,7 +34,7 @@

    <%= group["Name"] %>

    <% group["Examples"].each { |example| %> - <% if not example["SkipLanguages"] or not example["SkipLanguages"].include? "ruby" %> + <% if not example["SkipForLanguages"] or not example["SkipForLanguages"].include? "ruby" %> <% if @status_cfr && @status_cfr == "enabled" %> <% if example["CFREnabled"] == "AllAccounts" || example["CFREnabled"] == "CFROnly" %>

    "> diff --git a/app/views/monitor_api/index.html.erb b/app/views/monitor_api/index.html.erb index 0f6c745..ce443c2 100644 --- a/app/views/monitor_api/index.html.erb +++ b/app/views/monitor_api/index.html.erb @@ -26,7 +26,7 @@

    <%= group["Name"] %>

    <% group["Examples"].each { |example| %> - <% if not example["SkipLanguages"] or not example["SkipLanguages"].include? "ruby" %> + <% if not example["SkipForLanguages"] or not example["SkipForLanguages"].include? "ruby" %>

    "> "> <%= example["ExampleName"] %> diff --git a/app/views/room_api/index.html.erb b/app/views/room_api/index.html.erb index 02aa3e0..2aa929b 100644 --- a/app/views/room_api/index.html.erb +++ b/app/views/room_api/index.html.erb @@ -32,7 +32,7 @@

    <%= group["Name"] %>

    <% group["Examples"].each { |example| %> - <% if not example["SkipLanguages"] or not example["SkipLanguages"].include? "ruby" %> + <% if not example["SkipForLanguages"] or not example["SkipForLanguages"].include? "ruby" %>

    "> "> <%= example["ExampleName"] %> diff --git a/config/routes.rb b/config/routes.rb index 249f9eb..58ba44f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -48,6 +48,9 @@ get 'eg005' => 'eg005_clickwrap_responses#get' post 'eg005' => 'eg005_clickwrap_responses#create' + + get 'eg006' => 'eg006_embed_clickwrap#get' + post 'eg006' => 'eg006_embed_clickwrap#create' end end constraints ->(req) { req.session[:examples_API] == 'Monitor' } do From b6efede100572e06d3ce4aa25fa3fbf7ede4d0e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Dec 2022 19:56:10 +0000 Subject: [PATCH 175/363] Bump loofah from 2.18.0 to 2.19.1 in /quick_acg Bumps [loofah](https://github.com/flavorjones/loofah) from 2.18.0 to 2.19.1. - [Release notes](https://github.com/flavorjones/loofah/releases) - [Changelog](https://github.com/flavorjones/loofah/blob/main/CHANGELOG.md) - [Commits](https://github.com/flavorjones/loofah/compare/v2.18.0...v2.19.1) --- updated-dependencies: - dependency-name: loofah dependency-type: indirect ... Signed-off-by: dependabot[bot] --- quick_acg/Gemfile.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/quick_acg/Gemfile.lock b/quick_acg/Gemfile.lock index 0cdb2b7..d6a33a6 100644 --- a/quick_acg/Gemfile.lock +++ b/quick_acg/Gemfile.lock @@ -115,7 +115,7 @@ GEM listen (3.7.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.18.0) + loofah (2.19.1) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -127,11 +127,11 @@ GEM msgpack (1.5.3) multi_xml (0.6.0) nio4r (2.5.8) - nokogiri (1.13.6-x64-mingw32) + nokogiri (1.13.10-x64-mingw32) racc (~> 1.4) - nokogiri (1.13.6-x86_64-darwin) + nokogiri (1.13.10-x86_64-darwin) racc (~> 1.4) - nokogiri (1.13.6-x86_64-linux) + nokogiri (1.13.10-x86_64-linux) racc (~> 1.4) oauth2 (2.0.5) faraday (>= 0.17.3, < 3.0) @@ -160,7 +160,7 @@ GEM public_suffix (4.0.7) puma (4.3.12) nio4r (~> 2.0) - racc (1.6.0) + racc (1.6.1) rack (2.2.4) rack-protection (2.2.0) rack From 34523039ef01b017ce4f5a9e92db4a0a21ffd958 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Dec 2022 20:46:06 +0000 Subject: [PATCH 176/363] Bump loofah from 2.19.0 to 2.19.1 Bumps [loofah](https://github.com/flavorjones/loofah) from 2.19.0 to 2.19.1. - [Release notes](https://github.com/flavorjones/loofah/releases) - [Changelog](https://github.com/flavorjones/loofah/blob/main/CHANGELOG.md) - [Commits](https://github.com/flavorjones/loofah/compare/v2.19.0...v2.19.1) --- updated-dependencies: - dependency-name: loofah dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 3571ccb..a6e55fe 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -147,7 +147,7 @@ GEM listen (3.7.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.19.0) + loofah (2.19.1) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -167,9 +167,11 @@ GEM net-smtp (0.3.2) net-protocol nio4r (2.5.8) - nokogiri (1.13.8-x64-mingw-ucrt) + nokogiri (1.13.10-x64-mingw-ucrt) racc (~> 1.4) - nokogiri (1.13.8-x86_64-darwin) + nokogiri (1.13.10-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.13.10-x86_64-linux) racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) @@ -201,7 +203,7 @@ GEM public_suffix (5.0.0) puma (5.6.5) nio4r (~> 2.0) - racc (1.6.0) + racc (1.6.1) rack (2.2.4) rack-protection (3.0.2) rack @@ -299,6 +301,7 @@ GEM execjs (>= 0.3.0, < 3) unicode-display_width (2.3.0) version_gem (1.1.1) + wdm (0.1.1) web-console (4.2.0) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -314,6 +317,7 @@ GEM PLATFORMS x64-mingw-ucrt x86_64-darwin-21 + x86_64-linux DEPENDENCIES bootsnap (~> 1.7.3) @@ -322,7 +326,7 @@ DEPENDENCIES chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) docusign_admin (~> 1.1.0) - docusign_click (~> 1.2.0) + docusign_click (~> 1.2.2) docusign_esign (~> 3.19.0) docusign_monitor (~> 1.1.0) docusign_rooms (~> 1.2.0.rc1) From e89273241aeb77a21ed1e0535f1263e46a6a297d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 14:51:14 +0000 Subject: [PATCH 177/363] Bump rails-html-sanitizer from 1.4.3 to 1.4.4 Bumps [rails-html-sanitizer](https://github.com/rails/rails-html-sanitizer) from 1.4.3 to 1.4.4. - [Release notes](https://github.com/rails/rails-html-sanitizer/releases) - [Changelog](https://github.com/rails/rails-html-sanitizer/blob/master/CHANGELOG.md) - [Commits](https://github.com/rails/rails-html-sanitizer/compare/v1.4.3...v1.4.4) --- updated-dependencies: - dependency-name: rails-html-sanitizer dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 3571ccb..92f7697 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -147,7 +147,7 @@ GEM listen (3.7.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.19.0) + loofah (2.19.1) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -167,9 +167,11 @@ GEM net-smtp (0.3.2) net-protocol nio4r (2.5.8) - nokogiri (1.13.8-x64-mingw-ucrt) + nokogiri (1.13.10-x64-mingw-ucrt) racc (~> 1.4) - nokogiri (1.13.8-x86_64-darwin) + nokogiri (1.13.10-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.13.10-x86_64-linux) racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) @@ -201,7 +203,7 @@ GEM public_suffix (5.0.0) puma (5.6.5) nio4r (~> 2.0) - racc (1.6.0) + racc (1.6.1) rack (2.2.4) rack-protection (3.0.2) rack @@ -224,8 +226,8 @@ GEM rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.4.3) - loofah (~> 2.3) + rails-html-sanitizer (1.4.4) + loofah (~> 2.19, >= 2.19.1) railties (7.0.4) actionpack (= 7.0.4) activesupport (= 7.0.4) @@ -299,6 +301,7 @@ GEM execjs (>= 0.3.0, < 3) unicode-display_width (2.3.0) version_gem (1.1.1) + wdm (0.1.1) web-console (4.2.0) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -314,6 +317,7 @@ GEM PLATFORMS x64-mingw-ucrt x86_64-darwin-21 + x86_64-linux DEPENDENCIES bootsnap (~> 1.7.3) @@ -322,7 +326,7 @@ DEPENDENCIES chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) docusign_admin (~> 1.1.0) - docusign_click (~> 1.2.0) + docusign_click (~> 1.2.2) docusign_esign (~> 3.19.0) docusign_monitor (~> 1.1.0) docusign_rooms (~> 1.2.0.rc1) From 6aaca9fe6f3d5588a25bb7dfecee272a81be4ecd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 14:51:14 +0000 Subject: [PATCH 178/363] Bump rails-html-sanitizer from 1.4.3 to 1.4.4 in /quick_acg Bumps [rails-html-sanitizer](https://github.com/rails/rails-html-sanitizer) from 1.4.3 to 1.4.4. - [Release notes](https://github.com/rails/rails-html-sanitizer/releases) - [Changelog](https://github.com/rails/rails-html-sanitizer/blob/master/CHANGELOG.md) - [Commits](https://github.com/rails/rails-html-sanitizer/compare/v1.4.3...v1.4.4) --- updated-dependencies: - dependency-name: rails-html-sanitizer dependency-type: indirect ... Signed-off-by: dependabot[bot] --- quick_acg/Gemfile.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/quick_acg/Gemfile.lock b/quick_acg/Gemfile.lock index 0cdb2b7..a784e33 100644 --- a/quick_acg/Gemfile.lock +++ b/quick_acg/Gemfile.lock @@ -115,7 +115,7 @@ GEM listen (3.7.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.18.0) + loofah (2.19.1) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -127,11 +127,11 @@ GEM msgpack (1.5.3) multi_xml (0.6.0) nio4r (2.5.8) - nokogiri (1.13.6-x64-mingw32) + nokogiri (1.13.10-x64-mingw32) racc (~> 1.4) - nokogiri (1.13.6-x86_64-darwin) + nokogiri (1.13.10-x86_64-darwin) racc (~> 1.4) - nokogiri (1.13.6-x86_64-linux) + nokogiri (1.13.10-x86_64-linux) racc (~> 1.4) oauth2 (2.0.5) faraday (>= 0.17.3, < 3.0) @@ -160,7 +160,7 @@ GEM public_suffix (4.0.7) puma (4.3.12) nio4r (~> 2.0) - racc (1.6.0) + racc (1.6.1) rack (2.2.4) rack-protection (2.2.0) rack @@ -184,8 +184,8 @@ GEM rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.4.3) - loofah (~> 2.3) + rails-html-sanitizer (1.4.4) + loofah (~> 2.19, >= 2.19.1) railties (6.0.4.8) actionpack (= 6.0.4.8) activesupport (= 6.0.4.8) From 09b442910f767b9ebfb2860d259f4e8e44c48498 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Fri, 6 Jan 2023 00:40:54 +0200 Subject: [PATCH 179/363] Added search (#96) * added search and unit tests Co-authored-by: Karissa Jacobsen --- Gemfile | 5 +- Gemfile.lock | 11 +- app/assets/javascripts/search.js | 266 ++++++++++++++++ ...er.rb => aeg001_create_user_controller.rb} | 6 +- ...reate_active_clm_esign_user_controller.rb} | 6 +- ...eg003_bulk_export_user_data_controller.rb} | 6 +- ...er.rb => aeg004_import_user_controller.rb} | 6 +- ...er.rb => aeg005_audit_users_controller.rb} | 6 +- ...6_get_user_profile_by_email_controller.rb} | 6 +- ...get_user_profile_by_user_id_controller.rb} | 6 +- ..._product_permission_profile_controller.rb} | 6 +- ..._product_permission_profile_controller.rb} | 6 +- ... => ceg001_create_clickwrap_controller.rb} | 6 +- ...> ceg002_activate_clickwrap_controller.rb} | 6 +- ...reate_new_clickwrap_version_controller.rb} | 6 +- ...b => ceg004_list_clickwraps_controller.rb} | 6 +- ... ceg005_clickwrap_responses_controller.rb} | 6 +- ...b => ceg006_embed_clickwrap_controller.rb} | 8 +- app/controllers/ds_common_controller.rb | 79 ++--- ...=> eeg002_signing_via_email_controller.rb} | 6 +- ...rb => eeg003_list_envelopes_controller.rb} | 6 +- ....rb => eeg004_envelope_info_controller.rb} | 6 +- ... eeg005_envelope_recipients_controller.rb} | 6 +- ....rb => eeg006_envelope_docs_controller.rb} | 6 +- ... => eeg007_envelope_get_doc_controller.rb} | 6 +- ...b => eeg008_create_template_controller.rb} | 6 +- ...r.rb => eeg009_use_template_controller.rb} | 6 +- ... => eeg010_send_binary_docs_controller.rb} | 6 +- ... => eeg011_embedded_sending_controller.rb} | 6 +- ... => eeg012_embedded_console_controller.rb} | 6 +- ... eeg013_add_doc_to_template_controller.rb} | 6 +- ...b => eeg014_collect_payment_controller.rb} | 6 +- ...eg015_get_envelope_tab_data_controller.rb} | 6 +- ...eg016_set_envelope_tab_data_controller.rb} | 6 +- ...017_set_template_tab_values_controller.rb} | 7 +- ..._envelope_custom_field_data_controller.rb} | 6 +- ..._access_code_authentication_controller.rb} | 6 +- ...eeg020_phone_authentication_controller.rb} | 6 +- ...> eeg022_kba_authentication_controller.rb} | 6 +- ...> eeg023_idv_authentication_controller.rb} | 6 +- ...=> eeg024_permission_create_controller.rb} | 6 +- ..._permissions_set_user_group_controller.rb} | 6 +- ...sions_change_single_setting_controller.rb} | 6 +- ...> eeg027_permissions_delete_controller.rb} | 6 +- ...b => eeg028_brands_creating_controller.rb} | 6 +- ...29_brands_apply_to_envelope_controller.rb} | 6 +- ...30_brands_apply_to_template_controller.rb} | 6 +- ...g031_bulk_sending_envelopes_controller.rb} | 6 +- ...2_pauses_signature_workflow_controller.rb} | 6 +- ...unpauses_signature_workflow_controller.rb} | 6 +- ..._use_conditional_recipients_controller.rb} | 6 +- ...=> eeg035_scheduled_sending_controller.rb} | 6 +- ...b => eeg036_delayed_routing_controller.rb} | 6 +- ...r.rb => eeg037_sms_delivery_controller.rb} | 6 +- ...> eeg038_responsive_signing_controller.rb} | 6 +- ...=> eeg039_signing_in_person_controller.rb} | 4 +- ...040_set_document_visibility_controller.rb} | 6 +- ...eeg041_cfr_embedded_signing_controller.rb} | 6 +- ... => eeg001_embedded_signing_controller.rb} | 5 +- app/controllers/eg_controller.rb | 30 +- ...g001_get_monitoring_dataset_controller.rb} | 6 +- ...rb => meg002_post_web_query_controller.rb} | 6 +- ...eg001_create_room_with_data_controller.rb} | 6 +- ...2_create_room_with_template_controller.rb} | 6 +- ...eg003_export_data_from_room_controller.rb} | 6 +- ...=> reg004_add_forms_to_room_controller.rb} | 6 +- ...g005_get_rooms_with_filters_controller.rb} | 6 +- ..._external_form_fill_session_controller.rb} | 6 +- ...=> reg007_create_form_group_controller.rb} | 6 +- ...office_access_to_form_group_controller.rb} | 6 +- ...9_assign_form_to_form_group_controller.rb} | 6 +- app/helpers/application_helper.rb | 10 + .../eg017_set_template_tab_values_service.rb | 2 +- app/services/e_sign/get_data_service.rb | 2 +- app/services/jwt_auth/jwt_creator.rb | 22 +- app/services/utils.rb | 12 +- .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get_status.html.erb | 0 .../get.html.erb | 10 +- .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../results.html.erb | 0 app/views/ds_common/choose_api.erb | 19 -- app/views/ds_common/ds_must_authenticate.erb | 2 +- app/views/ds_common/index.html.erb | 117 +++---- .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../return.html.erb | 0 .../get.html.erb | 0 .../return.html.erb | 0 .../get.html.erb | 0 .../return.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 app/views/layouts/_head.erb | 3 - .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get.html.erb | 0 .../get_forms.html.erb | 0 .../get_rooms.html.erb | 0 .../get.html.erb | 0 .../get.erb | 0 .../get.erb | 0 app/views/room_api/return.html.erb | 2 +- config/appsettings.example.yml | 6 +- config/initializers/omniauth.rb | 6 +- config/routes.rb | 298 +++++++++--------- .../app/controllers/ds_common_controller.rb | 5 +- .../get.html.erb | 0 .../get.html.erb | 0 quick_acg/config/initializers/omniauth.rb | 6 +- quick_acg/config/routes.rb | 12 +- test/application_system_test_case.rb | 7 - test/controllers/.keep | 0 test/controllers/ds_controller_test.rb | 10 - ...eg002_signing_via_email_controller_test.rb | 15 - .../eg004_envelope_info_controller_test.rb | 15 - ...005_envelope_recipients_controller_test.rb | 15 - .../eg010_send_binary_docs_controller_test.rb | 15 - test/controllers/eg_controller_test.rb | 9 - .../embedded_signing_controller_test.rb | 15 - test/controllers/get_controller_test.rb | 10 - test/controllers/home_controller_test.rb | 10 - .../list_envelopes_controller_test.rb | 10 - test/eg001_embedded_signing_test.rb | 83 +++++ test/eg002_sign_via_email_test.rb | 139 ++++++++ test/eg008_create_template_test.rb | 143 +++++++++ test/eg009_use_template_test.rb | 81 +++++ test/eg013_add_doc_to_template_test.rb | 168 ++++++++++ test/eg017_set_template_tab_values_test.rb | 130 ++++++++ test/fixtures/.keep | 0 test/fixtures/files/.keep | 0 test/helpers/.keep | 0 test/integration/.keep | 0 test/mailers/.keep | 0 test/models/.keep | 0 test/run_tests.rb | 1 + test/system/.keep | 0 test/test_helper.rb | 142 ++++++++- 188 files changed, 1651 insertions(+), 688 deletions(-) create mode 100644 app/assets/javascripts/search.js rename app/controllers/admin_api/{eg001_create_user_controller.rb => aeg001_create_user_controller.rb} (92%) rename app/controllers/admin_api/{eg002_create_active_clm_esign_user_controller.rb => aeg002_create_active_clm_esign_user_controller.rb} (92%) rename app/controllers/admin_api/{eg003_bulk_export_user_data_controller.rb => aeg003_bulk_export_user_data_controller.rb} (88%) rename app/controllers/admin_api/{eg004_import_user_controller.rb => aeg004_import_user_controller.rb} (92%) rename app/controllers/admin_api/{eg005_audit_users_controller.rb => aeg005_audit_users_controller.rb} (84%) rename app/controllers/admin_api/{eg006_get_user_profile_by_email_controller.rb => aeg006_get_user_profile_by_email_controller.rb} (82%) rename app/controllers/admin_api/{eg007_get_user_profile_by_user_id_controller.rb => aeg007_get_user_profile_by_user_id_controller.rb} (82%) rename app/controllers/admin_api/{eg008_update_user_product_permission_profile_controller.rb => aeg008_update_user_product_permission_profile_controller.rb} (94%) rename app/controllers/admin_api/{eg009_delete_user_product_permission_profile_controller.rb => aeg009_delete_user_product_permission_profile_controller.rb} (94%) rename app/controllers/clickwrap/{eg001_create_clickwrap_controller.rb => ceg001_create_clickwrap_controller.rb} (82%) rename app/controllers/clickwrap/{eg002_activate_clickwrap_controller.rb => ceg002_activate_clickwrap_controller.rb} (80%) rename app/controllers/clickwrap/{eg003_create_new_clickwrap_version_controller.rb => ceg003_create_new_clickwrap_version_controller.rb} (80%) rename app/controllers/clickwrap/{eg004_list_clickwraps_controller.rb => ceg004_list_clickwraps_controller.rb} (77%) rename app/controllers/clickwrap/{eg005_clickwrap_responses_controller.rb => ceg005_clickwrap_responses_controller.rb} (79%) rename app/controllers/clickwrap/{eg006_embed_clickwrap_controller.rb => ceg006_embed_clickwrap_controller.rb} (86%) rename app/controllers/e_sign/{eg002_signing_via_email_controller.rb => eeg002_signing_via_email_controller.rb} (88%) rename app/controllers/e_sign/{eg003_list_envelopes_controller.rb => eeg003_list_envelopes_controller.rb} (77%) rename app/controllers/e_sign/{eg004_envelope_info_controller.rb => eeg004_envelope_info_controller.rb} (86%) rename app/controllers/e_sign/{eg005_envelope_recipients_controller.rb => eeg005_envelope_recipients_controller.rb} (86%) rename app/controllers/e_sign/{eg006_envelope_docs_controller.rb => eeg006_envelope_docs_controller.rb} (92%) rename app/controllers/e_sign/{eg007_envelope_get_doc_controller.rb => eeg007_envelope_get_doc_controller.rb} (88%) rename app/controllers/e_sign/{eg008_create_template_controller.rb => eeg008_create_template_controller.rb} (86%) rename app/controllers/e_sign/{eg009_use_template_controller.rb => eeg009_use_template_controller.rb} (89%) rename app/controllers/e_sign/{eg010_send_binary_docs_controller.rb => eeg010_send_binary_docs_controller.rb} (88%) rename app/controllers/e_sign/{eg011_embedded_sending_controller.rb => eeg011_embedded_sending_controller.rb} (85%) rename app/controllers/e_sign/{eg012_embedded_console_controller.rb => eeg012_embedded_console_controller.rb} (82%) rename app/controllers/e_sign/{eg013_add_doc_to_template_controller.rb => eeg013_add_doc_to_template_controller.rb} (92%) rename app/controllers/e_sign/{eg014_collect_payment_controller.rb => eeg014_collect_payment_controller.rb} (91%) rename app/controllers/e_sign/{eg015_get_envelope_tab_data_controller.rb => eeg015_get_envelope_tab_data_controller.rb} (80%) rename app/controllers/e_sign/{eg016_set_envelope_tab_data_controller.rb => eeg016_set_envelope_tab_data_controller.rb} (81%) rename app/controllers/e_sign/{eg017_set_template_tab_values_controller.rb => eeg017_set_template_tab_values_controller.rb} (79%) rename app/controllers/e_sign/{eg018_get_envelope_custom_field_data_controller.rb => eeg018_get_envelope_custom_field_data_controller.rb} (79%) rename app/controllers/e_sign/{eg019_access_code_authentication_controller.rb => eeg019_access_code_authentication_controller.rb} (85%) rename app/controllers/e_sign/{eg020_phone_authentication_controller.rb => eeg020_phone_authentication_controller.rb} (92%) rename app/controllers/e_sign/{eg022_kba_authentication_controller.rb => eeg022_kba_authentication_controller.rb} (84%) rename app/controllers/e_sign/{eg023_idv_authentication_controller.rb => eeg023_idv_authentication_controller.rb} (89%) rename app/controllers/e_sign/{eg024_permission_create_controller.rb => eeg024_permission_create_controller.rb} (82%) rename app/controllers/e_sign/{eg025_permissions_set_user_group_controller.rb => eeg025_permissions_set_user_group_controller.rb} (89%) rename app/controllers/e_sign/{eg026_permissions_change_single_setting_controller.rb => eeg026_permissions_change_single_setting_controller.rb} (87%) rename app/controllers/e_sign/{eg027_permissions_delete_controller.rb => eeg027_permissions_delete_controller.rb} (88%) rename app/controllers/e_sign/{eg028_brands_creating_controller.rb => eeg028_brands_creating_controller.rb} (84%) rename app/controllers/e_sign/{eg029_brands_apply_to_envelope_controller.rb => eeg029_brands_apply_to_envelope_controller.rb} (89%) rename app/controllers/e_sign/{eg030_brands_apply_to_template_controller.rb => eeg030_brands_apply_to_template_controller.rb} (92%) rename app/controllers/e_sign/{eg031_bulk_sending_envelopes_controller.rb => eeg031_bulk_sending_envelopes_controller.rb} (88%) rename app/controllers/e_sign/{eg032_pauses_signature_workflow_controller.rb => eeg032_pauses_signature_workflow_controller.rb} (87%) rename app/controllers/e_sign/{eg033_unpauses_signature_workflow_controller.rb => eeg033_unpauses_signature_workflow_controller.rb} (85%) rename app/controllers/e_sign/{eg034_use_conditional_recipients_controller.rb => eeg034_use_conditional_recipients_controller.rb} (91%) rename app/controllers/e_sign/{eg035_scheduled_sending_controller.rb => eeg035_scheduled_sending_controller.rb} (85%) rename app/controllers/e_sign/{eg036_delayed_routing_controller.rb => eeg036_delayed_routing_controller.rb} (90%) rename app/controllers/e_sign/{eg037_sms_delivery_controller.rb => eeg037_sms_delivery_controller.rb} (91%) rename app/controllers/e_sign/{eg038_responsive_signing_controller.rb => eeg038_responsive_signing_controller.rb} (83%) rename app/controllers/e_sign/{eg039_signing_in_person_controller.rb => eeg039_signing_in_person_controller.rb} (94%) rename app/controllers/e_sign/{eg040_set_document_visibility_controller.rb => eeg040_set_document_visibility_controller.rb} (92%) rename app/controllers/e_sign/{eg041_cfr_embedded_signing_controller.rb => eeg041_cfr_embedded_signing_controller.rb} (92%) rename app/controllers/{eg001_embedded_signing_controller.rb => eeg001_embedded_signing_controller.rb} (86%) rename app/controllers/monitor_api/{eg001_get_monitoring_dataset_controller.rb => meg001_get_monitoring_dataset_controller.rb} (83%) rename app/controllers/monitor_api/{eg002_post_web_query_controller.rb => meg002_post_web_query_controller.rb} (85%) rename app/controllers/room_api/{eg001_create_room_with_data_controller.rb => reg001_create_room_with_data_controller.rb} (83%) rename app/controllers/room_api/{eg002_create_room_with_template_controller.rb => reg002_create_room_with_template_controller.rb} (85%) rename app/controllers/room_api/{eg003_export_data_from_room_controller.rb => reg003_export_data_from_room_controller.rb} (80%) rename app/controllers/room_api/{eg004_add_forms_to_room_controller.rb => reg004_add_forms_to_room_controller.rb} (83%) rename app/controllers/room_api/{eg005_get_rooms_with_filters_controller.rb => reg005_get_rooms_with_filters_controller.rb} (81%) rename app/controllers/room_api/{eg006_create_an_external_form_fill_session_controller.rb => reg006_create_an_external_form_fill_session_controller.rb} (83%) rename app/controllers/room_api/{eg007_create_form_group_controller.rb => reg007_create_form_group_controller.rb} (78%) rename app/controllers/room_api/{eg008_grant_office_access_to_form_group_controller.rb => reg008_grant_office_access_to_form_group_controller.rb} (86%) rename app/controllers/room_api/{eg009_assign_form_to_form_group_controller.rb => reg009_assign_form_to_form_group_controller.rb} (87%) rename app/views/admin_api/{eg001_create_user => aeg001_create_user}/get.html.erb (100%) rename app/views/admin_api/{eg002_create_active_clm_esign_user => aeg002_create_active_clm_esign_user}/get.html.erb (100%) rename app/views/admin_api/{eg003_bulk_export_user_data => aeg003_bulk_export_user_data}/get.html.erb (100%) rename app/views/admin_api/{eg004_import_user => aeg004_import_user}/get.html.erb (100%) rename app/views/admin_api/{eg004_import_user => aeg004_import_user}/get_status.html.erb (100%) rename app/views/admin_api/{eg005_audit_users => aeg005_audit_users}/get.html.erb (96%) rename app/views/admin_api/{eg006_get_user_profile_by_email => aeg006_get_user_profile_by_email}/get.html.erb (100%) rename app/views/admin_api/{eg007_get_user_profile_by_user_id => aeg007_get_user_profile_by_user_id}/get.html.erb (100%) rename app/views/admin_api/{eg008_update_user_product_permission_profile => aeg008_update_user_product_permission_profile}/get.html.erb (100%) rename app/views/admin_api/{eg009_delete_user_product_permission_profile => aeg009_delete_user_product_permission_profile}/get.html.erb (100%) rename app/views/clickwrap/{eg001_create_clickwrap => ceg001_create_clickwrap}/get.html.erb (100%) rename app/views/clickwrap/{eg002_activate_clickwrap => ceg002_activate_clickwrap}/get.html.erb (100%) rename app/views/clickwrap/{eg003_create_new_clickwrap_version => ceg003_create_new_clickwrap_version}/get.html.erb (100%) rename app/views/clickwrap/{eg004_list_clickwraps => ceg004_list_clickwraps}/get.html.erb (100%) rename app/views/clickwrap/{eg005_clickwrap_responses => ceg005_clickwrap_responses}/get.html.erb (100%) rename app/views/clickwrap/{eg006_embed_clickwrap => ceg006_embed_clickwrap}/get.html.erb (100%) rename app/views/clickwrap/{eg006_embed_clickwrap => ceg006_embed_clickwrap}/results.html.erb (100%) delete mode 100644 app/views/ds_common/choose_api.erb rename app/views/e_sign/{eg002_signing_via_email => eeg002_signing_via_email}/get.html.erb (100%) rename app/views/e_sign/{eg003_list_envelopes => eeg003_list_envelopes}/get.html.erb (100%) rename app/views/e_sign/{eg004_envelope_info => eeg004_envelope_info}/get.html.erb (100%) rename app/views/e_sign/{eg005_envelope_recipients => eeg005_envelope_recipients}/get.html.erb (100%) rename app/views/e_sign/{eg006_envelope_docs => eeg006_envelope_docs}/get.html.erb (100%) rename app/views/e_sign/{eg007_envelope_get_doc => eeg007_envelope_get_doc}/get.html.erb (100%) rename app/views/e_sign/{eg008_create_template => eeg008_create_template}/get.html.erb (100%) rename app/views/e_sign/{eg009_use_template => eeg009_use_template}/get.html.erb (100%) rename app/views/e_sign/{eg010_send_binary_docs => eeg010_send_binary_docs}/get.html.erb (100%) rename app/views/e_sign/{eg011_embedded_sending => eeg011_embedded_sending}/get.html.erb (100%) rename app/views/e_sign/{eg012_embedded_console => eeg012_embedded_console}/get.html.erb (100%) rename app/views/e_sign/{eg013_add_doc_to_template => eeg013_add_doc_to_template}/get.html.erb (100%) rename app/views/e_sign/{eg014_collect_payment => eeg014_collect_payment}/get.html.erb (100%) rename app/views/e_sign/{eg015_get_envelope_tab_data => eeg015_get_envelope_tab_data}/get.html.erb (100%) rename app/views/e_sign/{eg016_set_envelope_tab_data => eeg016_set_envelope_tab_data}/get.html.erb (100%) rename app/views/e_sign/{eg017_set_template_tab_values => eeg017_set_template_tab_values}/get.html.erb (100%) rename app/views/e_sign/{eg018_get_envelope_custom_field_data => eeg018_get_envelope_custom_field_data}/get.html.erb (100%) rename app/views/e_sign/{eg019_access_code_authentication => eeg019_access_code_authentication}/get.html.erb (100%) rename app/views/e_sign/{eg020_phone_authentication => eeg020_phone_authentication}/get.html.erb (100%) rename app/views/e_sign/{eg022_kba_authentication => eeg022_kba_authentication}/get.html.erb (100%) rename app/views/e_sign/{eg023_idv_authentication => eeg023_idv_authentication}/get.html.erb (100%) rename app/views/e_sign/{eg024_permission_create => eeg024_permission_create}/get.html.erb (100%) rename app/views/e_sign/{eg025_permissions_set_user_group => eeg025_permissions_set_user_group}/get.html.erb (100%) rename app/views/e_sign/{eg026_permissions_change_single_setting => eeg026_permissions_change_single_setting}/get.html.erb (100%) rename app/views/e_sign/{eg027_permissions_delete => eeg027_permissions_delete}/get.html.erb (100%) rename app/views/e_sign/{eg028_brands_creating => eeg028_brands_creating}/get.html.erb (100%) rename app/views/e_sign/{eg029_brands_apply_to_envelope => eeg029_brands_apply_to_envelope}/get.html.erb (100%) rename app/views/e_sign/{eg030_brands_apply_to_template => eeg030_brands_apply_to_template}/get.html.erb (100%) rename app/views/e_sign/{eg031_bulk_sending_envelopes => eeg031_bulk_sending_envelopes}/get.html.erb (100%) rename app/views/e_sign/{eg032_pauses_signature_workflow => eeg032_pauses_signature_workflow}/get.html.erb (100%) rename app/views/e_sign/{eg032_pauses_signature_workflow => eeg032_pauses_signature_workflow}/return.html.erb (100%) rename app/views/e_sign/{eg033_unpauses_signature_workflow => eeg033_unpauses_signature_workflow}/get.html.erb (100%) rename app/views/e_sign/{eg033_unpauses_signature_workflow => eeg033_unpauses_signature_workflow}/return.html.erb (100%) rename app/views/e_sign/{eg034_use_conditional_recipients => eeg034_use_conditional_recipients}/get.html.erb (100%) rename app/views/e_sign/{eg034_use_conditional_recipients => eeg034_use_conditional_recipients}/return.html.erb (100%) rename app/views/e_sign/{eg035_scheduled_sending => eeg035_scheduled_sending}/get.html.erb (100%) rename app/views/e_sign/{eg036_delayed_routing => eeg036_delayed_routing}/get.html.erb (100%) rename app/views/e_sign/{eg037_sms_delivery => eeg037_sms_delivery}/get.html.erb (100%) rename app/views/e_sign/{eg038_responsive_signing => eeg038_responsive_signing}/get.html.erb (100%) rename app/views/e_sign/{eg039_signing_in_person => eeg039_signing_in_person}/get.html.erb (100%) rename app/views/e_sign/{eg040_set_document_visibility => eeg040_set_document_visibility}/get.html.erb (100%) rename app/views/e_sign/{eg041_cfr_embedded_signing => eeg041_cfr_embedded_signing}/get.html.erb (100%) rename app/views/{eg001_embedded_signing => eeg001_embedded_signing}/get.html.erb (100%) rename app/views/monitor_api/{eg001_get_monitoring_dataset => meg001_get_monitoring_dataset}/get.html.erb (100%) rename app/views/monitor_api/{eg002_post_web_query => meg002_post_web_query}/get.html.erb (100%) rename app/views/room_api/{eg001_create_room_with_data => reg001_create_room_with_data}/get.html.erb (100%) rename app/views/room_api/{eg002_create_room_with_template => reg002_create_room_with_template}/get.html.erb (100%) rename app/views/room_api/{eg003_export_data_from_room => reg003_export_data_from_room}/get.html.erb (100%) rename app/views/room_api/{eg004_add_forms_to_room => reg004_add_forms_to_room}/get.html.erb (100%) rename app/views/room_api/{eg005_get_rooms_with_filters => reg005_get_rooms_with_filters}/get.html.erb (100%) rename app/views/room_api/{eg006_create_an_external_form_fill_session => reg006_create_an_external_form_fill_session}/get_forms.html.erb (100%) rename app/views/room_api/{eg006_create_an_external_form_fill_session => reg006_create_an_external_form_fill_session}/get_rooms.html.erb (100%) rename app/views/room_api/{eg007_create_form_group => reg007_create_form_group}/get.html.erb (100%) rename app/views/room_api/{eg008_grant_office_access_to_form_group => reg008_grant_office_access_to_form_group}/get.erb (100%) rename app/views/room_api/{eg009_assign_form_to_form_group => reg009_assign_form_to_form_group}/get.erb (100%) rename quick_acg/app/views/e_sign/{eg041_cfr_embedded_signing => eeg041_cfr_embedded_signing}/get.html.erb (100%) rename quick_acg/app/views/{eg001_embedded_signing => eeg001_embedded_signing}/get.html.erb (100%) delete mode 100644 test/application_system_test_case.rb delete mode 100644 test/controllers/.keep delete mode 100644 test/controllers/ds_controller_test.rb delete mode 100644 test/controllers/eg002_signing_via_email_controller_test.rb delete mode 100644 test/controllers/eg004_envelope_info_controller_test.rb delete mode 100644 test/controllers/eg005_envelope_recipients_controller_test.rb delete mode 100644 test/controllers/eg010_send_binary_docs_controller_test.rb delete mode 100644 test/controllers/eg_controller_test.rb delete mode 100644 test/controllers/embedded_signing_controller_test.rb delete mode 100644 test/controllers/get_controller_test.rb delete mode 100644 test/controllers/home_controller_test.rb delete mode 100644 test/controllers/list_envelopes_controller_test.rb create mode 100644 test/eg001_embedded_signing_test.rb create mode 100644 test/eg002_sign_via_email_test.rb create mode 100644 test/eg008_create_template_test.rb create mode 100644 test/eg009_use_template_test.rb create mode 100644 test/eg013_add_doc_to_template_test.rb create mode 100644 test/eg017_set_template_tab_values_test.rb delete mode 100644 test/fixtures/.keep delete mode 100644 test/fixtures/files/.keep delete mode 100644 test/helpers/.keep delete mode 100644 test/integration/.keep delete mode 100644 test/mailers/.keep delete mode 100644 test/models/.keep create mode 100644 test/run_tests.rb delete mode 100644 test/system/.keep diff --git a/Gemfile b/Gemfile index 9df5ac4..bb0f9e0 100644 --- a/Gemfile +++ b/Gemfile @@ -65,11 +65,12 @@ group :test do gem 'selenium-webdriver', '~> 3.142.7' # Easy installation and use of chromedriver to run system tests with Chrome gem 'chromedriver-helper', '~> 2.1.1' + gem 'test-unit' end gem 'docusign_admin', '~> 1.1.0' gem 'docusign_click', '~> 1.2.2' -gem 'docusign_esign', '~> 3.19.0' +gem 'docusign_esign', '~> 3.20.0' gem 'docusign_monitor', '~> 1.1.0' gem 'docusign_rooms', '~> 1.2.0.rc1' gem 'omniauth-oauth2', '~> 1.7.1' @@ -78,3 +79,5 @@ gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', '~> 1.2022.1', '>= 1.2022.1' gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] + +gem "matrix", "~> 0.4.2" diff --git a/Gemfile.lock b/Gemfile.lock index 92f7697..60446ea 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -108,7 +108,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.19.0) + docusign_esign (3.20.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -153,6 +153,7 @@ GEM mail (2.7.1) mini_mime (>= 0.1.1) marcel (1.0.2) + matrix (0.4.2) method_source (0.9.2) mini_mime (1.1.2) minitest (5.16.3) @@ -193,6 +194,7 @@ GEM parallel (1.22.1) parser (3.1.2.1) ast (~> 2.4.1) + power_assert (2.0.1) pry (0.12.2) coderay (~> 1.1.0) method_source (~> 0.9.0) @@ -285,6 +287,8 @@ GEM activesupport (>= 5.2) sprockets (>= 3.0.0) sqlite3 (1.4.4) + test-unit (3.5.3) + power_assert thor (1.2.1) tilt (2.0.11) timeout (0.3.0) @@ -301,7 +305,6 @@ GEM execjs (>= 0.3.0, < 3) unicode-display_width (2.3.0) version_gem (1.1.1) - wdm (0.1.1) web-console (4.2.0) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -327,11 +330,12 @@ DEPENDENCIES coffee-rails (~> 5.0.0) docusign_admin (~> 1.1.0) docusign_click (~> 1.2.2) - docusign_esign (~> 3.19.0) + docusign_esign (~> 3.20.0) docusign_monitor (~> 1.1.0) docusign_rooms (~> 1.2.0.rc1) jbuilder (~> 2.11.5) listen (~> 3.7.1) + matrix (~> 0.4.2) omniauth-oauth2 (~> 1.7.1) omniauth-rails_csrf_protection pry-nav (~> 0.3.0) @@ -344,6 +348,7 @@ DEPENDENCIES spring (~> 2.1.0) spring-watcher-listen (~> 2.0.1) sqlite3 (~> 1.4.4) + test-unit turbolinks (~> 5.2.1) tzinfo-data (~> 1.2022.1, >= 1.2022.1) uglifier (~> 4.2.0) diff --git a/app/assets/javascripts/search.js b/app/assets/javascripts/search.js new file mode 100644 index 0000000..66ec52f --- /dev/null +++ b/app/assets/javascripts/search.js @@ -0,0 +1,266 @@ +const DS_SEARCH = (function () { + const API_TYPES = { + ESIGNATURE: "esignature", + MONITOR: "monitor", + CLICK: "click", + ROOMS: "rooms", + ADMIN: "admin", + }; + + const processJSONData = function () { + const json_raw = $("#api_json_data").text(); + const 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); + } + } + } + + const 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; + } + + const getExamplesByAPIType = function (apiType, codeExamples) { + let codeExamplesByAPI = codeExamples.find( + (x) => x.Name.toLowerCase() === apiType + ); + + if (codeExamplesByAPI != null) { + return [codeExamplesByAPI]; + } else { + return null; + } + }; + + const 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 "aeg"; + case API_TYPES.CLICK: + return "ceg"; + case API_TYPES.ROOMS: + return "reg"; + case API_TYPES.MONITOR: + return "meg"; + case API_TYPES.ESIGNATURE: + return "eg"; + } + } + + 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("c#")) { + if (element.Name.toLowerCase() !== API_TYPES.ESIGNATURE.toLowerCase() || + ((example.CFREnabled == "AllAccounts") || + ((cfrPart11 == "enabled") && (example.CFREnabled == "CFROnly")) || + ((cfrPart11 != "enabled") && (example.CFREnabled == "NonCFR")))) { + $("#filtered_code_examples").append( + "

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

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

    " + example.ExampleDescription + "

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

    "); + + 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("

    "); + } + } + } + ); + } + ); + } + ); +} + + const 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]); + }); + } + } + } +} \ No newline at end of file diff --git a/app/controllers/admin_api/eg001_create_user_controller.rb b/app/controllers/admin_api/aeg001_create_user_controller.rb similarity index 92% rename from app/controllers/admin_api/eg001_create_user_controller.rb rename to app/controllers/admin_api/aeg001_create_user_controller.rb index e906caa..87cdf46 100644 --- a/app/controllers/admin_api/eg001_create_user_controller.rb +++ b/app/controllers/admin_api/aeg001_create_user_controller.rb @@ -1,7 +1,7 @@ -class AdminApi::Eg001CreateUserController < EgController +class AdminApi::Aeg001CreateUserController < EgController include ApiCreator - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1) } + before_action -> { check_auth('Admin') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1, 'Admin') } def create args = { diff --git a/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb b/app/controllers/admin_api/aeg002_create_active_clm_esign_user_controller.rb similarity index 92% rename from app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb rename to app/controllers/admin_api/aeg002_create_active_clm_esign_user_controller.rb index b813ddf..dce0b8e 100644 --- a/app/controllers/admin_api/eg002_create_active_clm_esign_user_controller.rb +++ b/app/controllers/admin_api/aeg002_create_active_clm_esign_user_controller.rb @@ -1,6 +1,6 @@ -class AdminApi::Eg002CreateActiveClmEsignUserController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2) } +class AdminApi::Aeg002CreateActiveClmEsignUserController < EgController + before_action -> { check_auth('Admin') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2, 'Admin') } def create args = { diff --git a/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb b/app/controllers/admin_api/aeg003_bulk_export_user_data_controller.rb similarity index 88% rename from app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb rename to app/controllers/admin_api/aeg003_bulk_export_user_data_controller.rb index 6177eda..d79423a 100644 --- a/app/controllers/admin_api/eg003_bulk_export_user_data_controller.rb +++ b/app/controllers/admin_api/aeg003_bulk_export_user_data_controller.rb @@ -1,6 +1,6 @@ -class AdminApi::Eg003BulkExportUserDataController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 3) } +class AdminApi::Aeg003BulkExportUserDataController < EgController + before_action -> { check_auth('Admin') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 3, 'Admin') } def create session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? diff --git a/app/controllers/admin_api/eg004_import_user_controller.rb b/app/controllers/admin_api/aeg004_import_user_controller.rb similarity index 92% rename from app/controllers/admin_api/eg004_import_user_controller.rb rename to app/controllers/admin_api/aeg004_import_user_controller.rb index b1f0dcf..90dce63 100644 --- a/app/controllers/admin_api/eg004_import_user_controller.rb +++ b/app/controllers/admin_api/aeg004_import_user_controller.rb @@ -1,6 +1,6 @@ -class AdminApi::Eg004ImportUserController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 4) } +class AdminApi::Aeg004ImportUserController < EgController + before_action -> { check_auth('Admin') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 4, 'Admin') } def create session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? diff --git a/app/controllers/admin_api/eg005_audit_users_controller.rb b/app/controllers/admin_api/aeg005_audit_users_controller.rb similarity index 84% rename from app/controllers/admin_api/eg005_audit_users_controller.rb rename to app/controllers/admin_api/aeg005_audit_users_controller.rb index 70c7a95..4b65c56 100644 --- a/app/controllers/admin_api/eg005_audit_users_controller.rb +++ b/app/controllers/admin_api/aeg005_audit_users_controller.rb @@ -1,6 +1,6 @@ -class AdminApi::Eg005AuditUsersController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 5) } +class AdminApi::Aeg005AuditUsersController < EgController + before_action -> { check_auth('Admin') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 5, 'Admin') } def create session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? diff --git a/app/controllers/admin_api/eg006_get_user_profile_by_email_controller.rb b/app/controllers/admin_api/aeg006_get_user_profile_by_email_controller.rb similarity index 82% rename from app/controllers/admin_api/eg006_get_user_profile_by_email_controller.rb rename to app/controllers/admin_api/aeg006_get_user_profile_by_email_controller.rb index 51858f8..0af11c3 100644 --- a/app/controllers/admin_api/eg006_get_user_profile_by_email_controller.rb +++ b/app/controllers/admin_api/aeg006_get_user_profile_by_email_controller.rb @@ -1,7 +1,7 @@ -class AdminApi::Eg006GetUserProfileByEmailController < EgController +class AdminApi::Aeg006GetUserProfileByEmailController < EgController include ApiCreator - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 6) } + before_action -> { check_auth('Admin') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 6, 'Admin') } def create session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? diff --git a/app/controllers/admin_api/eg007_get_user_profile_by_user_id_controller.rb b/app/controllers/admin_api/aeg007_get_user_profile_by_user_id_controller.rb similarity index 82% rename from app/controllers/admin_api/eg007_get_user_profile_by_user_id_controller.rb rename to app/controllers/admin_api/aeg007_get_user_profile_by_user_id_controller.rb index d3e06e0..d21f01e 100644 --- a/app/controllers/admin_api/eg007_get_user_profile_by_user_id_controller.rb +++ b/app/controllers/admin_api/aeg007_get_user_profile_by_user_id_controller.rb @@ -1,7 +1,7 @@ -class AdminApi::Eg007GetUserProfileByUserIdController < EgController +class AdminApi::Aeg007GetUserProfileByUserIdController < EgController include ApiCreator - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 7) } + before_action -> { check_auth('Admin') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 7, 'Admin') } def create session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? diff --git a/app/controllers/admin_api/eg008_update_user_product_permission_profile_controller.rb b/app/controllers/admin_api/aeg008_update_user_product_permission_profile_controller.rb similarity index 94% rename from app/controllers/admin_api/eg008_update_user_product_permission_profile_controller.rb rename to app/controllers/admin_api/aeg008_update_user_product_permission_profile_controller.rb index bbca1f0..e5fef15 100644 --- a/app/controllers/admin_api/eg008_update_user_product_permission_profile_controller.rb +++ b/app/controllers/admin_api/aeg008_update_user_product_permission_profile_controller.rb @@ -1,6 +1,6 @@ -class AdminApi::Eg008UpdateUserProductPermissionProfileController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 8) } +class AdminApi::Aeg008UpdateUserProductPermissionProfileController < EgController + before_action -> { check_auth('Admin') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 8, 'Admin') } def create clm_email = session[:clm_email] diff --git a/app/controllers/admin_api/eg009_delete_user_product_permission_profile_controller.rb b/app/controllers/admin_api/aeg009_delete_user_product_permission_profile_controller.rb similarity index 94% rename from app/controllers/admin_api/eg009_delete_user_product_permission_profile_controller.rb rename to app/controllers/admin_api/aeg009_delete_user_product_permission_profile_controller.rb index 52c6183..e5fb322 100644 --- a/app/controllers/admin_api/eg009_delete_user_product_permission_profile_controller.rb +++ b/app/controllers/admin_api/aeg009_delete_user_product_permission_profile_controller.rb @@ -1,6 +1,6 @@ -class AdminApi::Eg009DeleteUserProductPermissionProfileController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 9) } +class AdminApi::Aeg009DeleteUserProductPermissionProfileController < EgController + before_action -> { check_auth('Admin') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 9, 'Admin') } def create clm_email = session[:clm_email] diff --git a/app/controllers/clickwrap/eg001_create_clickwrap_controller.rb b/app/controllers/clickwrap/ceg001_create_clickwrap_controller.rb similarity index 82% rename from app/controllers/clickwrap/eg001_create_clickwrap_controller.rb rename to app/controllers/clickwrap/ceg001_create_clickwrap_controller.rb index e6b4eb4..ccaa8a6 100644 --- a/app/controllers/clickwrap/eg001_create_clickwrap_controller.rb +++ b/app/controllers/clickwrap/ceg001_create_clickwrap_controller.rb @@ -1,6 +1,6 @@ -class Clickwrap::Eg001CreateClickwrapController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1) } +class Clickwrap::Ceg001CreateClickwrapController < EgController + before_action -> { check_auth('Click') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1, 'Click') } def create args = { diff --git a/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb b/app/controllers/clickwrap/ceg002_activate_clickwrap_controller.rb similarity index 80% rename from app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb rename to app/controllers/clickwrap/ceg002_activate_clickwrap_controller.rb index d6c8782..a5108cd 100644 --- a/app/controllers/clickwrap/eg002_activate_clickwrap_controller.rb +++ b/app/controllers/clickwrap/ceg002_activate_clickwrap_controller.rb @@ -1,6 +1,6 @@ -class Clickwrap::Eg002ActivateClickwrapController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2) } +class Clickwrap::Ceg002ActivateClickwrapController < EgController + before_action -> { check_auth('Click') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2, 'Click') } def create args = { diff --git a/app/controllers/clickwrap/eg003_create_new_clickwrap_version_controller.rb b/app/controllers/clickwrap/ceg003_create_new_clickwrap_version_controller.rb similarity index 80% rename from app/controllers/clickwrap/eg003_create_new_clickwrap_version_controller.rb rename to app/controllers/clickwrap/ceg003_create_new_clickwrap_version_controller.rb index a77e347..73f5f6a 100644 --- a/app/controllers/clickwrap/eg003_create_new_clickwrap_version_controller.rb +++ b/app/controllers/clickwrap/ceg003_create_new_clickwrap_version_controller.rb @@ -1,6 +1,6 @@ -class Clickwrap::Eg003CreateNewClickwrapVersionController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 3) } +class Clickwrap::Ceg003CreateNewClickwrapVersionController < EgController + before_action -> { check_auth('Click') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 3, 'Click') } def create args = { diff --git a/app/controllers/clickwrap/eg004_list_clickwraps_controller.rb b/app/controllers/clickwrap/ceg004_list_clickwraps_controller.rb similarity index 77% rename from app/controllers/clickwrap/eg004_list_clickwraps_controller.rb rename to app/controllers/clickwrap/ceg004_list_clickwraps_controller.rb index c5ce68b..a734dc0 100644 --- a/app/controllers/clickwrap/eg004_list_clickwraps_controller.rb +++ b/app/controllers/clickwrap/ceg004_list_clickwraps_controller.rb @@ -1,6 +1,6 @@ -class Clickwrap::Eg004ListClickwrapsController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 4) } +class Clickwrap::Ceg004ListClickwrapsController < EgController + before_action -> { check_auth('Click') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 4, 'Click') } def create args = { diff --git a/app/controllers/clickwrap/eg005_clickwrap_responses_controller.rb b/app/controllers/clickwrap/ceg005_clickwrap_responses_controller.rb similarity index 79% rename from app/controllers/clickwrap/eg005_clickwrap_responses_controller.rb rename to app/controllers/clickwrap/ceg005_clickwrap_responses_controller.rb index e2cbaef..6de4326 100644 --- a/app/controllers/clickwrap/eg005_clickwrap_responses_controller.rb +++ b/app/controllers/clickwrap/ceg005_clickwrap_responses_controller.rb @@ -1,6 +1,6 @@ -class Clickwrap::Eg005ClickwrapResponsesController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 5) } +class Clickwrap::Ceg005ClickwrapResponsesController < EgController + before_action -> { check_auth('Click') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 5, 'Click') } def create args = { diff --git a/app/controllers/clickwrap/eg006_embed_clickwrap_controller.rb b/app/controllers/clickwrap/ceg006_embed_clickwrap_controller.rb similarity index 86% rename from app/controllers/clickwrap/eg006_embed_clickwrap_controller.rb rename to app/controllers/clickwrap/ceg006_embed_clickwrap_controller.rb index df57dfd..98970b6 100644 --- a/app/controllers/clickwrap/eg006_embed_clickwrap_controller.rb +++ b/app/controllers/clickwrap/ceg006_embed_clickwrap_controller.rb @@ -1,6 +1,6 @@ -class Clickwrap::Eg006EmbedClickwrapController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 6) } +class Clickwrap::Ceg006EmbedClickwrapController < EgController + before_action -> { check_auth('Click') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 6, 'Click') } def create begin @@ -26,7 +26,7 @@ def create @title = @example['ExampleName'] @message = format_string(@example['ResultsPageText']) @agreementUrl = results["agreementUrl"] - render 'clickwrap/eg006_embed_clickwrap/results' + render 'clickwrap/ceg006_embed_clickwrap/results' end rescue DocuSign_Click::ApiError => e handle_error(e) diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index b9d8ea5..4423c13 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -12,63 +12,48 @@ def index def handle_redirects minimum_buffer_min = 10 if Rails.configuration.quickstart - @manifest = Utils::ManifestUtils.new.get_manifest(Rails.configuration.eSignManifestUrl) + @manifest = Utils::ManifestUtils.new.get_manifest(Rails.configuration.example_manifest_url) if session[:quickstarted].nil? - session[:examples_API] = 'eSignature' + session[:api] = 'eSignature' session[:quickstarted] = true redirect_to '/auth/docusign' elsif session[:been_here].nil? enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) if enableCFR == "enabled" session[:status_cfr] = "enabled" - redirect_to '/eg041' + @status_cfr = session[:status_cfr] + redirect_to '/eeg041' else - redirect_to '/eg001' + redirect_to '/eeg001' end else render_examples end elsif session[:ds_access_token].present? - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) - if enableCFR == "enabled" - session[:status_cfr] = "enabled" + if (!session[:api] || session[:api] == "eSignature") + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) + if enableCFR == "enabled" + session[:status_cfr] = "enabled" + end end - render_examples + render_examples else render_examples end end def render_examples - load_corresponding_manifest - - if session[:examples_API].nil? - choose_api - elsif session[:examples_API] == 'Rooms' - render 'room_api/index' - elsif session[:examples_API] == 'Click' - render 'clickwrap/index' - elsif session[:examples_API] == 'Monitor' - render 'monitor_api/index' - elsif session[:examples_API] == 'Admin' - render 'admin_api/index' + if(session[:ds_access_token].present? && !session[:status_cfr] && (!session[:api] || session[:api] == "eSignature")) + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) + if enableCFR == "enabled" + @status_cfr = "enabled" + session[:status_cfr] = "enabled" + end else @status_cfr = session[:status_cfr] - session[:examples_API] = 'eSignature' - render 'ds_common/index' end - end - - def choose_api - load_corresponding_manifest - render 'ds_common/choose_api' - end - - def api_selected - session.delete :eg - session[:examples_API] = params[:chosen_api] - redirect_to '/ds/mustAuthenticate' + load_manifest end def ds_return @@ -81,10 +66,10 @@ def ds_return end def ds_must_authenticate - load_corresponding_manifest + load_manifest - jwt_auth if session[:examples_API] == 'Monitor' - redirect_to '/auth/docusign' if Rails.configuration.quickstart && session[:been_here].nil? && (session[:examples_API] == 'eSignature') + jwt_auth if session[:api] == 'Monitor' + redirect_to '/auth/docusign' if Rails.configuration.quickstart && session[:been_here].nil? @title = 'Authenticate with DocuSign' @show_doc = Rails.application.config.documentation @@ -105,10 +90,10 @@ def jwt_auth end else session['omniauth.state'] = SecureRandom.hex - url = JwtAuth::JwtCreator.consent_url(session['omniauth.state'], session['examples_API']) + url = JwtAuth::JwtCreator.consent_url(session['omniauth.state'], session['api']) redirect_to root_path if session[:token].present? end - case session[:examples_API] + case session[:api] when 'Rooms' configuration = DocuSign_Rooms::Configuration.new DocuSign_Rooms::ApiClient.new(configuration) @@ -130,21 +115,7 @@ def error; end private - def load_corresponding_manifest - manifest_url = if session[:examples_API].nil? - Rails.configuration.eSignManifestUrl - elsif session[:examples_API] == 'Rooms' - Rails.configuration.roomsManifestUrl - elsif session[:examples_API] == 'Click' - Rails.configuration.clickManifestUrl - elsif session[:examples_API] == 'Monitor' - Rails.configuration.monitorManifestUrl - elsif session[:examples_API] == 'Admin' - Rails.configuration.adminManifestUrl - else - Rails.configuration.eSignManifestUrl - end - - @manifest = Utils::ManifestUtils.new.get_manifest(manifest_url) + def load_manifest + @manifest = Utils::ManifestUtils.new.get_manifest(Rails.configuration.example_manifest_url) end end diff --git a/app/controllers/e_sign/eg002_signing_via_email_controller.rb b/app/controllers/e_sign/eeg002_signing_via_email_controller.rb similarity index 88% rename from app/controllers/e_sign/eg002_signing_via_email_controller.rb rename to app/controllers/e_sign/eeg002_signing_via_email_controller.rb index f446636..a606a2c 100644 --- a/app/controllers/e_sign/eg002_signing_via_email_controller.rb +++ b/app/controllers/e_sign/eeg002_signing_via_email_controller.rb @@ -2,9 +2,9 @@ require_relative '../../services/utils' -class ESign::Eg002SigningViaEmailController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2) } +class ESign::Eeg002SigningViaEmailController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2, 'eSignature') } def create envelope_args = { diff --git a/app/controllers/e_sign/eg003_list_envelopes_controller.rb b/app/controllers/e_sign/eeg003_list_envelopes_controller.rb similarity index 77% rename from app/controllers/e_sign/eg003_list_envelopes_controller.rb rename to app/controllers/e_sign/eeg003_list_envelopes_controller.rb index f6d4442..459a242 100644 --- a/app/controllers/e_sign/eg003_list_envelopes_controller.rb +++ b/app/controllers/e_sign/eeg003_list_envelopes_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg003ListEnvelopesController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 3) } +class ESign::Eeg003ListEnvelopesController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 3, 'eSignature') } def create args = { diff --git a/app/controllers/e_sign/eg004_envelope_info_controller.rb b/app/controllers/e_sign/eeg004_envelope_info_controller.rb similarity index 86% rename from app/controllers/e_sign/eg004_envelope_info_controller.rb rename to app/controllers/e_sign/eeg004_envelope_info_controller.rb index 8a96792..ea10ea1 100644 --- a/app/controllers/e_sign/eg004_envelope_info_controller.rb +++ b/app/controllers/e_sign/eeg004_envelope_info_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg004EnvelopeInfoController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 4) } +class ESign::Eeg004EnvelopeInfoController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 4, 'eSignature') } def create envelope_id = session[:envelope_id] diff --git a/app/controllers/e_sign/eg005_envelope_recipients_controller.rb b/app/controllers/e_sign/eeg005_envelope_recipients_controller.rb similarity index 86% rename from app/controllers/e_sign/eg005_envelope_recipients_controller.rb rename to app/controllers/e_sign/eeg005_envelope_recipients_controller.rb index a346c70..a5d962d 100644 --- a/app/controllers/e_sign/eg005_envelope_recipients_controller.rb +++ b/app/controllers/e_sign/eeg005_envelope_recipients_controller.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true -class ESign::Eg005EnvelopeRecipientsController < EgController +class ESign::Eeg005EnvelopeRecipientsController < EgController include ApiCreator - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 5) } + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 5, 'eSignature') } skip_before_action :set_meta def create diff --git a/app/controllers/e_sign/eg006_envelope_docs_controller.rb b/app/controllers/e_sign/eeg006_envelope_docs_controller.rb similarity index 92% rename from app/controllers/e_sign/eg006_envelope_docs_controller.rb rename to app/controllers/e_sign/eeg006_envelope_docs_controller.rb index e404cb0..4eb859d 100644 --- a/app/controllers/e_sign/eg006_envelope_docs_controller.rb +++ b/app/controllers/e_sign/eeg006_envelope_docs_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg006EnvelopeDocsController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 6) } +class ESign::Eeg006EnvelopeDocsController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 6, 'eSignature') } def create envelope_id = session[:envelope_id] diff --git a/app/controllers/e_sign/eg007_envelope_get_doc_controller.rb b/app/controllers/e_sign/eeg007_envelope_get_doc_controller.rb similarity index 88% rename from app/controllers/e_sign/eg007_envelope_get_doc_controller.rb rename to app/controllers/e_sign/eeg007_envelope_get_doc_controller.rb index 8363f94..59303a8 100644 --- a/app/controllers/e_sign/eg007_envelope_get_doc_controller.rb +++ b/app/controllers/e_sign/eeg007_envelope_get_doc_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg007EnvelopeGetDocController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 7) } +class ESign::Eeg007EnvelopeGetDocController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 7, 'eSignature') } def create envelope_id = session[:envelope_id] diff --git a/app/controllers/e_sign/eg008_create_template_controller.rb b/app/controllers/e_sign/eeg008_create_template_controller.rb similarity index 86% rename from app/controllers/e_sign/eg008_create_template_controller.rb rename to app/controllers/e_sign/eeg008_create_template_controller.rb index 53bdb43..44a4f3d 100644 --- a/app/controllers/e_sign/eg008_create_template_controller.rb +++ b/app/controllers/e_sign/eeg008_create_template_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg008CreateTemplateController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 8) } +class ESign::Eeg008CreateTemplateController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 8, 'eSignature') } def create args = { diff --git a/app/controllers/e_sign/eg009_use_template_controller.rb b/app/controllers/e_sign/eeg009_use_template_controller.rb similarity index 89% rename from app/controllers/e_sign/eg009_use_template_controller.rb rename to app/controllers/e_sign/eeg009_use_template_controller.rb index fc98f48..62a1c7d 100644 --- a/app/controllers/e_sign/eg009_use_template_controller.rb +++ b/app/controllers/e_sign/eeg009_use_template_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg009UseTemplateController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 9) } +class ESign::Eeg009UseTemplateController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 9, 'eSignature') } def create template_id = session[:template_id] diff --git a/app/controllers/e_sign/eg010_send_binary_docs_controller.rb b/app/controllers/e_sign/eeg010_send_binary_docs_controller.rb similarity index 88% rename from app/controllers/e_sign/eg010_send_binary_docs_controller.rb rename to app/controllers/e_sign/eeg010_send_binary_docs_controller.rb index f0ed354..4039f64 100644 --- a/app/controllers/e_sign/eg010_send_binary_docs_controller.rb +++ b/app/controllers/e_sign/eeg010_send_binary_docs_controller.rb @@ -1,6 +1,6 @@ -class ESign::Eg010SendBinaryDocsController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 10) } +class ESign::Eeg010SendBinaryDocsController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 10, 'eSignature') } def create envelope_args = { diff --git a/app/controllers/e_sign/eg011_embedded_sending_controller.rb b/app/controllers/e_sign/eeg011_embedded_sending_controller.rb similarity index 85% rename from app/controllers/e_sign/eg011_embedded_sending_controller.rb rename to app/controllers/e_sign/eeg011_embedded_sending_controller.rb index 7e19c58..ad1f9ac 100644 --- a/app/controllers/e_sign/eg011_embedded_sending_controller.rb +++ b/app/controllers/e_sign/eeg011_embedded_sending_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg011EmbeddedSendingController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 11) } +class ESign::Eeg011EmbeddedSendingController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 11, 'eSignature') } def create envelope_args = { diff --git a/app/controllers/e_sign/eg012_embedded_console_controller.rb b/app/controllers/e_sign/eeg012_embedded_console_controller.rb similarity index 82% rename from app/controllers/e_sign/eg012_embedded_console_controller.rb rename to app/controllers/e_sign/eeg012_embedded_console_controller.rb index 68e1131..b2dc4cf 100644 --- a/app/controllers/e_sign/eg012_embedded_console_controller.rb +++ b/app/controllers/e_sign/eeg012_embedded_console_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg012EmbeddedConsoleController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 12) } +class ESign::Eeg012EmbeddedConsoleController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 12, 'eSignature') } def create envelope_id = session[:envelope_id] diff --git a/app/controllers/e_sign/eg013_add_doc_to_template_controller.rb b/app/controllers/e_sign/eeg013_add_doc_to_template_controller.rb similarity index 92% rename from app/controllers/e_sign/eg013_add_doc_to_template_controller.rb rename to app/controllers/e_sign/eeg013_add_doc_to_template_controller.rb index 302eb47..7bc2333 100644 --- a/app/controllers/e_sign/eg013_add_doc_to_template_controller.rb +++ b/app/controllers/e_sign/eeg013_add_doc_to_template_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg013AddDocToTemplateController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 13) } +class ESign::Eeg013AddDocToTemplateController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 13, 'eSignature') } def create template_id = session[:template_id] diff --git a/app/controllers/e_sign/eg014_collect_payment_controller.rb b/app/controllers/e_sign/eeg014_collect_payment_controller.rb similarity index 91% rename from app/controllers/e_sign/eg014_collect_payment_controller.rb rename to app/controllers/e_sign/eeg014_collect_payment_controller.rb index ef10847..182a2b8 100644 --- a/app/controllers/e_sign/eg014_collect_payment_controller.rb +++ b/app/controllers/e_sign/eeg014_collect_payment_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg014CollectPaymentController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 14) } +class ESign::Eeg014CollectPaymentController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 14, 'eSignature') } def create begin diff --git a/app/controllers/e_sign/eg015_get_envelope_tab_data_controller.rb b/app/controllers/e_sign/eeg015_get_envelope_tab_data_controller.rb similarity index 80% rename from app/controllers/e_sign/eg015_get_envelope_tab_data_controller.rb rename to app/controllers/e_sign/eeg015_get_envelope_tab_data_controller.rb index 313eaf9..f47566b 100644 --- a/app/controllers/e_sign/eg015_get_envelope_tab_data_controller.rb +++ b/app/controllers/e_sign/eeg015_get_envelope_tab_data_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg015GetEnvelopeTabDataController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 15) } +class ESign::Eeg015GetEnvelopeTabDataController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 15, 'eSignature') } def create envelope_id = session[:envelope_id] diff --git a/app/controllers/e_sign/eg016_set_envelope_tab_data_controller.rb b/app/controllers/e_sign/eeg016_set_envelope_tab_data_controller.rb similarity index 81% rename from app/controllers/e_sign/eg016_set_envelope_tab_data_controller.rb rename to app/controllers/e_sign/eeg016_set_envelope_tab_data_controller.rb index ce0cb67..ee9357f 100644 --- a/app/controllers/e_sign/eg016_set_envelope_tab_data_controller.rb +++ b/app/controllers/e_sign/eeg016_set_envelope_tab_data_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg016SetEnvelopeTabDataController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 16) } +class ESign::Eeg016SetEnvelopeTabDataController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 16, 'eSignature') } def create args = { diff --git a/app/controllers/e_sign/eg017_set_template_tab_values_controller.rb b/app/controllers/e_sign/eeg017_set_template_tab_values_controller.rb similarity index 79% rename from app/controllers/e_sign/eg017_set_template_tab_values_controller.rb rename to app/controllers/e_sign/eeg017_set_template_tab_values_controller.rb index bf1ee0b..6837932 100644 --- a/app/controllers/e_sign/eg017_set_template_tab_values_controller.rb +++ b/app/controllers/e_sign/eeg017_set_template_tab_values_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg017SetTemplateTabValuesController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 17) } +class ESign::Eeg017SetTemplateTabValuesController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 17, 'eSignature') } def create template_id = session[:template_id] @@ -13,6 +13,7 @@ def create signer_name: params['signerName'], cc_email: params['ccEmail'], cc_name: params['ccName'], + ds_ping_url: Rails.application.config.app_url, template_id: template_id } args = { diff --git a/app/controllers/e_sign/eg018_get_envelope_custom_field_data_controller.rb b/app/controllers/e_sign/eeg018_get_envelope_custom_field_data_controller.rb similarity index 79% rename from app/controllers/e_sign/eg018_get_envelope_custom_field_data_controller.rb rename to app/controllers/e_sign/eeg018_get_envelope_custom_field_data_controller.rb index d5fad90..cd05b28 100644 --- a/app/controllers/e_sign/eg018_get_envelope_custom_field_data_controller.rb +++ b/app/controllers/e_sign/eeg018_get_envelope_custom_field_data_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg018GetEnvelopeCustomFieldDataController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 18) } +class ESign::Eeg018GetEnvelopeCustomFieldDataController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 18, 'eSignature') } def create envelope_id = session[:envelope_id] diff --git a/app/controllers/e_sign/eg019_access_code_authentication_controller.rb b/app/controllers/e_sign/eeg019_access_code_authentication_controller.rb similarity index 85% rename from app/controllers/e_sign/eg019_access_code_authentication_controller.rb rename to app/controllers/e_sign/eeg019_access_code_authentication_controller.rb index 2649447..eb02c89 100644 --- a/app/controllers/e_sign/eg019_access_code_authentication_controller.rb +++ b/app/controllers/e_sign/eeg019_access_code_authentication_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg019AccessCodeAuthenticationController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 19) } +class ESign::Eeg019AccessCodeAuthenticationController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 19, 'eSignature') } def create # ***DS.snippet.0.start diff --git a/app/controllers/e_sign/eg020_phone_authentication_controller.rb b/app/controllers/e_sign/eeg020_phone_authentication_controller.rb similarity index 92% rename from app/controllers/e_sign/eg020_phone_authentication_controller.rb rename to app/controllers/e_sign/eeg020_phone_authentication_controller.rb index 8ac3505..930aeac 100644 --- a/app/controllers/e_sign/eg020_phone_authentication_controller.rb +++ b/app/controllers/e_sign/eeg020_phone_authentication_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg020PhoneAuthenticationController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 20) } +class ESign::Eeg020PhoneAuthenticationController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 20, 'eSignature') } def create envelope_args = { diff --git a/app/controllers/e_sign/eg022_kba_authentication_controller.rb b/app/controllers/e_sign/eeg022_kba_authentication_controller.rb similarity index 84% rename from app/controllers/e_sign/eg022_kba_authentication_controller.rb rename to app/controllers/e_sign/eeg022_kba_authentication_controller.rb index 3fcce4f..25da5a1 100644 --- a/app/controllers/e_sign/eg022_kba_authentication_controller.rb +++ b/app/controllers/e_sign/eeg022_kba_authentication_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg022KbaAuthenticationController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 22) } +class ESign::Eeg022KbaAuthenticationController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 22, 'eSignature') } def create envelope_args = { diff --git a/app/controllers/e_sign/eg023_idv_authentication_controller.rb b/app/controllers/e_sign/eeg023_idv_authentication_controller.rb similarity index 89% rename from app/controllers/e_sign/eg023_idv_authentication_controller.rb rename to app/controllers/e_sign/eeg023_idv_authentication_controller.rb index 8c9e48f..9620368 100644 --- a/app/controllers/e_sign/eg023_idv_authentication_controller.rb +++ b/app/controllers/e_sign/eeg023_idv_authentication_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg023IdvAuthenticationController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 23) } +class ESign::Eeg023IdvAuthenticationController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 23, 'eSignature') } def create envelope_args = { diff --git a/app/controllers/e_sign/eg024_permission_create_controller.rb b/app/controllers/e_sign/eeg024_permission_create_controller.rb similarity index 82% rename from app/controllers/e_sign/eg024_permission_create_controller.rb rename to app/controllers/e_sign/eeg024_permission_create_controller.rb index d61342d..d477569 100644 --- a/app/controllers/e_sign/eg024_permission_create_controller.rb +++ b/app/controllers/e_sign/eeg024_permission_create_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg024PermissionCreateController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 24) } +class ESign::Eeg024PermissionCreateController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 24, 'eSignature') } def create args = { diff --git a/app/controllers/e_sign/eg025_permissions_set_user_group_controller.rb b/app/controllers/e_sign/eeg025_permissions_set_user_group_controller.rb similarity index 89% rename from app/controllers/e_sign/eg025_permissions_set_user_group_controller.rb rename to app/controllers/e_sign/eeg025_permissions_set_user_group_controller.rb index 0408c70..505dd15 100644 --- a/app/controllers/e_sign/eg025_permissions_set_user_group_controller.rb +++ b/app/controllers/e_sign/eeg025_permissions_set_user_group_controller.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true -class ESign::Eg025PermissionsSetUserGroupController < EgController +class ESign::Eeg025PermissionsSetUserGroupController < EgController include ApiCreator - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 25) } + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 25, 'eSignature') } def get args = { diff --git a/app/controllers/e_sign/eg026_permissions_change_single_setting_controller.rb b/app/controllers/e_sign/eeg026_permissions_change_single_setting_controller.rb similarity index 87% rename from app/controllers/e_sign/eg026_permissions_change_single_setting_controller.rb rename to app/controllers/e_sign/eeg026_permissions_change_single_setting_controller.rb index a7f2573..9929a49 100644 --- a/app/controllers/e_sign/eg026_permissions_change_single_setting_controller.rb +++ b/app/controllers/e_sign/eeg026_permissions_change_single_setting_controller.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true -class ESign::Eg026PermissionsChangeSingleSettingController < EgController +class ESign::Eeg026PermissionsChangeSingleSettingController < EgController include ApiCreator - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 26) } + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 26, 'eSignature') } def get args = { diff --git a/app/controllers/e_sign/eg027_permissions_delete_controller.rb b/app/controllers/e_sign/eeg027_permissions_delete_controller.rb similarity index 88% rename from app/controllers/e_sign/eg027_permissions_delete_controller.rb rename to app/controllers/e_sign/eeg027_permissions_delete_controller.rb index a98f7a0..95291b4 100644 --- a/app/controllers/e_sign/eg027_permissions_delete_controller.rb +++ b/app/controllers/e_sign/eeg027_permissions_delete_controller.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true -class ESign::Eg027PermissionsDeleteController < EgController +class ESign::Eeg027PermissionsDeleteController < EgController include ApiCreator - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 27) } + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 27, 'eSignature') } def get args = { diff --git a/app/controllers/e_sign/eg028_brands_creating_controller.rb b/app/controllers/e_sign/eeg028_brands_creating_controller.rb similarity index 84% rename from app/controllers/e_sign/eg028_brands_creating_controller.rb rename to app/controllers/e_sign/eeg028_brands_creating_controller.rb index 1cf1ae2..6de5bec 100644 --- a/app/controllers/e_sign/eg028_brands_creating_controller.rb +++ b/app/controllers/e_sign/eeg028_brands_creating_controller.rb @@ -1,6 +1,6 @@ -class ESign::Eg028BrandsCreatingController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 28) } +class ESign::Eeg028BrandsCreatingController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 28, 'eSignature') } def create args = { diff --git a/app/controllers/e_sign/eg029_brands_apply_to_envelope_controller.rb b/app/controllers/e_sign/eeg029_brands_apply_to_envelope_controller.rb similarity index 89% rename from app/controllers/e_sign/eg029_brands_apply_to_envelope_controller.rb rename to app/controllers/e_sign/eeg029_brands_apply_to_envelope_controller.rb index 116f45d..5b13850 100644 --- a/app/controllers/e_sign/eg029_brands_apply_to_envelope_controller.rb +++ b/app/controllers/e_sign/eeg029_brands_apply_to_envelope_controller.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true -class ESign::Eg029BrandsApplyToEnvelopeController < EgController +class ESign::Eeg029BrandsApplyToEnvelopeController < EgController include ApiCreator - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 29) } + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 29, 'eSignature') } def get args = { diff --git a/app/controllers/e_sign/eg030_brands_apply_to_template_controller.rb b/app/controllers/e_sign/eeg030_brands_apply_to_template_controller.rb similarity index 92% rename from app/controllers/e_sign/eg030_brands_apply_to_template_controller.rb rename to app/controllers/e_sign/eeg030_brands_apply_to_template_controller.rb index 6adc75e..0bdbc01 100644 --- a/app/controllers/e_sign/eg030_brands_apply_to_template_controller.rb +++ b/app/controllers/e_sign/eeg030_brands_apply_to_template_controller.rb @@ -1,9 +1,9 @@ # frozen_string_literal: truebrand_lists = accounts_api.list_brands(args[:account_id], options = DocuSign_eSign::ListBrandsOptions.default) -class ESign::Eg030BrandsApplyToTemplateController < EgController +class ESign::Eeg030BrandsApplyToTemplateController < EgController include ApiCreator - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 30) } + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 30, 'eSignature') } def get args = { diff --git a/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb b/app/controllers/e_sign/eeg031_bulk_sending_envelopes_controller.rb similarity index 88% rename from app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb rename to app/controllers/e_sign/eeg031_bulk_sending_envelopes_controller.rb index cd425aa..a4b4e84 100644 --- a/app/controllers/e_sign/eg031_bulk_sending_envelopes_controller.rb +++ b/app/controllers/e_sign/eeg031_bulk_sending_envelopes_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg031BulkSendingEnvelopesController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 31) } +class ESign::Eeg031BulkSendingEnvelopesController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 31, 'eSignature') } def create signers = { diff --git a/app/controllers/e_sign/eg032_pauses_signature_workflow_controller.rb b/app/controllers/e_sign/eeg032_pauses_signature_workflow_controller.rb similarity index 87% rename from app/controllers/e_sign/eg032_pauses_signature_workflow_controller.rb rename to app/controllers/e_sign/eeg032_pauses_signature_workflow_controller.rb index 66c009e..6dec56d 100644 --- a/app/controllers/e_sign/eg032_pauses_signature_workflow_controller.rb +++ b/app/controllers/e_sign/eeg032_pauses_signature_workflow_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg032PausesSignatureWorkflowController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 32) } +class ESign::Eeg032PausesSignatureWorkflowController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 32, 'eSignature') } def create signers = { diff --git a/app/controllers/e_sign/eg033_unpauses_signature_workflow_controller.rb b/app/controllers/e_sign/eeg033_unpauses_signature_workflow_controller.rb similarity index 85% rename from app/controllers/e_sign/eg033_unpauses_signature_workflow_controller.rb rename to app/controllers/e_sign/eeg033_unpauses_signature_workflow_controller.rb index 6b65217..a791a82 100644 --- a/app/controllers/e_sign/eg033_unpauses_signature_workflow_controller.rb +++ b/app/controllers/e_sign/eeg033_unpauses_signature_workflow_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg033UnpausesSignatureWorkflowController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 33) } +class ESign::Eeg033UnpausesSignatureWorkflowController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 33, 'eSignature') } def update args = { diff --git a/app/controllers/e_sign/eg034_use_conditional_recipients_controller.rb b/app/controllers/e_sign/eeg034_use_conditional_recipients_controller.rb similarity index 91% rename from app/controllers/e_sign/eg034_use_conditional_recipients_controller.rb rename to app/controllers/e_sign/eeg034_use_conditional_recipients_controller.rb index d5ce4a5..38f3d48 100644 --- a/app/controllers/e_sign/eg034_use_conditional_recipients_controller.rb +++ b/app/controllers/e_sign/eeg034_use_conditional_recipients_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg034UseConditionalRecipientsController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 34) } +class ESign::Eeg034UseConditionalRecipientsController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 34, 'eSignature') } def create begin diff --git a/app/controllers/e_sign/eg035_scheduled_sending_controller.rb b/app/controllers/e_sign/eeg035_scheduled_sending_controller.rb similarity index 85% rename from app/controllers/e_sign/eg035_scheduled_sending_controller.rb rename to app/controllers/e_sign/eeg035_scheduled_sending_controller.rb index 76b1ad4..ee6a766 100644 --- a/app/controllers/e_sign/eg035_scheduled_sending_controller.rb +++ b/app/controllers/e_sign/eeg035_scheduled_sending_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg035ScheduledSendingController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 35) } +class ESign::Eeg035ScheduledSendingController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 35, 'eSignature') } def create envelope_args = { diff --git a/app/controllers/e_sign/eg036_delayed_routing_controller.rb b/app/controllers/e_sign/eeg036_delayed_routing_controller.rb similarity index 90% rename from app/controllers/e_sign/eg036_delayed_routing_controller.rb rename to app/controllers/e_sign/eeg036_delayed_routing_controller.rb index 2c3b5e5..7860c41 100644 --- a/app/controllers/e_sign/eg036_delayed_routing_controller.rb +++ b/app/controllers/e_sign/eeg036_delayed_routing_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg036DelayedRoutingController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 36) } +class ESign::Eeg036DelayedRoutingController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 36, 'eSignature') } def create begin diff --git a/app/controllers/e_sign/eg037_sms_delivery_controller.rb b/app/controllers/e_sign/eeg037_sms_delivery_controller.rb similarity index 91% rename from app/controllers/e_sign/eg037_sms_delivery_controller.rb rename to app/controllers/e_sign/eeg037_sms_delivery_controller.rb index b3efa8c..d02bf4e 100644 --- a/app/controllers/e_sign/eg037_sms_delivery_controller.rb +++ b/app/controllers/e_sign/eeg037_sms_delivery_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg037SmsDeliveryController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 37) } +class ESign::Eeg037SmsDeliveryController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 37, 'eSignature') } def create begin diff --git a/app/controllers/e_sign/eg038_responsive_signing_controller.rb b/app/controllers/e_sign/eeg038_responsive_signing_controller.rb similarity index 83% rename from app/controllers/e_sign/eg038_responsive_signing_controller.rb rename to app/controllers/e_sign/eeg038_responsive_signing_controller.rb index 3615836..cd05084 100644 --- a/app/controllers/e_sign/eg038_responsive_signing_controller.rb +++ b/app/controllers/e_sign/eeg038_responsive_signing_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg038ResponsiveSigningController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 38) } +class ESign::Eeg038ResponsiveSigningController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 38, 'eSignature') } def create args = { diff --git a/app/controllers/e_sign/eg039_signing_in_person_controller.rb b/app/controllers/e_sign/eeg039_signing_in_person_controller.rb similarity index 94% rename from app/controllers/e_sign/eg039_signing_in_person_controller.rb rename to app/controllers/e_sign/eeg039_signing_in_person_controller.rb index 84f3659..a5b1a10 100644 --- a/app/controllers/e_sign/eg039_signing_in_person_controller.rb +++ b/app/controllers/e_sign/eeg039_signing_in_person_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -class ESign::Eg039SigningInPersonController < EgController - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 39) } +class ESign::Eeg039SigningInPersonController < EgController + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 39, 'eSignature') } def create minimum_buffer_min = 10 diff --git a/app/controllers/e_sign/eg040_set_document_visibility_controller.rb b/app/controllers/e_sign/eeg040_set_document_visibility_controller.rb similarity index 92% rename from app/controllers/e_sign/eg040_set_document_visibility_controller.rb rename to app/controllers/e_sign/eeg040_set_document_visibility_controller.rb index 8d7eeec..d04643d 100644 --- a/app/controllers/e_sign/eg040_set_document_visibility_controller.rb +++ b/app/controllers/e_sign/eeg040_set_document_visibility_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -class ESign::Eg040SetDocumentVisibilityController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 40) } +class ESign::Eeg040SetDocumentVisibilityController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 40, 'eSignature') } def create envelope_args = { diff --git a/app/controllers/e_sign/eg041_cfr_embedded_signing_controller.rb b/app/controllers/e_sign/eeg041_cfr_embedded_signing_controller.rb similarity index 92% rename from app/controllers/e_sign/eg041_cfr_embedded_signing_controller.rb rename to app/controllers/e_sign/eeg041_cfr_embedded_signing_controller.rb index bb10f88..eea2290 100644 --- a/app/controllers/e_sign/eg041_cfr_embedded_signing_controller.rb +++ b/app/controllers/e_sign/eeg041_cfr_embedded_signing_controller.rb @@ -2,9 +2,9 @@ require_relative '../../services/utils' -class ESign::Eg041CfrEmbeddedSigningController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 41) } +class ESign::Eeg041CfrEmbeddedSigningController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 41, 'eSignature') } def create pdf_file_path = 'data/World_Wide_Corp_lorem.pdf' diff --git a/app/controllers/eg001_embedded_signing_controller.rb b/app/controllers/eeg001_embedded_signing_controller.rb similarity index 86% rename from app/controllers/eg001_embedded_signing_controller.rb rename to app/controllers/eeg001_embedded_signing_controller.rb index 0de17e9..3fd25de 100644 --- a/app/controllers/eg001_embedded_signing_controller.rb +++ b/app/controllers/eeg001_embedded_signing_controller.rb @@ -1,8 +1,7 @@ # frozen_string_literal: true -class Eg001EmbeddedSigningController < EgController - before_action :check_auth - # before_action -> { @manifest = Utils::ManifestUtils.new.get_manifest(Rails.configuration.eSignManifestUrl)} +class Eeg001EmbeddedSigningController < EgController + before_action -> { check_auth('eSignature') } before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1) } def create diff --git a/app/controllers/eg_controller.rb b/app/controllers/eg_controller.rb index 1faa174..7534b52 100644 --- a/app/controllers/eg_controller.rb +++ b/app/controllers/eg_controller.rb @@ -13,7 +13,7 @@ def eg_name end def set_eg - session[:eg] = controller_name.to(4) + session[:eg] = controller_name.to(5) end def get @@ -65,7 +65,17 @@ def param_gsub(parameter) parameter.gsub(/([^\w \-@.,])+/, '') end - def check_auth + def check_auth(api) + # if not authorized for same API type example or + # if it is an attempt to authorize from home page + # then user will be redirected to login page + unless (session[:api] == api) || ((api == 'eSignature') && !session[:api]) + session[:api] = api + params[:auth] = 'jwt-auth' if api == 'Monitor' + + return redirect_to '/ds/mustAuthenticate' + end + minimum_buffer_min = 10 token_ok = check_token(minimum_buffer_min) return if token_ok @@ -88,21 +98,7 @@ def create_source_path end def ensure_manifest - manifest_url = case session[:examples_API] - when 'Rooms' - Rails.configuration.roomsManifestUrl - when 'Click' - Rails.configuration.clickManifestUrl - when 'Monitor' - Rails.configuration.monitorManifestUrl - when 'Admin' - Rails.configuration.adminManifestUrl - else - Rails.configuration.eSignManifestUrl - end - - manifest = Utils::ManifestUtils.new.get_manifest(manifest_url) - @manifest = manifest + @manifest = Utils::ManifestUtils.new.get_manifest(Rails.configuration.example_manifest_url) end def format_string(string, *args) diff --git a/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb b/app/controllers/monitor_api/meg001_get_monitoring_dataset_controller.rb similarity index 83% rename from app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb rename to app/controllers/monitor_api/meg001_get_monitoring_dataset_controller.rb index 953dbc3..c3783ec 100644 --- a/app/controllers/monitor_api/eg001_get_monitoring_dataset_controller.rb +++ b/app/controllers/monitor_api/meg001_get_monitoring_dataset_controller.rb @@ -1,6 +1,6 @@ -class MonitorApi::Eg001GetMonitoringDatasetController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1) } +class MonitorApi::Meg001GetMonitoringDatasetController < EgController + before_action -> { check_auth('Monitor') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1, 'Monitor') } def create args = { diff --git a/app/controllers/monitor_api/eg002_post_web_query_controller.rb b/app/controllers/monitor_api/meg002_post_web_query_controller.rb similarity index 85% rename from app/controllers/monitor_api/eg002_post_web_query_controller.rb rename to app/controllers/monitor_api/meg002_post_web_query_controller.rb index d1270d4..f23cc66 100644 --- a/app/controllers/monitor_api/eg002_post_web_query_controller.rb +++ b/app/controllers/monitor_api/meg002_post_web_query_controller.rb @@ -1,6 +1,6 @@ -class MonitorApi::Eg002PostWebQueryController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2) } +class MonitorApi::Meg002PostWebQueryController < EgController + before_action -> { check_auth('Monitor') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2, 'Monitor') } def create args = { diff --git a/app/controllers/room_api/eg001_create_room_with_data_controller.rb b/app/controllers/room_api/reg001_create_room_with_data_controller.rb similarity index 83% rename from app/controllers/room_api/eg001_create_room_with_data_controller.rb rename to app/controllers/room_api/reg001_create_room_with_data_controller.rb index e1fdacb..d753a00 100644 --- a/app/controllers/room_api/eg001_create_room_with_data_controller.rb +++ b/app/controllers/room_api/reg001_create_room_with_data_controller.rb @@ -1,6 +1,6 @@ -class RoomApi::Eg001CreateRoomWithDataController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1) } +class RoomApi::Reg001CreateRoomWithDataController < EgController + before_action -> { check_auth('Rooms') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1, 'Rooms') } def create args = { diff --git a/app/controllers/room_api/eg002_create_room_with_template_controller.rb b/app/controllers/room_api/reg002_create_room_with_template_controller.rb similarity index 85% rename from app/controllers/room_api/eg002_create_room_with_template_controller.rb rename to app/controllers/room_api/reg002_create_room_with_template_controller.rb index 2a7048a..7d0ddfb 100644 --- a/app/controllers/room_api/eg002_create_room_with_template_controller.rb +++ b/app/controllers/room_api/reg002_create_room_with_template_controller.rb @@ -1,6 +1,6 @@ -class RoomApi::Eg002CreateRoomWithTemplateController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2) } +class RoomApi::Reg002CreateRoomWithTemplateController < EgController + before_action -> { check_auth('Rooms') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2, 'Rooms') } def create args = { diff --git a/app/controllers/room_api/eg003_export_data_from_room_controller.rb b/app/controllers/room_api/reg003_export_data_from_room_controller.rb similarity index 80% rename from app/controllers/room_api/eg003_export_data_from_room_controller.rb rename to app/controllers/room_api/reg003_export_data_from_room_controller.rb index 9c72229..e4a36a2 100644 --- a/app/controllers/room_api/eg003_export_data_from_room_controller.rb +++ b/app/controllers/room_api/reg003_export_data_from_room_controller.rb @@ -1,6 +1,6 @@ -class RoomApi::Eg003ExportDataFromRoomController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 3) } +class RoomApi::Reg003ExportDataFromRoomController < EgController + before_action -> { check_auth('Rooms') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 3, 'Rooms') } def create args = { diff --git a/app/controllers/room_api/eg004_add_forms_to_room_controller.rb b/app/controllers/room_api/reg004_add_forms_to_room_controller.rb similarity index 83% rename from app/controllers/room_api/eg004_add_forms_to_room_controller.rb rename to app/controllers/room_api/reg004_add_forms_to_room_controller.rb index a6e08f6..4c5a2b3 100644 --- a/app/controllers/room_api/eg004_add_forms_to_room_controller.rb +++ b/app/controllers/room_api/reg004_add_forms_to_room_controller.rb @@ -1,6 +1,6 @@ -class RoomApi::Eg004AddFormsToRoomController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 4) } +class RoomApi::Reg004AddFormsToRoomController < EgController + before_action -> { check_auth('Rooms') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 4, 'Rooms') } def create args = { diff --git a/app/controllers/room_api/eg005_get_rooms_with_filters_controller.rb b/app/controllers/room_api/reg005_get_rooms_with_filters_controller.rb similarity index 81% rename from app/controllers/room_api/eg005_get_rooms_with_filters_controller.rb rename to app/controllers/room_api/reg005_get_rooms_with_filters_controller.rb index 729497b..35bb503 100644 --- a/app/controllers/room_api/eg005_get_rooms_with_filters_controller.rb +++ b/app/controllers/room_api/reg005_get_rooms_with_filters_controller.rb @@ -1,6 +1,6 @@ -class RoomApi::Eg005GetRoomsWithFiltersController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 5) } +class RoomApi::Reg005GetRoomsWithFiltersController < EgController + before_action -> { check_auth('Rooms') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 5, 'Rooms') } def create args = { diff --git a/app/controllers/room_api/eg006_create_an_external_form_fill_session_controller.rb b/app/controllers/room_api/reg006_create_an_external_form_fill_session_controller.rb similarity index 83% rename from app/controllers/room_api/eg006_create_an_external_form_fill_session_controller.rb rename to app/controllers/room_api/reg006_create_an_external_form_fill_session_controller.rb index 5084696..6d3814d 100644 --- a/app/controllers/room_api/eg006_create_an_external_form_fill_session_controller.rb +++ b/app/controllers/room_api/reg006_create_an_external_form_fill_session_controller.rb @@ -1,6 +1,6 @@ -class RoomApi::Eg006CreateAnExternalFormFillSessionController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 6) } +class RoomApi::Reg006CreateAnExternalFormFillSessionController < EgController + before_action -> { check_auth('Rooms') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 6, 'Rooms') } def create args = { diff --git a/app/controllers/room_api/eg007_create_form_group_controller.rb b/app/controllers/room_api/reg007_create_form_group_controller.rb similarity index 78% rename from app/controllers/room_api/eg007_create_form_group_controller.rb rename to app/controllers/room_api/reg007_create_form_group_controller.rb index ccd6c6a..4ae34d6 100644 --- a/app/controllers/room_api/eg007_create_form_group_controller.rb +++ b/app/controllers/room_api/reg007_create_form_group_controller.rb @@ -1,6 +1,6 @@ -class RoomApi::Eg007CreateFormGroupController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 7) } +class RoomApi::Reg007CreateFormGroupController < EgController + before_action -> { check_auth('Rooms') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 7, 'Rooms') } def create args = { diff --git a/app/controllers/room_api/eg008_grant_office_access_to_form_group_controller.rb b/app/controllers/room_api/reg008_grant_office_access_to_form_group_controller.rb similarity index 86% rename from app/controllers/room_api/eg008_grant_office_access_to_form_group_controller.rb rename to app/controllers/room_api/reg008_grant_office_access_to_form_group_controller.rb index ea9c120..83a57c6 100644 --- a/app/controllers/room_api/eg008_grant_office_access_to_form_group_controller.rb +++ b/app/controllers/room_api/reg008_grant_office_access_to_form_group_controller.rb @@ -1,6 +1,6 @@ -class RoomApi::Eg008GrantOfficeAccessToFormGroupController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 8) } +class RoomApi::Reg008GrantOfficeAccessToFormGroupController < EgController + before_action -> { check_auth('Rooms') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 8, 'Rooms') } def create args = { diff --git a/app/controllers/room_api/eg009_assign_form_to_form_group_controller.rb b/app/controllers/room_api/reg009_assign_form_to_form_group_controller.rb similarity index 87% rename from app/controllers/room_api/eg009_assign_form_to_form_group_controller.rb rename to app/controllers/room_api/reg009_assign_form_to_form_group_controller.rb index 03958e6..761fb7b 100644 --- a/app/controllers/room_api/eg009_assign_form_to_form_group_controller.rb +++ b/app/controllers/room_api/reg009_assign_form_to_form_group_controller.rb @@ -1,6 +1,6 @@ -class RoomApi::Eg009AssignFormToFormGroupController < EgController - before_action :check_auth - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 9) } +class RoomApi::Reg009AssignFormToFormGroupController < EgController + before_action -> { check_auth('Rooms') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 9, 'Rooms') } def create args = { diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index edbd83e..765de0d 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,7 +1,17 @@ # frozen_string_literal: true module ApplicationHelper + require 'json/ext' + def format_string(string, *args) string.gsub(/\{(\d+)\}/) { |s| args[s.to_i] } end + + def to_json(hash) + hash.to_json + end + + def example_available?(example) + !(example['SkipForLanguages']) or !example['SkipForLanguages'].include? 'ruby' + end end diff --git a/app/services/e_sign/eg017_set_template_tab_values_service.rb b/app/services/e_sign/eg017_set_template_tab_values_service.rb index a444a7a..e4214be 100644 --- a/app/services/e_sign/eg017_set_template_tab_values_service.rb +++ b/app/services/e_sign/eg017_set_template_tab_values_service.rb @@ -11,7 +11,7 @@ def initialize(args) # ***DS.snippet.0.start def worker - ds_ping_url = Rails.application.config.app_url + ds_ping_url = args[:ds_ping_url] ds_return_url = "#{ds_ping_url}/ds_common-return" signer_client_id = 1000 envelope_args = args[:envelope_args] diff --git a/app/services/e_sign/get_data_service.rb b/app/services/e_sign/get_data_service.rb index 2769df5..ff7d250 100644 --- a/app/services/e_sign/get_data_service.rb +++ b/app/services/e_sign/get_data_service.rb @@ -30,7 +30,7 @@ def is_cfr(account_id) worker accounts_api = DocuSign_eSign::AccountsApi.new @api_client account_details = accounts_api.get_account_information(account_id) - account_details.status21_cfr_part11 + return account_details.status21_cfr_part11 end private diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index d67d689..afdca21 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -9,14 +9,14 @@ class JwtCreator # DocuSign authorization URI to obtain individual consent # https://developers.docusign.com/platform/auth/jwt/jwt-get-token # https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/ - def self.consent_url(state, examples_API) + def self.consent_url(state, api) # GET /oauth/auth # This endpoint is used to obtain consent and is the first step in several authentication flows. # https://developers.docusign.com/platform/auth/reference/obtain-consent - scope = 'signature impersonation' - scope = "#{scope} 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" if examples_API == 'Rooms' - scope = "#{scope} click.manage click.send" if examples_API == 'Click' - scope = "#{scope} organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" if examples_API == 'Admin' + scope = 'signature impersonation' if %w[eSignature Monitor].include?(api) + scope = 'signature impersonation 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' if api == 'Rooms' + scope = 'impersonation click.manage click.send' if api == 'Click' + scope = 'impersonation organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' if api == 'Admin' base_uri = "#{Rails.configuration.authorization_server}/oauth/auth" response_type = 'code' @@ -32,17 +32,17 @@ def initialize(session) @session = session scope = 'signature impersonation' @client_module = DocuSign_eSign - if session[:examples_API] == 'Rooms' + if session[:api] == 'Rooms' scope = "#{scope} 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" @client_module = DocuSign_Rooms end - if session[:examples_API] == 'Click' - scope = "#{scope} click.manage click.send" + if session[:api] == 'Click' + scope = 'click.manage click.send' @client_module = DocuSign_Click end - @client_module = DocuSign_Monitor if session[:examples_API] == 'Monitor' - if session[:examples_API] == 'Admin' - scope = "#{scope} organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read" + @client_module = DocuSign_Monitor if session[:api] == 'Monitor' + if session[:api] == 'Admin' + scope = 'organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' @client_module = DocuSign_Admin end diff --git a/app/services/utils.rb b/app/services/utils.rb index 6f2d4e7..75432af 100644 --- a/app/services/utils.rb +++ b/app/services/utils.rb @@ -6,10 +6,14 @@ def get_manifest(manifest_url) JSON.parse(res.body) end - def get_example(manifest, number) - manifest['Groups'].each do |group| - group['Examples'].each do |example| - return example if example['ExampleNumber'] == number + def get_example(manifest, number, api_name='eSignature') + manifest['APIs'].each do |api| + next unless api_name == api['Name'] + + api['Groups'].each do |group| + group['Examples'].each do |example| + return example if example['ExampleNumber'] == number + end end end end diff --git a/app/views/admin_api/eg001_create_user/get.html.erb b/app/views/admin_api/aeg001_create_user/get.html.erb similarity index 100% rename from app/views/admin_api/eg001_create_user/get.html.erb rename to app/views/admin_api/aeg001_create_user/get.html.erb diff --git a/app/views/admin_api/eg002_create_active_clm_esign_user/get.html.erb b/app/views/admin_api/aeg002_create_active_clm_esign_user/get.html.erb similarity index 100% rename from app/views/admin_api/eg002_create_active_clm_esign_user/get.html.erb rename to app/views/admin_api/aeg002_create_active_clm_esign_user/get.html.erb diff --git a/app/views/admin_api/eg003_bulk_export_user_data/get.html.erb b/app/views/admin_api/aeg003_bulk_export_user_data/get.html.erb similarity index 100% rename from app/views/admin_api/eg003_bulk_export_user_data/get.html.erb rename to app/views/admin_api/aeg003_bulk_export_user_data/get.html.erb diff --git a/app/views/admin_api/eg004_import_user/get.html.erb b/app/views/admin_api/aeg004_import_user/get.html.erb similarity index 100% rename from app/views/admin_api/eg004_import_user/get.html.erb rename to app/views/admin_api/aeg004_import_user/get.html.erb diff --git a/app/views/admin_api/eg004_import_user/get_status.html.erb b/app/views/admin_api/aeg004_import_user/get_status.html.erb similarity index 100% rename from app/views/admin_api/eg004_import_user/get_status.html.erb rename to app/views/admin_api/aeg004_import_user/get_status.html.erb diff --git a/app/views/admin_api/eg005_audit_users/get.html.erb b/app/views/admin_api/aeg005_audit_users/get.html.erb similarity index 96% rename from app/views/admin_api/eg005_audit_users/get.html.erb rename to app/views/admin_api/aeg005_audit_users/get.html.erb index 5117b86..f9adbfb 100644 --- a/app/views/admin_api/eg005_audit_users/get.html.erb +++ b/app/views/admin_api/aeg005_audit_users/get.html.erb @@ -1,5 +1,5 @@ -<%= render('partials/example_info') %> - -
    - <%= render('partials/submit_button') %> -
    +<%= render('partials/example_info') %> + +
    + <%= render('partials/submit_button') %> +
    diff --git a/app/views/admin_api/eg006_get_user_profile_by_email/get.html.erb b/app/views/admin_api/aeg006_get_user_profile_by_email/get.html.erb similarity index 100% rename from app/views/admin_api/eg006_get_user_profile_by_email/get.html.erb rename to app/views/admin_api/aeg006_get_user_profile_by_email/get.html.erb diff --git a/app/views/admin_api/eg007_get_user_profile_by_user_id/get.html.erb b/app/views/admin_api/aeg007_get_user_profile_by_user_id/get.html.erb similarity index 100% rename from app/views/admin_api/eg007_get_user_profile_by_user_id/get.html.erb rename to app/views/admin_api/aeg007_get_user_profile_by_user_id/get.html.erb diff --git a/app/views/admin_api/eg008_update_user_product_permission_profile/get.html.erb b/app/views/admin_api/aeg008_update_user_product_permission_profile/get.html.erb similarity index 100% rename from app/views/admin_api/eg008_update_user_product_permission_profile/get.html.erb rename to app/views/admin_api/aeg008_update_user_product_permission_profile/get.html.erb diff --git a/app/views/admin_api/eg009_delete_user_product_permission_profile/get.html.erb b/app/views/admin_api/aeg009_delete_user_product_permission_profile/get.html.erb similarity index 100% rename from app/views/admin_api/eg009_delete_user_product_permission_profile/get.html.erb rename to app/views/admin_api/aeg009_delete_user_product_permission_profile/get.html.erb diff --git a/app/views/clickwrap/eg001_create_clickwrap/get.html.erb b/app/views/clickwrap/ceg001_create_clickwrap/get.html.erb similarity index 100% rename from app/views/clickwrap/eg001_create_clickwrap/get.html.erb rename to app/views/clickwrap/ceg001_create_clickwrap/get.html.erb diff --git a/app/views/clickwrap/eg002_activate_clickwrap/get.html.erb b/app/views/clickwrap/ceg002_activate_clickwrap/get.html.erb similarity index 100% rename from app/views/clickwrap/eg002_activate_clickwrap/get.html.erb rename to app/views/clickwrap/ceg002_activate_clickwrap/get.html.erb diff --git a/app/views/clickwrap/eg003_create_new_clickwrap_version/get.html.erb b/app/views/clickwrap/ceg003_create_new_clickwrap_version/get.html.erb similarity index 100% rename from app/views/clickwrap/eg003_create_new_clickwrap_version/get.html.erb rename to app/views/clickwrap/ceg003_create_new_clickwrap_version/get.html.erb diff --git a/app/views/clickwrap/eg004_list_clickwraps/get.html.erb b/app/views/clickwrap/ceg004_list_clickwraps/get.html.erb similarity index 100% rename from app/views/clickwrap/eg004_list_clickwraps/get.html.erb rename to app/views/clickwrap/ceg004_list_clickwraps/get.html.erb diff --git a/app/views/clickwrap/eg005_clickwrap_responses/get.html.erb b/app/views/clickwrap/ceg005_clickwrap_responses/get.html.erb similarity index 100% rename from app/views/clickwrap/eg005_clickwrap_responses/get.html.erb rename to app/views/clickwrap/ceg005_clickwrap_responses/get.html.erb diff --git a/app/views/clickwrap/eg006_embed_clickwrap/get.html.erb b/app/views/clickwrap/ceg006_embed_clickwrap/get.html.erb similarity index 100% rename from app/views/clickwrap/eg006_embed_clickwrap/get.html.erb rename to app/views/clickwrap/ceg006_embed_clickwrap/get.html.erb diff --git a/app/views/clickwrap/eg006_embed_clickwrap/results.html.erb b/app/views/clickwrap/ceg006_embed_clickwrap/results.html.erb similarity index 100% rename from app/views/clickwrap/eg006_embed_clickwrap/results.html.erb rename to app/views/clickwrap/ceg006_embed_clickwrap/results.html.erb diff --git a/app/views/ds_common/choose_api.erb b/app/views/ds_common/choose_api.erb deleted file mode 100644 index ff11754..0000000 --- a/app/views/ds_common/choose_api.erb +++ /dev/null @@ -1,19 +0,0 @@ -
    - <%= sanitize @manifest["SupportingTexts"]["SelectAPIPage"]["SelectAPIHeader"] %> -

    -

    - <%= hidden_field_tag :authenticity_token, form_authenticity_token %> -
    -
    - -
    -
    -

    -
    -
    \ No newline at end of file diff --git a/app/views/ds_common/ds_must_authenticate.erb b/app/views/ds_common/ds_must_authenticate.erb index 9e77ef6..03759d0 100644 --- a/app/views/ds_common/ds_must_authenticate.erb +++ b/app/views/ds_common/ds_must_authenticate.erb @@ -5,7 +5,7 @@ <%= hidden_field_tag :authenticity_token, form_authenticity_token %>
    +
    + +
    + + <% @manifest["APIs"].each { |api| %> + <% api["Groups"].each { |group| %> +

    <%= group["Name"] %>

    + + <% group["Examples"].each { |example| %> + <% if example_available? example %> + <% if example["CFREnabled"] == "AllAccounts" || + @status_cfr == "enabled" && example["CFREnabled"] == "CFROnly" || + @status_cfr != "enabled" && example["CFREnabled"] == "NonCFR" + %> + <% prefix = if api["Name"] == "Admin" + "a" + elsif api["Name"] == "Click" + "c" + elsif api["Name"] == "Rooms" + "r" + elsif api["Name"] == "Monitor" + "m" + else + "e" + end %> + +

    "> + "> + <%= example["ExampleName"] %> + +

    + +

    <%= sanitize example["ExampleDescription"] %>

    + + <% if example["LinksToAPIMethod"].length > 1 %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsedPlural"] %> + <% else %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsed"] %> + <% end %> + + <% example["LinksToAPIMethod"].each do |link| %> + "><%= link["PathName"] %> + <% end %> +

    + <% end %> + <% end %> + <% } %> + <% } %> + <% } %> +

    + + + + + + + diff --git a/app/views/e_sign/eg002_signing_via_email/get.html.erb b/app/views/e_sign/eeg002_signing_via_email/get.html.erb similarity index 100% rename from app/views/e_sign/eg002_signing_via_email/get.html.erb rename to app/views/e_sign/eeg002_signing_via_email/get.html.erb diff --git a/app/views/e_sign/eg003_list_envelopes/get.html.erb b/app/views/e_sign/eeg003_list_envelopes/get.html.erb similarity index 100% rename from app/views/e_sign/eg003_list_envelopes/get.html.erb rename to app/views/e_sign/eeg003_list_envelopes/get.html.erb diff --git a/app/views/e_sign/eg004_envelope_info/get.html.erb b/app/views/e_sign/eeg004_envelope_info/get.html.erb similarity index 100% rename from app/views/e_sign/eg004_envelope_info/get.html.erb rename to app/views/e_sign/eeg004_envelope_info/get.html.erb diff --git a/app/views/e_sign/eg005_envelope_recipients/get.html.erb b/app/views/e_sign/eeg005_envelope_recipients/get.html.erb similarity index 100% rename from app/views/e_sign/eg005_envelope_recipients/get.html.erb rename to app/views/e_sign/eeg005_envelope_recipients/get.html.erb diff --git a/app/views/e_sign/eg006_envelope_docs/get.html.erb b/app/views/e_sign/eeg006_envelope_docs/get.html.erb similarity index 100% rename from app/views/e_sign/eg006_envelope_docs/get.html.erb rename to app/views/e_sign/eeg006_envelope_docs/get.html.erb diff --git a/app/views/e_sign/eg007_envelope_get_doc/get.html.erb b/app/views/e_sign/eeg007_envelope_get_doc/get.html.erb similarity index 100% rename from app/views/e_sign/eg007_envelope_get_doc/get.html.erb rename to app/views/e_sign/eeg007_envelope_get_doc/get.html.erb diff --git a/app/views/e_sign/eg008_create_template/get.html.erb b/app/views/e_sign/eeg008_create_template/get.html.erb similarity index 100% rename from app/views/e_sign/eg008_create_template/get.html.erb rename to app/views/e_sign/eeg008_create_template/get.html.erb diff --git a/app/views/e_sign/eg009_use_template/get.html.erb b/app/views/e_sign/eeg009_use_template/get.html.erb similarity index 100% rename from app/views/e_sign/eg009_use_template/get.html.erb rename to app/views/e_sign/eeg009_use_template/get.html.erb diff --git a/app/views/e_sign/eg010_send_binary_docs/get.html.erb b/app/views/e_sign/eeg010_send_binary_docs/get.html.erb similarity index 100% rename from app/views/e_sign/eg010_send_binary_docs/get.html.erb rename to app/views/e_sign/eeg010_send_binary_docs/get.html.erb diff --git a/app/views/e_sign/eg011_embedded_sending/get.html.erb b/app/views/e_sign/eeg011_embedded_sending/get.html.erb similarity index 100% rename from app/views/e_sign/eg011_embedded_sending/get.html.erb rename to app/views/e_sign/eeg011_embedded_sending/get.html.erb diff --git a/app/views/e_sign/eg012_embedded_console/get.html.erb b/app/views/e_sign/eeg012_embedded_console/get.html.erb similarity index 100% rename from app/views/e_sign/eg012_embedded_console/get.html.erb rename to app/views/e_sign/eeg012_embedded_console/get.html.erb diff --git a/app/views/e_sign/eg013_add_doc_to_template/get.html.erb b/app/views/e_sign/eeg013_add_doc_to_template/get.html.erb similarity index 100% rename from app/views/e_sign/eg013_add_doc_to_template/get.html.erb rename to app/views/e_sign/eeg013_add_doc_to_template/get.html.erb diff --git a/app/views/e_sign/eg014_collect_payment/get.html.erb b/app/views/e_sign/eeg014_collect_payment/get.html.erb similarity index 100% rename from app/views/e_sign/eg014_collect_payment/get.html.erb rename to app/views/e_sign/eeg014_collect_payment/get.html.erb diff --git a/app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb b/app/views/e_sign/eeg015_get_envelope_tab_data/get.html.erb similarity index 100% rename from app/views/e_sign/eg015_get_envelope_tab_data/get.html.erb rename to app/views/e_sign/eeg015_get_envelope_tab_data/get.html.erb diff --git a/app/views/e_sign/eg016_set_envelope_tab_data/get.html.erb b/app/views/e_sign/eeg016_set_envelope_tab_data/get.html.erb similarity index 100% rename from app/views/e_sign/eg016_set_envelope_tab_data/get.html.erb rename to app/views/e_sign/eeg016_set_envelope_tab_data/get.html.erb diff --git a/app/views/e_sign/eg017_set_template_tab_values/get.html.erb b/app/views/e_sign/eeg017_set_template_tab_values/get.html.erb similarity index 100% rename from app/views/e_sign/eg017_set_template_tab_values/get.html.erb rename to app/views/e_sign/eeg017_set_template_tab_values/get.html.erb diff --git a/app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb b/app/views/e_sign/eeg018_get_envelope_custom_field_data/get.html.erb similarity index 100% rename from app/views/e_sign/eg018_get_envelope_custom_field_data/get.html.erb rename to app/views/e_sign/eeg018_get_envelope_custom_field_data/get.html.erb diff --git a/app/views/e_sign/eg019_access_code_authentication/get.html.erb b/app/views/e_sign/eeg019_access_code_authentication/get.html.erb similarity index 100% rename from app/views/e_sign/eg019_access_code_authentication/get.html.erb rename to app/views/e_sign/eeg019_access_code_authentication/get.html.erb diff --git a/app/views/e_sign/eg020_phone_authentication/get.html.erb b/app/views/e_sign/eeg020_phone_authentication/get.html.erb similarity index 100% rename from app/views/e_sign/eg020_phone_authentication/get.html.erb rename to app/views/e_sign/eeg020_phone_authentication/get.html.erb diff --git a/app/views/e_sign/eg022_kba_authentication/get.html.erb b/app/views/e_sign/eeg022_kba_authentication/get.html.erb similarity index 100% rename from app/views/e_sign/eg022_kba_authentication/get.html.erb rename to app/views/e_sign/eeg022_kba_authentication/get.html.erb diff --git a/app/views/e_sign/eg023_idv_authentication/get.html.erb b/app/views/e_sign/eeg023_idv_authentication/get.html.erb similarity index 100% rename from app/views/e_sign/eg023_idv_authentication/get.html.erb rename to app/views/e_sign/eeg023_idv_authentication/get.html.erb diff --git a/app/views/e_sign/eg024_permission_create/get.html.erb b/app/views/e_sign/eeg024_permission_create/get.html.erb similarity index 100% rename from app/views/e_sign/eg024_permission_create/get.html.erb rename to app/views/e_sign/eeg024_permission_create/get.html.erb diff --git a/app/views/e_sign/eg025_permissions_set_user_group/get.html.erb b/app/views/e_sign/eeg025_permissions_set_user_group/get.html.erb similarity index 100% rename from app/views/e_sign/eg025_permissions_set_user_group/get.html.erb rename to app/views/e_sign/eeg025_permissions_set_user_group/get.html.erb diff --git a/app/views/e_sign/eg026_permissions_change_single_setting/get.html.erb b/app/views/e_sign/eeg026_permissions_change_single_setting/get.html.erb similarity index 100% rename from app/views/e_sign/eg026_permissions_change_single_setting/get.html.erb rename to app/views/e_sign/eeg026_permissions_change_single_setting/get.html.erb diff --git a/app/views/e_sign/eg027_permissions_delete/get.html.erb b/app/views/e_sign/eeg027_permissions_delete/get.html.erb similarity index 100% rename from app/views/e_sign/eg027_permissions_delete/get.html.erb rename to app/views/e_sign/eeg027_permissions_delete/get.html.erb diff --git a/app/views/e_sign/eg028_brands_creating/get.html.erb b/app/views/e_sign/eeg028_brands_creating/get.html.erb similarity index 100% rename from app/views/e_sign/eg028_brands_creating/get.html.erb rename to app/views/e_sign/eeg028_brands_creating/get.html.erb diff --git a/app/views/e_sign/eg029_brands_apply_to_envelope/get.html.erb b/app/views/e_sign/eeg029_brands_apply_to_envelope/get.html.erb similarity index 100% rename from app/views/e_sign/eg029_brands_apply_to_envelope/get.html.erb rename to app/views/e_sign/eeg029_brands_apply_to_envelope/get.html.erb diff --git a/app/views/e_sign/eg030_brands_apply_to_template/get.html.erb b/app/views/e_sign/eeg030_brands_apply_to_template/get.html.erb similarity index 100% rename from app/views/e_sign/eg030_brands_apply_to_template/get.html.erb rename to app/views/e_sign/eeg030_brands_apply_to_template/get.html.erb diff --git a/app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb b/app/views/e_sign/eeg031_bulk_sending_envelopes/get.html.erb similarity index 100% rename from app/views/e_sign/eg031_bulk_sending_envelopes/get.html.erb rename to app/views/e_sign/eeg031_bulk_sending_envelopes/get.html.erb diff --git a/app/views/e_sign/eg032_pauses_signature_workflow/get.html.erb b/app/views/e_sign/eeg032_pauses_signature_workflow/get.html.erb similarity index 100% rename from app/views/e_sign/eg032_pauses_signature_workflow/get.html.erb rename to app/views/e_sign/eeg032_pauses_signature_workflow/get.html.erb diff --git a/app/views/e_sign/eg032_pauses_signature_workflow/return.html.erb b/app/views/e_sign/eeg032_pauses_signature_workflow/return.html.erb similarity index 100% rename from app/views/e_sign/eg032_pauses_signature_workflow/return.html.erb rename to app/views/e_sign/eeg032_pauses_signature_workflow/return.html.erb diff --git a/app/views/e_sign/eg033_unpauses_signature_workflow/get.html.erb b/app/views/e_sign/eeg033_unpauses_signature_workflow/get.html.erb similarity index 100% rename from app/views/e_sign/eg033_unpauses_signature_workflow/get.html.erb rename to app/views/e_sign/eeg033_unpauses_signature_workflow/get.html.erb diff --git a/app/views/e_sign/eg033_unpauses_signature_workflow/return.html.erb b/app/views/e_sign/eeg033_unpauses_signature_workflow/return.html.erb similarity index 100% rename from app/views/e_sign/eg033_unpauses_signature_workflow/return.html.erb rename to app/views/e_sign/eeg033_unpauses_signature_workflow/return.html.erb diff --git a/app/views/e_sign/eg034_use_conditional_recipients/get.html.erb b/app/views/e_sign/eeg034_use_conditional_recipients/get.html.erb similarity index 100% rename from app/views/e_sign/eg034_use_conditional_recipients/get.html.erb rename to app/views/e_sign/eeg034_use_conditional_recipients/get.html.erb diff --git a/app/views/e_sign/eg034_use_conditional_recipients/return.html.erb b/app/views/e_sign/eeg034_use_conditional_recipients/return.html.erb similarity index 100% rename from app/views/e_sign/eg034_use_conditional_recipients/return.html.erb rename to app/views/e_sign/eeg034_use_conditional_recipients/return.html.erb diff --git a/app/views/e_sign/eg035_scheduled_sending/get.html.erb b/app/views/e_sign/eeg035_scheduled_sending/get.html.erb similarity index 100% rename from app/views/e_sign/eg035_scheduled_sending/get.html.erb rename to app/views/e_sign/eeg035_scheduled_sending/get.html.erb diff --git a/app/views/e_sign/eg036_delayed_routing/get.html.erb b/app/views/e_sign/eeg036_delayed_routing/get.html.erb similarity index 100% rename from app/views/e_sign/eg036_delayed_routing/get.html.erb rename to app/views/e_sign/eeg036_delayed_routing/get.html.erb diff --git a/app/views/e_sign/eg037_sms_delivery/get.html.erb b/app/views/e_sign/eeg037_sms_delivery/get.html.erb similarity index 100% rename from app/views/e_sign/eg037_sms_delivery/get.html.erb rename to app/views/e_sign/eeg037_sms_delivery/get.html.erb diff --git a/app/views/e_sign/eg038_responsive_signing/get.html.erb b/app/views/e_sign/eeg038_responsive_signing/get.html.erb similarity index 100% rename from app/views/e_sign/eg038_responsive_signing/get.html.erb rename to app/views/e_sign/eeg038_responsive_signing/get.html.erb diff --git a/app/views/e_sign/eg039_signing_in_person/get.html.erb b/app/views/e_sign/eeg039_signing_in_person/get.html.erb similarity index 100% rename from app/views/e_sign/eg039_signing_in_person/get.html.erb rename to app/views/e_sign/eeg039_signing_in_person/get.html.erb diff --git a/app/views/e_sign/eg040_set_document_visibility/get.html.erb b/app/views/e_sign/eeg040_set_document_visibility/get.html.erb similarity index 100% rename from app/views/e_sign/eg040_set_document_visibility/get.html.erb rename to app/views/e_sign/eeg040_set_document_visibility/get.html.erb diff --git a/app/views/e_sign/eg041_cfr_embedded_signing/get.html.erb b/app/views/e_sign/eeg041_cfr_embedded_signing/get.html.erb similarity index 100% rename from app/views/e_sign/eg041_cfr_embedded_signing/get.html.erb rename to app/views/e_sign/eeg041_cfr_embedded_signing/get.html.erb diff --git a/app/views/eg001_embedded_signing/get.html.erb b/app/views/eeg001_embedded_signing/get.html.erb similarity index 100% rename from app/views/eg001_embedded_signing/get.html.erb rename to app/views/eeg001_embedded_signing/get.html.erb diff --git a/app/views/layouts/_head.erb b/app/views/layouts/_head.erb index aaff989..e984b57 100644 --- a/app/views/layouts/_head.erb +++ b/app/views/layouts/_head.erb @@ -45,9 +45,6 @@ Login (current) <% end %> - <% if session["ds_user_name"] %> diff --git a/app/views/monitor_api/eg001_get_monitoring_dataset/get.html.erb b/app/views/monitor_api/meg001_get_monitoring_dataset/get.html.erb similarity index 100% rename from app/views/monitor_api/eg001_get_monitoring_dataset/get.html.erb rename to app/views/monitor_api/meg001_get_monitoring_dataset/get.html.erb diff --git a/app/views/monitor_api/eg002_post_web_query/get.html.erb b/app/views/monitor_api/meg002_post_web_query/get.html.erb similarity index 100% rename from app/views/monitor_api/eg002_post_web_query/get.html.erb rename to app/views/monitor_api/meg002_post_web_query/get.html.erb diff --git a/app/views/room_api/eg001_create_room_with_data/get.html.erb b/app/views/room_api/reg001_create_room_with_data/get.html.erb similarity index 100% rename from app/views/room_api/eg001_create_room_with_data/get.html.erb rename to app/views/room_api/reg001_create_room_with_data/get.html.erb diff --git a/app/views/room_api/eg002_create_room_with_template/get.html.erb b/app/views/room_api/reg002_create_room_with_template/get.html.erb similarity index 100% rename from app/views/room_api/eg002_create_room_with_template/get.html.erb rename to app/views/room_api/reg002_create_room_with_template/get.html.erb diff --git a/app/views/room_api/eg003_export_data_from_room/get.html.erb b/app/views/room_api/reg003_export_data_from_room/get.html.erb similarity index 100% rename from app/views/room_api/eg003_export_data_from_room/get.html.erb rename to app/views/room_api/reg003_export_data_from_room/get.html.erb diff --git a/app/views/room_api/eg004_add_forms_to_room/get.html.erb b/app/views/room_api/reg004_add_forms_to_room/get.html.erb similarity index 100% rename from app/views/room_api/eg004_add_forms_to_room/get.html.erb rename to app/views/room_api/reg004_add_forms_to_room/get.html.erb diff --git a/app/views/room_api/eg005_get_rooms_with_filters/get.html.erb b/app/views/room_api/reg005_get_rooms_with_filters/get.html.erb similarity index 100% rename from app/views/room_api/eg005_get_rooms_with_filters/get.html.erb rename to app/views/room_api/reg005_get_rooms_with_filters/get.html.erb diff --git a/app/views/room_api/eg006_create_an_external_form_fill_session/get_forms.html.erb b/app/views/room_api/reg006_create_an_external_form_fill_session/get_forms.html.erb similarity index 100% rename from app/views/room_api/eg006_create_an_external_form_fill_session/get_forms.html.erb rename to app/views/room_api/reg006_create_an_external_form_fill_session/get_forms.html.erb diff --git a/app/views/room_api/eg006_create_an_external_form_fill_session/get_rooms.html.erb b/app/views/room_api/reg006_create_an_external_form_fill_session/get_rooms.html.erb similarity index 100% rename from app/views/room_api/eg006_create_an_external_form_fill_session/get_rooms.html.erb rename to app/views/room_api/reg006_create_an_external_form_fill_session/get_rooms.html.erb diff --git a/app/views/room_api/eg007_create_form_group/get.html.erb b/app/views/room_api/reg007_create_form_group/get.html.erb similarity index 100% rename from app/views/room_api/eg007_create_form_group/get.html.erb rename to app/views/room_api/reg007_create_form_group/get.html.erb diff --git a/app/views/room_api/eg008_grant_office_access_to_form_group/get.erb b/app/views/room_api/reg008_grant_office_access_to_form_group/get.erb similarity index 100% rename from app/views/room_api/eg008_grant_office_access_to_form_group/get.erb rename to app/views/room_api/reg008_grant_office_access_to_form_group/get.erb diff --git a/app/views/room_api/eg009_assign_form_to_form_group/get.erb b/app/views/room_api/reg009_assign_form_to_form_group/get.erb similarity index 100% rename from app/views/room_api/eg009_assign_form_to_form_group/get.erb rename to app/views/room_api/reg009_assign_form_to_form_group/get.erb diff --git a/app/views/room_api/return.html.erb b/app/views/room_api/return.html.erb index 5b0db4e..d884e11 100644 --- a/app/views/room_api/return.html.erb +++ b/app/views/room_api/return.html.erb @@ -2,7 +2,7 @@

    Result

    -<% if @scenarios_name == 'eg006_create_an_external_form_fill_session' %> +<% if @scenarios_name == 'reg006_create_an_external_form_fill_session' %> >link <% end %> diff --git a/config/appsettings.example.yml b/config/appsettings.example.yml index 29a45b5..09510e0 100644 --- a/config/appsettings.example.yml +++ b/config/appsettings.example.yml @@ -36,11 +36,7 @@ default: &default gateway_name: "stripe" gateway_display_name: "Stripe" github_example_url: https://github.com/docusign/code-examples-ruby/tree/master/app/services/ - eSignManifestUrl: "https://raw.githubusercontent.com/docusign/code-examples-csharp/master/manifest/eSignatureManifest.json" - clickManifestUrl: "https://raw.githubusercontent.com/docusign/code-examples-csharp/master/manifest/ClickManifest.json" - roomsManifestUrl: "https://raw.githubusercontent.com/docusign/code-examples-csharp/master/manifest/RoomsManifest.json" - adminManifestUrl: "https://raw.githubusercontent.com/docusign/code-examples-csharp/master/manifest/AdminManifest.json" - monitorManifestUrl: "https://raw.githubusercontent.com/docusign/code-examples-csharp/master/manifest/MonitorManifest.json" + example_manifest_url: "https://raw.githubusercontent.com/docusign/code-examples-csharp/master/manifest/CodeExamplesManifest.json" documentation: false api_only: false diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 7bc52f7..97c8b40 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -39,13 +39,13 @@ strategy.options[:authorize_params].prompt = strategy.options.prompt unless strategy.options[:allow_silent_authentication] session = strategy.session - case session[:examples_API] + case session[:api] when 'Rooms' strategy.options[:authorize_params].scope = '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' when 'Click' - strategy.options[:authorize_params].scope = 'signature click.manage click.send' + strategy.options[:authorize_params].scope = 'click.manage click.send' when 'Admin' - strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' + strategy.options[:authorize_params].scope = 'organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' end } end diff --git a/config/routes.rb b/config/routes.rb index 58ba44f..e287016 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,220 +1,214 @@ # frozen_string_literal: true Rails.application.routes.draw do - constraints ->(req) { req.session[:examples_API] == 'Rooms' } do - scope module: 'room_api' do - get 'eg001' => 'eg001_create_room_with_data#get' - post 'eg001' => 'eg001_create_room_with_data#create' + scope module: 'room_api' do + get 'reg001' => 'reg001_create_room_with_data#get' + post 'reg001' => 'reg001_create_room_with_data#create' - get 'eg002' => 'eg002_create_room_with_template#get' - post 'eg002' => 'eg002_create_room_with_template#create' + get 'reg002' => 'reg002_create_room_with_template#get' + post 'reg002' => 'reg002_create_room_with_template#create' - get 'eg003' => 'eg003_export_data_from_room#get' - post 'eg003' => 'eg003_export_data_from_room#create' + get 'reg003' => 'reg003_export_data_from_room#get' + post 'reg003' => 'reg003_export_data_from_room#create' - get 'eg004' => 'eg004_add_forms_to_room#get' - post 'eg004' => 'eg004_add_forms_to_room#create' + get 'reg004' => 'reg004_add_forms_to_room#get' + post 'reg004' => 'reg004_add_forms_to_room#create' - get 'eg005' => 'eg005_get_rooms_with_filters#get' - post 'eg005' => 'eg005_get_rooms_with_filters#create' + get 'reg005' => 'reg005_get_rooms_with_filters#get' + post 'reg005' => 'reg005_get_rooms_with_filters#create' - get 'eg006' => 'eg006_create_an_external_form_fill_session#get_rooms' - get 'eg006_forms' => 'eg006_create_an_external_form_fill_session#get_forms' - post 'eg006' => 'eg006_create_an_external_form_fill_session#create' + get 'reg006' => 'reg006_create_an_external_form_fill_session#get_rooms' + get 'reg006_forms' => 'reg006_create_an_external_form_fill_session#get_forms' + post 'reg006' => 'reg006_create_an_external_form_fill_session#create' - get 'eg007' => 'eg007_create_form_group#get' - post 'eg007' => 'eg007_create_form_group#create' + get 'reg007' => 'reg007_create_form_group#get' + post 'reg007' => 'reg007_create_form_group#create' - get 'eg008' => 'eg008_grant_office_access_to_form_group#get' - post 'eg008' => 'eg008_grant_office_access_to_form_group#create' + get 'reg008' => 'reg008_grant_office_access_to_form_group#get' + post 'reg008' => 'reg008_grant_office_access_to_form_group#create' - get 'eg009' => 'eg009_assign_form_to_form_group#get' - post 'eg009' => 'eg009_assign_form_to_form_group#create' - end + get 'reg009' => 'reg009_assign_form_to_form_group#get' + post 'reg009' => 'reg009_assign_form_to_form_group#create' end - constraints ->(req) { req.session[:examples_API] == 'Click' } do - scope module: 'clickwrap' do - get 'eg001' => 'eg001_create_clickwrap#get' - post 'eg001' => 'eg001_create_clickwrap#create' - get 'eg002' => 'eg002_activate_clickwrap#get' - post 'eg002' => 'eg002_activate_clickwrap#create' + scope module: 'clickwrap' do + get 'ceg001' => 'ceg001_create_clickwrap#get' + post 'ceg001' => 'ceg001_create_clickwrap#create' - get 'eg003' => 'eg003_create_new_clickwrap_version#get' - post 'eg003' => 'eg003_create_new_clickwrap_version#create' + get 'ceg002' => 'ceg002_activate_clickwrap#get' + post 'ceg002' => 'ceg002_activate_clickwrap#create' - get 'eg004' => 'eg004_list_clickwraps#get' - post 'eg004' => 'eg004_list_clickwraps#create' + get 'ceg003' => 'ceg003_create_new_clickwrap_version#get' + post 'ceg003' => 'ceg003_create_new_clickwrap_version#create' - get 'eg005' => 'eg005_clickwrap_responses#get' - post 'eg005' => 'eg005_clickwrap_responses#create' + get 'ceg004' => 'ceg004_list_clickwraps#get' + post 'ceg004' => 'ceg004_list_clickwraps#create' - get 'eg006' => 'eg006_embed_clickwrap#get' - post 'eg006' => 'eg006_embed_clickwrap#create' - end + get 'ceg005' => 'ceg005_clickwrap_responses#get' + post 'ceg005' => 'ceg005_clickwrap_responses#create' + + get 'ceg006' => 'ceg006_embed_clickwrap#get' + post 'ceg006' => 'ceg006_embed_clickwrap#create' end - constraints ->(req) { req.session[:examples_API] == 'Monitor' } do - scope module: 'monitor_api' do - get 'eg001' => 'eg001_get_monitoring_dataset#get' - post 'eg001' => 'eg001_get_monitoring_dataset#create' - get 'eg002' => 'eg002_post_web_query#get' - post 'eg002' => 'eg002_post_web_query#create' - end + + scope module: 'monitor_api' do + get 'meg001' => 'meg001_get_monitoring_dataset#get' + post 'meg001' => 'meg001_get_monitoring_dataset#create' + get 'meg002' => 'meg002_post_web_query#get' + post 'meg002' => 'meg002_post_web_query#create' end - constraints ->(req) { req.session[:examples_API] == 'Admin' } do - scope module: 'admin_api' do - get 'eg001' => 'eg001_create_user#get' - post 'eg001' => 'eg001_create_user#create' - get 'eg002' => 'eg002_create_active_clm_esign_user#get' - post 'eg002' => 'eg002_create_active_clm_esign_user#create' + scope module: 'admin_api' do + get 'aeg001' => 'aeg001_create_user#get' + post 'aeg001' => 'aeg001_create_user#create' + + get 'aeg002' => 'aeg002_create_active_clm_esign_user#get' + post 'aeg002' => 'aeg002_create_active_clm_esign_user#create' - get 'eg003' => 'eg003_bulk_export_user_data#get' - post 'eg003' => 'eg003_bulk_export_user_data#create' + get 'aeg003' => 'aeg003_bulk_export_user_data#get' + post 'aeg003' => 'aeg003_bulk_export_user_data#create' - get 'eg004' => 'eg004_import_user#get' - post 'eg004' => 'eg004_import_user#create' - get 'eg004status' => 'eg004_import_user#check_status' + get 'aeg004' => 'aeg004_import_user#get' + post 'aeg004' => 'aeg004_import_user#create' + get 'aeg004status' => 'aeg004_import_user#check_status' - get 'eg005' => 'eg005_audit_users#get' - post 'eg005' => 'eg005_audit_users#create' + get 'aeg005' => 'aeg005_audit_users#get' + post 'aeg005' => 'aeg005_audit_users#create' - get 'eg006' => 'eg006_get_user_profile_by_email#get' - post 'eg006' => 'eg006_get_user_profile_by_email#create' + get 'aeg006' => 'aeg006_get_user_profile_by_email#get' + post 'aeg006' => 'aeg006_get_user_profile_by_email#create' - get 'eg007' => 'eg007_get_user_profile_by_user_id#get' - post 'eg007' => 'eg007_get_user_profile_by_user_id#create' + get 'aeg007' => 'aeg007_get_user_profile_by_user_id#get' + post 'aeg007' => 'aeg007_get_user_profile_by_user_id#create' - get 'eg008' => 'eg008_update_user_product_permission_profile#get' - post 'eg008' => 'eg008_update_user_product_permission_profile#create' + get 'aeg008' => 'aeg008_update_user_product_permission_profile#get' + post 'aeg008' => 'aeg008_update_user_product_permission_profile#create' - get 'eg009' => 'eg009_delete__user_product_permission_profile#get' - post 'eg009' => 'eg009_delete__user_product_permission_profile#create' - end + get 'aeg009' => 'aeg009_delete_user_product_permission_profile#get' + post 'aeg009' => 'aeg009_delete_user_product_permission_profile#create' end - constraints ->(req) { req.session[:examples_API] == 'eSignature' } do - get '/eg001' => 'eg001_embedded_signing#get' - post '/eg001' => 'eg001_embedded_signing#create' - scope module: 'e_sign' do - # Example controllers... - get 'eg002' => 'eg002_signing_via_email#get' - post 'eg002' => 'eg002_signing_via_email#create' + get '/eeg001' => 'eeg001_embedded_signing#get' + post '/eeg001' => 'eeg001_embedded_signing#create' - get 'eg003' => 'eg003_list_envelopes#get' - post 'eg003' => 'eg003_list_envelopes#create' + scope module: 'e_sign' do + # Example controllers... + get 'eeg002' => 'eeg002_signing_via_email#get' + post 'eeg002' => 'eeg002_signing_via_email#create' - get 'eg004' => 'eg004_envelope_info#get' - post 'eg004' => 'eg004_envelope_info#create' + get 'eeg003' => 'eeg003_list_envelopes#get' + post 'eeg003' => 'eeg003_list_envelopes#create' - get 'eg005' => 'eg005_envelope_recipients#get' - post 'eg005' => 'eg005_envelope_recipients#create' + get 'eeg004' => 'eeg004_envelope_info#get' + post 'eeg004' => 'eeg004_envelope_info#create' - get 'eg006' => 'eg006_envelope_docs#get' - post 'eg006' => 'eg006_envelope_docs#create' + get 'eeg005' => 'eeg005_envelope_recipients#get' + post 'eeg005' => 'eeg005_envelope_recipients#create' - get 'eg007' => 'eg007_envelope_get_doc#get' - post 'eg007' => 'eg007_envelope_get_doc#create' + get 'eeg006' => 'eeg006_envelope_docs#get' + post 'eeg006' => 'eeg006_envelope_docs#create' - get 'eg008' => 'eg008_create_template#get' - post 'eg008' => 'eg008_create_template#create' + get 'eeg007' => 'eeg007_envelope_get_doc#get' + post 'eeg007' => 'eeg007_envelope_get_doc#create' - get 'eg009' => 'eg009_use_template#get' - post 'eg009' => 'eg009_use_template#create' + get 'eeg008' => 'eeg008_create_template#get' + post 'eeg008' => 'eeg008_create_template#create' - get 'eg010' => 'eg010_send_binary_docs#get' - post 'eg010' => 'eg010_send_binary_docs#create' + get 'eeg009' => 'eeg009_use_template#get' + post 'eeg009' => 'eeg009_use_template#create' - get 'eg011' => 'eg011_embedded_sending#get' - post 'eg011' => 'eg011_embedded_sending#create' + get 'eeg010' => 'eeg010_send_binary_docs#get' + post 'eeg010' => 'eeg010_send_binary_docs#create' - get 'eg012' => 'eg012_embedded_console#get' - post 'eg012' => 'eg012_embedded_console#create' + get 'eeg011' => 'eeg011_embedded_sending#get' + post 'eeg011' => 'eeg011_embedded_sending#create' - get 'eg013' => 'eg013_add_doc_to_template#get' - post 'eg013' => 'eg013_add_doc_to_template#create' + get 'eeg012' => 'eeg012_embedded_console#get' + post 'eeg012' => 'eeg012_embedded_console#create' - get 'eg014' => 'eg014_collect_payment#get' - post 'eg014' => 'eg014_collect_payment#create' + get 'eeg013' => 'eeg013_add_doc_to_template#get' + post 'eeg013' => 'eeg013_add_doc_to_template#create' - get 'eg015' => 'eg015_get_envelope_tab_data#get' - post 'eg015' => 'eg015_get_envelope_tab_data#create' + get 'eeg014' => 'eeg014_collect_payment#get' + post 'eeg014' => 'eeg014_collect_payment#create' - get 'eg016' => 'eg016_set_envelope_tab_data#get' - post 'eg016' => 'eg016_set_envelope_tab_data#create' + get 'eeg015' => 'eeg015_get_envelope_tab_data#get' + post 'eeg015' => 'eeg015_get_envelope_tab_data#create' - get 'eg017' => 'eg017_set_template_tab_values#get' - post 'eg017' => 'eg017_set_template_tab_values#create' + get 'eeg016' => 'eeg016_set_envelope_tab_data#get' + post 'eeg016' => 'eeg016_set_envelope_tab_data#create' - get 'eg018' => 'eg018_get_envelope_custom_field_data#get' - post 'eg018' => 'eg018_get_envelope_custom_field_data#create' + get 'eeg017' => 'eeg017_set_template_tab_values#get' + post 'eeg017' => 'eeg017_set_template_tab_values#create' - get 'eg019' => 'eg019_access_code_authentication#get' - post 'eg019' => 'eg019_access_code_authentication#create' + get 'eeg018' => 'eeg018_get_envelope_custom_field_data#get' + post 'eeg018' => 'eeg018_get_envelope_custom_field_data#create' - get 'eg020' => 'eg020_phone_authentication#get' - post 'eg020' => 'eg020_phone_authentication#create' + get 'eeg019' => 'eeg019_access_code_authentication#get' + post 'eeg019' => 'eeg019_access_code_authentication#create' - get 'eg022' => 'eg022_kba_authentication#get' - post 'eg022' => 'eg022_kba_authentication#create' + get 'eeg020' => 'eeg020_phone_authentication#get' + post 'eeg020' => 'eeg020_phone_authentication#create' - get 'eg023' => 'eg023_idv_authentication#get' - post 'eg023' => 'eg023_idv_authentication#create' + get 'eeg022' => 'eeg022_kba_authentication#get' + post 'eeg022' => 'eeg022_kba_authentication#create' - get 'eg024' => 'eg024_permission_create#get' - post 'eg024' => 'eg024_permission_create#create' + get 'eeg023' => 'eeg023_idv_authentication#get' + post 'eeg023' => 'eeg023_idv_authentication#create' - get 'eg025' => 'eg025_permissions_set_user_group#get' - post 'eg025' => 'eg025_permissions_set_user_group#create' + get 'eeg024' => 'eeg024_permission_create#get' + post 'eeg024' => 'eeg024_permission_create#create' - get 'eg026' => 'eg026_permissions_change_single_setting#get' - post 'eg026' => 'eg026_permissions_change_single_setting#create' + get 'eeg025' => 'eeg025_permissions_set_user_group#get' + post 'eeg025' => 'eeg025_permissions_set_user_group#create' - get 'eg027' => 'eg027_permissions_delete#get' - post 'eg027' => 'eg027_permissions_delete#create' + get 'eeg026' => 'eeg026_permissions_change_single_setting#get' + post 'eeg026' => 'eeg026_permissions_change_single_setting#create' - get 'eg028' => 'eg028_brands_creating#get' - post 'eg028' => 'eg028_brands_creating#create' + get 'eeg027' => 'eeg027_permissions_delete#get' + post 'eeg027' => 'eeg027_permissions_delete#create' - get 'eg029' => 'eg029_brands_apply_to_envelope#get' - post 'eg029' => 'eg029_brands_apply_to_envelope#create' + get 'eeg028' => 'eeg028_brands_creating#get' + post 'eeg028' => 'eeg028_brands_creating#create' - get 'eg030' => 'eg030_brands_apply_to_template#get' - post 'eg030' => 'eg030_brands_apply_to_template#create' + get 'eeg029' => 'eeg029_brands_apply_to_envelope#get' + post 'eeg029' => 'eeg029_brands_apply_to_envelope#create' - get 'eg031' => 'eg031_bulk_sending_envelopes#get' - post 'eg031' => 'eg031_bulk_sending_envelopes#create' + get 'eeg030' => 'eeg030_brands_apply_to_template#get' + post 'eeg030' => 'eeg030_brands_apply_to_template#create' - get 'eg032' => 'eg032_pauses_signature_workflow#get' - post 'eg032' => 'eg032_pauses_signature_workflow#create' + get 'eeg031' => 'eeg031_bulk_sending_envelopes#get' + post 'eeg031' => 'eeg031_bulk_sending_envelopes#create' - get 'eg033' => 'eg033_unpauses_signature_workflow#get' - put 'eg033' => 'eg033_unpauses_signature_workflow#update' + get 'eeg032' => 'eeg032_pauses_signature_workflow#get' + post 'eeg032' => 'eeg032_pauses_signature_workflow#create' - get 'eg034' => 'eg034_use_conditional_recipients#get' - post 'eg034' => 'eg034_use_conditional_recipients#create' + get 'eeg033' => 'eeg033_unpauses_signature_workflow#get' + put 'eeg033' => 'eeg033_unpauses_signature_workflow#update' - get 'eg035' => 'eg035_scheduled_sending#get' - post 'eg035' => 'eg035_scheduled_sending#create' + get 'eeg034' => 'eeg034_use_conditional_recipients#get' + post 'eeg034' => 'eeg034_use_conditional_recipients#create' - get 'eg036' => 'eg036_delayed_routing#get' - post 'eg036' => 'eg036_delayed_routing#create' + get 'eeg035' => 'eeg035_scheduled_sending#get' + post 'eeg035' => 'eeg035_scheduled_sending#create' - get 'eg037' => 'eg037_sms_delivery#get' - post 'eg037' => 'eg037_sms_delivery#create' + get 'eeg036' => 'eeg036_delayed_routing#get' + post 'eeg036' => 'eeg036_delayed_routing#create' - get 'eg038' => 'eg038_responsive_signing#get' - post 'eg038' => 'eg038_responsive_signing#create' + get 'eeg037' => 'eeg037_sms_delivery#get' + post 'eeg037' => 'eeg037_sms_delivery#create' - get 'eg039' => 'eg039_signing_in_person#get' - post 'eg039' => 'eg039_signing_in_person#create' + get 'eeg038' => 'eeg038_responsive_signing#get' + post 'eeg038' => 'eeg038_responsive_signing#create' - get 'eg040' => 'eg040_set_document_visibility#get' - post 'eg040' => 'eg040_set_document_visibility#create' + get 'eeg039' => 'eeg039_signing_in_person#get' + post 'eeg039' => 'eeg039_signing_in_person#create' - get 'eg041' => 'eg041_cfr_embedded_signing#get' - post 'eg041' => 'eg041_cfr_embedded_signing#create' - end + get 'eeg040' => 'eeg040_set_document_visibility#get' + post 'eeg040' => 'eeg040_set_document_visibility#create' + + get 'eeg041' => 'eeg041_cfr_embedded_signing#get' + post 'eeg041' => 'eeg041_cfr_embedded_signing#create' end root 'ds_common#index' @@ -239,10 +233,6 @@ get '/ds/mustAuthenticateJwt' => 'ds_common#ds_must_authenticate_jwt' post '/ds/mustAuthenticateJwt' => 'ds_common#ds_must_authenticate' - get '/ds/chooseApi' => 'ds_common#choose_api' - - post '/ds/apiSelected' => 'ds_common#api_selected' - get '/ds/session' => 'session#show' # default root diff --git a/quick_acg/app/controllers/ds_common_controller.rb b/quick_acg/app/controllers/ds_common_controller.rb index 1e00524..f5b2630 100644 --- a/quick_acg/app/controllers/ds_common_controller.rb +++ b/quick_acg/app/controllers/ds_common_controller.rb @@ -2,6 +2,7 @@ class DsCommonController < ApplicationController def index + session[:api] = 'eSignature' @show_doc = Rails.application.config.documentation handle_redirects end @@ -14,9 +15,9 @@ def handle_redirects enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) if enableCFR == "enabled" session[:status_cfr] = "enabled" - redirect_to '/eg041' + redirect_to '/eeg041' else - redirect_to '/eg001' + redirect_to '/eeg001' end end end diff --git a/quick_acg/app/views/e_sign/eg041_cfr_embedded_signing/get.html.erb b/quick_acg/app/views/e_sign/eeg041_cfr_embedded_signing/get.html.erb similarity index 100% rename from quick_acg/app/views/e_sign/eg041_cfr_embedded_signing/get.html.erb rename to quick_acg/app/views/e_sign/eeg041_cfr_embedded_signing/get.html.erb diff --git a/quick_acg/app/views/eg001_embedded_signing/get.html.erb b/quick_acg/app/views/eeg001_embedded_signing/get.html.erb similarity index 100% rename from quick_acg/app/views/eg001_embedded_signing/get.html.erb rename to quick_acg/app/views/eeg001_embedded_signing/get.html.erb diff --git a/quick_acg/config/initializers/omniauth.rb b/quick_acg/config/initializers/omniauth.rb index 7bc52f7..97c8b40 100644 --- a/quick_acg/config/initializers/omniauth.rb +++ b/quick_acg/config/initializers/omniauth.rb @@ -39,13 +39,13 @@ strategy.options[:authorize_params].prompt = strategy.options.prompt unless strategy.options[:allow_silent_authentication] session = strategy.session - case session[:examples_API] + case session[:api] when 'Rooms' strategy.options[:authorize_params].scope = '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' when 'Click' - strategy.options[:authorize_params].scope = 'signature click.manage click.send' + strategy.options[:authorize_params].scope = 'click.manage click.send' when 'Admin' - strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' + strategy.options[:authorize_params].scope = 'organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' end } end diff --git a/quick_acg/config/routes.rb b/quick_acg/config/routes.rb index fe2c640..65b03db 100644 --- a/quick_acg/config/routes.rb +++ b/quick_acg/config/routes.rb @@ -2,26 +2,26 @@ require_relative '../../app/controllers/eg_controller' require_relative '../../app/controllers/session_controller' require_relative '../../app/services/api_creator' -require_relative '../../app/controllers/eg001_embedded_signing_controller' +require_relative '../../app/controllers/eeg001_embedded_signing_controller' require_relative '../../app/services/eg001_embedded_signing_service' require_relative '../../app/services/utils.rb' class ESign end -require_relative '../../app/controllers/e_sign/eg041_cfr_embedded_signing_controller' +require_relative '../../app/controllers/e_sign/eeg041_cfr_embedded_signing_controller' require_relative '../../app/services/e_sign/eg041_cfr_embedded_signing_service' require_relative '../../app/services/e_sign/get_data_service' Rails.application.routes.draw do root 'ds_common#index' - get '/eg001' => 'eg001_embedded_signing#get' - post '/eg001' => 'eg001_embedded_signing#create' + get '/eeg001' => 'eeg001_embedded_signing#get' + post '/eeg001' => 'eeg001_embedded_signing#create' scope module: 'e_sign' do - get 'eg041' => 'eg041_cfr_embedded_signing#get' - post 'eg041' => 'eg041_cfr_embedded_signing#create' + get 'eeg041' => 'eeg041_cfr_embedded_signing#get' + post 'eeg041' => 'eeg041_cfr_embedded_signing#create' end # Login starts with POST'ing to: /auth/docusign # /auth/docusign is an internal route created by OmniAuth and the docusign strategy from: /lib/docusign.rb diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb deleted file mode 100644 index 652febb..0000000 --- a/test/application_system_test_case.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -class ApplicationSystemTestCase < ActionDispatch::SystemTestCase - driven_by :selenium, using: :chrome, screen_size: [1400, 1400] -end diff --git a/test/controllers/.keep b/test/controllers/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/controllers/ds_controller_test.rb b/test/controllers/ds_controller_test.rb deleted file mode 100644 index fefb0f4..0000000 --- a/test/controllers/ds_controller_test.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -class DsControllerTest < ActionDispatch::IntegrationTest - test 'should get ds_return' do - get ds_ds_return_url - assert_response :success - end -end diff --git a/test/controllers/eg002_signing_via_email_controller_test.rb b/test/controllers/eg002_signing_via_email_controller_test.rb deleted file mode 100644 index 40b54b4..0000000 --- a/test/controllers/eg002_signing_via_email_controller_test.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -class Eg002SigningViaEmailControllerTest < ActionDispatch::IntegrationTest - test 'should get get' do - get eg002_signing_via_email_get_url - assert_response :success - end - - test 'should get create' do - get eg002_signing_via_email_create_url - assert_response :success - end -end diff --git a/test/controllers/eg004_envelope_info_controller_test.rb b/test/controllers/eg004_envelope_info_controller_test.rb deleted file mode 100644 index b822342..0000000 --- a/test/controllers/eg004_envelope_info_controller_test.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -class Eg004EnvelopeInfoControllerTest < ActionDispatch::IntegrationTest - test 'should get get' do - get eg004_envelope_info_get_url - assert_response :success - end - - test 'should get create' do - get eg004_envelope_info_create_url - assert_response :success - end -end diff --git a/test/controllers/eg005_envelope_recipients_controller_test.rb b/test/controllers/eg005_envelope_recipients_controller_test.rb deleted file mode 100644 index 63265ee..0000000 --- a/test/controllers/eg005_envelope_recipients_controller_test.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -class Eg005EnvelopeRecipientsControllerTest < ActionDispatch::IntegrationTest - test 'should get get' do - get eg005_envelope_recipients_get_url - assert_response :success - end - - test 'should get create' do - get eg005_envelope_recipients_create_url - assert_response :success - end -end diff --git a/test/controllers/eg010_send_binary_docs_controller_test.rb b/test/controllers/eg010_send_binary_docs_controller_test.rb deleted file mode 100644 index f791f1b..0000000 --- a/test/controllers/eg010_send_binary_docs_controller_test.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -class Eg010SendBinaryDocsControllerTest < ActionDispatch::IntegrationTest - test 'should get get' do - get eg010_send_binary_docs_get_url - assert_response :success - end - - test 'should get create' do - get eg010_send_binary_docs_create_url - assert_response :success - end -end diff --git a/test/controllers/eg_controller_test.rb b/test/controllers/eg_controller_test.rb deleted file mode 100644 index 26c5fcb..0000000 --- a/test/controllers/eg_controller_test.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -class EgControllerTest < ActionDispatch::IntegrationTest - # test "the truth" do - # assert true - # end -end diff --git a/test/controllers/embedded_signing_controller_test.rb b/test/controllers/embedded_signing_controller_test.rb deleted file mode 100644 index 4a682d2..0000000 --- a/test/controllers/embedded_signing_controller_test.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -class EmbeddedSigningControllerTest < ActionDispatch::IntegrationTest - test 'should get get' do - get embedded_signing_get_url - assert_response :success - end - - test 'should get create' do - get embedded_signing_create_url - assert_response :success - end -end diff --git a/test/controllers/get_controller_test.rb b/test/controllers/get_controller_test.rb deleted file mode 100644 index 7d59028..0000000 --- a/test/controllers/get_controller_test.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -class GetControllerTest < ActionDispatch::IntegrationTest - test 'should get create' do - get get_create_url - assert_response :success - end -end diff --git a/test/controllers/home_controller_test.rb b/test/controllers/home_controller_test.rb deleted file mode 100644 index 77f010f..0000000 --- a/test/controllers/home_controller_test.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -class HomeControllerTest < ActionDispatch::IntegrationTest - test 'should get index' do - get home_index_url - assert_response :success - end -end diff --git a/test/controllers/list_envelopes_controller_test.rb b/test/controllers/list_envelopes_controller_test.rb deleted file mode 100644 index 375f5e1..0000000 --- a/test/controllers/list_envelopes_controller_test.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -class ListEnvelopesControllerTest < ActionDispatch::IntegrationTest - test 'should get create' do - get list_envelopes_create_url - assert_response :success - end -end diff --git a/test/eg001_embedded_signing_test.rb b/test/eg001_embedded_signing_test.rb new file mode 100644 index 0000000..70f0cac --- /dev/null +++ b/test/eg001_embedded_signing_test.rb @@ -0,0 +1,83 @@ +require 'test/unit' +require 'docusign_esign' +require 'json' +require_relative 'test_helper' +require_relative '../app/services/api_creator' +require_relative '../app/services/eg001_embedded_signing_service' + +class Eg001EmbeddedSigningTest < TestHelper + setup do + setup_test_data + + args = { + account_id: @account_id, + base_path: @base_path, + access_token: @access_token, + signer_email: @config['signer_email'], + signer_name: @config['signer_name'], + ds_ping_url: @data[:ds_ping_url], + signer_client_id: @data[:signer_client_id], + pdf_filename: @data[:doc_pdf] + } + + @eg001_embedded_signing_service = Eg001EmbeddedSigningService.new(args) + end + + test 'should create and send an envelope if correct data is provided' do + redirect_url = @eg001_embedded_signing_service.worker + + assert_not_nil redirect_url + assert_not_empty redirect_url + end + + test 'should create correct envelope definition if correct data is provided' do + expected_document = create_ds_document(@data[:doc_pdf], 'Lorem Ipsum', 'pdf', '1') + + expected_sign_here_tab = DocuSign_eSign::SignHere.new + expected_sign_here_tab.anchor_string = '/sn1/' + expected_sign_here_tab.anchor_units = 'pixels' + expected_sign_here_tab.anchor_x_offset = '20' + expected_sign_here_tab.anchor_y_offset = '10' + + expected_tabs = DocuSign_eSign::Tabs.new + expected_tabs.sign_here_tabs = [expected_sign_here_tab] + + expected_signer = DocuSign_eSign::Signer.new + expected_signer.email = @config['signer_email'] + expected_signer.name = @config['signer_name'] + expected_signer.client_user_id = @data[:signer_client_id] + expected_signer.recipient_id = 1 + + expected_signer.tabs = expected_tabs + + expected_recipient = DocuSign_eSign::Recipients.new + expected_recipient.signers = [expected_signer] + + expected_envelope = DocuSign_eSign::EnvelopeDefinition.new + expected_envelope.email_subject = 'Please sign this document sent from Ruby SDK' + expected_envelope.documents = [expected_document] + expected_envelope.recipients = expected_recipient + expected_envelope.status = 'sent' + + envelope = @eg001_embedded_signing_service.send(:make_envelope, @data[:signer_client_id], @data[:doc_pdf], @config['signer_email'], @config['signer_name']) + + assert_not_nil envelope + assert_equal expected_envelope, envelope + end + + test 'should create correct recipient view if correct data is provided' do + expected_view_request = DocuSign_eSign::RecipientViewRequest.new + expected_view_request.return_url = "#{@data[:ds_return_url]}?state=123" + expected_view_request.authentication_method = 'none' + expected_view_request.email = @config['signer_email'] + expected_view_request.user_name = @config['signer_name'] + expected_view_request.client_user_id = @data[:signer_client_id] + expected_view_request.ping_frequency = '600' + expected_view_request.ping_url = @data[:ds_ping_url] + + recipient_view = @eg001_embedded_signing_service.send(:make_recipient_view_request, @data[:signer_client_id], @data[:ds_return_url], @data[:ds_ping_url], @config['signer_email'], @config['signer_name']) + + assert_not_nil recipient_view + assert_equal expected_view_request, recipient_view + end +end diff --git a/test/eg002_sign_via_email_test.rb b/test/eg002_sign_via_email_test.rb new file mode 100644 index 0000000..1a06f9e --- /dev/null +++ b/test/eg002_sign_via_email_test.rb @@ -0,0 +1,139 @@ +require 'test/unit' +require 'docusign_esign' +require_relative './test_helper' +require_relative '../app/services/api_creator' +require_relative '../app/services/e_sign/eg002_signing_via_email_service' + +class Eg002SignViaEmailTest < TestHelper + setup do + setup_test_data + + envelope_args = { + signer_email: @config['signer_email'], + signer_name: @config['signer_name'], + cc_email: @data[:cc_email], + cc_name: @data[:cc_name], + status: 'sent', + doc_docx: @data[:doc_docx], + doc_pdf: @data[:doc_pdf] + } + @args = { + account_id: @account_id, + base_path: @base_path, + access_token: @access_token, + envelope_args: envelope_args + } + + @eg002 = ESign::Eg002SigningViaEmailService.new(@args) + end + + test 'should create and send an envelope if correct data is provided' do + results = @eg002.worker + + assert_not_nil results + assert_not_empty results + assert_not_nil results['envelope_id'] + assert_not_empty results['envelope_id'] + end + + test 'should create correct envelope definition if correct data is provided' do + expected_html_document = create_ds_document(expected_html_doc, 'Order acknowledgement', 'html', '1') + expected_docx_document = create_ds_document(@data[:doc_docx], 'Battle Plan', 'docx', '2') + expected_pdf_document = create_ds_document(@data[:doc_pdf], 'Lorem Ipsum', 'pdf', '3') + + expected_sign_here_tab1 = DocuSign_eSign::SignHere.new + expected_sign_here_tab1.anchor_string = '**signature_1**' + expected_sign_here_tab1.anchor_units = 'pixels' + expected_sign_here_tab1.anchor_x_offset = '20' + expected_sign_here_tab1.anchor_y_offset = '10' + + expected_sign_here_tab2 = DocuSign_eSign::SignHere.new + expected_sign_here_tab2.anchor_string = '/sn1/' + expected_sign_here_tab2.anchor_units = 'pixels' + expected_sign_here_tab2.anchor_x_offset = '20' + expected_sign_here_tab2.anchor_y_offset = '10' + + expected_tabs = DocuSign_eSign::Tabs.new + expected_tabs.sign_here_tabs = [expected_sign_here_tab1, expected_sign_here_tab2] + + expected_signer = DocuSign_eSign::Signer.new + expected_signer.email = @config['signer_email'] + expected_signer.name = @config['signer_name'] + expected_signer.recipient_id = '1' + expected_signer.routing_order = '1' + + expected_signer.tabs = expected_tabs + + expected_cc = DocuSign_eSign::CarbonCopy.new + expected_cc.email = @data[:cc_email] + expected_cc.name = @data[:cc_name] + expected_cc.routing_order = '2' + expected_cc.recipient_id = '2' + + expected_recipient = DocuSign_eSign::Recipients.new + expected_recipient.signers = [expected_signer] + expected_recipient.carbon_copies = [expected_cc] + + expected_envelope = DocuSign_eSign::EnvelopeDefinition.new + expected_envelope.email_subject = 'Please sign this document set' + expected_envelope.documents = [expected_html_document, expected_docx_document, expected_pdf_document] + expected_envelope.recipients = expected_recipient + expected_envelope.status = 'sent' + + envelope_args = { + signer_email: @config['signer_email'], + signer_name: @config['signer_name'], + cc_email: @data[:cc_email], + cc_name: @data[:cc_name], + status: 'sent', + doc_docx: @data[:doc_docx], + doc_pdf: @data[:doc_pdf] + } + + envelope = @eg002.send(:make_envelope, envelope_args) + + assert_not_nil envelope + assert_equal expected_envelope, envelope + end + + test 'should create correct html document if correct data is provided' do + envelope_args = { + signer_email: @config['signer_email'], + signer_name: @config['signer_name'], + cc_email: @data[:cc_email], + cc_name: @data[:cc_name] + } + + html_document = @eg002.send(:create_document1, envelope_args) + + assert_not_nil html_document + assert_not_empty html_document + assert_equal expected_html_doc, html_document + end + + def expected_html_doc + " + + + + + + +

    World Wide Corp

    +

    Order Processing Division

    +

    Ordered by #{@config['signer_name']}

    +

    Email: #{@config['signer_email']}

    +

    Copy to: #{@data[:cc_name]}, #{@data[: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**/

    + + " + end +end + diff --git a/test/eg008_create_template_test.rb b/test/eg008_create_template_test.rb new file mode 100644 index 0000000..2ab2159 --- /dev/null +++ b/test/eg008_create_template_test.rb @@ -0,0 +1,143 @@ +require 'test/unit' +require_relative './test_helper' +require_relative '../app/services/api_creator' +require_relative '../app/services/e_sign/eg008_create_template_service' + +class Eg008CreateTemplateTest < TestHelper + setup do + setup_test_data + + args = { + account_id: @account_id, + base_path: @base_path, + access_token: @access_token, + template_name: @data[:template_name] + } + + @eg008 = ESign::Eg008CreateTemplateService.new(args) + end + + test 'should create template if correct data is provided' do + results = @eg008.worker + + TestData.set_template_id results[:template_id] + + assert_not_nil results + assert_not_nil results[:template_id] + assert_not_nil results[:template_name] + assert_not_empty results[:template_id] + assert_not_empty results[:template_name] + end + + test 'should create correct template definition if correct data is provided' do + expected_document = create_ds_document(@data[:doc_for_template], 'Lorem Ipsum', 'pdf', '1') + + expected_sign_here = DocuSign_eSign::SignHere.new + expected_sign_here.document_id = '1' + expected_sign_here.page_number = '1' + expected_sign_here.x_position = '191' + expected_sign_here.y_position = '148' + + expected_check1 = DocuSign_eSign::Checkbox.new( + 'documentId' => '1', 'pageNumber' => '1', + 'xPosition' => '75', 'yPosition' => '417', 'tabLabel' => 'ckAuthorization' + ) + + expected_check2 = DocuSign_eSign::Checkbox.new( + 'documentId' => '1', 'pageNumber' => '1', + 'xPosition' => '75', 'yPosition' => '447', 'tabLabel' => 'ckAuthentication' + ) + expected_check3 = DocuSign_eSign::Checkbox.new( + 'documentId' => '1', 'pageNumber' => '1', + 'xPosition' => '75', 'yPosition' => '478', 'tabLabel' => 'ckAgreement' + ) + expected_check4 = DocuSign_eSign::Checkbox.new( + 'documentId' => '1', 'pageNumber' => '1', + 'xPosition' => '75', 'yPosition' => '508', 'tabLabel' => 'ckAcknowledgement' + ) + + expected_list1 = DocuSign_eSign::List.new( + 'documentId' => '1', + 'pageNumber' => '1', + 'xPosition' => '142', + 'yPosition' => '291', + 'font' => 'helvetica', + 'fontSize' => 'size14', + 'tabLabel' => 'list', + 'required' => 'false', + 'listItems' => [ + DocuSign_eSign::ListItem.new('text' => 'Red', 'value' => 'red'), + DocuSign_eSign::ListItem.new('text' => 'Orange', 'value' => 'orange'), + DocuSign_eSign::ListItem.new('text' => 'Yellow', 'value' => 'yellow'), + DocuSign_eSign::ListItem.new('text' => 'Green', 'value' => 'green'), + DocuSign_eSign::ListItem.new('text' => 'Blue', 'value' => 'blue'), + DocuSign_eSign::ListItem.new('text' => 'Indigo', 'value' => 'indigo'), + DocuSign_eSign::ListItem.new('text' => 'Violet', 'value' => 'violet') + ] + ) + + expected_number1 = DocuSign_eSign::Number.new( + 'documentId' => '1', 'pageNumber' => '1', + 'xPosition' => '163', 'yPosition' => '260', + 'font' => 'helvetica', 'fontSize' => 'size14', + 'tabLabel' => 'numbersOnly', 'width' => '84', 'required' => 'false' + ) + expected_radio_group = DocuSign_eSign::RadioGroup.new( + 'documentId' => '1', 'groupName' => 'radio1', + 'radios' => [ + DocuSign_eSign::Radio.new('pageNumber' => '1', 'xPosition' => '142', + 'yPosition' => '384', 'value' => 'white', + 'required' => 'false'), + DocuSign_eSign::Radio.new('pageNumber' => '1', 'xPosition' => '74', + 'yPosition' => '384', 'value' => 'red', + 'required' => 'false'), + DocuSign_eSign::Radio.new('pageNumber' => '1', 'xPosition' => '220', + 'yPosition' => '384', 'value' => 'blue', + 'required' => 'false') + ] + ) + + expected_text = DocuSign_eSign::Text.new( + 'documentId' => '1', 'pageNumber' => '1', + 'xPosition' => '153', 'yPosition' => '230', + 'font' => 'helvetica', 'fontSize' => 'size14', + 'tabLabel' => 'text', 'height' => '23', + 'width' => '84', 'required' => 'false' + ) + + expected_tabs = DocuSign_eSign::Tabs.new + expected_tabs.sign_here_tabs = [expected_sign_here] + expected_tabs.checkbox_tabs = [expected_check1, expected_check2, expected_check3, expected_check4] + expected_tabs.list_tabs = [expected_list1] + expected_tabs.number_tabs = [expected_number1] + expected_tabs.radio_group_tabs = [expected_radio_group] + expected_tabs.text_tabs = [expected_text] + + expected_signer = DocuSign_eSign::Signer.new + expected_signer.role_name = 'signer' + expected_signer.recipient_id = '1' + expected_signer.routing_order = '1' + expected_signer.tabs = expected_tabs + + expected_cc = DocuSign_eSign::CarbonCopy.new + expected_cc.role_name = 'cc' + expected_cc.recipient_id = '2' + expected_cc.routing_order = '2' + + expected_recipients = DocuSign_eSign::Recipients.new + expected_recipients.signers = [expected_signer] + expected_recipients.carbon_copies = [expected_cc] + + expected_template = DocuSign_eSign::EnvelopeTemplate.new + expected_template.documents = [expected_document] + expected_template.name = @data[:template_name] + expected_template.email_subject = 'Please sign this document' + expected_template.recipients = expected_recipients + expected_template.status = 'created' + + template = @eg008.send(:make_template_req) + + assert_not_nil template + assert_equal expected_template, template + end +end diff --git a/test/eg009_use_template_test.rb b/test/eg009_use_template_test.rb new file mode 100644 index 0000000..51bb884 --- /dev/null +++ b/test/eg009_use_template_test.rb @@ -0,0 +1,81 @@ +require 'test/unit' +require_relative './test_helper' +require_relative '../app/services/api_creator' +require_relative '../app/services/e_sign/eg009_use_template_service' + +class Eg009UseTemplateTest < TestHelper + setup do + setup_test_data + + envelope_args = { + signer_email: @config['signer_email'], + signer_name: @config['signer_name'], + cc_email: @data[:cc_email], + cc_name: @data[:cc_name], + template_id: TestData.get_template_id + } + args = { + account_id: @account_id, + base_path: @base_path, + access_token: @access_token, + envelope_args: envelope_args + } + + @eg009 = ESign::Eg009UseTemplateService.new(args) + end + + test 'should create the envelope with template if correct data is provided' do + results = @eg009.worker + + assert_not_nil results + assert_not_nil results[:envelope_id] + assert_not_empty results[:envelope_id] + end + + test 'should create correct envelope definition if correct data is provided' do + expected_check1 = DocuSign_eSign::Checkbox.new + expected_check1.tab_label = 'ckAuthorization' + expected_check1.selected = true + + expected_check3 = DocuSign_eSign::Checkbox.new + expected_check3.tab_label = 'ckAgreement' + expected_check3.selected = true + + expected_text = DocuSign_eSign::Text.new + expected_text.tab_label = 'text' + expected_text.value = 'Jabberwocky!' + + expected_tabs = DocuSign_eSign::Tabs.new + expected_tabs.checkbox_tabs = [expected_check1, expected_check3] + expected_tabs.text_tabs = [expected_text] + + expected_signer = DocuSign_eSign::TemplateRole.new + expected_signer.email = @config['signer_email'] + expected_signer.name = @config['signer_name'] + expected_signer.role_name = 'signer' + expected_signer.tabs = expected_tabs + + expected_cc = DocuSign_eSign::TemplateRole.new + expected_cc.email = @data[:cc_email] + expected_cc.name = @data[:cc_name] + expected_cc.role_name = 'cc' + + expected_envelope = DocuSign_eSign::EnvelopeDefinition.new + expected_envelope.status = 'sent' + expected_envelope.template_id = TestData.get_template_id + expected_envelope.template_roles = [expected_signer, expected_cc] + + envelope_args = { + signer_email: @config['signer_email'], + signer_name: @config['signer_name'], + cc_email: @data[:cc_email], + cc_name: @data[:cc_name], + template_id: TestData.get_template_id + } + + envelope = @eg009.send(:make_envelope, envelope_args) + + assert_not_nil envelope + assert_equal expected_envelope, envelope + end +end diff --git a/test/eg013_add_doc_to_template_test.rb b/test/eg013_add_doc_to_template_test.rb new file mode 100644 index 0000000..ced9a91 --- /dev/null +++ b/test/eg013_add_doc_to_template_test.rb @@ -0,0 +1,168 @@ +require 'test/unit' +require_relative './test_helper' +require_relative '../app/services/api_creator' +require_relative '../app/services/e_sign/eg013_add_doc_to_template_service' + +class Eg013AddDocToTemplateTest < TestHelper + setup do + setup_test_data + + envelope_args = { + signer_email: @config['signer_email'], + signer_name: @config['signer_name'], + cc_email: @data[:cc_email], + cc_name: @data[:cc_name], + item: @data[:item], + quantity: @data[:quantity], + signer_client_id: @data[:signer_client_id], + template_id: TestData.get_template_id, + ds_return_url: @data[:ds_return_url] + } + args = { + account_id: @account_id, + base_path: @base_path, + access_token: @access_token, + envelope_args: envelope_args + } + + @eg013 = ESign::Eg013AddDocToTemplateService.new(args) + end + + test 'should correctly add document to a template if correct data is provided' do + results = @eg013.worker + + assert_not_nil results + assert_not_nil results[:envelope_id] + assert_not_empty results[:envelope_id] + assert_not_nil results[:redirect_url] + assert_not_empty results[:redirect_url] + end + + test 'should create the correct envelope definition if correct data is provided' do + expected_signer1 = DocuSign_eSign::Signer.new + expected_signer1.email = @config['signer_email'] + expected_signer1.name = @config['signer_name'] + expected_signer1.role_name = 'signer' + expected_signer1.recipient_id = '1' + expected_signer1.client_user_id = @data[:signer_client_id] + + expected_cc1 = DocuSign_eSign::CarbonCopy.new + expected_cc1.email = @data[:cc_email] + expected_cc1.name = @data[:cc_name] + expected_cc1.role_name = 'cc' + expected_cc1.recipient_id = '2' + + expected_recipients_server_template = DocuSign_eSign::Recipients.new + expected_recipients_server_template.carbon_copies = [expected_cc1] + expected_recipients_server_template.signers = [expected_signer1] + + expected_server_template = DocuSign_eSign::ServerTemplate.new + expected_server_template.sequence = '1' + expected_server_template.template_id = TestData.get_template_id + + expected_inline_template1 = DocuSign_eSign::InlineTemplate.new + expected_inline_template1.sequence = '2' + expected_inline_template1.recipients = expected_recipients_server_template + + expected_comp_template1 = DocuSign_eSign::CompositeTemplate.new + expected_comp_template1.server_templates = [expected_server_template] + expected_comp_template1.inline_templates = [expected_inline_template1] + + expected_sign_here1 = DocuSign_eSign::SignHere.new + expected_sign_here1.anchor_string = '**signature_1**' + expected_sign_here1.anchor_y_offset = '10' + expected_sign_here1.anchor_units = 'pixels' + expected_sign_here1.anchor_x_offset = '20' + + expected_signer1_tabs = DocuSign_eSign::Tabs.new + expected_signer1_tabs.sign_here_tabs = [expected_sign_here1] + + expected_signer1_added_doc = DocuSign_eSign::Signer.new + expected_signer1_added_doc.email = @config['signer_email'] + expected_signer1_added_doc.name = @config['signer_name'] + expected_signer1_added_doc.role_name = 'signer' + expected_signer1_added_doc.recipient_id = '1' + expected_signer1_added_doc.client_user_id = @data[:signer_client_id] + expected_signer1_added_doc.tabs = expected_signer1_tabs + + expected_recipients_added_doc = DocuSign_eSign::Recipients.new + expected_recipients_added_doc.carbon_copies = [expected_cc1] + expected_recipients_added_doc.signers = [expected_signer1_added_doc] + + expected_doc = create_ds_document(expected_html_doc, 'Appendix 1--Sales order', 'html', '1') + + expected_inline_template2 = DocuSign_eSign::InlineTemplate.new + expected_inline_template2.sequence = '1' + expected_inline_template2.recipients = expected_recipients_added_doc + + expected_comp_template2 = DocuSign_eSign::CompositeTemplate.new + expected_comp_template2.composite_template_id = '2' + expected_comp_template2.inline_templates = [expected_inline_template2] + expected_comp_template2.document = expected_doc + + expected_envelope = DocuSign_eSign::EnvelopeDefinition.new + expected_envelope.status = 'sent' + expected_envelope.composite_templates = [expected_comp_template1, expected_comp_template2] + + envelope_args = { + signer_email: @config['signer_email'], + signer_name: @config['signer_name'], + cc_email: @data[:cc_email], + cc_name: @data[:cc_name], + item: @data[:item], + quantity: @data[:quantity], + signer_client_id: @data[:signer_client_id], + template_id: TestData.get_template_id, + ds_return_url: @data[:ds_return_url] + } + + envelope = @eg013.send(:make_envelope, envelope_args) + + assert_not_nil envelope + assert_equal expected_envelope, envelope + end + + test 'should return correct HTML document if correct data is provided' do + envelope_args = { + signer_email: @config['signer_email'], + signer_name: @config['signer_name'], + cc_email: @data[:cc_email], + cc_name: @data[:cc_name], + item: @data[:item], + quantity: @data[:quantity] + } + + html_doc = @eg013.send(:create_document1, envelope_args) + + assert_not_nil html_doc + assert_not_empty html_doc + assert_equal expected_html_doc, html_doc + end + + def expected_html_doc + <<~HEREDOC + + + + + + +

    World Wide Corp

    +

    Order Processing Division

    +

    Ordered by #{@config['signer_name']}

    +

    Email: #{@config['signer_email']}

    +

    Copy to: #{@data[:cc_name]}, #{@data[:cc_email]}

    +

    Item: #{@data[:item]}, quantity: #{@data[:quantity]} at market price.

    +

    + 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**/

    + + + HEREDOC + end +end diff --git a/test/eg017_set_template_tab_values_test.rb b/test/eg017_set_template_tab_values_test.rb new file mode 100644 index 0000000..9f27c64 --- /dev/null +++ b/test/eg017_set_template_tab_values_test.rb @@ -0,0 +1,130 @@ +require 'test/unit' +require_relative './test_helper' +require_relative '../app/services/api_creator' +require_relative '../app/services/e_sign/eg017_set_template_tab_values_service' + +class Eg017SetTemplateTabValuesTest < TestHelper + setup do + setup_test_data + + envelope_args = { + signer_email: @config['signer_email'], + signer_name: @config['signer_name'], + cc_email: @data[:cc_email], + cc_name: @data[:cc_name], + template_id: TestData.get_template_id + } + args = { + account_id: @account_id, + base_path: @base_path, + access_token: @access_token, + ds_ping_url: @data[:ds_ping_url], + envelope_args: envelope_args + } + + @eg017 = ESign::Eg017SetTemplateTabValuesService.new(args) + end + + test 'should correctly set the tab values of template if correct data is provided' do + results = @eg017.worker + + assert_not_nil results + assert_not_empty results + end + + test 'should create correct envelope definition if correct data is provided' do + expected_list1 = DocuSign_eSign::List.new + expected_list1.value = 'Green' + expected_list1.document_id = '1' + expected_list1.page_number = '1' + expected_list1.tab_label = 'list' + + expected_check1 = DocuSign_eSign::Checkbox.new + expected_check1.tab_label = 'ckAuthorization' + expected_check1.selected = 'true' + + expected_check3 = DocuSign_eSign::Checkbox.new + expected_check3.tab_label = 'ckAgreement' + expected_check3.selected = 'true' + + expected_radio = DocuSign_eSign::Radio.new + expected_radio.value = 'white' + expected_radio.selected = 'true' + + expected_radio_group = DocuSign_eSign::RadioGroup.new + expected_radio_group.group_name = 'radio1' + expected_radio_group.radios = [expected_radio] + + expected_text = DocuSign_eSign::Text.new + expected_text.tab_label = 'text' + expected_text.value = 'Jabberwocky!' + + expected_text_extra = DocuSign_eSign::Text.new + expected_text_extra.document_id = '1' + expected_text_extra.page_number = '1' + expected_text_extra.x_position = '280' + expected_text_extra.y_position = '172' + expected_text_extra.font = 'helvetica' + expected_text_extra.font_size = 'size14' + expected_text_extra.tab_label = 'added text field' + expected_text_extra.height = '23' + expected_text_extra.width = '84' + expected_text_extra.required = 'false' + expected_text_extra.bold = 'true' + expected_text_extra.value = @config['signer_name'] + expected_text_extra.locked = 'false' + expected_text_extra.tab_id = 'name' + + expected_tabs = DocuSign_eSign::Tabs.new + expected_tabs.list_tabs = [expected_list1] + expected_tabs.checkbox_tabs = [expected_check1, expected_check3] + expected_tabs.radio_group_tabs = [expected_radio_group] + expected_tabs.text_tabs = [expected_text, expected_text_extra] + + expected_signer = DocuSign_eSign::TemplateRole.new + expected_signer.client_user_id = 1000 + expected_signer.email = @config['signer_email'] + expected_signer.name = @config['signer_name'] + expected_signer.role_name = 'signer' + expected_signer.tabs = expected_tabs + + expected_cc = DocuSign_eSign::TemplateRole.new + expected_cc.email = @data[:cc_email] + expected_cc.name = @data[:cc_name] + expected_cc.role_name = 'cc' + + expected_envelope = DocuSign_eSign::EnvelopeDefinition.new + expected_envelope.template_roles = [expected_signer, expected_cc] + expected_envelope.status = 'sent' + expected_envelope.template_id = TestData.get_template_id + + envelope_args = { + signer_email: @config['signer_email'], + signer_name: @config['signer_name'], + cc_email: @data[:cc_email], + cc_name: @data[:cc_name], + template_id: TestData.get_template_id + } + + envelope = @eg017.send(:make_envelope, envelope_args) + + assert_not_nil envelope + assert_equal expected_envelope, envelope + end + + test 'should create correct recipient view request if correct data is provided' do + expected_view_request = DocuSign_eSign::RecipientViewRequest.new + expected_view_request.return_url = "#{@data[:ds_return_url]}?state=123" + expected_view_request.authentication_method = 'none' + expected_view_request.email = @config['signer_email'] + expected_view_request.user_name = @config['signer_name'] + expected_view_request.client_user_id = @data[:signer_client_id] + expected_view_request.ping_frequency = '600' + expected_view_request.ping_url = @data[:ds_ping_url] + + view_request = @eg017.send(:make_recipient_view_request, @config['signer_email'], @config['signer_name'], @data[:signer_client_id], @data[:ds_return_url], @data[:ds_ping_url]) + + assert_not_nil view_request + assert_equal expected_view_request, view_request + end +end diff --git a/test/fixtures/.keep b/test/fixtures/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/helpers/.keep b/test/helpers/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/integration/.keep b/test/integration/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/mailers/.keep b/test/mailers/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/models/.keep b/test/models/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/run_tests.rb b/test/run_tests.rb new file mode 100644 index 0000000..5d78783 --- /dev/null +++ b/test/run_tests.rb @@ -0,0 +1 @@ +Dir["#{File.dirname(File.absolute_path(__FILE__))}/**/*_test.rb"].sort.each { |file| require file } diff --git a/test/system/.keep b/test/system/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/test_helper.rb b/test/test_helper.rb index 2ee518e..08fb86b 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,12 +1,138 @@ -# frozen_string_literal: true +require 'docusign_esign' +require 'yaml' +require 'test/unit' -ENV['RAILS_ENV'] ||= 'test' -require_relative '../config/environment' -require 'rails/test_help' +$_scopes = %w[ + signature impersonation +] -class ActiveSupport::TestCase - # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. - fixtures :all +class TestHelper < Test::Unit::TestCase + def setup_test_data + auth_results = authenticate - # Add more helper methods to be used by all tests here... + @config = get_config_data + @data = get_common_data + + @account_id = auth_results[:account_id] + @access_token = auth_results[:access_token] + @base_path = auth_results[:base_path] + end + + def authenticate + ds_config = get_config_data + data = get_common_data + + configuration = DocuSign_eSign::Configuration.new + configuration.debugging = true + api_client = DocuSign_eSign::ApiClient.new(configuration) + api_client.set_oauth_base_path(data[:authorization_server]) + + rsa_pk = './config/docusign_private_key.txt' + begin + token = api_client.request_jwt_user_token(ds_config['jwt_integration_key'], ds_config['impersonated_user_guid'], rsa_pk, 3600, $_scopes) + user_info_response = api_client.get_user_info(token.access_token) + account = user_info_response.accounts.find(&:is_default) + + { + access_token: token.access_token, + account_id: account.account_id, + base_path: account.base_uri + } + rescue OpenSSL::PKey::RSAError => e + Rails.logger.error e.inspect + + raise "Please add your private RSA key to: #{rsa_pk}" if File.read(rsa_pk).starts_with? '{RSA_PRIVATE_KEY}' + + raise + rescue DocuSign_eSign::ApiError => e + body = JSON.parse(e.response_body) + if body['error'] == 'consent_required' + authenticate if get_consent + else + puts 'API Error' + puts body['error'] + puts body['message'] + exit + end + end + end + + def get_config_data + config_file_path = './config/appsettings.yml' + begin + config_file_contents = File.read(config_file_path) + rescue Errno::ENOENT + warn 'Missing config file' + raise + end + YAML.unsafe_load(config_file_contents)['default'] + end + + def get_common_data + { + cc_name: 'Test Name', + cc_email: 'test@mail.com', + authorization_server: 'account-d.docusign.com', + signer_client_id: 1000, + ds_ping_url: 'http://localhost:3000', + ds_return_url: 'http://localhost:3000/ds_common-return', + doc_docx: './data/World_Wide_Corp_Battle_Plan_Trafalgar.docx', + doc_pdf: './data/World_Wide_Corp_lorem.pdf', + doc_for_template: './data/World_Wide_Corp_fields.pdf', + item: 'Item', + quantity: 5, + template_name: 'Example Signer and CC template' + } + end + + def create_ds_document(filepath_or_content, name, file_ext, doc_id) + content = File.exist?(filepath_or_content) ? File.binread(filepath_or_content) : filepath_or_content + + document = DocuSign_eSign::Document.new + document.document_base64 = Base64.encode64(content) + document.name = name + document.file_extension = file_ext + document.document_id = doc_id + + document + end + + private + + def get_consent + ds_config = get_config_data + + url_scopes = $_scopes.join('+') + # Construct consent URL + redirect_uri = 'https://developers.docusign.com/platform/auth/consent' + consent_url = "#{ds_config['authorization_server']}/oauth/auth?response_type=code&" \ + "scope=#{url_scopes}&client_id=#{ds_config['jwt_integration_key']}&" \ + "redirect_uri=#{redirect_uri}" + + puts 'Open the following URL in your browser to grant consent to the application:' + puts consent_url + puts "Consent granted? \n 1)Yes \n 2)No" + continue = gets + if continue.chomp == '1' + true + else + puts 'Please grant consent' + exit + end + end +end + +class TestData + @template_id + + def self.get_template_id + @template_id + end + + def self.set_template_id(id) + @template_id = id + end +end + +class ESign end From ff5c39f04b9d34433010867353da55b41b177fa1 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Sat, 21 Jan 2023 01:40:47 +0200 Subject: [PATCH 180/363] Added CI/CD workflow (#105) * add ci/cd workflow, code style fixes --- .github/workflows/rubyonrails.yml | 40 +++++++++++++ .rubocop.yml | 18 ++++++ .ruby-version | 2 +- Gemfile | 3 +- Gemfile.lock | 2 +- .../ceg006_embed_clickwrap_controller.rb | 48 +++++++-------- app/controllers/ds_common_controller.rb | 27 ++++----- .../eeg014_collect_payment_controller.rb | 52 ++++++++-------- .../eeg020_phone_authentication_controller.rb | 8 +-- ...32_pauses_signature_workflow_controller.rb | 8 +-- ..._unpauses_signature_workflow_controller.rb | 8 +-- ...4_use_conditional_recipients_controller.rb | 60 +++++++++---------- .../eeg036_delayed_routing_controller.rb | 52 ++++++++-------- .../e_sign/eeg037_sms_delivery_controller.rb | 56 +++++++++-------- .../eeg039_signing_in_person_controller.rb | 8 +-- ...g040_set_document_visibility_controller.rb | 8 +-- .../eeg041_cfr_embedded_signing_controller.rb | 8 +-- .../eeg001_embedded_signing_controller.rb | 8 +-- ...eg001_get_monitoring_dataset_controller.rb | 2 +- .../meg002_post_web_query_controller.rb | 2 +- .../eg006_embed_clickwrap_service.rb | 19 +++--- .../eg041_cfr_embedded_signing_service.rb | 32 +++++----- app/services/e_sign/get_data_service.rb | 4 +- .../eg001_get_monitoring_dataset_service.rb | 7 +-- .../eg002_post_web_query_service.rb | 6 +- app/services/utils.rb | 2 +- bin/rails | 15 ++--- bin/rake | 13 +--- bin/setup | 33 +++++----- .../app/controllers/ds_common_controller.rb | 6 +- quick_acg/config/routes.rb | 2 +- test/eg001_embedded_signing_test.rb | 2 +- test/eg002_sign_via_email_test.rb | 2 +- test/eg008_create_template_test.rb | 1 + test/eg009_use_template_test.rb | 1 + test/eg013_add_doc_to_template_test.rb | 1 + test/eg017_set_template_tab_values_test.rb | 1 + test/test_helper.rb | 30 +++++++--- 38 files changed, 320 insertions(+), 277 deletions(-) create mode 100644 .github/workflows/rubyonrails.yml diff --git a/.github/workflows/rubyonrails.yml b/.github/workflows/rubyonrails.yml new file mode 100644 index 0000000..01316ce --- /dev/null +++ b/.github/workflows/rubyonrails.yml @@ -0,0 +1,40 @@ +# This workflow uses actions that are not certified by GitHub. They are +# provided by a third-party and are governed by separate terms of service, +# privacy policy, and support documentation. +# +# This workflow will install a prebuilt Ruby version, install dependencies, and +# run tests and linters. +name: "Ruby on Rails CI" +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install Ruby and gems + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + ruby-version: 3.1.2 + + - name: Run linter + run: bundle exec rubocop --parallel + + - name: Run tests + run: | + gem install docusign_esign + ruby test/run_tests.rb + env: + CLIENT_ID: ${{ secrets.CLIENT_ID }} + USER_ID: ${{ secrets.USER_ID }} + SIGNER_EMAIL: ${{ secrets.SIGNER_EMAIL }} + SIGNER_NAME: ${{ secrets.SIGNER_NAME }} + PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} + diff --git a/.rubocop.yml b/.rubocop.yml index 97c9888..33c44d9 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,3 +1,15 @@ +AllCops: + Exclude: + - '**/db/**/*' + - '**/config/**/*' + - '**/test/**/*' + - '**/bin/**/*' + - '**/*test*' + - '**/vendor/**/*' + +Layout/EndOfLine: + Enabled: false + Layout/LineLength: Enabled: false @@ -7,6 +19,12 @@ Style/ClassAndModuleChildren: Style/Documentation: Enabled: false +Lint/EnsureReturn: + Enabled: false + +Style/HashSyntax: + Enabled: false + Style/StringLiterals: EnforcedStyle: single_quotes diff --git a/.ruby-version b/.ruby-version index fbafd6b..ef538c2 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.7.2 \ No newline at end of file +3.1.2 diff --git a/Gemfile b/Gemfile index bb0f9e0..4c48daa 100644 --- a/Gemfile +++ b/Gemfile @@ -77,7 +77,6 @@ gem 'omniauth-oauth2', '~> 1.7.1' gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem +gem 'matrix', '~> 0.4.2' gem 'tzinfo-data', '~> 1.2022.1', '>= 1.2022.1' gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] - -gem "matrix", "~> 0.4.2" diff --git a/Gemfile.lock b/Gemfile.lock index 60446ea..df71bf9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -142,7 +142,7 @@ GEM jbuilder (2.11.5) actionview (>= 5.0.0) activesupport (>= 5.0.0) - json (2.6.2) + json (2.6.3) jwt (2.5.0) listen (3.7.1) rb-fsevent (~> 0.10, >= 0.10.3) diff --git a/app/controllers/clickwrap/ceg006_embed_clickwrap_controller.rb b/app/controllers/clickwrap/ceg006_embed_clickwrap_controller.rb index 98970b6..3d739a6 100644 --- a/app/controllers/clickwrap/ceg006_embed_clickwrap_controller.rb +++ b/app/controllers/clickwrap/ceg006_embed_clickwrap_controller.rb @@ -3,34 +3,32 @@ class Clickwrap::Ceg006EmbedClickwrapController < EgController before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 6, 'Click') } def create - begin - args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - clickwrap_id: params[:clickwrapId], - full_name: params[:fullName], - email: params[:email], - company: params[:company], - title: params[:title], - date: params[:date] - } + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + clickwrap_id: params[:clickwrapId], + full_name: params[:fullName], + email: params[:email], + company: params[:company], + title: params[:title], + date: params[:date] + } - results = Clickwrap::Eg006EmbedClickwrapService.new(args).worker + results = Clickwrap::Eg006EmbedClickwrapService.new(args).worker - if results == nil - @error_code = '200' - @error_message = '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.' - render 'ds_common/error' - else - @title = @example['ExampleName'] - @message = format_string(@example['ResultsPageText']) - @agreementUrl = results["agreementUrl"] - render 'clickwrap/ceg006_embed_clickwrap/results' - end - rescue DocuSign_Click::ApiError => e - handle_error(e) + if results.nil? + @error_code = '200' + @error_message = '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.' + render 'ds_common/error' + else + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText']) + @agreementUrl = results['agreementUrl'] + render 'clickwrap/ceg006_embed_clickwrap/results' end + rescue DocuSign_Click::ApiError => e + handle_error(e) end def get diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index 4423c13..56d76b4 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -10,7 +10,6 @@ def index end def handle_redirects - minimum_buffer_min = 10 if Rails.configuration.quickstart @manifest = Utils::ManifestUtils.new.get_manifest(Rails.configuration.example_manifest_url) @@ -19,9 +18,9 @@ def handle_redirects session[:quickstarted] = true redirect_to '/auth/docusign' elsif session[:been_here].nil? - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) - if enableCFR == "enabled" - session[:status_cfr] = "enabled" + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR == 'enabled' + session[:status_cfr] = 'enabled' @status_cfr = session[:status_cfr] redirect_to '/eeg041' else @@ -31,24 +30,22 @@ def handle_redirects render_examples end elsif session[:ds_access_token].present? - if (!session[:api] || session[:api] == "eSignature") - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) - if enableCFR == "enabled" - session[:status_cfr] = "enabled" - end + if !session[:api] || session[:api] == 'eSignature' + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + session[:status_cfr] = 'enabled' if enableCFR == 'enabled' end - render_examples + render_examples else render_examples end end def render_examples - if(session[:ds_access_token].present? && !session[:status_cfr] && (!session[:api] || session[:api] == "eSignature")) - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) - if enableCFR == "enabled" - @status_cfr = "enabled" - session[:status_cfr] = "enabled" + if session[:ds_access_token].present? && !session[:status_cfr] && (!session[:api] || session[:api] == 'eSignature') + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR == 'enabled' + @status_cfr = 'enabled' + session[:status_cfr] = 'enabled' end else @status_cfr = session[:status_cfr] diff --git a/app/controllers/e_sign/eeg014_collect_payment_controller.rb b/app/controllers/e_sign/eeg014_collect_payment_controller.rb index 182a2b8..f3dd68b 100644 --- a/app/controllers/e_sign/eeg014_collect_payment_controller.rb +++ b/app/controllers/e_sign/eeg014_collect_payment_controller.rb @@ -5,37 +5,35 @@ class ESign::Eeg014CollectPaymentController < EgController before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 14, 'eSignature') } def create - begin - envelope_args = { - signer_email: param_gsub(params['signerEmail']), - signer_name: param_gsub(params['signerName']), - cc_email: param_gsub(params['ccEmail']), - cc_name: param_gsub(params['ccName']), - gateway_account_id: Rails.application.config.gateway_account_id, - gateway_name: Rails.application.config.gateway_name, - gateway_display_name: Rails.application.config.gateway_display_name - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + cc_email: param_gsub(params['ccEmail']), + cc_name: param_gsub(params['ccName']), + gateway_account_id: Rails.application.config.gateway_account_id, + gateway_name: Rails.application.config.gateway_name, + gateway_display_name: Rails.application.config.gateway_display_name + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } - results = ESign::Eg014CollectPaymentService.new(args).worker - @title = @example['ExampleName'] - @message = format_string(@example['ResultsPageText'], results[:envelope_id]) - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + results = ESign::Eg014CollectPaymentService.new(args).worker + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results[:envelope_id]) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end def get - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) - if enableCFR == "enabled" - session[:status_cfr] = "enabled" - @title = "Not CFR Part 11 compatible" + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR == 'enabled' + session[:status_cfr] = 'enabled' + @title = 'Not CFR Part 11 compatible' @error_information = @manifest['SupportingTexts']['CFRError'] render 'ds_common/error' end diff --git a/app/controllers/e_sign/eeg020_phone_authentication_controller.rb b/app/controllers/e_sign/eeg020_phone_authentication_controller.rb index 930aeac..d6ad9a5 100644 --- a/app/controllers/e_sign/eeg020_phone_authentication_controller.rb +++ b/app/controllers/e_sign/eeg020_phone_authentication_controller.rb @@ -41,10 +41,10 @@ def create end def get - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) - if enableCFR == "enabled" - session[:status_cfr] = "enabled" - @title = "Not CFR Part 11 compatible" + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR == 'enabled' + session[:status_cfr] = 'enabled' + @title = 'Not CFR Part 11 compatible' @error_information = @manifest['SupportingTexts']['CFRError'] render 'ds_common/error' end diff --git a/app/controllers/e_sign/eeg032_pauses_signature_workflow_controller.rb b/app/controllers/e_sign/eeg032_pauses_signature_workflow_controller.rb index 6dec56d..b561e85 100644 --- a/app/controllers/e_sign/eeg032_pauses_signature_workflow_controller.rb +++ b/app/controllers/e_sign/eeg032_pauses_signature_workflow_controller.rb @@ -27,10 +27,10 @@ def create end def get - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) - if enableCFR == "enabled" - session[:status_cfr] = "enabled" - @title = "Not CFR Part 11 compatible" + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR == 'enabled' + session[:status_cfr] = 'enabled' + @title = 'Not CFR Part 11 compatible' @error_information = @manifest['SupportingTexts']['CFRError'] render 'ds_common/error' end diff --git a/app/controllers/e_sign/eeg033_unpauses_signature_workflow_controller.rb b/app/controllers/e_sign/eeg033_unpauses_signature_workflow_controller.rb index a791a82..cbb1174 100644 --- a/app/controllers/e_sign/eeg033_unpauses_signature_workflow_controller.rb +++ b/app/controllers/e_sign/eeg033_unpauses_signature_workflow_controller.rb @@ -20,10 +20,10 @@ def update end def get - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) - if enableCFR == "enabled" - session[:status_cfr] = "enabled" - @title = "Not CFR Part 11 compatible" + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR == 'enabled' + session[:status_cfr] = 'enabled' + @title = 'Not CFR Part 11 compatible' @error_information = @manifest['SupportingTexts']['CFRError'] render 'ds_common/error' end diff --git a/app/controllers/e_sign/eeg034_use_conditional_recipients_controller.rb b/app/controllers/e_sign/eeg034_use_conditional_recipients_controller.rb index 38f3d48..1dc1a5a 100644 --- a/app/controllers/e_sign/eeg034_use_conditional_recipients_controller.rb +++ b/app/controllers/e_sign/eeg034_use_conditional_recipients_controller.rb @@ -5,45 +5,43 @@ class ESign::Eeg034UseConditionalRecipientsController < EgController before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 34, 'eSignature') } def create - begin - signers = { - signerEmail1: request['signerEmail1'], - signerName1: request['signerName1'], + signers = { + signerEmail1: request['signerEmail1'], + signerName1: request['signerName1'], - signerEmailNotChecked: request['signerEmailNotChecked'], - signerNameNotChecked: request['signerNameNotChecked'], + signerEmailNotChecked: request['signerEmailNotChecked'], + signerNameNotChecked: request['signerNameNotChecked'], - signerEmailChecked: request['signerEmailChecked'], - signerNameChecked: request['signerNameChecked'] - } + signerEmailChecked: request['signerEmailChecked'], + signerNameChecked: request['signerNameChecked'] + } - args = { - accountId: session['ds_account_id'], - basePath: session['ds_base_path'], - accessToken: session['ds_access_token'] - } + args = { + accountId: session['ds_account_id'], + basePath: session['ds_base_path'], + accessToken: session['ds_access_token'] + } - results = ESign::Eg034UseConditionalRecipientsService.new(args, signers).worker - @envelop_id = results.to_hash[:envelopeId].to_s - render 'e_sign/eg034_use_conditional_recipients/return' - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - if error['errorCode']['WORKFLOW_UPDATE_RECIPIENTROUTING_NOT_ALLOWED'] - @error_message = @example['CustomErrorTexts'][0]['ErrorMessage'] - @error_information = @example['CustomErrorTexts'][0]['ErrorMessage'] - else - @error_message = error['message'] - end - render 'ds_common/error' + results = ESign::Eg034UseConditionalRecipientsService.new(args, signers).worker + @envelop_id = results.to_hash[:envelopeId].to_s + render 'e_sign/eg034_use_conditional_recipients/return' + rescue DocuSign_eSign::ApiError => e + error = JSON.parse e.response_body + @error_code = error['errorCode'] + if error['errorCode']['WORKFLOW_UPDATE_RECIPIENTROUTING_NOT_ALLOWED'] + @error_message = @example['CustomErrorTexts'][0]['ErrorMessage'] + @error_information = @example['CustomErrorTexts'][0]['ErrorMessage'] + else + @error_message = error['message'] end + render 'ds_common/error' end def get - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) - if enableCFR == "enabled" - session[:status_cfr] = "enabled" - @title = "Not CFR Part 11 compatible" + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR == 'enabled' + session[:status_cfr] = 'enabled' + @title = 'Not CFR Part 11 compatible' @error_information = @manifest['SupportingTexts']['CFRError'] render 'ds_common/error' end diff --git a/app/controllers/e_sign/eeg036_delayed_routing_controller.rb b/app/controllers/e_sign/eeg036_delayed_routing_controller.rb index 7860c41..e863437 100644 --- a/app/controllers/e_sign/eeg036_delayed_routing_controller.rb +++ b/app/controllers/e_sign/eeg036_delayed_routing_controller.rb @@ -5,36 +5,34 @@ class ESign::Eeg036DelayedRoutingController < EgController before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 36, 'eSignature') } def create - begin - envelope_args = { - signer1_email: param_gsub(params['signer1Email']), - signer1_name: param_gsub(params['signer1Name']), - signer2_email: param_gsub(params['signer2Email']), - signer2_name: param_gsub(params['signer2Name']), - delay: param_gsub(params['delay']), - status: 'sent' - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } - results = ESign::Eg036DelayedRoutingService.new(args).worker - session[:envelope_id] = results['envelope_id'] - @title = @example['ExampleName'] - @message = format_string(@example['ResultsPageText'], results['envelope_id']) - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + envelope_args = { + signer1_email: param_gsub(params['signer1Email']), + signer1_name: param_gsub(params['signer1Name']), + signer2_email: param_gsub(params['signer2Email']), + signer2_name: param_gsub(params['signer2Name']), + delay: param_gsub(params['delay']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + results = ESign::Eg036DelayedRoutingService.new(args).worker + session[:envelope_id] = results['envelope_id'] + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results['envelope_id']) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end def get - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) - if enableCFR == "enabled" - session[:status_cfr] = "enabled" - @title = "Not CFR Part 11 compatible" + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR == 'enabled' + session[:status_cfr] = 'enabled' + @title = 'Not CFR Part 11 compatible' @error_information = @manifest['SupportingTexts']['CFRError'] render 'ds_common/error' end diff --git a/app/controllers/e_sign/eeg037_sms_delivery_controller.rb b/app/controllers/e_sign/eeg037_sms_delivery_controller.rb index d02bf4e..ac82553 100644 --- a/app/controllers/e_sign/eeg037_sms_delivery_controller.rb +++ b/app/controllers/e_sign/eeg037_sms_delivery_controller.rb @@ -5,41 +5,39 @@ class ESign::Eeg037SmsDeliveryController < EgController before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 37, 'eSignature') } def create - begin - envelope_args = { - signer_name: param_gsub(params['signer_name']), - cc_name: param_gsub(params['cc_name']), - cc_phone_number: param_gsub(params['cc_phone_number']), - cc_country_code: param_gsub(params['cc_country_code']), - phone_number: param_gsub(params['phone_number']), - country_code: param_gsub(params['country_code']), - status: 'sent' - } - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - envelope_args: envelope_args - } + envelope_args = { + signer_name: param_gsub(params['signer_name']), + cc_name: param_gsub(params['cc_name']), + cc_phone_number: param_gsub(params['cc_phone_number']), + cc_country_code: param_gsub(params['cc_country_code']), + phone_number: param_gsub(params['phone_number']), + country_code: param_gsub(params['country_code']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } - results = ESign::Eg037SmsDeliveryService.new(args).worker - session[:envelope_id] = results['envelope_id'] - @title = @example['ExampleName'] - @message = format_string(@example['ResultsPageText'], results['envelope_id']) - render 'ds_common/example_done' - rescue DocuSign_eSign::ApiError => e - handle_error(e) - end + results = ESign::Eg037SmsDeliveryService.new(args).worker + session[:envelope_id] = results['envelope_id'] + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results['envelope_id']) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) end def get - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) - if enableCFR == "enabled" - session[:status_cfr] = "enabled" - @title = "Not CFR Part 11 compatible" + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR == 'enabled' + session[:status_cfr] = 'enabled' + @title = 'Not CFR Part 11 compatible' @error_information = @manifest['SupportingTexts']['CFRError'] render 'ds_common/error' end super end -end \ No newline at end of file +end diff --git a/app/controllers/e_sign/eeg039_signing_in_person_controller.rb b/app/controllers/e_sign/eeg039_signing_in_person_controller.rb index a5b1a10..d6e2222 100644 --- a/app/controllers/e_sign/eeg039_signing_in_person_controller.rb +++ b/app/controllers/e_sign/eeg039_signing_in_person_controller.rb @@ -37,10 +37,10 @@ def create end def get - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) - if enableCFR == "enabled" - session[:status_cfr] = "enabled" - @title = "Not CFR Part 11 compatible" + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR == 'enabled' + session[:status_cfr] = 'enabled' + @title = 'Not CFR Part 11 compatible' @error_information = @manifest['SupportingTexts']['CFRError'] render 'ds_common/error' end diff --git a/app/controllers/e_sign/eeg040_set_document_visibility_controller.rb b/app/controllers/e_sign/eeg040_set_document_visibility_controller.rb index d04643d..0e75106 100644 --- a/app/controllers/e_sign/eeg040_set_document_visibility_controller.rb +++ b/app/controllers/e_sign/eeg040_set_document_visibility_controller.rb @@ -42,10 +42,10 @@ def create end def get - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) - if enableCFR == "enabled" - session[:status_cfr] = "enabled" - @title = "Not CFR Part 11 compatible" + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR == 'enabled' + session[:status_cfr] = 'enabled' + @title = 'Not CFR Part 11 compatible' @error_information = @manifest['SupportingTexts']['CFRError'] render 'ds_common/error' end diff --git a/app/controllers/e_sign/eeg041_cfr_embedded_signing_controller.rb b/app/controllers/e_sign/eeg041_cfr_embedded_signing_controller.rb index eea2290..99357c6 100644 --- a/app/controllers/e_sign/eeg041_cfr_embedded_signing_controller.rb +++ b/app/controllers/e_sign/eeg041_cfr_embedded_signing_controller.rb @@ -41,10 +41,10 @@ def create end def get - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) - if enableCFR != "enabled" - @title = "Must use a CFR Part 11 enabled account" - @error_information = "This example requires a CFR Part 11 account. Please return to the homepage to run one of the examples that is compatible or authenticate with a different account." + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR != 'enabled' + @title = 'Must use a CFR Part 11 enabled account' + @error_information = 'This example requires a CFR Part 11 account. Please return to the homepage to run one of the examples that is compatible or authenticate with a different account.' render 'ds_common/error' end super diff --git a/app/controllers/eeg001_embedded_signing_controller.rb b/app/controllers/eeg001_embedded_signing_controller.rb index 3fd25de..5b2b093 100644 --- a/app/controllers/eeg001_embedded_signing_controller.rb +++ b/app/controllers/eeg001_embedded_signing_controller.rb @@ -27,10 +27,10 @@ def create end def get - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) - if enableCFR == "enabled" - session[:status_cfr] = "enabled" - @title = "Not CFR Part 11 compatible" + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR == 'enabled' + session[:status_cfr] = 'enabled' + @title = 'Not CFR Part 11 compatible' @error_information = @manifest['SupportingTexts']['CFRError'] render 'ds_common/error' end diff --git a/app/controllers/monitor_api/meg001_get_monitoring_dataset_controller.rb b/app/controllers/monitor_api/meg001_get_monitoring_dataset_controller.rb index c3783ec..e96cad3 100644 --- a/app/controllers/monitor_api/meg001_get_monitoring_dataset_controller.rb +++ b/app/controllers/monitor_api/meg001_get_monitoring_dataset_controller.rb @@ -13,7 +13,7 @@ def create @title = @example['ExampleName'] - if results != "Monitor not enabled" + if results != 'Monitor not enabled' @message = @example['ResultsPageText'] @json = results.to_json.to_json else diff --git a/app/controllers/monitor_api/meg002_post_web_query_controller.rb b/app/controllers/monitor_api/meg002_post_web_query_controller.rb index f23cc66..0cb4c6a 100644 --- a/app/controllers/monitor_api/meg002_post_web_query_controller.rb +++ b/app/controllers/monitor_api/meg002_post_web_query_controller.rb @@ -16,7 +16,7 @@ def create @title = @example['ExampleName'] - if results != "Monitor not enabled" + if results != 'Monitor not enabled' @message = @example['ResultsPageText'] @json = results.to_json.to_json else diff --git a/app/services/clickwrap/eg006_embed_clickwrap_service.rb b/app/services/clickwrap/eg006_embed_clickwrap_service.rb index 9792fd7..b966aa6 100644 --- a/app/services/clickwrap/eg006_embed_clickwrap_service.rb +++ b/app/services/clickwrap/eg006_embed_clickwrap_service.rb @@ -14,7 +14,7 @@ def worker api_client = DocuSign_Click::ApiClient.new configuration api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - api_client.config.debugging = true; + api_client.config.debugging = true # document_data = DocuSign_Click::DocumentData.new({ # full_name: args[:full_name], @@ -25,18 +25,17 @@ def worker # }) document_data = { - "fullName" => args[:full_name], - "email" => args[:email], - "company" => args[:company], - "title" => args[:title], - "date" => args[:date] + 'fullName' => args[:full_name], + 'email' => args[:email], + 'company' => args[:company], + 'title' => args[:title], + 'date' => args[:date] } - userAgreementRequest = DocuSign_Click::UserAgreementRequest.new({ - clientUserId: args[:email], - documentData: document_data - }) + clientUserId: args[:email], + documentData: document_data + }) accounts_api = DocuSign_Click::AccountsApi.new(api_client) diff --git a/app/services/e_sign/eg041_cfr_embedded_signing_service.rb b/app/services/e_sign/eg041_cfr_embedded_signing_service.rb index f7cb0d7..4795a8b 100644 --- a/app/services/e_sign/eg041_cfr_embedded_signing_service.rb +++ b/app/services/e_sign/eg041_cfr_embedded_signing_service.rb @@ -14,7 +14,7 @@ def worker envelope_args = args[:envelope_args] accounts_api = create_account_api(args) - #Obtain your workflow_id + # Obtain your workflow_id workflow_results = accounts_api.get_account_identity_verification(args[:account_id]) if workflow_results.identity_verification @@ -32,14 +32,14 @@ def worker envelope_id = envelope.envelope_id view_request = DocuSign_eSign::RecipientViewRequest.new({ - returnUrl: "#{envelope_args[:ds_return_url]}?state=123", - authenticationMethod: "none", - email: envelope_args[:signer_email], - userName: "#{envelope_args[:signer_name]}", - clientUserId: envelope_args[:signer_client_id], - pingFrequency: 600, - pingUrl: envelope_args[:ds_ping_url] - }) + returnUrl: "#{envelope_args[:ds_return_url]}?state=123", + authenticationMethod: 'none', + email: envelope_args[:signer_email], + userName: envelope_args[:signer_name], + clientUserId: envelope_args[:signer_client_id], + pingFrequency: 600, + pingUrl: envelope_args[:ds_ping_url] + }) results = envelope_api.create_recipient_view(args[:account_id], envelope_id, view_request) @@ -47,6 +47,7 @@ def worker end private + def make_envelope(args, workflow_id) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document sent from Ruby SDK' @@ -74,16 +75,15 @@ def make_envelope(args, workflow_id) identity_verification.workflow_id = workflow_id identity_verification.input_options = [input_option] - # Create a signer recipient to sign the document, identified by name and email # We're setting the parameters via the object creation signer1 = DocuSign_eSign::Signer.new({ - email: args[:signer_email], - name: args[:signer_name], - clientUserId: args[:signer_client_id], - recipientId: 1, - identityVerification: identity_verification - }) + email: args[:signer_email], + name: args[:signer_name], + clientUserId: args[:signer_client_id], + recipientId: 1, + identityVerification: identity_verification + }) # The DocuSign platform searches throughout your envelope's documents for matching # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 # since they use the same anchor string for their "signer 1" tabs. diff --git a/app/services/e_sign/get_data_service.rb b/app/services/e_sign/get_data_service.rb index ff7d250..f22b1ae 100644 --- a/app/services/e_sign/get_data_service.rb +++ b/app/services/e_sign/get_data_service.rb @@ -26,11 +26,11 @@ def get_current_user_name user_info.name end - def is_cfr(account_id) + def cfr?(account_id) worker accounts_api = DocuSign_eSign::AccountsApi.new @api_client account_details = accounts_api.get_account_information(account_id) - return account_details.status21_cfr_part11 + account_details.status21_cfr_part11 end private diff --git a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb index 5766882..f99acc7 100644 --- a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb +++ b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb @@ -21,15 +21,14 @@ def worker begin @response = monitor_api.get_stream(args[:data_set_name], args[:version]).data # step 3 end - rescue + rescue StandardError # error, probalby no Monitor enabled - @response = "Monitor not enabled" + @response = 'Monitor not enabled' else - Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" + Rails.logger.info 'Responses for loops are displayed here. Only the final loop is displayed on the response page' Rails.logger.info @response.inspect ensure return @response end - end end diff --git a/app/services/monitor_api/eg002_post_web_query_service.rb b/app/services/monitor_api/eg002_post_web_query_service.rb index d93d240..ef18699 100644 --- a/app/services/monitor_api/eg002_post_web_query_service.rb +++ b/app/services/monitor_api/eg002_post_web_query_service.rb @@ -21,11 +21,11 @@ def worker begin @response = monitor_api.post_web_query(args[:data_set_name], args[:version], get_query) # step 3 end - rescue + rescue StandardError # error, probalby no Monitor enabled - @response = "Monitor not enabled" + @response = 'Monitor not enabled' else - Rails.logger.info "Responses for loops are displayed here. Only the final loop is displayed on the response page" + Rails.logger.info 'Responses for loops are displayed here. Only the final loop is displayed on the response page' Rails.logger.info @response.inspect ensure return @response diff --git a/app/services/utils.rb b/app/services/utils.rb index 75432af..0263c93 100644 --- a/app/services/utils.rb +++ b/app/services/utils.rb @@ -6,7 +6,7 @@ def get_manifest(manifest_url) JSON.parse(res.body) end - def get_example(manifest, number, api_name='eSignature') + def get_example(manifest, number, api_name = 'eSignature') manifest['APIs'].each do |api| next unless api_name == api['Name'] diff --git a/bin/rails b/bin/rails index 3504c3f..7bcc36e 100755 --- a/bin/rails +++ b/bin/rails @@ -1,11 +1,4 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -begin - load File.expand_path('spring', __dir__) -rescue LoadError => e - raise unless e.message.include?('spring') -end -APP_PATH = File.expand_path('../config/application', __dir__) -require_relative '../config/boot' -require 'rails/commands' +#!/usr/bin/env ruby.exe +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake index 1fe6cf0..01f7fc0 100755 --- a/bin/rake +++ b/bin/rake @@ -1,11 +1,4 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -begin - load File.expand_path('spring', __dir__) -rescue LoadError => e - raise unless e.message.include?('spring') -end -require_relative '../config/boot' -require 'rake' +#!/usr/bin/env ruby.exe +require_relative "../config/boot" +require "rake" Rake.application.run diff --git a/bin/setup b/bin/setup index c2e43ce..5e463ee 100755 --- a/bin/setup +++ b/bin/setup @@ -1,38 +1,33 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -require 'fileutils' -include FileUtils +#!/usr/bin/env ruby.exe +require "fileutils" # path to your application root. -APP_ROOT = File.expand_path('..', __dir__) +APP_ROOT = File.expand_path("..", __dir__) def system!(*args) system(*args) || abort("\n== Command #{args} failed ==") end -chdir APP_ROOT do - # This script is a starting point to setup your application. +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. # Add necessary setup steps to this file. - puts '== Installing dependencies ==' - system! 'gem install bundler --conservative' - system('bundle check') || system!('bundle install') - - # Install JavaScript dependencies if using Yarn - # system('bin/yarn') + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") # puts "\n== Copying sample files ==" - # unless File.exist?('config/database.yml') - # cp 'config/database.yml.sample', 'config/database.yml' + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" # end puts "\n== Preparing database ==" - system! 'bin/rails db:setup' + system! "bin/rails db:prepare" puts "\n== Removing old logs and tempfiles ==" - system! 'bin/rails log:clear tmp:clear' + system! "bin/rails log:clear tmp:clear" puts "\n== Restarting application server ==" - system! 'bin/rails restart' + system! "bin/rails restart" end diff --git a/quick_acg/app/controllers/ds_common_controller.rb b/quick_acg/app/controllers/ds_common_controller.rb index f5b2630..d5f40da 100644 --- a/quick_acg/app/controllers/ds_common_controller.rb +++ b/quick_acg/app/controllers/ds_common_controller.rb @@ -12,9 +12,9 @@ def handle_redirects session[:quickstarted] = true redirect_to '/auth/docusign' else - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).is_cfr(session[:ds_account_id]) - if enableCFR == "enabled" - session[:status_cfr] = "enabled" + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR == 'enabled' + session[:status_cfr] = 'enabled' redirect_to '/eeg041' else redirect_to '/eeg001' diff --git a/quick_acg/config/routes.rb b/quick_acg/config/routes.rb index 65b03db..2c44db4 100644 --- a/quick_acg/config/routes.rb +++ b/quick_acg/config/routes.rb @@ -4,7 +4,7 @@ require_relative '../../app/services/api_creator' require_relative '../../app/controllers/eeg001_embedded_signing_controller' require_relative '../../app/services/eg001_embedded_signing_service' -require_relative '../../app/services/utils.rb' +require_relative '../../app/services/utils' class ESign end diff --git a/test/eg001_embedded_signing_test.rb b/test/eg001_embedded_signing_test.rb index 70f0cac..e7f806b 100644 --- a/test/eg001_embedded_signing_test.rb +++ b/test/eg001_embedded_signing_test.rb @@ -1,5 +1,5 @@ +require 'rubygems' require 'test/unit' -require 'docusign_esign' require 'json' require_relative 'test_helper' require_relative '../app/services/api_creator' diff --git a/test/eg002_sign_via_email_test.rb b/test/eg002_sign_via_email_test.rb index 1a06f9e..c740631 100644 --- a/test/eg002_sign_via_email_test.rb +++ b/test/eg002_sign_via_email_test.rb @@ -1,5 +1,5 @@ +require 'rubygems' require 'test/unit' -require 'docusign_esign' require_relative './test_helper' require_relative '../app/services/api_creator' require_relative '../app/services/e_sign/eg002_signing_via_email_service' diff --git a/test/eg008_create_template_test.rb b/test/eg008_create_template_test.rb index 2ab2159..f2d59a4 100644 --- a/test/eg008_create_template_test.rb +++ b/test/eg008_create_template_test.rb @@ -1,3 +1,4 @@ +require 'rubygems' require 'test/unit' require_relative './test_helper' require_relative '../app/services/api_creator' diff --git a/test/eg009_use_template_test.rb b/test/eg009_use_template_test.rb index 51bb884..945c32a 100644 --- a/test/eg009_use_template_test.rb +++ b/test/eg009_use_template_test.rb @@ -1,3 +1,4 @@ +require 'rubygems' require 'test/unit' require_relative './test_helper' require_relative '../app/services/api_creator' diff --git a/test/eg013_add_doc_to_template_test.rb b/test/eg013_add_doc_to_template_test.rb index ced9a91..c7e5264 100644 --- a/test/eg013_add_doc_to_template_test.rb +++ b/test/eg013_add_doc_to_template_test.rb @@ -1,3 +1,4 @@ +require 'rubygems' require 'test/unit' require_relative './test_helper' require_relative '../app/services/api_creator' diff --git a/test/eg017_set_template_tab_values_test.rb b/test/eg017_set_template_tab_values_test.rb index 9f27c64..5bec176 100644 --- a/test/eg017_set_template_tab_values_test.rb +++ b/test/eg017_set_template_tab_values_test.rb @@ -1,3 +1,4 @@ +require 'rubygems' require 'test/unit' require_relative './test_helper' require_relative '../app/services/api_creator' diff --git a/test/test_helper.rb b/test/test_helper.rb index 08fb86b..0526704 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,6 +1,8 @@ -require 'docusign_esign' +require 'bundler/inline' + require 'yaml' require 'test/unit' +require 'docusign_esign' $_scopes = %w[ signature impersonation @@ -28,6 +30,10 @@ def authenticate api_client.set_oauth_base_path(data[:authorization_server]) rsa_pk = './config/docusign_private_key.txt' + unless File.exist? rsa_pk + rsa_pk = ENV['PRIVATE_KEY'] + end + begin token = api_client.request_jwt_user_token(ds_config['jwt_integration_key'], ds_config['impersonated_user_guid'], rsa_pk, 3600, $_scopes) user_info_response = api_client.get_user_info(token.access_token) @@ -59,13 +65,23 @@ def authenticate def get_config_data config_file_path = './config/appsettings.yml' - begin - config_file_contents = File.read(config_file_path) - rescue Errno::ENOENT - warn 'Missing config file' - raise + if File.exist? config_file_path + begin + config_file_contents = File.read(config_file_path) + rescue Errno::ENOENT + warn 'Missing config file' + raise + end + YAML.unsafe_load(config_file_contents)['default'] + else + config = {} + config['jwt_integration_key'] = ENV['CLIENT_ID'] + config['impersonated_user_guid'] = ENV['USER_ID'] + config['signer_email'] = ENV['SIGNER_EMAIL'] + config['signer_name'] = ENV['SIGNER_NAME'] + + config end - YAML.unsafe_load(config_file_contents)['default'] end def get_common_data From 4ee36cc4b2e7e5dd9f4ff6891aed3d33766211f2 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Fri, 20 Jan 2023 15:55:35 -0800 Subject: [PATCH 181/363] Dependabot updates (#110) dependabot updates --- Gemfile | 2 +- Gemfile.lock | 12 ++++++------ quick_acg/Gemfile.lock | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Gemfile b/Gemfile index 4c48daa..5b03c96 100644 --- a/Gemfile +++ b/Gemfile @@ -52,7 +52,7 @@ group :development do gem 'listen', '~> 3.7.1' gem 'web-console', '~> 4.2.0' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring - gem 'pry-nav', '~> 0.3.0' + gem 'pry-nav', '~> 1.0.0' gem 'pry-rails', '~> 0.3.9' gem 'rubocop', '~> 1.36', require: false gem 'spring', '~> 2.1.0' diff --git a/Gemfile.lock b/Gemfile.lock index df71bf9..858880b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -133,7 +133,7 @@ GEM faraday-net_http (3.0.0) ffi (1.15.5) ffi (1.15.5-x64-mingw-ucrt) - globalid (1.0.0) + globalid (1.0.1) activesupport (>= 5.0) hashie (5.0.0) i18n (1.12.0) @@ -156,7 +156,7 @@ GEM matrix (0.4.2) method_source (0.9.2) mini_mime (1.1.2) - minitest (5.16.3) + minitest (5.17.0) msgpack (1.6.0) multi_xml (0.6.0) net-imap (0.3.1) @@ -198,15 +198,15 @@ GEM pry (0.12.2) coderay (~> 1.1.0) method_source (~> 0.9.0) - pry-nav (0.3.0) - pry (>= 0.9.10, < 0.13.0) + pry-nav (1.0.0) + pry (>= 0.9.10, < 0.15) pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (5.0.0) puma (5.6.5) nio4r (~> 2.0) racc (1.6.1) - rack (2.2.4) + rack (2.2.6.2) rack-protection (3.0.2) rack rack-test (2.0.2) @@ -338,7 +338,7 @@ DEPENDENCIES matrix (~> 0.4.2) omniauth-oauth2 (~> 1.7.1) omniauth-rails_csrf_protection - pry-nav (~> 0.3.0) + pry-nav (~> 1.0.0) pry-rails (~> 0.3.9) puma (~> 5.6.4) rails (~> 7.0.3) diff --git a/quick_acg/Gemfile.lock b/quick_acg/Gemfile.lock index a784e33..7602786 100644 --- a/quick_acg/Gemfile.lock +++ b/quick_acg/Gemfile.lock @@ -102,10 +102,10 @@ GEM faraday-net_http (2.0.3) ffi (1.15.5) ffi (1.15.5-x64-mingw32) - globalid (1.0.0) + globalid (1.0.1) activesupport (>= 5.0) hashie (5.0.0) - i18n (1.10.0) + i18n (1.12.0) concurrent-ruby (~> 1.0) io-like (0.3.1) jbuilder (2.10.2) @@ -123,7 +123,7 @@ GEM marcel (1.0.2) method_source (0.9.2) mini_mime (1.1.2) - minitest (5.16.2) + minitest (5.17.0) msgpack (1.5.3) multi_xml (0.6.0) nio4r (2.5.8) @@ -254,7 +254,7 @@ GEM websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.0) + zeitwerk (2.6.6) PLATFORMS x64-mingw32 From 9dbf678a20ea3a0bfb0ed76ea9e22fa2fece5bbf Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Wed, 25 Jan 2023 14:43:17 +0200 Subject: [PATCH 182/363] fixed home page --- app/views/ds_common/index.html.erb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index 640e0f3..ef99678 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -38,9 +38,10 @@ <% group["Examples"].each { |example| %> <% if example_available? example %> - <% if example["CFREnabled"] == "AllAccounts" || - @status_cfr == "enabled" && example["CFREnabled"] == "CFROnly" || - @status_cfr != "enabled" && example["CFREnabled"] == "NonCFR" + <% if api["Name"].downcase != "esignature" || + example["CFREnabled"] == "AllAccounts" || + @status_cfr == "enabled" && example["CFREnabled"] == "CFROnly" || + @status_cfr != "enabled" && example["CFREnabled"] == "NonCFR" %> <% prefix = if api["Name"] == "Admin" "a" From 30d6f49648259eb157bbabd0864d035a3d081198 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Wed, 25 Jan 2023 10:18:40 -0800 Subject: [PATCH 183/363] Fixing issue with main page not showing all code examples --- app/views/ds_common/index.html.erb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index 640e0f3..ef99678 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -38,9 +38,10 @@ <% group["Examples"].each { |example| %> <% if example_available? example %> - <% if example["CFREnabled"] == "AllAccounts" || - @status_cfr == "enabled" && example["CFREnabled"] == "CFROnly" || - @status_cfr != "enabled" && example["CFREnabled"] == "NonCFR" + <% if api["Name"].downcase != "esignature" || + example["CFREnabled"] == "AllAccounts" || + @status_cfr == "enabled" && example["CFREnabled"] == "CFROnly" || + @status_cfr != "enabled" && example["CFREnabled"] == "NonCFR" %> <% prefix = if api["Name"] == "Admin" "a" From eaf0e9e67ab237fe265b0d54429a56c8cc49a54c Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Wed, 8 Feb 2023 13:35:37 -0800 Subject: [PATCH 184/363] Ruby fixes (#112) * fixes based on testing all examples --- .../aeg001_create_user_controller.rb | 16 ++++++++------- .../aeg004_import_user_controller.rb | 2 +- app/controllers/ds_common_controller.rb | 4 ++-- ...g017_set_template_tab_values_controller.rb | 9 ++++++--- ...32_pauses_signature_workflow_controller.rb | 2 +- ..._unpauses_signature_workflow_controller.rb | 2 +- ...4_use_conditional_recipients_controller.rb | 2 +- .../eg017_set_template_tab_values_service.rb | 6 +++--- app/services/jwt_auth/jwt_creator.rb | 10 +++++----- .../get.html.erb | 4 ++-- .../get.html.erb | 4 ++-- .../ceg002_activate_clickwrap/get.html.erb | 2 +- .../get.html.erb | 2 +- .../ceg005_clickwrap_responses/get.html.erb | 2 +- .../ceg006_embed_clickwrap/get.html.erb | 4 ++-- .../e_sign/eeg004_envelope_info/get.html.erb | 4 ++-- .../eeg005_envelope_recipients/get.html.erb | 4 ++-- .../e_sign/eeg006_envelope_docs/get.html.erb | 4 ++-- .../eeg007_envelope_get_doc/get.html.erb | 6 +++--- .../e_sign/eeg009_use_template/get.html.erb | 4 ++-- .../eeg012_embedded_console/get.html.erb | 2 +- .../eeg013_add_doc_to_template/get.html.erb | 4 ++-- .../eeg015_get_envelope_tab_data/get.html.erb | 4 ++-- .../get.html.erb | 20 +++++++++---------- .../get.html.erb | 4 ++-- .../get.html.erb | 4 ++-- .../get.html.erb | 4 ++-- .../reg003_export_data_from_room/get.html.erb | 2 +- .../reg004_add_forms_to_room/get.html.erb | 2 +- .../get_forms.html.erb | 4 ++-- .../get_rooms.html.erb | 4 ++-- .../get.erb | 2 +- .../reg009_assign_form_to_form_group/get.erb | 2 +- config/initializers/omniauth.rb | 4 ++-- quick_acg/config/initializers/omniauth.rb | 4 ++-- test/eg017_set_template_tab_values_test.rb | 4 ++-- 36 files changed, 84 insertions(+), 79 deletions(-) diff --git a/app/controllers/admin_api/aeg001_create_user_controller.rb b/app/controllers/admin_api/aeg001_create_user_controller.rb index 87cdf46..757a133 100644 --- a/app/controllers/admin_api/aeg001_create_user_controller.rb +++ b/app/controllers/admin_api/aeg001_create_user_controller.rb @@ -31,14 +31,16 @@ def create ] } - results = AdminApi::Eg001CreateUserService.new(args, user_data).worker + begin + results = AdminApi::Eg001CreateUserService.new(args, user_data).worker - @title = @example['ExampleName'] - @message = @example['ResultsPageText'] - @json = results.to_json.to_json - render 'ds_common/example_done' - rescue DocuSign_Admin::ApiError => e - handle_error(e) + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) + end end def get diff --git a/app/controllers/admin_api/aeg004_import_user_controller.rb b/app/controllers/admin_api/aeg004_import_user_controller.rb index 90dce63..1d3e3d2 100644 --- a/app/controllers/admin_api/aeg004_import_user_controller.rb +++ b/app/controllers/admin_api/aeg004_import_user_controller.rb @@ -40,7 +40,7 @@ def check_status @title = @example['ExampleName'] @message = @example['AdditionalPage'][0]['ResultsPageText'] @json = results.to_json.to_json - render 'admin_api/eg004_import_user/get_status.html.erb' + render 'admin_api/aeg004_import_user/get_status.html.erb' rescue DocuSign_Admin::ApiError => e error = JSON.parse e.response_body @error_code = e.code diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index 56d76b4..9112e99 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -29,7 +29,7 @@ def handle_redirects else render_examples end - elsif session[:ds_access_token].present? + elsif session[:ds_access_token].present? && session[:ds_account_id].present? if !session[:api] || session[:api] == 'eSignature' enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) session[:status_cfr] = 'enabled' if enableCFR == 'enabled' @@ -41,7 +41,7 @@ def handle_redirects end def render_examples - if session[:ds_access_token].present? && !session[:status_cfr] && (!session[:api] || session[:api] == 'eSignature') + if session[:ds_access_token].present? && session[:ds_account_id].present? && !session[:status_cfr] && (!session[:api] || session[:api] == 'eSignature') enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) if enableCFR == 'enabled' @status_cfr = 'enabled' diff --git a/app/controllers/e_sign/eeg017_set_template_tab_values_controller.rb b/app/controllers/e_sign/eeg017_set_template_tab_values_controller.rb index 6837932..e024a70 100644 --- a/app/controllers/e_sign/eeg017_set_template_tab_values_controller.rb +++ b/app/controllers/e_sign/eeg017_set_template_tab_values_controller.rb @@ -22,9 +22,12 @@ def create access_token: session['ds_access_token'], envelope_args: envelope_args } - - redirect_url = ESign::Eg017SetTemplateTabValuesService.new(args).worker - redirect_to redirect_url + begin + redirect_url = ESign::Eg017SetTemplateTabValuesService.new(args).worker + redirect_to redirect_url + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end elsif !template_id @title = @example['ExampleName'] @template_ok = false diff --git a/app/controllers/e_sign/eeg032_pauses_signature_workflow_controller.rb b/app/controllers/e_sign/eeg032_pauses_signature_workflow_controller.rb index b561e85..d2d229b 100644 --- a/app/controllers/e_sign/eeg032_pauses_signature_workflow_controller.rb +++ b/app/controllers/e_sign/eeg032_pauses_signature_workflow_controller.rb @@ -23,7 +23,7 @@ def create @envelop_id = results.to_hash[:envelopeId].to_s session[:envelope_id] = @envelop_id - render 'e_sign/eg032_pauses_signature_workflow/return' + render 'e_sign/eeg032_pauses_signature_workflow/return' end def get diff --git a/app/controllers/e_sign/eeg033_unpauses_signature_workflow_controller.rb b/app/controllers/e_sign/eeg033_unpauses_signature_workflow_controller.rb index cbb1174..001a3bc 100644 --- a/app/controllers/e_sign/eeg033_unpauses_signature_workflow_controller.rb +++ b/app/controllers/e_sign/eeg033_unpauses_signature_workflow_controller.rb @@ -16,7 +16,7 @@ def update results = ESign::Eg033UnpausesSignatureWorkflowService.new(args).worker @envelop_id = results.to_hash[:envelopeId].to_s - render 'e_sign/eg033_unpauses_signature_workflow/return' + render 'e_sign/eeg033_unpauses_signature_workflow/return' end def get diff --git a/app/controllers/e_sign/eeg034_use_conditional_recipients_controller.rb b/app/controllers/e_sign/eeg034_use_conditional_recipients_controller.rb index 1dc1a5a..0ab2001 100644 --- a/app/controllers/e_sign/eeg034_use_conditional_recipients_controller.rb +++ b/app/controllers/e_sign/eeg034_use_conditional_recipients_controller.rb @@ -24,7 +24,7 @@ def create results = ESign::Eg034UseConditionalRecipientsService.new(args, signers).worker @envelop_id = results.to_hash[:envelopeId].to_s - render 'e_sign/eg034_use_conditional_recipients/return' + render 'e_sign/eeg034_use_conditional_recipients/return' rescue DocuSign_eSign::ApiError => e error = JSON.parse e.response_body @error_code = error['errorCode'] diff --git a/app/services/e_sign/eg017_set_template_tab_values_service.rb b/app/services/e_sign/eg017_set_template_tab_values_service.rb index e4214be..3af1cb3 100644 --- a/app/services/e_sign/eg017_set_template_tab_values_service.rb +++ b/app/services/e_sign/eg017_set_template_tab_values_service.rb @@ -11,10 +11,10 @@ def initialize(args) # ***DS.snippet.0.start def worker - ds_ping_url = args[:ds_ping_url] - ds_return_url = "#{ds_ping_url}/ds_common-return" signer_client_id = 1000 envelope_args = args[:envelope_args] + ds_ping_url = envelope_args[:ds_ping_url] + ds_return_url = "#{ds_ping_url}/ds_common-return" # Step 4. Construct the request body envelope_definition = make_envelope(envelope_args) @@ -28,7 +28,7 @@ def worker view_request = make_recipient_view_request(envelope_args[:signer_email], envelope_args[:signer_name], signer_client_id, ds_return_url, ds_ping_url) # Call the CreateRecipientView API - results = create_envelope_api(args).create_recipient_view args[:account_id], envelope_id, view_request + results = envelope_api.create_recipient_view args[:account_id], envelope_id, view_request # Redirect the user to the embedded signing # Don't use an iframe! diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index afdca21..0282cb2 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -15,8 +15,8 @@ def self.consent_url(state, api) # https://developers.docusign.com/platform/auth/reference/obtain-consent scope = 'signature impersonation' if %w[eSignature Monitor].include?(api) scope = 'signature impersonation 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' if api == 'Rooms' - scope = 'impersonation click.manage click.send' if api == 'Click' - scope = 'impersonation organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' if api == 'Admin' + scope = 'signature impersonation click.manage click.send' if api == 'Click' + scope = 'signature impersonation organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' if api == 'Admin' base_uri = "#{Rails.configuration.authorization_server}/oauth/auth" response_type = 'code' @@ -33,16 +33,16 @@ def initialize(session) scope = 'signature impersonation' @client_module = DocuSign_eSign if session[:api] == 'Rooms' - scope = "#{scope} 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" + scope = "#{scope} 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" @client_module = DocuSign_Rooms end if session[:api] == 'Click' - scope = 'click.manage click.send' + scope = 'signature click.manage click.send' @client_module = DocuSign_Click end @client_module = DocuSign_Monitor if session[:api] == 'Monitor' if session[:api] == 'Admin' - scope = 'organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' + scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' @client_module = DocuSign_Admin end diff --git a/app/views/admin_api/aeg008_update_user_product_permission_profile/get.html.erb b/app/views/admin_api/aeg008_update_user_product_permission_profile/get.html.erb index ea6b984..76ce3c1 100644 --- a/app/views/admin_api/aeg008_update_user_product_permission_profile/get.html.erb +++ b/app/views/admin_api/aeg008_update_user_product_permission_profile/get.html.erb @@ -61,9 +61,9 @@ }); <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="aeg002"') %> -
    + <%= render('partials/continue_button') %>
    <% end %> \ No newline at end of file diff --git a/app/views/admin_api/aeg009_delete_user_product_permission_profile/get.html.erb b/app/views/admin_api/aeg009_delete_user_product_permission_profile/get.html.erb index 6e76b0e..fc298b8 100644 --- a/app/views/admin_api/aeg009_delete_user_product_permission_profile/get.html.erb +++ b/app/views/admin_api/aeg009_delete_user_product_permission_profile/get.html.erb @@ -24,9 +24,9 @@ <%= render('partials/submit_button') %> <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="aeg002"') %> -
    + <%= render('partials/continue_button') %>
    <% end %> \ No newline at end of file diff --git a/app/views/clickwrap/ceg002_activate_clickwrap/get.html.erb b/app/views/clickwrap/ceg002_activate_clickwrap/get.html.erb index 88faa14..849c03f 100644 --- a/app/views/clickwrap/ceg002_activate_clickwrap/get.html.erb +++ b/app/views/clickwrap/ceg002_activate_clickwrap/get.html.erb @@ -20,6 +20,6 @@ <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="eg001"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="ceg001"') %> <% end %> \ No newline at end of file diff --git a/app/views/clickwrap/ceg003_create_new_clickwrap_version/get.html.erb b/app/views/clickwrap/ceg003_create_new_clickwrap_version/get.html.erb index bb8575d..758bd64 100644 --- a/app/views/clickwrap/ceg003_create_new_clickwrap_version/get.html.erb +++ b/app/views/clickwrap/ceg003_create_new_clickwrap_version/get.html.erb @@ -11,6 +11,6 @@ <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="eg001"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="ceg001"') %> <% end %> \ No newline at end of file diff --git a/app/views/clickwrap/ceg005_clickwrap_responses/get.html.erb b/app/views/clickwrap/ceg005_clickwrap_responses/get.html.erb index ab1e10c..77600a4 100644 --- a/app/views/clickwrap/ceg005_clickwrap_responses/get.html.erb +++ b/app/views/clickwrap/ceg005_clickwrap_responses/get.html.erb @@ -19,6 +19,6 @@ <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="eg001"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="ceg001"') %> <% end %> \ No newline at end of file diff --git a/app/views/clickwrap/ceg006_embed_clickwrap/get.html.erb b/app/views/clickwrap/ceg006_embed_clickwrap/get.html.erb index 2142fe0..ab1bbf8 100644 --- a/app/views/clickwrap/ceg006_embed_clickwrap/get.html.erb +++ b/app/views/clickwrap/ceg006_embed_clickwrap/get.html.erb @@ -57,7 +57,7 @@ <% elsif @inactive_clickwraps.count.positive? %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="ceg002"') %> <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="eg001"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="ceg001"') %> <% end %> diff --git a/app/views/e_sign/eeg004_envelope_info/get.html.erb b/app/views/e_sign/eeg004_envelope_info/get.html.erb index 69c11dd..a551238 100644 --- a/app/views/e_sign/eeg004_envelope_info/get.html.erb +++ b/app/views/e_sign/eeg004_envelope_info/get.html.erb @@ -8,9 +8,9 @@ <% else %> -<%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %> +<%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eeg002"') %> -
    + <%= render('partials/continue_button') %>
    <% end %> diff --git a/app/views/e_sign/eeg005_envelope_recipients/get.html.erb b/app/views/e_sign/eeg005_envelope_recipients/get.html.erb index 302f88e..6d88541 100644 --- a/app/views/e_sign/eeg005_envelope_recipients/get.html.erb +++ b/app/views/e_sign/eeg005_envelope_recipients/get.html.erb @@ -13,9 +13,9 @@ <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eeg002"') %> -
    + <%= render('partials/continue_button') %>
    <% end %> diff --git a/app/views/e_sign/eeg006_envelope_docs/get.html.erb b/app/views/e_sign/eeg006_envelope_docs/get.html.erb index 0feb105..4611406 100644 --- a/app/views/e_sign/eeg006_envelope_docs/get.html.erb +++ b/app/views/e_sign/eeg006_envelope_docs/get.html.erb @@ -13,9 +13,9 @@ <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eeg002"') %> -
    + <%= render('partials/continue_button') %>
    <% end %> diff --git a/app/views/e_sign/eeg007_envelope_get_doc/get.html.erb b/app/views/e_sign/eeg007_envelope_get_doc/get.html.erb index 1717f34..2e733c0 100644 --- a/app/views/e_sign/eeg007_envelope_get_doc/get.html.erb +++ b/app/views/e_sign/eeg007_envelope_get_doc/get.html.erb @@ -6,15 +6,15 @@ <% redirect_to6_index = 1 %> <% if !@envelope_ok %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eeg002"') %>
    <%= render('partials/continue_button') %>
    <% elsif !@documents_ok %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to6_index]["RedirectText"], 'href="eg006"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to6_index]["RedirectText"], 'href="eeg006"') %> -
    + <%= render('partials/continue_button') %>
    <% else %> diff --git a/app/views/e_sign/eeg009_use_template/get.html.erb b/app/views/e_sign/eeg009_use_template/get.html.erb index 11825a7..ab7e376 100644 --- a/app/views/e_sign/eeg009_use_template/get.html.erb +++ b/app/views/e_sign/eeg009_use_template/get.html.erb @@ -44,9 +44,9 @@ <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to8_index]["RedirectText"], 'href="eg008"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to8_index]["RedirectText"], 'href="eeg008"') %> -
    + <%= render('partials/continue_button') %>
    <% end %> diff --git a/app/views/e_sign/eeg012_embedded_console/get.html.erb b/app/views/e_sign/eeg012_embedded_console/get.html.erb index 5d7fb5d..e382b79 100644 --- a/app/views/e_sign/eeg012_embedded_console/get.html.erb +++ b/app/views/e_sign/eeg012_embedded_console/get.html.erb @@ -5,7 +5,7 @@ <% redirect_to2_index = 0 %> <% if !@envelope_ok %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eeg002"') %> <% end %>
    diff --git a/app/views/e_sign/eeg013_add_doc_to_template/get.html.erb b/app/views/e_sign/eeg013_add_doc_to_template/get.html.erb index 34a6f5e..5cf3d46 100644 --- a/app/views/e_sign/eeg013_add_doc_to_template/get.html.erb +++ b/app/views/e_sign/eeg013_add_doc_to_template/get.html.erb @@ -70,9 +70,9 @@
    <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to8_index]["RedirectText"], 'href="eg008"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to8_index]["RedirectText"], 'href="eeg008"') %> -
    + <%= render('partials/continue_button') %>
    <% end %> \ No newline at end of file diff --git a/app/views/e_sign/eeg015_get_envelope_tab_data/get.html.erb b/app/views/e_sign/eeg015_get_envelope_tab_data/get.html.erb index 302f88e..6d88541 100644 --- a/app/views/e_sign/eeg015_get_envelope_tab_data/get.html.erb +++ b/app/views/e_sign/eeg015_get_envelope_tab_data/get.html.erb @@ -13,9 +13,9 @@ <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eg002"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eeg002"') %> -
    + <%= render('partials/continue_button') %>
    <% end %> diff --git a/app/views/e_sign/eeg017_set_template_tab_values/get.html.erb b/app/views/e_sign/eeg017_set_template_tab_values/get.html.erb index 1164469..84f4ccc 100644 --- a/app/views/e_sign/eeg017_set_template_tab_values/get.html.erb +++ b/app/views/e_sign/eeg017_set_template_tab_values/get.html.erb @@ -3,8 +3,8 @@ <% form_index = 0 %> <% signer_email_index = 0 %> <% signer_name_index = 1 %> -<% cc_email_index = 2 %> -<% cc_name_index = 3 %> +<% cc_name_index = 2 %> +<% cc_email_index = 3 %> <% redirect_to8_index = 0 %> <% if @template_ok %> @@ -27,6 +27,12 @@ placeholder="<%= @example["Forms"][form_index]["Inputs"][signer_name_index]["InputPlaceholder"] %>" name="signerName" value="<%= @config.signer_name %>" required>
    +
    + + " name="ccName" + required> +
    " required /> <%= render('partials/email_should_differ_from_signer') %>
    -
    - - " name="ccName" - required> -
    <%= render('partials/submit_button') %> <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to8_index]["RedirectText"], 'href="eg008"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to8_index]["RedirectText"], 'href="eeg008"') %> -
    + <%= render('partials/continue_button') %>
    <% end %> \ No newline at end of file diff --git a/app/views/e_sign/eeg018_get_envelope_custom_field_data/get.html.erb b/app/views/e_sign/eeg018_get_envelope_custom_field_data/get.html.erb index a334c07..d225eb2 100644 --- a/app/views/e_sign/eeg018_get_envelope_custom_field_data/get.html.erb +++ b/app/views/e_sign/eeg018_get_envelope_custom_field_data/get.html.erb @@ -13,9 +13,9 @@ <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to16_index]["RedirectText"], 'href="eg016"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to16_index]["RedirectText"], 'href="eeg016"') %> -
    + <%= render('partials/continue_button') %>
    <% end %> diff --git a/app/views/e_sign/eeg030_brands_apply_to_template/get.html.erb b/app/views/e_sign/eeg030_brands_apply_to_template/get.html.erb index d4afe48..c0b04d4 100644 --- a/app/views/e_sign/eeg030_brands_apply_to_template/get.html.erb +++ b/app/views/e_sign/eeg030_brands_apply_to_template/get.html.erb @@ -52,9 +52,9 @@ <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to8_index]["RedirectText"], 'href="eg008"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to8_index]["RedirectText"], 'href="eeg008"') %> -
    + <%= render('partials/continue_button') %>
    <% end %> \ No newline at end of file diff --git a/app/views/e_sign/eeg033_unpauses_signature_workflow/get.html.erb b/app/views/e_sign/eeg033_unpauses_signature_workflow/get.html.erb index 116d5ed..bd71b37 100644 --- a/app/views/e_sign/eeg033_unpauses_signature_workflow/get.html.erb +++ b/app/views/e_sign/eeg033_unpauses_signature_workflow/get.html.erb @@ -5,9 +5,9 @@ <% redirect_to32_index = 0 %> <% if session[:envelope_id] %> - <%= form_tag eg033_path, method: :put do -%> + <%= form_tag eeg033_path, method: :put do -%> <%= submit_tag 'Submit', class: 'btn btn-docu'%> <%- end -%> <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to32_index]["RedirectText"], 'href="eg032"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to32_index]["RedirectText"], 'href="eeg032"') %> <% end %> \ No newline at end of file diff --git a/app/views/room_api/reg003_export_data_from_room/get.html.erb b/app/views/room_api/reg003_export_data_from_room/get.html.erb index 2e61356..e1ccf41 100644 --- a/app/views/room_api/reg003_export_data_from_room/get.html.erb +++ b/app/views/room_api/reg003_export_data_from_room/get.html.erb @@ -20,5 +20,5 @@ <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="eg001"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="reg001"') %> <% end %> diff --git a/app/views/room_api/reg004_add_forms_to_room/get.html.erb b/app/views/room_api/reg004_add_forms_to_room/get.html.erb index 9e7d9e2..21316c2 100644 --- a/app/views/room_api/reg004_add_forms_to_room/get.html.erb +++ b/app/views/room_api/reg004_add_forms_to_room/get.html.erb @@ -27,7 +27,7 @@ <% elsif @rooms.count.zero? %>
    - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="eg001"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="reg001"') %>
    <% end %> diff --git a/app/views/room_api/reg006_create_an_external_form_fill_session/get_forms.html.erb b/app/views/room_api/reg006_create_an_external_form_fill_session/get_forms.html.erb index 55203ef..6b83800 100644 --- a/app/views/room_api/reg006_create_an_external_form_fill_session/get_forms.html.erb +++ b/app/views/room_api/reg006_create_an_external_form_fill_session/get_forms.html.erb @@ -6,7 +6,7 @@ <% unless @form_libraries.blank? %> -
    + <% if @example["Forms"][form_index]["FormName"] %> <%= sanitize @example["Forms"][form_index]["FormName"] %> <% end %> @@ -22,7 +22,7 @@ <% else %>
    - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to4_index]["RedirectText"], 'href="eg004"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to4_index]["RedirectText"], 'href="reg004"') %>
    <% end %> \ No newline at end of file diff --git a/app/views/room_api/reg006_create_an_external_form_fill_session/get_rooms.html.erb b/app/views/room_api/reg006_create_an_external_form_fill_session/get_rooms.html.erb index 4d1f5df..0189098 100644 --- a/app/views/room_api/reg006_create_an_external_form_fill_session/get_rooms.html.erb +++ b/app/views/room_api/reg006_create_an_external_form_fill_session/get_rooms.html.erb @@ -6,7 +6,7 @@ <% if @rooms.count.positive? %> - + <% if @example["Forms"][form_index]["FormName"] %> <%= sanitize @example["Forms"][form_index]["FormName"] %> <% end %> @@ -21,7 +21,7 @@ <% else %>
    - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="eg001"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="reg001"') %>
    <% end %> \ No newline at end of file diff --git a/app/views/room_api/reg008_grant_office_access_to_form_group/get.erb b/app/views/room_api/reg008_grant_office_access_to_form_group/get.erb index 04a3037..472da17 100644 --- a/app/views/room_api/reg008_grant_office_access_to_form_group/get.erb +++ b/app/views/room_api/reg008_grant_office_access_to_form_group/get.erb @@ -23,6 +23,6 @@
    <% else %>
    - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to7_index]["RedirectText"], 'href="eg007"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to7_index]["RedirectText"], 'href="reg007"') %>
    <% end %> \ No newline at end of file diff --git a/app/views/room_api/reg009_assign_form_to_form_group/get.erb b/app/views/room_api/reg009_assign_form_to_form_group/get.erb index 9fbe685..b76c58b 100644 --- a/app/views/room_api/reg009_assign_form_to_form_group/get.erb +++ b/app/views/room_api/reg009_assign_form_to_form_group/get.erb @@ -23,6 +23,6 @@ <% else %>
    - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to7_index]["RedirectText"], 'href="eg007"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to7_index]["RedirectText"], 'href="reg007"') %>
    <% end %> \ No newline at end of file diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 97c8b40..230fc11 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -43,9 +43,9 @@ when 'Rooms' strategy.options[:authorize_params].scope = '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' when 'Click' - strategy.options[:authorize_params].scope = 'click.manage click.send' + strategy.options[:authorize_params].scope = 'signature click.manage click.send' when 'Admin' - strategy.options[:authorize_params].scope = 'organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' + strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' end } end diff --git a/quick_acg/config/initializers/omniauth.rb b/quick_acg/config/initializers/omniauth.rb index 97c8b40..230fc11 100644 --- a/quick_acg/config/initializers/omniauth.rb +++ b/quick_acg/config/initializers/omniauth.rb @@ -43,9 +43,9 @@ when 'Rooms' strategy.options[:authorize_params].scope = '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' when 'Click' - strategy.options[:authorize_params].scope = 'click.manage click.send' + strategy.options[:authorize_params].scope = 'signature click.manage click.send' when 'Admin' - strategy.options[:authorize_params].scope = 'organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' + strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' end } end diff --git a/test/eg017_set_template_tab_values_test.rb b/test/eg017_set_template_tab_values_test.rb index 5bec176..f914968 100644 --- a/test/eg017_set_template_tab_values_test.rb +++ b/test/eg017_set_template_tab_values_test.rb @@ -13,13 +13,13 @@ class Eg017SetTemplateTabValuesTest < TestHelper signer_name: @config['signer_name'], cc_email: @data[:cc_email], cc_name: @data[:cc_name], - template_id: TestData.get_template_id + template_id: TestData.get_template_id, + ds_ping_url: @data[:ds_ping_url], } args = { account_id: @account_id, base_path: @base_path, access_token: @access_token, - ds_ping_url: @data[:ds_ping_url], envelope_args: envelope_args } From 5bd8703123b5ce004863737a8524ee8e36f8a334 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Mon, 6 Mar 2023 12:20:25 -0800 Subject: [PATCH 185/363] Devdocs 9661 (#113) * add new rooms code example --- Gemfile | 4 ++-- Gemfile.lock | 8 ++++---- ...reg001_create_room_with_data_controller.rb | 2 +- ...02_create_room_with_template_controller.rb | 2 +- ...n_external_form_fill_session_controller.rb | 19 ++++++++++++------- ...e_an_external_form_fill_session_service.rb | 9 +++------ app/services/room_api/get_data_service.rb | 7 ++++--- .../results.html.erb | 12 ++++++++++++ quick_acg/Gemfile | 2 +- 9 files changed, 40 insertions(+), 25 deletions(-) create mode 100644 app/views/room_api/reg006_create_an_external_form_fill_session/results.html.erb diff --git a/Gemfile b/Gemfile index 5b03c96..d23ea33 100644 --- a/Gemfile +++ b/Gemfile @@ -70,9 +70,9 @@ end gem 'docusign_admin', '~> 1.1.0' gem 'docusign_click', '~> 1.2.2' -gem 'docusign_esign', '~> 3.20.0' +gem 'docusign_esign', '~> 3.21.0' gem 'docusign_monitor', '~> 1.1.0' -gem 'docusign_rooms', '~> 1.2.0.rc1' +gem 'docusign_rooms', '~> 1.3.0' gem 'omniauth-oauth2', '~> 1.7.1' gem 'omniauth-rails_csrf_protection' diff --git a/Gemfile.lock b/Gemfile.lock index 858880b..80c7e42 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -108,7 +108,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.20.0) + docusign_esign (3.21.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -118,7 +118,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_rooms (1.2.0.rc1) + docusign_rooms (1.3.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -330,9 +330,9 @@ DEPENDENCIES coffee-rails (~> 5.0.0) docusign_admin (~> 1.1.0) docusign_click (~> 1.2.2) - docusign_esign (~> 3.20.0) + docusign_esign (~> 3.21.0) docusign_monitor (~> 1.1.0) - docusign_rooms (~> 1.2.0.rc1) + docusign_rooms (~> 1.3.0) jbuilder (~> 2.11.5) listen (~> 3.7.1) matrix (~> 0.4.2) diff --git a/app/controllers/room_api/reg001_create_room_with_data_controller.rb b/app/controllers/room_api/reg001_create_room_with_data_controller.rb index d753a00..fa99f71 100644 --- a/app/controllers/room_api/reg001_create_room_with_data_controller.rb +++ b/app/controllers/room_api/reg001_create_room_with_data_controller.rb @@ -6,7 +6,7 @@ def create args = { room_name: params[:roomName], office_id: RoomApi::GetDataService.new(session).get_offices[0]['officeId'], - role_id: RoomApi::GetDataService.new(session).get_roles[2]['roleId'], + role_id: RoomApi::GetDataService.new(session).get_default_admin_role_id, account_id: session[:ds_account_id], base_path: session[:ds_base_path], access_token: session[:ds_access_token] diff --git a/app/controllers/room_api/reg002_create_room_with_template_controller.rb b/app/controllers/room_api/reg002_create_room_with_template_controller.rb index 7d0ddfb..6fc40bc 100644 --- a/app/controllers/room_api/reg002_create_room_with_template_controller.rb +++ b/app/controllers/room_api/reg002_create_room_with_template_controller.rb @@ -6,7 +6,7 @@ def create args = { room_name: params[:roomName], office_id: RoomApi::GetDataService.new(session).get_offices[0]['officeId'], - role_id: RoomApi::GetDataService.new(session).get_roles[2]['roleId'], + role_id: RoomApi::GetDataService.new(session).get_default_admin_role_id, template_id: params['templateId'], account_id: session[:ds_account_id], base_path: session[:ds_base_path], diff --git a/app/controllers/room_api/reg006_create_an_external_form_fill_session_controller.rb b/app/controllers/room_api/reg006_create_an_external_form_fill_session_controller.rb index 6d3814d..691dea0 100644 --- a/app/controllers/room_api/reg006_create_an_external_form_fill_session_controller.rb +++ b/app/controllers/room_api/reg006_create_an_external_form_fill_session_controller.rb @@ -8,16 +8,21 @@ def create room_id: params['roomId'], account_id: session[:ds_account_id], base_path: session[:ds_base_path], - access_token: session[:ds_access_token] + access_token: session[:ds_access_token], + allowed_host: request.host_with_port } + begin + results = RoomApi::Eg006CreateAnExternalFormFillSessionService.new(args).worker - results = RoomApi::Eg006CreateAnExternalFormFillSessionService.new(args).worker + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json + @url = results.url - @title = @example['ExampleName'] - @message = @example['ResultsPageText'] - @json = results.to_json.to_json - - render 'ds_common/example_done' + render 'room_api/reg006_create_an_external_form_fill_session/results' + rescue DocuSign_Rooms::ApiError => e + handle_error(e) + end end def get_rooms diff --git a/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb b/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb index 1841406..912c862 100644 --- a/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb +++ b/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb @@ -16,11 +16,7 @@ def worker rooms_api = DocuSign_Rooms::ExternalFormFillSessionsApi.new(api_client) - begin - rooms_api.create_external_form_fill_session(args[:account_id], body(args)) - rescue Exception - nil - end + rooms_api.create_external_form_fill_session(args[:account_id], body(args)) end private @@ -28,7 +24,8 @@ def worker def body(args) DocuSign_Rooms::ExternalFormFillSessionForCreate.new({ formId: args[:form_id], - roomId: args[:room_id] + roomId: args[:room_id], + xFrameAllowedUrl: "http://#{args[:allowed_host]}" }) end end diff --git a/app/services/room_api/get_data_service.rb b/app/services/room_api/get_data_service.rb index 0384c3b..f10b0e8 100644 --- a/app/services/room_api/get_data_service.rb +++ b/app/services/room_api/get_data_service.rb @@ -20,12 +20,13 @@ def get_offices offices.as_json['officeSummaries'] end - def get_roles + def get_default_admin_role_id worker roles_api = DocuSign_Rooms::RolesApi.new(@api_client) - roles = roles_api.get_roles(args[:account_id]) - roles.as_json['roles'] + roles = roles_api.get_roles(args[:account_id]).as_json['roles'] + default_admin_role = roles.find { |role| role['name'] == 'Default Admin' } + default_admin_role['roleId'] end def get_rooms diff --git a/app/views/room_api/reg006_create_an_external_form_fill_session/results.html.erb b/app/views/room_api/reg006_create_an_external_form_fill_session/results.html.erb new file mode 100644 index 0000000..f6cefe1 --- /dev/null +++ b/app/views/room_api/reg006_create_an_external_form_fill_session/results.html.erb @@ -0,0 +1,12 @@ +

    <%= @title %>

    +<% if !@message.nil? %> +

    <%= @message.html_safe %>

    +<% end %> + +<%= @json %> + + + +

    Continue

    diff --git a/quick_acg/Gemfile b/quick_acg/Gemfile index 09d66d9..eafa580 100644 --- a/quick_acg/Gemfile +++ b/quick_acg/Gemfile @@ -66,7 +66,7 @@ group :test do gem 'chromedriver-helper', '~> 2.1.1' end -gem 'docusign_esign', '~> 3.19.0' +gem 'docusign_esign', '~> 3.21.0' gem 'omniauth-oauth2', '~> 1.7.1' gem 'omniauth-rails_csrf_protection' From 598140ec673180ebd1311565ff3103a9e863b6d7 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Thu, 9 Mar 2023 12:57:02 -0800 Subject: [PATCH 186/363] update esign 8 and 16 for numerical tabs (#114) * update esign 8 and 16 for numerical tabs --- app/assets/javascripts/search.js | 2 +- app/controllers/ds_common_controller.rb | 11 +++- .../eeg008_create_template_controller.rb | 2 +- .../e_sign/eeg009_use_template_controller.rb | 2 + ...eeg016_set_envelope_tab_data_controller.rb | 12 +++-- .../e_sign/eg008_create_template_service.rb | 8 +-- .../eg016_set_envelope_tab_data_service.rb | 52 +++++++++++++------ .../eeg015_get_envelope_tab_data/get.html.erb | 6 +-- .../eeg016_set_envelope_tab_data/get.html.erb | 4 +- test/eg008_create_template_test.rb | 8 +-- test/test_helper.rb | 2 +- 11 files changed, 72 insertions(+), 37 deletions(-) diff --git a/app/assets/javascripts/search.js b/app/assets/javascripts/search.js index 66ec52f..dcdaacf 100644 --- a/app/assets/javascripts/search.js +++ b/app/assets/javascripts/search.js @@ -125,7 +125,7 @@ const DS_SEARCH = (function () { case API_TYPES.MONITOR: return "meg"; case API_TYPES.ESIGNATURE: - return "eg"; + return "eeg"; } } diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index 9112e99..f7825cc 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -29,7 +29,7 @@ def handle_redirects else render_examples end - elsif session[:ds_access_token].present? && session[:ds_account_id].present? + elsif check_token if !session[:api] || session[:api] == 'eSignature' enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) session[:status_cfr] = 'enabled' if enableCFR == 'enabled' @@ -41,7 +41,7 @@ def handle_redirects end def render_examples - if session[:ds_access_token].present? && session[:ds_account_id].present? && !session[:status_cfr] && (!session[:api] || session[:api] == 'eSignature') + if check_token && !session[:status_cfr] && (!session[:api] || session[:api] == 'eSignature') enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) if enableCFR == 'enabled' @status_cfr = 'enabled' @@ -115,4 +115,11 @@ def error; end def load_manifest @manifest = Utils::ManifestUtils.new.get_manifest(Rails.configuration.example_manifest_url) end + + def check_token(buffer_in_min = 10) + buffer = buffer_in_min * 60 + expires_at = session[:ds_expires_at] + remaining_duration = expires_at.nil? ? 0 : expires_at - buffer.seconds.from_now.to_i + remaining_duration.positive? + end end diff --git a/app/controllers/e_sign/eeg008_create_template_controller.rb b/app/controllers/e_sign/eeg008_create_template_controller.rb index 44a4f3d..43b08fd 100644 --- a/app/controllers/e_sign/eeg008_create_template_controller.rb +++ b/app/controllers/e_sign/eeg008_create_template_controller.rb @@ -9,7 +9,7 @@ def create account_id: session['ds_account_id'], base_path: session['ds_base_path'], access_token: session['ds_access_token'], - template_name: 'Example Signer and CC template' + template_name: 'Example Signer and CC template v2' } results = ESign::Eg008CreateTemplateService.new(args).worker session[:template_id] = results[:template_id] diff --git a/app/controllers/e_sign/eeg009_use_template_controller.rb b/app/controllers/e_sign/eeg009_use_template_controller.rb index 62a1c7d..9e4f625 100644 --- a/app/controllers/e_sign/eeg009_use_template_controller.rb +++ b/app/controllers/e_sign/eeg009_use_template_controller.rb @@ -25,6 +25,8 @@ def create } results = ESign::Eg009UseTemplateService.new(args).worker + + session[:envelope_id] = results[:envelope_id] # results is an object that implements ArrayAccess. Convert to a regular array: @title = @example['ExampleName'] @message = format_string(@example['ResultsPageText'], results[:envelope_id]) diff --git a/app/controllers/e_sign/eeg016_set_envelope_tab_data_controller.rb b/app/controllers/e_sign/eeg016_set_envelope_tab_data_controller.rb index ee9357f..bdcb013 100644 --- a/app/controllers/e_sign/eeg016_set_envelope_tab_data_controller.rb +++ b/app/controllers/e_sign/eeg016_set_envelope_tab_data_controller.rb @@ -14,11 +14,15 @@ def create account_id: session['ds_account_id'] } - results = ESign::Eg016SetEnvelopeTabDataService.new(args).worker + begin + results = ESign::Eg016SetEnvelopeTabDataService.new(args).worker - # Save for future use within the example launcher - session[:envelope_id] = results[:envelope_id] + # Save for future use within the example launcher + session[:envelope_id] = results[:envelope_id] - redirect_to results[:url] + redirect_to results[:url] + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end end end diff --git a/app/services/e_sign/eg008_create_template_service.rb b/app/services/e_sign/eg008_create_template_service.rb index b8d74f2..50d4a80 100644 --- a/app/services/e_sign/eg008_create_template_service.rb +++ b/app/services/e_sign/eg008_create_template_service.rb @@ -114,11 +114,11 @@ def make_template_req ] ) - number1 = DocuSign_eSign::Number.new( + numerical = DocuSign_eSign::Numerical.new( 'documentId' => '1', 'pageNumber' => '1', 'xPosition' => '163', 'yPosition' => '260', - 'font' => 'helvetica', 'fontSize' => 'size14', - 'tabLabel' => 'numbersOnly', 'width' => '84', 'required' => 'false' + 'font' => 'helvetica', 'fontSize' => 'size14', 'validationType' => 'Currency', + 'tabLabel' => 'numericalCurrency', 'width' => '84', 'required' => 'false' ) radio_group = DocuSign_eSign::RadioGroup.new( 'documentId' => '1', 'groupName' => 'radio1', @@ -148,7 +148,7 @@ def make_template_req 'signHereTabs' => [sign_here], 'checkboxTabs' => [check1, check2, check3, check4], 'listTabs' => [list1], - 'numberTabs' => [number1], + 'numericalTabs' => [numerical], 'radioGroupTabs' => [radio_group], 'textTabs' => [text] ) diff --git a/app/services/e_sign/eg016_set_envelope_tab_data_service.rb b/app/services/e_sign/eg016_set_envelope_tab_data_service.rb index f52b701..a042cbe 100644 --- a/app/services/e_sign/eg016_set_envelope_tab_data_service.rb +++ b/app/services/e_sign/eg016_set_envelope_tab_data_service.rb @@ -86,7 +86,6 @@ def make_envelope(signer_email, signer_name, signer_client_id, pdf_filename) }) # Step 3. Create Tabs and CustomFields - salary = '$123,000' sign_here1 = DocuSign_eSign::SignHere.new sign_here1.anchor_string = '/sn1/' @@ -111,7 +110,7 @@ def make_envelope(signer_email, signer_name, signer_client_id, pdf_filename) text_familiar.anchor_string = '/familiar/' text_familiar.anchor_units = 'pixels' text_familiar.anchor_y_offset = '-9' - text_familiar.anchor_y_offset = '5' + text_familiar.anchor_x_offset = '5' text_familiar.font = 'Helvetica' text_familiar.font_size = 'size11' text_familiar.bold = 'true' @@ -120,23 +119,46 @@ def make_envelope(signer_email, signer_name, signer_client_id, pdf_filename) text_familiar.tab_id = 'familiar_name' text_familiar.tab_label = 'Familiar name' - text_salary = DocuSign_eSign::Text.new - text_salary.anchor_string = '/salary/' - text_salary.anchor_units = 'pixels' - text_salary.anchor_y_offset = '-9' - text_salary.anchor_y_offset = '5' - text_salary.font = 'Helvetica' - text_salary.font_size = 'size11' - text_salary.bold = 'true' - text_salary.value = salary - text_salary.locked = 'true' - text_salary.tab_id = 'salary' - text_salary.tab_label = 'Salary' + locale_policy_tab = DocuSign_eSign::LocalePolicyTab.new + locale_policy_tab.culture_name = 'en-US' + locale_policy_tab.currency_code = 'usd' + locale_policy_tab.currency_positive_format = 'csym_1_comma_234_comma_567_period_89' + locale_policy_tab.currency_negative_format = 'minus_csym_1_comma_234_comma_567_period_89' + locale_policy_tab.use_long_currency_format = 'true' + + numerical_salary = DocuSign_eSign::Numerical.new + numerical_salary.page_number = '1' + numerical_salary.document_id = '1' + numerical_salary.x_position = '210' + numerical_salary.y_position = '235' + numerical_salary.height = '20' + numerical_salary.width = '70' + numerical_salary.min_numerical_value = '0' + numerical_salary.max_numerical_value = '1000000' + numerical_salary.validation_type = 'Currency' + numerical_salary.font = 'Helvetica' + numerical_salary.font_size = 'size11' + numerical_salary.bold = 'true' + numerical_salary.tab_id = 'salary' + numerical_salary.tab_label = 'Salary' + numerical_salary.numerical_value = '123000' + numerical_salary.locale_policy = locale_policy_tab + + salary_custom_field = DocuSign_eSign::TextCustomField.new + salary_custom_field.name = 'salary' + salary_custom_field.required = 'false' + salary_custom_field.show = 'true' + salary_custom_field.value = '123000' + + cf = DocuSign_eSign::CustomFields.new + cf.text_custom_fields = [salary_custom_field] + envelope_definition.custom_fields = cf # Tabs are set per recipient / signer tabs = DocuSign_eSign::Tabs.new tabs.sign_here_tabs = [sign_here1] - tabs.text_tabs = [text_legal, text_familiar, text_salary] + tabs.text_tabs = [text_legal, text_familiar] + tabs.numerical_tabs = [numerical_salary] signer1.tabs = tabs # Add the recipients to the envelope object diff --git a/app/views/e_sign/eeg015_get_envelope_tab_data/get.html.erb b/app/views/e_sign/eeg015_get_envelope_tab_data/get.html.erb index 6d88541..b209679 100644 --- a/app/views/e_sign/eeg015_get_envelope_tab_data/get.html.erb +++ b/app/views/e_sign/eeg015_get_envelope_tab_data/get.html.erb @@ -1,7 +1,7 @@ <%= render('partials/example_info') %> <% form_index = 0 %> -<% redirect_to2_index = 0 %> +<% redirect_to9_index = 0 %> <% if @envelope_ok %>
    @@ -13,9 +13,9 @@
    <% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eeg002"') %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to9_index]["RedirectText"], 'href="eeg009"') %> -
    + <%= render('partials/continue_button') %>
    <% end %> diff --git a/app/views/e_sign/eeg016_set_envelope_tab_data/get.html.erb b/app/views/e_sign/eeg016_set_envelope_tab_data/get.html.erb index 2fdf193..eca3750 100644 --- a/app/views/e_sign/eeg016_set_envelope_tab_data/get.html.erb +++ b/app/views/e_sign/eeg016_set_envelope_tab_data/get.html.erb @@ -1,8 +1,8 @@ <%= render('partials/example_info') %> <% form_index = 0 %> -<% signer_email_index = 0 %> -<% signer_name_index = 1 %> +<% signer_name_index = 0 %> +<% signer_email_index = 1 %>
    <% if @example["Forms"][form_index]["FormName"] %> diff --git a/test/eg008_create_template_test.rb b/test/eg008_create_template_test.rb index f2d59a4..c571062 100644 --- a/test/eg008_create_template_test.rb +++ b/test/eg008_create_template_test.rb @@ -77,11 +77,11 @@ class Eg008CreateTemplateTest < TestHelper ] ) - expected_number1 = DocuSign_eSign::Number.new( + expected_numerical = DocuSign_eSign::Numerical.new( 'documentId' => '1', 'pageNumber' => '1', 'xPosition' => '163', 'yPosition' => '260', - 'font' => 'helvetica', 'fontSize' => 'size14', - 'tabLabel' => 'numbersOnly', 'width' => '84', 'required' => 'false' + 'font' => 'helvetica', 'fontSize' => 'size14', 'validationType' => 'Currency', + 'tabLabel' => 'numericalCurrency', 'width' => '84', 'required' => 'false' ) expected_radio_group = DocuSign_eSign::RadioGroup.new( 'documentId' => '1', 'groupName' => 'radio1', @@ -110,7 +110,7 @@ class Eg008CreateTemplateTest < TestHelper expected_tabs.sign_here_tabs = [expected_sign_here] expected_tabs.checkbox_tabs = [expected_check1, expected_check2, expected_check3, expected_check4] expected_tabs.list_tabs = [expected_list1] - expected_tabs.number_tabs = [expected_number1] + expected_tabs.numerical_tabs = [expected_numerical] expected_tabs.radio_group_tabs = [expected_radio_group] expected_tabs.text_tabs = [expected_text] diff --git a/test/test_helper.rb b/test/test_helper.rb index 0526704..f1925f8 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -97,7 +97,7 @@ def get_common_data doc_for_template: './data/World_Wide_Corp_fields.pdf', item: 'Item', quantity: 5, - template_name: 'Example Signer and CC template' + template_name: 'Example Signer and CC template v2' } end From 03e29035558b238f940cde39fbbeba0ac5bc1d82 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Mon, 20 Mar 2023 14:30:28 -0700 Subject: [PATCH 187/363] fix routing issue (#120) --- app/views/ds_common/example_done.erb | 2 +- app/views/e_sign/eeg007_envelope_get_doc/get.html.erb | 2 +- .../e_sign/eeg032_pauses_signature_workflow/return.html.erb | 2 +- app/views/room_api/reg005_get_rooms_with_filters/get.html.erb | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/ds_common/example_done.erb b/app/views/ds_common/example_done.erb index 75df06b..e599966 100644 --- a/app/views/ds_common/example_done.erb +++ b/app/views/ds_common/example_done.erb @@ -12,7 +12,7 @@ <% end %> <% if @check_status %> -

    Check the request status

    +

    Check the request status

    <% end %>

    Continue

    \ No newline at end of file diff --git a/app/views/e_sign/eeg007_envelope_get_doc/get.html.erb b/app/views/e_sign/eeg007_envelope_get_doc/get.html.erb index 2e733c0..254f241 100644 --- a/app/views/e_sign/eeg007_envelope_get_doc/get.html.erb +++ b/app/views/e_sign/eeg007_envelope_get_doc/get.html.erb @@ -8,7 +8,7 @@ <% if !@envelope_ok %> <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to2_index]["RedirectText"], 'href="eeg002"') %> - + <%= render('partials/continue_button') %>
    <% elsif !@documents_ok %> diff --git a/app/views/e_sign/eeg032_pauses_signature_workflow/return.html.erb b/app/views/e_sign/eeg032_pauses_signature_workflow/return.html.erb index e998339..6a2fabd 100644 --- a/app/views/e_sign/eeg032_pauses_signature_workflow/return.html.erb +++ b/app/views/e_sign/eeg032_pauses_signature_workflow/return.html.erb @@ -5,7 +5,7 @@ Envelope ID: <%= @envelop_id %>

    - To resume a workflow after first recipient signs the envelope use Unpause a signature workflow + To resume a workflow after first recipient signs the envelope use Unpause a signature workflow

    Continue

    \ No newline at end of file diff --git a/app/views/room_api/reg005_get_rooms_with_filters/get.html.erb b/app/views/room_api/reg005_get_rooms_with_filters/get.html.erb index 1c0601d..db5ed54 100644 --- a/app/views/room_api/reg005_get_rooms_with_filters/get.html.erb +++ b/app/views/room_api/reg005_get_rooms_with_filters/get.html.erb @@ -26,9 +26,9 @@

    Problem: you don't have any rooms. Please first create a room using - Create a new room + Create a new room or - Create room with a template. + Create room with a template.
    Thank you.

    From 0c18b6b20ed13a5423817802f7e296de2ba40cc7 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Fri, 21 Apr 2023 19:41:57 +0300 Subject: [PATCH 188/363] Added unit/integration tests for 6 code examples (#119) * added tests --- .github/workflows/rubyonrails.yml | 1 + .../ceg001_create_clickwrap_controller.rb | 1 + .../ceg002_activate_clickwrap_controller.rb | 3 +- .../eg001_create_clickwrap_service.rb | 3 +- .../eg002_activate_clickwrap_service.rb | 22 ++- .../e_sign/eg024_permission_create_service.rb | 5 +- test/eg001_create_clickwrap_test.rb | 31 ++++ test/eg001_embedded_signing_test.rb | 2 +- test/eg002_activate_clickwrap_test.rb | 39 ++++ test/eg002_sign_via_email_test.rb | 2 +- test/eg008_create_template_test.rb | 2 +- test/eg009_use_template_test.rb | 2 +- test/eg013_add_doc_to_template_test.rb | 2 +- test/eg017_set_template_tab_values_test.rb | 2 +- test/eg024_permission_create_test.rb | 62 +++++++ test/eg028_brands_creating_test.rb | 33 ++++ test/eg029_brands_apply_to_envelope_test.rb | 86 +++++++++ test/eg031_bulk_sending_envelopes_test.rb | 173 ++++++++++++++++++ test/test_helper.rb | 72 +++++++- 19 files changed, 511 insertions(+), 32 deletions(-) create mode 100644 test/eg001_create_clickwrap_test.rb create mode 100644 test/eg002_activate_clickwrap_test.rb create mode 100644 test/eg024_permission_create_test.rb create mode 100644 test/eg028_brands_creating_test.rb create mode 100644 test/eg029_brands_apply_to_envelope_test.rb create mode 100644 test/eg031_bulk_sending_envelopes_test.rb diff --git a/.github/workflows/rubyonrails.yml b/.github/workflows/rubyonrails.yml index 01316ce..6a933ce 100644 --- a/.github/workflows/rubyonrails.yml +++ b/.github/workflows/rubyonrails.yml @@ -30,6 +30,7 @@ jobs: - name: Run tests run: | gem install docusign_esign + gem install docusign_click ruby test/run_tests.rb env: CLIENT_ID: ${{ secrets.CLIENT_ID }} diff --git a/app/controllers/clickwrap/ceg001_create_clickwrap_controller.rb b/app/controllers/clickwrap/ceg001_create_clickwrap_controller.rb index ccaa8a6..cc3ea4d 100644 --- a/app/controllers/clickwrap/ceg001_create_clickwrap_controller.rb +++ b/app/controllers/clickwrap/ceg001_create_clickwrap_controller.rb @@ -7,6 +7,7 @@ def create account_id: session[:ds_account_id], base_path: session[:ds_base_path], access_token: session[:ds_access_token], + doc_pdf: File.join('data', Rails.configuration.doc_terms_pdf), clickwrap_name: request[:clickwrapName] } diff --git a/app/controllers/clickwrap/ceg002_activate_clickwrap_controller.rb b/app/controllers/clickwrap/ceg002_activate_clickwrap_controller.rb index a5108cd..38664f3 100644 --- a/app/controllers/clickwrap/ceg002_activate_clickwrap_controller.rb +++ b/app/controllers/clickwrap/ceg002_activate_clickwrap_controller.rb @@ -18,6 +18,7 @@ def create end def get - @clickwraps = Clickwrap::Eg002ActivateClickwrapService.new(session).get_inactive_clickwraps + statuses = %w[inactive draft] + @clickwraps = Clickwrap::Eg002ActivateClickwrapService.new(session).get_inactive_clickwraps(statuses).as_json end end diff --git a/app/services/clickwrap/eg001_create_clickwrap_service.rb b/app/services/clickwrap/eg001_create_clickwrap_service.rb index ab807a5..1203bca 100644 --- a/app/services/clickwrap/eg001_create_clickwrap_service.rb +++ b/app/services/clickwrap/eg001_create_clickwrap_service.rb @@ -31,8 +31,7 @@ def worker # Read file from a local directory # The reads could raise an exception if the file is not available! - doc_pdf = Rails.configuration.doc_terms_pdf - doc_b64 = Base64.encode64(File.binread(File.join('data', doc_pdf))) + doc_b64 = Base64.encode64(File.binread(args[:doc_pdf])) # Create the document model. documents = [ diff --git a/app/services/clickwrap/eg002_activate_clickwrap_service.rb b/app/services/clickwrap/eg002_activate_clickwrap_service.rb index 26867e1..a9079ff 100644 --- a/app/services/clickwrap/eg002_activate_clickwrap_service.rb +++ b/app/services/clickwrap/eg002_activate_clickwrap_service.rb @@ -29,7 +29,7 @@ def worker ) end - def get_inactive_clickwraps + def get_inactive_clickwraps(statuses) configuration = DocuSign_Click::Configuration.new configuration.host = args[:ds_base_path] @@ -38,14 +38,16 @@ def get_inactive_clickwraps accounts_api = DocuSign_Click::AccountsApi.new(api_client) - options = DocuSign_Click::GetClickwrapsOptions.new - options.status = 'inactive' - - results = accounts_api.get_clickwraps( - args[:ds_account_id], - options - ) - puts results.as_json['clickwraps'] - results.as_json['clickwraps'] + clickwraps = [] + statuses.each do |status| + options = DocuSign_Click::GetClickwrapsOptions.new + options.status = status + clickwraps.concat accounts_api.get_clickwraps( + args[:ds_account_id], + options + ).clickwraps + end + + clickwraps end end diff --git a/app/services/e_sign/eg024_permission_create_service.rb b/app/services/e_sign/eg024_permission_create_service.rb index a12b8ef..9fdf010 100644 --- a/app/services/e_sign/eg024_permission_create_service.rb +++ b/app/services/e_sign/eg024_permission_create_service.rb @@ -21,8 +21,7 @@ def worker private def make_permission_profile_settings - permission_profile = DocuSign_eSign::PermissionProfile.new - pr_settings = { + { useNewDocuSignExperienceInterface: 0, allowBulkSending: 'true', allowEnvelopeSending: 'true', @@ -49,7 +48,5 @@ def make_permission_profile_settings powerFormRole: 'admin', vaultingMode: 'none' } - permission_profile.settings = pr_settings - permission_profile end end diff --git a/test/eg001_create_clickwrap_test.rb b/test/eg001_create_clickwrap_test.rb new file mode 100644 index 0000000..f502b36 --- /dev/null +++ b/test/eg001_create_clickwrap_test.rb @@ -0,0 +1,31 @@ +require 'date' +require 'rubygems' +require 'test/unit' +require_relative './test_helper' +require_relative '../app/services/api_creator' +require_relative '../app/services/clickwrap/eg001_create_clickwrap_service' + +class Eg001CreateClickwrapTest < TestHelper + setup do + setup_test_data [api_type[:click]] + + args = { + account_id: @account_id, + base_path: @base_path, + access_token: @access_token, + doc_pdf: @data[:term_of_service], + clickwrap_name: "#{@data[:clickwrap_name]}_#{Time.now.strftime("%s%L")}" + } + + @ceg001 = Clickwrap::Eg001CreateClickwrapService.new(args) + end + + test 'should correctly create clickwrap if correct data is provided' do + results = @ceg001.worker + + TestData.set_clickwrap_id(results.clickwrap_id) + + assert_not_nil results + assert_not_empty results.clickwrap_id + end +end diff --git a/test/eg001_embedded_signing_test.rb b/test/eg001_embedded_signing_test.rb index e7f806b..95a4039 100644 --- a/test/eg001_embedded_signing_test.rb +++ b/test/eg001_embedded_signing_test.rb @@ -7,7 +7,7 @@ class Eg001EmbeddedSigningTest < TestHelper setup do - setup_test_data + setup_test_data [api_type[:e_sign]] args = { account_id: @account_id, diff --git a/test/eg002_activate_clickwrap_test.rb b/test/eg002_activate_clickwrap_test.rb new file mode 100644 index 0000000..0ae85ab --- /dev/null +++ b/test/eg002_activate_clickwrap_test.rb @@ -0,0 +1,39 @@ +require 'date' +require 'rubygems' +require 'test/unit' +require_relative './test_helper' +require_relative '../app/services/api_creator' +require_relative '../app/services/clickwrap/eg002_activate_clickwrap_service' + +class Eg002ActivateClickwrapTest < TestHelper + setup do + setup_test_data [api_type[:click]] + + args = { + account_id: @account_id, + base_path: @base_path, + access_token: @access_token, + + ds_account_id: @account_id, + ds_base_path: @base_path, + ds_access_token: @access_token, + + clickwrap_id: TestData.get_clickwrap_id + } + + @ceg002 = Clickwrap::Eg002ActivateClickwrapService.new(args) + end + + test 'should correctly activate clickwrap if correct data is provided' do + results = @ceg002.worker + + assert_not_nil results + end + + test 'should get the list of inactive clickwraps if correct data is provided' do + statuses = %w[inactive draft] + results = @ceg002.get_inactive_clickwraps statuses + + assert_not_nil results + end +end diff --git a/test/eg002_sign_via_email_test.rb b/test/eg002_sign_via_email_test.rb index c740631..b07fbd3 100644 --- a/test/eg002_sign_via_email_test.rb +++ b/test/eg002_sign_via_email_test.rb @@ -6,7 +6,7 @@ class Eg002SignViaEmailTest < TestHelper setup do - setup_test_data + setup_test_data [api_type[:e_sign]] envelope_args = { signer_email: @config['signer_email'], diff --git a/test/eg008_create_template_test.rb b/test/eg008_create_template_test.rb index c571062..0d7e498 100644 --- a/test/eg008_create_template_test.rb +++ b/test/eg008_create_template_test.rb @@ -6,7 +6,7 @@ class Eg008CreateTemplateTest < TestHelper setup do - setup_test_data + setup_test_data [api_type[:e_sign]] args = { account_id: @account_id, diff --git a/test/eg009_use_template_test.rb b/test/eg009_use_template_test.rb index 945c32a..f99afad 100644 --- a/test/eg009_use_template_test.rb +++ b/test/eg009_use_template_test.rb @@ -6,7 +6,7 @@ class Eg009UseTemplateTest < TestHelper setup do - setup_test_data + setup_test_data [api_type[:e_sign]] envelope_args = { signer_email: @config['signer_email'], diff --git a/test/eg013_add_doc_to_template_test.rb b/test/eg013_add_doc_to_template_test.rb index c7e5264..7b9b71d 100644 --- a/test/eg013_add_doc_to_template_test.rb +++ b/test/eg013_add_doc_to_template_test.rb @@ -6,7 +6,7 @@ class Eg013AddDocToTemplateTest < TestHelper setup do - setup_test_data + setup_test_data [api_type[:e_sign]] envelope_args = { signer_email: @config['signer_email'], diff --git a/test/eg017_set_template_tab_values_test.rb b/test/eg017_set_template_tab_values_test.rb index f914968..e818293 100644 --- a/test/eg017_set_template_tab_values_test.rb +++ b/test/eg017_set_template_tab_values_test.rb @@ -6,7 +6,7 @@ class Eg017SetTemplateTabValuesTest < TestHelper setup do - setup_test_data + setup_test_data [api_type[:e_sign]] envelope_args = { signer_email: @config['signer_email'], diff --git a/test/eg024_permission_create_test.rb b/test/eg024_permission_create_test.rb new file mode 100644 index 0000000..7e4d3ad --- /dev/null +++ b/test/eg024_permission_create_test.rb @@ -0,0 +1,62 @@ +require 'date' +require 'rubygems' +require 'test/unit' +require_relative './test_helper' +require_relative '../app/services/api_creator' +require_relative '../app/services/e_sign/eg024_permission_create_service' + +class Eg024PermissionCreateTest < TestHelper + setup do + setup_test_data [api_type[:e_sign]] + + args = { + account_id: @account_id, + base_path: @base_path, + access_token: @access_token, + permission_profile_name: "#{@data[:permission_profile_name]}_#{Time.now.strftime("%s%L")}" + } + + @eg024 = ESign::Eg024PermissionCreateService.new(args) + end + + test 'should correctly create permission profile if correct data is provided' do + results = @eg024.worker + + assert_not_nil results + end + + test 'should create correct permission profile settings if correct data is provided' do + expected_permission_profile_settings = { + useNewDocuSignExperienceInterface: 0, + allowBulkSending: 'true', + allowEnvelopeSending: 'true', + allowSignerAttachments: 'true', + allowTaggingInSendAndCorrect: 'true', + allowWetSigningOverride: 'true', + allowedAddressBookAccess: 'personalAndShared', + allowedTemplateAccess: 'share', + enableRecipientViewingNotifications: 'true', + enableSequentialSigningInterface: 'true', + receiveCompletedSelfSignedDocumentsAsEmailLinks: 'false', + signingUiVersion: 'v2', + useNewSendingInterface: 'true', + allowApiAccess: 'true', + allowApiAccessToAccount: 'true', + allowApiSendingOnBehalfOfOthers: 'true', + allowApiSequentialSigning: 'true', + enableApiRequestLogging: 'true', + allowDocuSignDesktopClient: 'false', + allowSendersToSetRecipientEmailLanguage: 'true', + allowVaulting: 'false', + allowedToBeEnvelopeTransferRecipient: 'true', + enableTransactionPointIntegration: 'false', + powerFormRole: 'admin', + vaultingMode: 'none' + } + + permission_profile_settings = @eg024.send(:make_permission_profile_settings) + + assert_not_nil permission_profile_settings + assert_equal expected_permission_profile_settings, permission_profile_settings + end +end diff --git a/test/eg028_brands_creating_test.rb b/test/eg028_brands_creating_test.rb new file mode 100644 index 0000000..5d67b81 --- /dev/null +++ b/test/eg028_brands_creating_test.rb @@ -0,0 +1,33 @@ +require 'date' +require 'rubygems' +require 'test/unit' +require_relative './test_helper' +require_relative '../app/services/api_creator' +require_relative '../app/services/e_sign/eg028_brands_creating_service' + +class Eg028BrandsCreatingTest < TestHelper + setup do + setup_test_data [api_type[:e_sign]] + + args = { + account_id: @account_id, + base_path: @base_path, + access_token: @access_token, + brandName: "#{@data[:brand_name]}_#{Time.now.strftime("%s%L")}", + defaultBrandLanguage: @data[:default_brand_language] + } + + @eg028 = ESign::Eg028BrandsCreatingService.new(args) + end + + test 'should correctly create brand if correct data is provided' do + results = @eg028.worker + + TestData.set_brand_id results.brands[0].brand_id + + assert_not_nil results + assert_not_nil results.brands + assert_not_nil results.brands[0] + assert_not_empty results.brands[0].brand_id + end +end diff --git a/test/eg029_brands_apply_to_envelope_test.rb b/test/eg029_brands_apply_to_envelope_test.rb new file mode 100644 index 0000000..a95deed --- /dev/null +++ b/test/eg029_brands_apply_to_envelope_test.rb @@ -0,0 +1,86 @@ +require 'date' +require 'rubygems' +require 'test/unit' +require_relative './test_helper' +require_relative '../app/services/api_creator' +require_relative '../app/services/e_sign/eg029_brands_apply_to_envelope_service' + +class Eg029BrandsApplyToEnvelopeTest < TestHelper + setup do + setup_test_data [api_type[:e_sign]] + + envelope_args = { + signer_email: @config['signer_email'], + signer_name: @config['signer_name'], + brand_id: TestData.get_brand_id, + status: 'sent' + } + args = { + account_id: @account_id, + base_path: @base_path, + access_token: @access_token, + envelope_args: envelope_args + } + + @eg029 = ESign::Eg029BrandsApplyToEnvelopeService.new(args) + end + + test 'should correctly apply brand to envelope if correct data is provided' do + results = @eg029.worker + + assert_not_nil results + end + + test 'should correctly create envelope definition if correct data is provided' do + args = { + signer_email: @config['signer_email'], + signer_name: @config['signer_name'], + brand_id: TestData.get_brand_id, + status: 'sent' + } + + expected_document = create_ds_document(@data[:doc_pdf], 'NDA', 'pdf', '1') + + expected_signer = DocuSign_eSign::Signer.new + expected_signer.name = @config['signer_name'] + expected_signer.email = @config['signer_email'] + expected_signer.role_name = 'signer' + expected_signer.note = '' + expected_signer.routing_order = '1' + expected_signer.status = args[:status] + expected_signer.delivery_method = 'email' + expected_signer.recipient_id = '1' + + expected_sign_here = DocuSign_eSign::SignHere.new + expected_sign_here.document_id = '1' + expected_sign_here.name = 'SignHereTab' + expected_sign_here.page_number = '1' + expected_sign_here.recipient_id = '1' + expected_sign_here.tab_label = 'SignHereTab' + expected_sign_here.x_position = '75' + expected_sign_here.y_position = '572' + + expected_signer_tabs = DocuSign_eSign::Tabs.new({ + signHereTabs: [expected_sign_here] + }) + expected_signer.tabs = expected_signer_tabs + + expected_recipients = DocuSign_eSign::Recipients.new( + signers: [expected_signer] + ) + + expected_envelope = DocuSign_eSign::EnvelopeDefinition.new + expected_envelope.email_blurb = 'Sample text for email body' + expected_envelope.email_subject = 'Please Sign' + expected_envelope.envelope_id_stamping = true + expected_envelope.brand_id = args[:brands] + expected_envelope.documents = [expected_document] + expected_envelope.recipients = expected_recipients + expected_envelope.status = 'sent' + + envelope = @eg029.send(:make_envelope, args) + + assert_not_nil envelope + assert_equal expected_envelope, envelope + end +end diff --git a/test/eg031_bulk_sending_envelopes_test.rb b/test/eg031_bulk_sending_envelopes_test.rb new file mode 100644 index 0000000..f32042a --- /dev/null +++ b/test/eg031_bulk_sending_envelopes_test.rb @@ -0,0 +1,173 @@ +require 'date' +require 'rubygems' +require 'test/unit' +require_relative './test_helper' +require_relative '../app/services/api_creator' +require_relative '../app/services/e_sign/eg031_bulk_sending_envelopes_service' + +class Eg031BulkSendingEnvelopesTest < TestHelper + setup do + setup_test_data [api_type[:e_sign]] + + signers = { + signer_email: @config['signer_email'], + signer_name: @config['signer_name'], + cc_email: @data[:cc_email], + cc_name: @data[:cc_name], + status: 'created', + + signer_email1: @data[:signer1_email], + signer_name1: @data[:signer1_name], + cc_email1: @data[:cc1_email], + cc_name1: @data[:cc1_name], + } + args = { + account_id: @account_id, + base_path: @base_path, + access_token: @access_token, + } + + @eg031 = ESign::Eg031BulkSendingEnvelopesService.new(args, signers) + end + + test 'should correctly bulk send the envelope if correct data is provided' do + results = @eg031.worker + + assert_not_nil results + end + + test 'should create correct bulk sending list if correct data is provided' do + args = { + signer_email: @config['signer_email'], + signer_name: @config['signer_name'], + cc_email: @data[:cc_email], + cc_name: @data[:cc_name], + status: 'created', + + signer_email1: @data[:signer1_email], + signer_name1: @data[:signer1_name], + cc_email1: @data[:cc1_email], + cc_name1: @data[:cc1_name], + } + + expected_bulk_sending_list = DocuSign_eSign::BulkSendingList.new( + name: 'sample.csv', + bulkCopies: [ + DocuSign_eSign::BulkSendingCopy.new( + recipients: [ + DocuSign_eSign::BulkSendingCopyRecipient.new( + roleName: 'signer', + tabs: [], + name: @config['signer_name'], + email: @config['signer_email'] + ), + DocuSign_eSign::BulkSendingCopyRecipient.new( + roleName: 'cc', + tabs: [], + name: @data[:cc_name], + email: @data[:cc_email] + ) + ], + custom_fields: [] + ), + DocuSign_eSign::BulkSendingCopy.new( + recipients: [ + DocuSign_eSign::BulkSendingCopyRecipient.new( + roleName: 'signer', + tabs: [], + name: @data[:signer1_name], + email: @data[:signer1_email] + ), + DocuSign_eSign::BulkSendingCopyRecipient.new( + roleName: 'cc', + tabs: [], + name: @data[:cc1_name], + email: @data[:cc1_email] + ) + ], + custom_fields: [] + ) + ] + ) + + results = @eg031.send(:create_bulk_sending_list, args) + + assert_not_nil results + assert_equal expected_bulk_sending_list, results + end + + test 'should create correct custom fields if correct data is provided' do + bulk_list_id = 'bulk_list_id' + + expected_custom_fields = DocuSign_eSign::CustomFields.new( + listCustomFields: [], + textCustomFields: [ + DocuSign_eSign::TextCustomField.new( + name: 'mailingListId', + required: 'false', + show: 'false', + value: bulk_list_id + ) + ] + ) + + results = @eg031.send(:custom_fields, bulk_list_id) + + assert_not_nil results + assert_equal expected_custom_fields, results + end + + test 'should correctly create envelope definition if correct data is provided' do + expected_document = create_ds_document(@data[:doc_pdf], 'Lorem Ipsum', 'pdf', '2') + + expected_sign_here = DocuSign_eSign::SignHere.new + expected_sign_here.anchor_string = '/sn1/' + expected_sign_here.anchor_units = 'pixels' + expected_sign_here.anchor_x_offset = '20' + expected_sign_here.anchor_y_offset = '10' + + expected_signer_tabs = DocuSign_eSign::Tabs.new({ + signHereTabs: [expected_sign_here] + }) + + expected_signer = DocuSign_eSign::Signer.new + expected_signer.name = 'Multi Bulk Recipient::signer' + expected_signer.email = 'multiBulkRecipients-signer@docusign.com' + expected_signer.role_name = 'signer' + expected_signer.note = '' + expected_signer.routing_order = 1 + expected_signer.status = 'created' + expected_signer.delivery_method = 'email' + expected_signer.recipient_id = '1' + expected_signer.recipient_type = 'signer' + expected_signer.tabs = expected_signer_tabs + + expected_cc = DocuSign_eSign::CarbonCopy.new + expected_cc.name = 'Multi Bulk Recipient::cc' + expected_cc.email = 'multiBulkRecipients-cc@docusign.com' + expected_cc.role_name = 'cc' + expected_cc.note = '' + expected_cc.routing_order = 2 + expected_cc.status = 'created' + expected_cc.delivery_method = 'email' + expected_cc.recipient_id = '2' + expected_cc.recipient_type = 'cc' + + expected_recipients = DocuSign_eSign::Recipients.new( + signers: [expected_signer], + carbonCopies: [expected_cc] + ) + + expected_envelope = DocuSign_eSign::EnvelopeDefinition.new + expected_envelope.email_subject = 'Please sign this document set' + expected_envelope.envelope_id_stamping = 'true' + expected_envelope.documents = [expected_document] + expected_envelope.recipients = expected_recipients + expected_envelope.status = 'created' + + envelope = @eg031.send(:make_envelope) + + assert_not_nil envelope + assert_equal expected_envelope, envelope + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index f1925f8..7cee366 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -3,14 +3,27 @@ require 'yaml' require 'test/unit' require 'docusign_esign' +require 'docusign_click' + +$_scopes = %w[signature impersonation] +$_click_scopes = %w[click.manage click.send] +$_rooms_scopes = %w[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] +$_admin_scopes = %w[organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read] -$_scopes = %w[ - signature impersonation -] class TestHelper < Test::Unit::TestCase - def setup_test_data - auth_results = authenticate + def api_type + { + e_sign: 'ESign', + click: 'Click', + rooms: 'Rooms', + monitor: 'Monitor', + admin: 'Admin' + } + end + + def setup_test_data(api_types) + auth_results = authenticate api_types @config = get_config_data @data = get_common_data @@ -20,7 +33,7 @@ def setup_test_data @base_path = auth_results[:base_path] end - def authenticate + def authenticate(api_types) ds_config = get_config_data data = get_common_data @@ -34,8 +47,20 @@ def authenticate rsa_pk = ENV['PRIVATE_KEY'] end + scopes = $_scopes + + if api_types.include?(api_type[:click]) + scopes = scopes.concat($_click_scopes) + end + if api_types.include?(api_type[:rooms]) + scopes = scopes.concat($_rooms_scopes) + end + if api_types.include?(api_type[:admin]) + scopes = scopes.concat($_admin_scopes) + end + begin - token = api_client.request_jwt_user_token(ds_config['jwt_integration_key'], ds_config['impersonated_user_guid'], rsa_pk, 3600, $_scopes) + token = api_client.request_jwt_user_token(ds_config['jwt_integration_key'], ds_config['impersonated_user_guid'], rsa_pk, 3600, scopes) user_info_response = api_client.get_user_info(token.access_token) account = user_info_response.accounts.find(&:is_default) @@ -53,7 +78,7 @@ def authenticate rescue DocuSign_eSign::ApiError => e body = JSON.parse(e.response_body) if body['error'] == 'consent_required' - authenticate if get_consent + authenticate api_types if get_consent else puts 'API Error' puts body['error'] @@ -88,16 +113,24 @@ def get_common_data { cc_name: 'Test Name', cc_email: 'test@mail.com', + signer1_email: 'test.signer2@mail.com', + signer1_name: 'Test signer2', + cc1_email: 'test.cc2@mail.com', + cc1_name: 'Test cc2', authorization_server: 'account-d.docusign.com', signer_client_id: 1000, ds_ping_url: 'http://localhost:3000', ds_return_url: 'http://localhost:3000/ds_common-return', doc_docx: './data/World_Wide_Corp_Battle_Plan_Trafalgar.docx', doc_pdf: './data/World_Wide_Corp_lorem.pdf', + term_of_service: './data/Term_Of_Service.pdf', doc_for_template: './data/World_Wide_Corp_fields.pdf', item: 'Item', quantity: 5, - template_name: 'Example Signer and CC template v2' + template_name: 'Example Signer and CC template v2', + permission_profile_name: 'Test_Permission_Profile', + brand_name: 'Test_Brand_Name', + default_brand_language: 'en' } end @@ -140,15 +173,36 @@ def get_consent class TestData @template_id + @brand_id + @clickwrap_id def self.get_template_id @template_id end + def self.get_brand_id + @brand_id + end + + def self.get_clickwrap_id + @clickwrap_id + end + def self.set_template_id(id) @template_id = id end + + def self.set_brand_id(id) + @brand_id = id + end + + def self.set_clickwrap_id(id) + @clickwrap_id = id + end end class ESign end + +class Clickwrap +end From 5ef813753435742690cf62873e5e9c00ce1f34fd Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Fri, 21 Apr 2023 19:47:49 +0300 Subject: [PATCH 189/363] Add Document Generation code example (#121) * add DocGen code example --- Gemfile | 30 +- Gemfile.lock | 271 +++++++-------- .../eeg042_document_generation_controller.rb | 33 ++ app/services/admin_api/get_data_service.rb | 2 +- .../eg042_document_generation_service.rb | 163 +++++++++ .../eeg042_document_generation/get.html.erb | 52 +++ config/appsettings.example.yml | 1 + config/routes.rb | 3 + data/Offer_Letter_Demo.docx | Bin 0 -> 37132 bytes jwt_console_project/jwt_console.rb | 2 +- quick_acg/Gemfile | 35 +- quick_acg/Gemfile.lock | 323 ++++++++++-------- quick_acg/config/application.rb | 2 +- 13 files changed, 599 insertions(+), 318 deletions(-) create mode 100644 app/controllers/e_sign/eeg042_document_generation_controller.rb create mode 100644 app/services/e_sign/eg042_document_generation_service.rb create mode 100644 app/views/e_sign/eeg042_document_generation/get.html.erb create mode 100644 data/Offer_Letter_Demo.docx diff --git a/Gemfile b/Gemfile index d23ea33..3099bf9 100644 --- a/Gemfile +++ b/Gemfile @@ -6,11 +6,11 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '~>3.1.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 7.0.3' +gem 'rails', '~> 7.0.4.3' # Use sqlite3 as the database for Active Record -gem 'sqlite3', '~> 1.4.4' +gem 'sqlite3', '~> 1.6.1' # Use Puma as the app server -gem 'puma', '~> 5.6.4' +gem 'puma', '~> 6.1.1' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets @@ -44,39 +44,39 @@ end group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console - gem 'byebug', '~> 11.1.1', platforms: %i[mri mingw x64_mingw] + gem 'byebug', '~> 11.1.3', platforms: %i[mri mingw x64_mingw] end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. - gem 'listen', '~> 3.7.1' + gem 'listen', '~> 3.8.0' gem 'web-console', '~> 4.2.0' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'pry-nav', '~> 1.0.0' gem 'pry-rails', '~> 0.3.9' - gem 'rubocop', '~> 1.36', require: false - gem 'spring', '~> 2.1.0' - gem 'spring-watcher-listen', '~> 2.0.1' + gem 'rubocop', '~> 1.48.1', require: false + gem 'spring', '~> 4.1.1' + gem 'spring-watcher-listen', '~> 2.1.0' end group :test do # Adds support for Capybara system testing and selenium driver - gem 'capybara', '~> 3.31.0' - gem 'selenium-webdriver', '~> 3.142.7' + gem 'capybara', '~> 3.38.0' + gem 'selenium-webdriver', '~> 4.8.1' # Easy installation and use of chromedriver to run system tests with Chrome gem 'chromedriver-helper', '~> 2.1.1' gem 'test-unit' end gem 'docusign_admin', '~> 1.1.0' -gem 'docusign_click', '~> 1.2.2' -gem 'docusign_esign', '~> 3.21.0' +gem 'docusign_click', '~> 1.3.0' +gem 'docusign_esign', '~> 3.22.0' gem 'docusign_monitor', '~> 1.1.0' gem 'docusign_rooms', '~> 1.3.0' -gem 'omniauth-oauth2', '~> 1.7.1' +gem 'omniauth-oauth2', '~> 1.8.0' gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'matrix', '~> 0.4.2' -gem 'tzinfo-data', '~> 1.2022.1', '>= 1.2022.1' -gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] +gem 'tzinfo-data', '~> 1.2022.7', '>= 1.2022.7' +gem 'wdm', '>= 0.1.1', platforms: %i[mingw mswin x64_mingw] diff --git a/Gemfile.lock b/Gemfile.lock index 80c7e42..a0e96a0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,67 +1,67 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.0.4) - actionpack (= 7.0.4) - activesupport (= 7.0.4) + actioncable (7.0.4.3) + actionpack (= 7.0.4.3) + activesupport (= 7.0.4.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.4) - actionpack (= 7.0.4) - activejob (= 7.0.4) - activerecord (= 7.0.4) - activestorage (= 7.0.4) - activesupport (= 7.0.4) + actionmailbox (7.0.4.3) + actionpack (= 7.0.4.3) + activejob (= 7.0.4.3) + activerecord (= 7.0.4.3) + activestorage (= 7.0.4.3) + activesupport (= 7.0.4.3) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.0.4) - actionpack (= 7.0.4) - actionview (= 7.0.4) - activejob (= 7.0.4) - activesupport (= 7.0.4) + actionmailer (7.0.4.3) + actionpack (= 7.0.4.3) + actionview (= 7.0.4.3) + activejob (= 7.0.4.3) + activesupport (= 7.0.4.3) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.0) - actionpack (7.0.4) - actionview (= 7.0.4) - activesupport (= 7.0.4) + actionpack (7.0.4.3) + actionview (= 7.0.4.3) + activesupport (= 7.0.4.3) rack (~> 2.0, >= 2.2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.4) - actionpack (= 7.0.4) - activerecord (= 7.0.4) - activestorage (= 7.0.4) - activesupport (= 7.0.4) + actiontext (7.0.4.3) + actionpack (= 7.0.4.3) + activerecord (= 7.0.4.3) + activestorage (= 7.0.4.3) + activesupport (= 7.0.4.3) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.4) - activesupport (= 7.0.4) + actionview (7.0.4.3) + activesupport (= 7.0.4.3) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (7.0.4) - activesupport (= 7.0.4) + activejob (7.0.4.3) + activesupport (= 7.0.4.3) globalid (>= 0.3.6) - activemodel (7.0.4) - activesupport (= 7.0.4) - activerecord (7.0.4) - activemodel (= 7.0.4) - activesupport (= 7.0.4) - activestorage (7.0.4) - actionpack (= 7.0.4) - activejob (= 7.0.4) - activerecord (= 7.0.4) - activesupport (= 7.0.4) + activemodel (7.0.4.3) + activesupport (= 7.0.4.3) + activerecord (7.0.4.3) + activemodel (= 7.0.4.3) + activesupport (= 7.0.4.3) + activestorage (7.0.4.3) + actionpack (= 7.0.4.3) + activejob (= 7.0.4.3) + activerecord (= 7.0.4.3) + activesupport (= 7.0.4.3) marcel (~> 1.0) mini_mime (>= 1.1.0) - activesupport (7.0.4) + activesupport (7.0.4.3) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -76,15 +76,15 @@ GEM msgpack (~> 1.0) builder (3.2.4) byebug (11.1.3) - capybara (3.31.0) + capybara (3.38.0) addressable + matrix mini_mime (>= 0.1.3) nokogiri (~> 1.8) rack (>= 1.6.0) rack-test (>= 0.6.3) - regexp_parser (~> 1.5) + regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - childprocess (3.0.0) chromedriver-helper (2.1.1) archive-zip (~> 0.10) nokogiri (~> 1.8) @@ -96,19 +96,20 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.1.10) + concurrent-ruby (1.2.2) crass (1.0.6) + date (3.3.3) docusign_admin (1.1.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_click (1.2.2) + docusign_click (1.3.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.21.0) + docusign_esign (3.22.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -123,17 +124,17 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - erubi (1.11.0) - ethon (0.15.0) + erubi (1.12.0) + ethon (0.16.0) ffi (>= 1.15.0) execjs (2.8.1) - faraday (2.6.0) + faraday (2.7.4) faraday-net_http (>= 2.0, < 3.1) ruby2_keywords (>= 0.0.4) - faraday-net_http (3.0.0) + faraday-net_http (3.0.2) ffi (1.15.5) ffi (1.15.5-x64-mingw-ucrt) - globalid (1.0.1) + globalid (1.1.0) activesupport (>= 5.0) hashie (5.0.0) i18n (1.12.0) @@ -143,36 +144,38 @@ GEM actionview (>= 5.0.0) activesupport (>= 5.0.0) json (2.6.3) - jwt (2.5.0) - listen (3.7.1) + jwt (2.7.0) + listen (3.8.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) loofah (2.19.1) crass (~> 1.0.2) nokogiri (>= 1.5.9) - mail (2.7.1) + mail (2.8.1) mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp marcel (1.0.2) matrix (0.4.2) - method_source (0.9.2) + method_source (1.0.0) mini_mime (1.1.2) - minitest (5.17.0) - msgpack (1.6.0) + minitest (5.18.0) + msgpack (1.6.1) multi_xml (0.6.0) - net-imap (0.3.1) + net-imap (0.3.4) + date net-protocol net-pop (0.1.2) net-protocol - net-protocol (0.1.3) + net-protocol (0.2.1) timeout - net-smtp (0.3.2) + net-smtp (0.3.3) net-protocol nio4r (2.5.8) - nokogiri (1.13.10-x64-mingw-ucrt) + nokogiri (1.14.2-x64-mingw-ucrt) racc (~> 1.4) - nokogiri (1.13.10-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.13.10-x86_64-linux) + nokogiri (1.14.2-x86_64-linux) racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) @@ -181,58 +184,58 @@ GEM rack (>= 1.2, < 4) snaky_hash (~> 2.0) version_gem (~> 1.1) - omniauth (2.1.0) + omniauth (2.1.1) hashie (>= 3.4.6) rack (>= 2.2.3) rack-protection - omniauth-oauth2 (1.7.3) + omniauth-oauth2 (1.8.0) oauth2 (>= 1.4, < 3) - omniauth (>= 1.9, < 3) + omniauth (~> 2.0) omniauth-rails_csrf_protection (1.0.1) actionpack (>= 4.2) omniauth (~> 2.0) parallel (1.22.1) - parser (3.1.2.1) + parser (3.2.1.1) ast (~> 2.4.1) - power_assert (2.0.1) - pry (0.12.2) - coderay (~> 1.1.0) - method_source (~> 0.9.0) + power_assert (2.0.3) + pry (0.14.2) + coderay (~> 1.1) + method_source (~> 1.0) pry-nav (1.0.0) pry (>= 0.9.10, < 0.15) pry-rails (0.3.9) pry (>= 0.10.4) - public_suffix (5.0.0) - puma (5.6.5) + public_suffix (5.0.1) + puma (6.1.1) nio4r (~> 2.0) - racc (1.6.1) - rack (2.2.6.2) - rack-protection (3.0.2) + racc (1.6.2) + rack (2.2.6.4) + rack-protection (3.0.5) rack - rack-test (2.0.2) + rack-test (2.1.0) rack (>= 1.3) - rails (7.0.4) - actioncable (= 7.0.4) - actionmailbox (= 7.0.4) - actionmailer (= 7.0.4) - actionpack (= 7.0.4) - actiontext (= 7.0.4) - actionview (= 7.0.4) - activejob (= 7.0.4) - activemodel (= 7.0.4) - activerecord (= 7.0.4) - activestorage (= 7.0.4) - activesupport (= 7.0.4) + rails (7.0.4.3) + actioncable (= 7.0.4.3) + actionmailbox (= 7.0.4.3) + actionmailer (= 7.0.4.3) + actionpack (= 7.0.4.3) + actiontext (= 7.0.4.3) + actionview (= 7.0.4.3) + activejob (= 7.0.4.3) + activemodel (= 7.0.4.3) + activerecord (= 7.0.4.3) + activestorage (= 7.0.4.3) + activesupport (= 7.0.4.3) bundler (>= 1.15.0) - railties (= 7.0.4) + railties (= 7.0.4.3) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.4.4) + rails-html-sanitizer (1.5.0) loofah (~> 2.19, >= 2.19.1) - railties (7.0.4) - actionpack (= 7.0.4) - activesupport (= 7.0.4) + railties (7.0.4.3) + actionpack (= 7.0.4.3) + activesupport (= 7.0.4.3) method_source rake (>= 12.2) thor (~> 1.0) @@ -242,21 +245,21 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - regexp_parser (1.8.2) + regexp_parser (2.7.0) rexml (3.2.5) - rubocop (1.36.0) + rubocop (1.48.1) json (~> 2.3) parallel (~> 1.10) - parser (>= 3.1.2.1) + parser (>= 3.2.0.0) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.20.1, < 2.0) + rubocop-ast (>= 1.26.0, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.21.0) - parser (>= 3.1.1.0) - ruby-progressbar (1.11.0) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.27.0) + parser (>= 3.2.1.0) + ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) rubyzip (2.3.2) sass-rails (6.0.0) @@ -269,90 +272,92 @@ GEM sprockets (> 3.0) sprockets-rails tilt - selenium-webdriver (3.142.7) - childprocess (>= 0.5, < 4.0) - rubyzip (>= 1.2.2) + selenium-webdriver (4.8.1) + rexml (~> 3.2, >= 3.2.5) + rubyzip (>= 1.2.2, < 3.0) + websocket (~> 1.0) snaky_hash (2.0.1) hashie version_gem (~> 1.1, >= 1.1.1) - spring (2.1.1) - spring-watcher-listen (2.0.1) + spring (4.1.1) + spring-watcher-listen (2.1.0) listen (>= 2.7, < 4.0) - spring (>= 1.2, < 3.0) - sprockets (4.1.1) + spring (>= 4) + sprockets (4.2.0) concurrent-ruby (~> 1.0) - rack (> 1, < 3) + rack (>= 2.2.4, < 4) sprockets-rails (3.4.2) actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) - sqlite3 (1.4.4) - test-unit (3.5.3) + sqlite3 (1.6.1-x64-mingw-ucrt) + sqlite3 (1.6.1-x86_64-linux) + test-unit (3.5.7) power_assert thor (1.2.1) - tilt (2.0.11) - timeout (0.3.0) + tilt (2.1.0) + timeout (0.3.2) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) typhoeus (1.4.0) ethon (>= 0.9.0) - tzinfo (2.0.5) + tzinfo (2.0.6) concurrent-ruby (~> 1.0) - tzinfo-data (1.2022.4) + tzinfo-data (1.2022.7) tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) - unicode-display_width (2.3.0) - version_gem (1.1.1) + unicode-display_width (2.4.2) + version_gem (1.1.2) web-console (4.2.0) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) + websocket (1.2.9) websocket-driver (0.7.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.1) + zeitwerk (2.6.7) PLATFORMS x64-mingw-ucrt - x86_64-darwin-21 x86_64-linux DEPENDENCIES bootsnap (~> 1.7.3) - byebug (~> 11.1.1) - capybara (~> 3.31.0) + byebug (~> 11.1.3) + capybara (~> 3.38.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) docusign_admin (~> 1.1.0) - docusign_click (~> 1.2.2) - docusign_esign (~> 3.21.0) + docusign_click (~> 1.3.0) + docusign_esign (~> 3.22.0) docusign_monitor (~> 1.1.0) docusign_rooms (~> 1.3.0) jbuilder (~> 2.11.5) - listen (~> 3.7.1) + listen (~> 3.8.0) matrix (~> 0.4.2) - omniauth-oauth2 (~> 1.7.1) + omniauth-oauth2 (~> 1.8.0) omniauth-rails_csrf_protection pry-nav (~> 1.0.0) pry-rails (~> 0.3.9) - puma (~> 5.6.4) - rails (~> 7.0.3) - rubocop (~> 1.36) + puma (~> 6.1.1) + rails (~> 7.0.4.3) + rubocop (~> 1.48.1) sass-rails (~> 6.0.0) - selenium-webdriver (~> 3.142.7) - spring (~> 2.1.0) - spring-watcher-listen (~> 2.0.1) - sqlite3 (~> 1.4.4) + selenium-webdriver (~> 4.8.1) + spring (~> 4.1.1) + spring-watcher-listen (~> 2.1.0) + sqlite3 (~> 1.6.1) test-unit turbolinks (~> 5.2.1) - tzinfo-data (~> 1.2022.1, >= 1.2022.1) + tzinfo-data (~> 1.2022.7, >= 1.2022.7) uglifier (~> 4.2.0) - wdm (>= 0.1.0) + wdm (>= 0.1.1) web-console (~> 4.2.0) RUBY VERSION diff --git a/app/controllers/e_sign/eeg042_document_generation_controller.rb b/app/controllers/e_sign/eeg042_document_generation_controller.rb new file mode 100644 index 0000000..5e1d502 --- /dev/null +++ b/app/controllers/e_sign/eeg042_document_generation_controller.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require_relative '../../services/utils' + +class ESign::Eeg042DocumentGenerationController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 42, 'eSignature') } + + def create + envelope_args = { + candidate_email: param_gsub(params['candidate_email']), + candidate_name: param_gsub(params['candidate_name']), + manager_name: param_gsub(params['manager_name']), + job_title: param_gsub(params['job_title']), + salary: param_gsub(params['salary']), + start_date: param_gsub(params['start_date']), + doc_file: File.join('data', Rails.application.config.doc_offer_letter) + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + results = ESign::Eg042DocumentGenerationService.new(args).worker + session[:envelope_id] = results['envelope_id'] + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results['envelope_id']) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end +end diff --git a/app/services/admin_api/get_data_service.rb b/app/services/admin_api/get_data_service.rb index c6e7726..fd0e441 100644 --- a/app/services/admin_api/get_data_service.rb +++ b/app/services/admin_api/get_data_service.rb @@ -51,7 +51,7 @@ def check_user_exists_by_email(email) options.email = email response = users_api.get_users(args[:organization_id], options) - return false if response.users.length.zero? || response.users[0].user_status == 'closed' + return false if response.users.empty? || response.users[0].user_status == 'closed' true end diff --git a/app/services/e_sign/eg042_document_generation_service.rb b/app/services/e_sign/eg042_document_generation_service.rb new file mode 100644 index 0000000..81faf17 --- /dev/null +++ b/app/services/e_sign/eg042_document_generation_service.rb @@ -0,0 +1,163 @@ +# frozen_string_literal: true + +class ESign::Eg042DocumentGenerationService + attr_reader :args + + include ApiCreator + + def initialize(args) + @args = args + end + + def worker + envelope_api = create_envelope_api(args) + template_api = create_template_api(args) + + account_id = args[:account_id] + envelope_args = args[:envelope_args] + + # Step 1. Create the template + template = template_api.create_template(account_id, template_data) + template_id = template.template_id + + # Step 2. Update template document + document_id = '1' + template_api.update_document(account_id, document_id, template_id, template_document(envelope_args)) + + # Step 3. Update recipient tabs + recipient_id = '1' + template_api.create_tabs(account_id, recipient_id, template_id, recipient_tabs) + + # Step 4. Create draft envelope + envelope_definition = make_envelope(template_id, envelope_args) + envelope = envelope_api.create_envelope(account_id, envelope_definition) + envelope_id = envelope.envelope_id + + # Step 5: Get the document id + doc_gen_form_fields_response = envelope_api.get_envelope_doc_gen_form_fields(account_id, envelope_id) + document_id_guid = doc_gen_form_fields_response.doc_gen_form_fields[0].document_id + + # Step 6: Merge the data fields + form_fields_request = form_fields(envelope_args, document_id_guid) + envelope_api.update_envelope_doc_gen_form_fields( + account_id, + envelope_id, + form_fields_request + ) + + # Step 7. Send the envelope + send_envelope_req = DocuSign_eSign::Envelope.new(status: 'sent') + envelope = envelope_api.update(account_id, envelope_id, send_envelope_req) + { 'envelope_id' => envelope.envelope_id } + end + + private + + def template_data + # Create recipients + signer = DocuSign_eSign::Signer.new( + roleName: 'signer', + recipientId: '1', + routingOrder: '1' + ) + recipients = DocuSign_eSign::Recipients.new( + signers: [signer] + ) + + # Create the envelope template model + DocuSign_eSign::EnvelopeTemplate.new( + name: 'Example document generation template', + description: 'Example template created via the API', + emailSubject: 'Please sign this document', + shared: 'false', + recipients: recipients, + status: 'created' + ) + end + + def template_document(args) + # Create the document model + document = DocuSign_eSign::Document.new( + documentBase64: Base64.encode64(File.binread(args[:doc_file])), + name: 'OfferLetterDemo.docx', + fileExtension: 'docx', + documentId: 1, + order: 1, + pages: 1 + ) + + DocuSign_eSign::EnvelopeDefinition.new( + documents: [document] + ) + end + + def recipient_tabs + # Create tabs + sign_here = DocuSign_eSign::SignHere.new( + anchorString: 'Employee Signature', + anchorUnits: 'pixels', + anchorXOffset: '5', + anchorYOffset: '-22' + ) + date_signed = DocuSign_eSign::DateSigned.new( + anchorString: 'Date', + anchorUnits: 'pixels', + anchorYOffset: '-22' + ) + DocuSign_eSign::Tabs.new( + signHereTabs: [sign_here], + dateSignedTabs: [date_signed] + ) + end + + def make_envelope(template_id, args) + # Create the signer model + signer = DocuSign_eSign::TemplateRole.new( + email: args[:candidate_email], + name: args[:candidate_name], + roleName: 'signer' + ) + + # Create the envelope model + DocuSign_eSign::EnvelopeDefinition.new( + templateRoles: [signer], + status: 'created', + templateId: template_id + ) + end + + def form_fields(args, document_id_guid) + candidate_name_field = DocuSign_eSign::DocGenFormField.new( + name: 'Candidate_Name', + value: args[:candidate_name] + ) + manager_name_field = DocuSign_eSign::DocGenFormField.new( + name: 'Manager_Name', + value: args[:manager_name] + ) + job_title_field = DocuSign_eSign::DocGenFormField.new( + name: 'Job_Title', + value: args[:job_title] + ) + salary_field = DocuSign_eSign::DocGenFormField.new( + name: 'Salary', + value: args[:salary] + ) + start_date_field = DocuSign_eSign::DocGenFormField.new( + name: 'Start_Date', + value: args[:start_date] + ) + doc_gen_form_fields_list = [ + candidate_name_field, manager_name_field, salary_field, job_title_field, start_date_field + ] + + doc_gen_form_fields = DocuSign_eSign::DocGenFormFields.new( + documentId: document_id_guid, + docGenFormFieldList: doc_gen_form_fields_list + ) + + DocuSign_eSign::DocGenFormFieldRequest.new( + docGenFormFields: [doc_gen_form_fields] + ) + end +end diff --git a/app/views/e_sign/eeg042_document_generation/get.html.erb b/app/views/e_sign/eeg042_document_generation/get.html.erb new file mode 100644 index 0000000..d20f81d --- /dev/null +++ b/app/views/e_sign/eeg042_document_generation/get.html.erb @@ -0,0 +1,52 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% candidate_email_index = 0 %> +<% candidate_name_index = 1 %> +<% manager_name_index = 2 %> +<% job_title_index = 3 %> +<% salary_index = 4 %> +<% start_date_index = 5 %> + +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + + <%= render('partials/email_will_not_be_shared') %> +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    + <%= render('partials/submit_button') %> +
    \ No newline at end of file diff --git a/config/appsettings.example.yml b/config/appsettings.example.yml index 09510e0..c6526d4 100644 --- a/config/appsettings.example.yml +++ b/config/appsettings.example.yml @@ -33,6 +33,7 @@ default: &default doc_docx: World_Wide_Corp_Battle_Plan_Trafalgar.docx doc_pdf: World_Wide_Corp_lorem.pdf doc_terms_pdf: Term_Of_Service.pdf + doc_offer_letter: Offer_Letter_Demo.docx gateway_name: "stripe" gateway_display_name: "Stripe" github_example_url: https://github.com/docusign/code-examples-ruby/tree/master/app/services/ diff --git a/config/routes.rb b/config/routes.rb index e287016..dd2ce3d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -209,6 +209,9 @@ get 'eeg041' => 'eeg041_cfr_embedded_signing#get' post 'eeg041' => 'eeg041_cfr_embedded_signing#create' + + get 'eeg042' => 'eeg042_document_generation#get' + post 'eeg042' => 'eeg042_document_generation#create' end root 'ds_common#index' diff --git a/data/Offer_Letter_Demo.docx b/data/Offer_Letter_Demo.docx new file mode 100644 index 0000000000000000000000000000000000000000..a8d6d59fe73b6a2d94788c3e701573ddaa5cd3a3 GIT binary patch literal 37132 zcmagGV|1l$vo#vqPRF*>v2EMVN;E#9j^Pe|?a?f4kZ`m@oiL4NXiPnCRWCtuEBpZ1&iY zJ_0@i^FX|%O~`CARQG6cJ2YvLXhB@xfQ>Cp>hdK5ifmtA5y~R1$>1ATF0}8E;Ex>4 zM%&`LUs@|f8U>Bp5)wIh35JlRiXG_H6Q65pp3Il+P4Gr>gAzExp8$KYE&Ll+4b1Gw z*wUG*Rw$`cC$y5ZG<6`J)vQt|7=Ki@0TybK;D;7f(`n_b9Nqf?9o`O1KXixSqcR46 zku*T;R_;zvR=^y|GOMCx8QxjYO(69&jp@`m2hV}Wh6@TZQCdh>TSuyOVMYg;!q&V0 zLd}$F^w8!V)V48@PA?U?0943SM;ig??2npig=NG+5oUy)FocCT9#+JZfK&0JY9jF! zj^47o*h4Y$5O6rNg3*OR%0v;pEPBuN#elCkrj0!(Ayw@W{VUg3oxor4q0|EG>HORf z0~F4o@32SVorbb%Ad(#ssg7!y74RY!e3Z@R6>D@pX$ALytslGrxlvkY!fmlzfi4UF zCpB9TcC#SsbNBPJY=!yh4CFVZFOfJ)xI@y1d(ulrG2oTKo}#w^xwI3Gd4p}oO^5k6 zt}yXEe)+Ih*h^eZ+upaB#FUR-vQ>Qj0hlYe{&_qlDg*iUgSOSFBqySNH3q zq^+*S-kD7I*EXVn_Wc4jB#lc!= zG5Z@>nm|ggd2v(eLIFCN%MK){lAKImo75J>_bSd5&DU0gy51|sLdPoQ`A^CP_|o5%%E=ic7XXd}aL({SL{KlcDq9A)V4W}0 zJ*m<44Gpl565SvI$XTBxCUR(zD>JnaC?*`JFXC0R8}&qQH&@jN2jQH0s;gMu%k-yY zpiQ~-HWZp39ml({TC&nF?v`|upF2r~D+2LVY^a~5n(N6l?#lr6*a!?KKmK<9oIiUpFp zXW+jo?g{mEtQl+aT@?EyJdQYuQfi1*qnz~<_IR>y7o^{l5E8wZq-lqmbCi{raDc|% zcyHf756cP+1Xw@2@^x(@+D#o8yJb3AF6=VrCcbxKPdkrCUlr6R<=w8Zs#=j}N$2`2Rt|a2J z+V5y^ior}e`c*!qrxO5}eouI{Js(@8o%;q=7M;FA?Z0>hZZBMe%XDV{TuPq-y}KJ0C!})W^{bLw_{j07{H$66k24bX^43VK|!$7*=9& zcVLQ)uv249MrlzpDUo0{5i2;5HXs%)z|3(2!kWIbjyKosrp1|ngpQ_w__;7osd zDD;wCZKRpAau3@kxw($xs`v7Fsc5u}9vtq_WW$eQ4widcZ(XE)d)YhOmoDZA81M54 zZKxERqG#C5wk;l)kP5()m*yRhz#4GkFwr%D=D7yWmZ9fOMmmUB8$dbEhoM+a1uoFU z`enqM6(we_DZXc}DQdH-n3W`!XxyhyAOSDpYt!6Dqxc&ePXC-{DIh-x$RzQ!WA@9z`VVnaWZ>CqIE}BE6 ze?F@#0VQf}j#U2~+1e42)OEQr#8Q2<8q*39c}~uo9TucKx5AI)^@W2kEl{U(gix`r zpo%Cqe+K-UV$Yf2md+q2YWk`Se;s-`$7MgIIe^jxIG8K>%umILd%CnS5N^jbAFdbq+wUH1tU`^Ro{1UvH zLw$yoxij1`S`VXv!!lky>L;t1LBLCB*J%VAo45Pt#>Kl((eo^^`e#_NJ>Sw^XZH3M zFW1XolI6}=#YSG%KdVOE(M%U!^K>VYgeFBl%`iX4v(S;K>(*BH(`Y!!Puq8orHh^_ z8(n`niP4LzY_53Zslary)09ZL38+m~z$5ubHi4+kR%qmbRMCLw`YK?k$I3fsK^ah(Ru6rROAu z-u@#3s98%Q7wm|5iqKJUm`cEJyH;&4v);fOA1sI$ZY^)mR6g~GFVR|^Vl^lq{{b&4 zt=*F^=Dr&I_j2f~X+xi_LpI54^L@PK&k(^sNfJ_?wr~Uj1at=VpOOUSzv;oo+1kj| z!NSJ;A64=@QC4n%5h+-{7mxUAjTD^_?dL@R4BNRMXlqQOMicMSU&-SO`^+9C(xed8 z{iv;{;k~1WN9nP=Ljd@3(%^U)m=4Qm5WUjv%T2u-vA?s5xk|tx6{mxAb7qHg;<3~P z=c~8BI3SZUC1H*;F(}`ZOnrgA&+a0UGp}HZp$-atNZ1quE-7E`JQ(c~tGeJg-U&-W zGMMWG36=~iAb35S6nekSp!4k>CTn+1%B7cjsEM09Wc2qHa3fuC9k1-1yMK*|Qq@Q4Hp#&GpMqccY31<1>~x>G(rj z{eHR(aS@A##5OlPND^C}%lu0+w0A{+9ObTe8l9H3OB0~p1`{eUC0LtKa0cvvAPB;J zeV%@rfnYclA!*-DY#M+ev52MQIX^i(tE#gpZTT!g^C|8rS~`LC^v2m3iHXI(4x#bj zXLkqxkDnw_g?$0vM8*sLpZtXU-+pp5b#nUllHz!u8@v%o(m<}u$(Mm+?=6Hcf#+s451rzoTE+|G)7K;RS%t|DD6Zq%gWcm3%(7o&nhMCEvld6;&^H6B| zO>_(RYxq;PX8O6}z*-X;Ma(T{=P$>N)iqADp6X%c9LMWP+sB~T)9sC%oEisx`> zOu;yOe>xNQ;%avdN&)Q7dpR7BNag40elV4bRK*X4X~2X;*OxnZOXQbF7;=3EL9tL= zA>CHm(Udx+Muq3EFXt6mr#1VNU;cJCMkOqX#or}$yFRpsz^k!|T z1H0beS$CQ>6hDV-7wY^f_V0xB$6=%gdgcYIzK&10B9v!@XDKs}zJm{EEQJr_D0)=> zvP#*E8t(>{C8_%4UzIP^!W;4SM!cBBNwemI90fHvQYXwuZ(Q%{H@r&Ha~gtvNAsOj zPP#ud93PtZ`J2|qutw;cMEIWR*o35ymfuzO)5^!*`_Dc#1^XLcShwGj@Tzcja#%yV zz2>y*r`Wqtw+@0c-|B579f4IUtikzH))PLW;&|ZW@D&jNQBfPx8m~!qhD~t|!g}r3 zq^9yfI?pRxka3NAgyW*(EzRndq%nWLy5$q%KQR>3Fi-^ko$IF%|0#z4C)dqvZJbmL zjjT-n4Wgv~o$EzVND&e=U;*&l+d#@Al9j9Yzs_0jA6u<`@(90k9Zi1oJJ&I{s`wfs zngg;#66=O|4C5Jb9WDMub@lL0+Gy_cq~W6dh_B1Gvuf&W{WS*??W!1ulWLh$_s27H zxNa|bX8RBj3_S!Q8HiY;GW-LeyoN1q-8bH(GIzB*PTFQj2f?D2D5*UtBQ1Aad+jM1 zAxhK+Ajl3Fe#R$@9sNZY#m_NJs&Wh*T~XwWCoBIu*l1C(+1J{rLiI`4c%=0JOqK(- zDn<-m$p*U3j=qu)Ka$rzJ_>6af0kyr@p_}-OeBz%*DN;*RpE*kar0sZq12FMfHv#L z{Ak@h@iJKB+X}c$+L3x!a-ou!5EQk(GQlVnlpgR4LS8Wv+HLeGL9bOlqN83+#2qwM zsshR}QPE{(qAn?gy?a$}gumKn?4yjv8quY?GC=>ccj&?0Zycf4>Z+$y68;$J6HKs%-%Ddo*(!hH$r+a$Ax}VLCk-o0>uBJ0w;GX(|?KJKx0j5 zkK?**n!>L{kT&eJkZ4baw8CP843~3sDp>H#ziRfuk4zt`#uXh6?(cK`zc0j@mnmCK^_Q zJMA3m0wGN9B6Y(N$Pp1Q4^6^CFFb6*Cd@bCBLim5QjO3??(;)UN1>tu{5D|dK6+XRe6BLNRS`y4Njb| zX962JEhP(u)nfpa6tx3x7ECEFRG(X53_KWe12OC{RNf4=-Bu^)b$?4bDVLI}Jjqtp z+~_!aZY86k3uFY>Ej4&450u<5DU{xF`idcQ4oTH0kpY57b%`a455dIxVt7$BqLQC^ zjVnW<5#W=OqW1h}-UGlS^+9?`827Y8Zdb}(nRDm`g9Z0FT=Ys*m6Wc65^@a_b5*qBuHfO~*yqCTV|w4c^vt0-Vo{w!^<-3O%g=KVv2Hoj*9DOXA9>*~u0+Nt$Ju5eJp@dJOQ|FX{>G zR*TZMM7IdEV;c@7J1emNDA+h`B+l<_-_|=J*x>8Fk}Fif+RKmNm6mCgn4LPK`QsGZoDj^zKh1Q z4b$%H(RC(h0X~#JRIk5xB%GDq0gYUV5K?$vK>b{bm)Vgu2C3OBi=Ly|r#t=BUwM#G zEQ5%xJ;h^H7v#1cBH+c6Pw~w<)kevjDI;y{~uTPR905x~5*Y(hP zzvQnkG?ZHS;`b;kskBPgW3)_6`0N5%!C5M-aBU(#*SFxWdAfC~`K{uaGJZhL9950? z*FGM>EA+yHr+$-CYjDsMG9$WBep@vh%y1@nsypVH(1r_zY^&8f!Dj!w4L8nQAB7EY$t3J$h*j{lD6vg7(J2N>Z(zEzfi zlWmrhag}~av?x#7^X8R6lmF;*%X98F-ReudXF*V$wux&t4Tf+G=;T;qqYCF!xUY+YK*uvJG9n8o`;qf*r?g z^gPDXJ@dir=3n}T*n!Enc=#WKd0%GwHH6gbYZ?9kC=JdCkMt#)-yR=hk2wF-8@N4F zzol=>lm25Ljr#w?=3iKn6~`S`1(4nY-UBUblH!3fCD0Ngu}Hc7Rifyiz1G4OEhjHy zIuV0zAL4IFlBEu|_hg>#ou*|NVgtA#3s^z13k0`>5#qtm(~5|suJ%|6I9CnY25?EC z6{T6*qxfX0WR7uRyiJ>c>yW)-;JaD!7|G;Hs2+lZ!l;c;!_P1%Fa#iv3y49^_`vhB z?qQMWJ@6E+-q}$WL|inWr3~hiBia>GDhW3%X~I}9XYPipiE%UO{i-#p;*HT^6&>cj zjBi%-9}^t?3e3McdTL`c)eH`%DAjTcSg7mj%DHE)Ok;AvRqbm+10C(F-h&_)9a=YM zTt2Kl_t*`?3Rb8mLy1w}cd#mDKMF0?#-NT4n#acb7(60<5A{sPYrOUc3e1njgG@y` zpX)J}D8{v8FA!PS`>gr+mOaypi&h~ZbCPa5Y#5qvvewrs40g`QEp}&(o6EFsNHu@R zZTJ?5mu&iOVShmUtT3B=xl#GMO~0DGg~;;~i?1 zhIvj*HfpjJY)?HZ?({+1*_H7iL0>pn^IpaK<*j~*UtMRe|1?PQrEct~S9pdVr&6|1 z>6%210A|3_t0<->KdxT1{c@K72Zdi+tTXN3Hd6dw!_~yr_}~0x_^+J)N9JbFOxgr8 z!U1hl{N)zuE`e^e0tYY0SiM8oxKxBdvIo&h;IzLI#0jiDsqJ`%6x>B~; zCN}4hG~yMUO9|Q)xM3zVuvNYYqg=c`7H_DTUefP8WiuRQshkC#CfeHR{m?DsA)y4G zjE-xsnq6~AtX9|soey{r6OI889$Ju~;;#_~|e3mkDz+0$q9 zQ~tE<%X%kDhARxNIOfzj4orpRfD>j*V)^kleKT@5f5u};{m@8_P+BGzt#IiFjwFdT zv*&oU-{s}DZljf+&*l>5}S;IIE4IV0#_0+|~L{8;{t8#i&h zo;Ep-^nf{;BG8(SZcpcZWNW|=C3+<+H^-UH%*3l0^A80uO^`C8 zQKH2UQY^PRruwVz1qM;RhrEPD9TN(5K17A(E``c>b6O!ln(%|oEGxZj>&!{dlMILH znmPGV8lwgUgEC*#kdOW5$swWXNP_7HyP!F9^L+)2$LJ?rki=*|rx5og#p6dmYn z5W76RB~W`{EG^j3NAajPD;)jd=X}h3^$ws#etvW!8|h@k?T{%m-9uO2r)#DqcLIvo zM2LuZ9Z<_pd$};`Sr`4^4PnWO+qDl)zBNhIkMeq;)eH7bfnO1NN2uT7%pDT#k;dbLXM(Na$ zGm5bf*isna)Rbe0(E2!ls&Y?;-)~kd;$YjdLH-U!UjkZYRTl_0){ik@G2&OJ6M$b{ z54Mm)vRTfG<(1d3ffkk-zM51vkQIC#P!}>wP`9o6hoR{38$eP*YR)uoUOs6FIbmzu!TG@H{87-eMTrxR%l|0;4W1Y zTAbpz%+rEa<&J$`=j~rSCD6Rpo|_bnotxt2dunmY$n9g&z}<1rUafhGSXMNO^>sRD zpi}o+6oPMk-fYhNa)ODtAg9azex{YdH3a~a%q%~|kAQX{xI|!Mtb$iKQ8n|OeDzR4 z!@A@CQxc+yIbd-bh|#fQ0;_PQKl~i4)9Q=^M|w4G7!igFF=lj0ib;!so63=68dxMK z=iU1EY(i}42=Nw{5wg2Di$;c^SGB3?uyv7^oCBe>Z6fw{Og*`_b9m@nJ`Z(eTV8Iy zxBUOGrjrR?!_)V6s*B-2NfzAiLi8_d{+C+$-`x4HV5v$P|JL4UB0YIugpD<(CDuQL z_N}CdW^5v0H>htP0<{w2tEE4l(4p(_pbB8=%m=eMJ@Pg_)t&btD}O~FvPvsS2}mn9 zw;$d&xOHtQ>?#~9If;RmkZ`n5U%3#>K;N@eTX>3lg}G$0g?*$jQQ#=_lNCc=s8bs! z3ouwudJy%9!doR5|1wL(X6^Yy8k(T&Ny#D=Q5X7Ul38v^)``VQIpbCske>@qKxqX( zdLo%KNqb|Mv|*+(WMb!cjJQ0Bg-H=~jf9%d`~%kh97CK*lPGK?4aq}6yw+!nWzZy; zFsDEdA_kAPX17TA;VkXJ!49yHYMTj_u)o{gQ->i4u7Bt#lK~+D?IOl`X7ELR*}&R* z&VN>xtLx4A^6#J@=V%Y>pG{c%H`@PaaR~d3^nZc;U%)0ze^2<~LUa9G!@Tr2;Gu~c zoiKwMafA+lD+jGfGWex<3~c2QWE3oV5peh3-wzs+FD^HxPm>+(nE)E>bd(6>T9{(+ z(;ow;7%IpxDTi1Z1M#ru?G+cO)1*x$GW6)GMEQU;kvTjgCR9&qSsC2ZNu&mfvJoC5 z;yWRdy<%%yMqhJ*7K8Gx#keOI_;P;o?jXF-KJ4z;!)?ydbcz|=2$3GCHWzbyXS79S zd`;HB0Q_GsNfy*N*PU~R4!?6pM5l#Pf@TIMd?^idS+ zkNLjgfP`A*!iYWmHeT*OYG?HS4n!w_skJG?zu*6LKtogBc8v|K2l1~fl9MahTEZ8Y zGmLg~X0s#?t4%1rMS2RBa)IESWK==#OpXgSV;+u+hW~~ORtUO=KYGXc02rXonZQW? zmVdT*wMaG;Bog#5>4Rr1fA`b#GqGNm3yR_%l%t@=I%A}|)qHQ=Gz2NakHap#76le~ zB1Im7q@h+rxjM!gYv0cm)kZR5Ttm=(~yGY9@Z zw~w*z#TKYnT!tc$!evRskW0H*a8U?wx-> z*DCkBZ9zZdWNXm5JX@-yejybk?rK0P@<;Y!!qG$>_Dp5j>_&C-xF~q;to~*%`^LU} zU#hyBIq24f2MvyyKtpkdzpM6xn)c#V^>s45*P=~xc6orjAQ9OO0Mxo8xxPi?0)^Sc zNgTGOL#{XoE2p{&~&CpT+n2aX*$g zKhiUGw3)OfXdjpCc{k7g#q&1z{MJIS#q*&Si>dj3rr+)HF_LSm%z&=7#q0aA`%-b$ z^Lchu^205$&1BLbQKVK&1plc_?amR-`~;97~ina$S^pA)Y7AL7%BL zZuGgBgZv53GJxJgNA9e^txgi;U5VZiD2 zSo|y8JYpB>hG()x+;Y@uyEL-#M(QIzK?+))ttw{_4>_O3VgoTAMNLxwc+dII-rXfr z9H$o|wwDdI#JPF1ETUp1Vj6w`wQ#D9ph*FyWV13g+w33sMcEFAz$UeO5mFy>@J6+_ zR)U&Gf0(^R#A!aQF2|c>IX!008rxgDGu7ykXFso3QCS?>U2nLfQBzq*&G~nNUm2Yr zUYcV%YRsw06TWI=l@XXUZv_;KCG`-vdUk2}O+4iqoc$!rD#+u#Cy`?3f*$OM;h4SB(Q#0ClZyHP9du)x-JM zT2aF3EeXO5UrmA}M~E)V$o`6DHK*^&uinUTi3$Zv`3)KWQz8TIy<<_526M z1jcCWm(!U7>;mKPNqsWL7&<+7a;8{{+s_ls+?|j5d8*<@gEFOvQA3Du@y`Y@&(Az` zuTB$E#F`$NysWJcA%0Zw?qNOZtbqUI`@udz^ga$Y34nVQNhm{t-win#Z_D4JXozZy zvnK7wruAmk_7x#Lgdjs6^jLyt)w8EbDSs@HuD0>@NNHHgjtUh%AJ2+c#mt#Z0_6G- za-7sc$MHcyj)>*TJ?nynI8+P``hgPf&t-u2v-EYn>L9eVn(toemR+ylRO8YIQ!`O^jD zprxfXA>yZ9KU6EF}`J1<<1XTigH* zTTIlI%@y-=rDXo4%bTm)-j#q(>Vk$Zk~U?jPmMZja|2WQ#q|jSc$}v)sr|vBOO4fR759@^ zSS=(d5)6oom6Z>vgNVhpcJq2+X|)=Y1Ha>I%&)c8?y7Z?m6Wq}o!O@v{`XU3)jfFM9Y6}^eqo#D|)LV@Ywtek;{A1s-6hkbf%{@m2}VQcj0fn_mr`4FZ?jkk(B zam>;nV@r*X+8s9*RwrjpBlHd#Z@hCWXGK!@+RCw`It&mP#*Tcl<|6SS>J4vrVu-af zVi!y!clSra^g}|q!yB&N*^rg=9qG2=a{hi!GY|9( zRq$g?4R%d^KUN0-3W5q!)Q5$ub+S>;>$ossQn3B;6MIdqERuwW967I?*J95QbP@lZ zE*ly*P6^U8H)jn=ayTZi{Ua1cgEd#-=DP$Or^n_4gGHz&L3Di5j=zAJ{AA!zkCbSL zwg6_4kFfjA%%2>w#z<|#TdN4;j8xfCcaeNM9A2{3%6ujSCczfIiygE%q2m{K<))Z$Pa?ynGeD*G=&c`$UfcwjB1vMC** znD;y6SdNg5kw!lxQGR(X%7q1*+&s#fR|?8j2Xy%U34wN)*Y5i{p*7L?4BMMH!_QZr zIfS8v!chYw@Mml3Ra&0mgPe88p(8fo2|5!DeyAy- z_g`Y_E`*xPo+V&5f?*?=b>W%q(C-6`jVD_H=~~v_2y<93jK9@<+n5foT9CnJf(YfX z$0#+{C6HdH_+K7x5@1tRIuLS)7WUhOcK7?wjFcRYC7p_!Y=jFU!W$+9OF6pG$Q9Fn zPjjae#uhRZa~hEmHyIe| zf$j@sZ{`q`!MoXv5;soLB8_?M>rTH$rPNnJ>s5Pt7#n|%u<+uISCR`eD{(_D=fk0c z%7DY87AkltODQ|gn|Hw;K5KfoP*NU!M?lueN=4-uXKLNDL_Ch`1|O4< zDIpoQCb*0IYX>CQjn1&F?-WW}(mwg6ZGh7~V&s!=jTGZ3*JYuzgw-@*08HCY_b7tt zcEkqXvbLuzVe?!X@gX-5k|a%|Jm3 zV(9L$UDUnto-4&CM$Ti5KAlLo|G9Rk}MU#B{3Hbu?^s{%%Z-3 zeGhYeA^meTu>;E27GJzZNT#z|?N`DvJM&Z;G`A*pqYB}io*QRIyoSGk$peZn;er^C zk9T=*syc-0VG)AjvwD{Lc77x@EJ1fytgcrEUc3-Eq};$pmW|$Pbmz_j{D3?ajtpf| ztVl!aOP`7P1DJn{f+ZY(+*JV7+k|DH>Sg2xD9T!=dK?-W8(s9Be%;2oLr>_LeDvDT zjFb$ndWIsG$R+F9bY99jlsq~E5fO#$;i}6TeK&aJisC~553joj|6mew!g=l)J}z+T zSz@ltZxFB9pVgydF;+gl7W66G7vWv@3$vH3}c+ih_uhEpZXq z8|js;pz+F4jc19R+Wc~iJt-v%=)g5Z!fj1_EH#NrE#K*;HRTN?qQ;d)2hstUm7~{e zkd2Mi0eeska=sItTL*9=B1w0;O6Ms8dWX?Fp(&A6?K{ZOK2xa)TSnPz`R$LU_^LQg z9B!S~Z7z9(>?t}$@s54-eouz&76I0TLlOYvzK@Q}&xF2|uqNx$Kn%Db+gHhYQs@1d zmULL)7xfZxRt;~9kxlk^qBu45qY-7IMJ2dq%_+eR(xsd+E-2l3o`ot!s6%GUDJI~W z%Rx8gC!U5&$H(~*V28hvxjdENjG-q#HjgP-qPf#5?e;33M$S+`(`vqx4Bx#?jm)^Z z6AT3`0aq(LN17HALtw>2_9*z8)+shD)!=4-;vhPi5V$XH6G<%WuI3@n;VG|9iO=Qj z=K=1GS|w3zF#0ZI?O+&1iJbY82@HG|zC88;W@b@>6TNXO#o(CY_dcrmw?c2Dtx%J0 zrd&s|IWzAVOKkrX1)_Jj@R`vt{qHh)*%%d6fHqN8IYC6~r5rksi}mU_wRg|gu%%D( zk=$&vNJDu}J3vRB!56q^T*(;wgeMrt1(kIo4GEEyiN0J!BDgSzfdT}z2=r+sY*bs_ z+S`Nw&VO-%v28TqJ86(1i7oKNNSu?Y^UjhAVm>+hwK!lQ6j z(M|MM9M{PiE`3#HO~NrI1awoW0JlTV%c!)MQ~~uQyRI#*_luo)ULS<=RFpq^^LEWuA!ZfQ@^6bM%Zwg*uJvZl@aTkXAhga` z8#W>95y_En%6G8Qvmc+cQ?#m2C5r8RBxqmXgjgRZ8wQw5TxeqO^dt3ABn=xXZ;-7~ z2d{7!nRlbl3Yi47hTtQ9uM!lajyEU39y0Av=Z-4+DcJa4CWe>GG>){&_-o6kIib|r zLzqB1HN{T8m7uAGiQT*hNJslfTY$k{{ZiQ;cBbF|%@MdLnzGL*Jm!D-%!dgfu|xz! z4qNxe5MEAh#C=l{OiMd40j{JW{>y8yZ-G`disUiA6>G$usE&Jp&cr#cB`3QvMI?jU zfCC8ft#`g0U%33mk2yBIB6P~O(3I%%8&AEP zl%YSXP4<||F@UI-?Z6GU8Ij03|IC7X!1y|&_wxq<6<2F~YkHnH|0c&E5T+nJ<%4EE zb;us@wpDTIVpQHHSIBb4-l-gpwwyCNvm`^;)s?@{)M(RgiXSS!h4hnQ%_R>1_z+&s zWKnI@QZ<+>^uXk4I+}=2p>=>swkx(_HgB*J4Kf*K?e|qEIzBOx%de7^_yX~646ZkQ_&?B~mEY8#6(Jcyw5@SV#duV?wp&%Kg%3%|!e%pkkwYfeD`2RZ7 z&na0_&dtA4xee$=Tf}CNl8p8yFYI&RS4z7+x6A(vo5%56ZE(dxLodj|`d*x~W3z1k z7bNtI%rSW59RqB0OauL(?!Ai<$gIk}DCmpTYl#=`U!T@2@M3izPK7EC_nKc_vGb)G zh%}TT;lKH&ON!_ORh`4P6fo7360bIp=LdMJpju~4;jRLTdSuaS33K{^EY_2=Yqqb8 z5t}9RaE+C2SnvXGBll=wYpCU=qYna*7W-)uPaW2VaM1-IZp)@+1Rv?mtT;=USM&hRuD}qu?OGvRKf> zg**2o>=vqNkX`MGfle-=K;{t^MEXTzVc_aSXIzWxYSZUmRL{JpfD~tYP#VLYgl;54 ziv2tnGf%O(=&{_0Clsw5krC=jay-X+A|8^9VOEg1UZNTs4JwC*`cSW~WvMBKL-4WO zDpOI4B{~67^sO>lW{UzLAZ)0$gk~T*XTak=6Wp3qC?cLsA)n^0LFa*HG|$!Q>Ycs*h9;Ld`}A8=qm|zmp-hJA8i7vV*A=&R4X}xe+?S? zFR+tDcBslSQy%y1Mw-gSp)rvxEv8y0v3#>Islt@=sbt^hVq_|uQL1sDZ(RXkc@14|2pfQ}g5F<#oI z>FN|+97>?d4^sz-8S{@%Q0u!kz1~L8krMm%`Zh`KA1Kmkgl>4wH7T9bH<0FG8&R6e zE#jK|W9ZF6#7*ILxpjTT?>mlMlb!mDGE}!-6Tv`wqk$V=K@aU9v3?^t=3hbD1hw8T z^G+Uy89`M@-Q1!+)jwZ#rPh0x`okB|#yH%v;NwDG{0WwJ5-oC1uqtMvO}0Ydb}PJ+ zdDX{Sp9VOs>}^m7>of3^2(FPgRo#N!qKUNE+=iP!l#cDSmsgTE zdEq3uYLzjlOZ`H!W)rP)t&Ik4QDffzJ_?NOQRuLPwwJ~te=Rp?JV-DGVz_0-@B7WZ zSt>jbIj_(oO8;h4fKWi2=$2A%h_Nuec@QWCAys2t58%3AKvM`non{~_N>c5>s6_z( zR5ATsxuE1SIGnWnG=kss8#tAPsbYaF+v-hS=(5ZA8m9Ixn56d@$TTHwc6%?Q9=ZFW zf5s7(XBWyEO^Zxt@F{+*Ao!l=Z*@&A!N(9Ty$x$@p`v)kQoig`_=~MSm7crZ*H;Ck zHaw_bwCUclcl9eRQ1IL*nirnF11fOKS#AdysSvOe zv=*4$RFK=Sximk zUvk!kp0(3UhGH!_sbBuVU#Iy?5Lh@>g=2Wm`hD*q6Gn6`ln&$+bnA4E%MURe(F z11p!7H5A!DkTpmP4?V3nz;K>}{WX6%*1PG62Voo+UBd$Iehsj{6C4E$d3#b?dFh|h zt9Dnnd}O6Xr?GldgAt%#m^#xO>0g{_{19%Z7YLm@a{eS^;Ud^$_xh^P6>9N12k`D< z`#Tiw0-qzy!LP*Oej;qY+AM8DGGiC+%^p)=Y_>TaJ!M;79BL(-QzmW-nNwy5XEh8CA4WPhc_C;5Z2fBhO$Cf{kiOW0x`^B+Wa;<3sjuO4a z#fcjdXanFBi+13TKNby*{0D_85N0EAC+C$VC#)t=vih&~K!54AyyW%1uYQ^gpJ&$*ikPl6r(!yiB*>=R}m$YC3|}i>q*t-`f>ly9u*cYV(n#r)2$0_D|({-5dzJ zXI{ub?le~e2_=_tPy1Gdl-Bo_V=1Y;9xr3PY!)YB>?(25$UtElQ=4!;pHwLATI$ty z9k>TFmJ{^hQG--Sz3FFiT}U~e##|#kK`A)iegZjX>!pm2iBkV9slzZ%7N zWI<$`FB)WtIN>Ghx5(JEw2JfWHTyvQvHg}}wa#8i-o`$H8Okap$5F=DF+2f|vbzOB zu{W8=W+LL(c)-gf6y-j3y$$Co5}s~-JX_=&z1P(}V-uq-ZFi$SkuB<1;<#?l-2*#q zoQW1N?tBX!)_NToA~t`BO~#9vr-SpMflUHVV_$;z=(J^(OZhLI6&j&159$l_h|}u*Q1g4(2<_mhp2A0=Iq#s38)sL;okGBd0W#z z2{9l9S4&ZmX6>vl^!`mmf^~70-ZK_}GfmX}`VlBUOMUi!x|7$8P&!0@T!CjA#b^=cr&@Z7mELE^sj;}7mqyy zE{*in+2Q4Bdl8VR*KJeF?v8Y(3dLcz{3`9kik(rWOBGl5Ddl^}U6Q?4Ywe;ybKu&e ztN)JV*H5A<_&Enh?29KPYm1w?;3Vf*vR&)&by83 zE$JOom-s?%S!cXTgP%hPuvEuDu52#|oy-wJ-1UeOS z?Rw6id|^qgMKn%FUJ7}!d%l|%I?@$;rli+-K6z!Bjv0cfB34MVq1LePJNKiC#Hh_c zB%FSwW&zi{mu^g=E5AK57SE}2lC~wyZfg$uo0GPT_vyTL>rfh~G1ec9_t|GqDyS z_@EHYOihQ9x|dnvMJT06&WsT1ITIx?9%b*a7prB*`Lr$z)o$!ku4zka)Op`f^*UL{ zqR*dY59d|Ne$xlK=cfH0@1gc|7pXm|7W2$?p7uf|T(svUagdn(?O*ir=Y6vLgClxEsT17l+9Ce$UgIXt&%M-pK1 z6yIeD>oMQJjW3Yi<0A6KFdL-3mJT-L+{G0w#}}44r#Ji*8C5cv$vl9#+*1{JxA|;4 zWak)3@A&j|I-P4M%iupJ66TL~7TTVSwzxONS(432w*2<;S!n-J&~|ijY=+&U*!GG; zzid3GSGZYZ_&ooG88@}9Et@ln&V?ZIr@+x{B`nhN29N%8H%%CEkmc~}jfc@z86oj< z3Po2cDm=BuL?Iij>OmFl-jLEM{QaxIb!0GhV#8Lt|D7_$MOoCFt=+gXKh^xmr!}$J zCHISfi(XA~xnlRj>uS7$@B2jozEPCRpS1uVUsRhe4&_)Ag~v+ySNW-T$Pp^4X-WS1 zs(DNc2pK?d-v_t_UV!USti_&t=Uc!3_{f)%+WYqJ8mub?8^wo~YGqMSsQ9~;{|7@r zyuTF9=7iTs57>+R|0$ab1IL}U*lgL|s@&hE*yljM=Yv18*rb*w{@0CG*r+vaP(R<0 zc$*Sw`h@Cnj-uos1RpzmDrV!{4G!t8Qn6@b{~j?crb}XQK2pyebN)N^B%<95#C%N7 zwfjbtis+>QGPjtGO`m_H^IlzAh0AM%i`S+pOJ)AJmE^RY+_l0}8I?;}Q3@jCLHYiS zh!Av1i0%6+8DH(4XHr%MtXX)7878KFvi;=a#1_;WLPx{#?nk9AkZcH_}WPW$c5 zUwIR|B~gAO?xtH#YZC0%TLIevA+N8Zf2iZ8rtK7)9Ts`Gq3;7;TU^YuI|-9nS7fk* zSN>Jq=O?icl(Yn{JJNJZfsj}C29cGaiO%Z%{7%yGB?fO#iWOJlaQCa@5&N83q!roXkIX7C;_{*O%9gtz}t2)H)e^%hDN*w=GmemiRCQ<8UA zxixzM?&1#Z3jtIw5{kV5Lo^DGzEio)KN4<{rD$2yMyjVa<*%#zP!Eo_Bar0NMeHsz{gdzWiQ-O=t_|52 zG{6rCO)h*i4Ff{lJ@5%1Zj zf;_PHb9!+A_8#P(fYnDCl*yT67bXce)G*Rk9O@@%vn`pWx#f=*)-COUi}gwxyNy0I z^_flfZJ&SbQdjNo!nv*i&N)Avx-sX_xAnF$rH32OWX!&y0UXJ>&RV>Th1b(D!;d?4 zSa!;{uak@${_e;Najf;hF`4mbd8p4N%ljj{20+cogPM7?8~I2*kmNm^yp-KI;ZzLP zY!g@r)*L&F=x<^-l*!Pn5ep=Fgq@%BAMWkgU-L^f!-vrMmg0e?z~ZrNjm~`F{&b*z z9r3$KvzgIwWcMkOT?3$ZJV1Ryo{XJ4+4-^7?XLrX^E#TLEUN{ita4eQAnG1szTR5Wlfxg#uY*7xf-P&_&mKs<3`w^g&;hp_ST=6q7dde4S% zvhUWhb^`x34H260zFG=rsf*E{INx7b zl=1%0>xu{?jS-Oh@+08Lpzus;KsEBJ5Ws+DA#Z-@1Xu_7Ys&Kl4;1wTo^w<)x_2ae z@wC!MI{hC&`dI*>e2F*plk7KE881X3_IeB38cqIMDeE~N3_t4d#!SWJvXQU9YQ(zq z4|;Xux#a2lz5@2`1=v&M#HKkQ&WO-oU7m|3X2{;HWF0JWd}D@#qhq9u7w%c3qY~D6 zA7gwK?S7M#(!NQ}Qcv~d@BNECFoGK5kiuNWZ-x|bzC_JG%s+V&4O+tVBeWneq zA7|BXKBhELawg$wyX;Uu&b{I{@hIZ?2Cw#B;Y}+~`?BluBg-+v22gyD{6X=Z^8X?t z*%_A;~er zc~(Y?a}(|0&ck`>SLwJnjGB65U^Vsg(ZCQMA?&-gwwldE2HBJfADAh@1Xy5@Lh&*mH!uR9OCK16l^X2jglKqxddWo`a5Yr;`)GJ)M+ z?~ua!9R(;q&qJ+q-W&4EaD~=~mv#O_z(+^&aZRDmWL-=ql(%ht{yGO0S|Wi2>h__l39^3%nm%9h zT<_U*tx6hubv0lFz&F(*Qg&&!Qv;tm*JnVYNHOAhDVO${*zN~zXN?L!wI^QzXwQ-@ z?NQg$ULT9c!>DVQrj5_{tY54C1nz6$a7JW#kS8n&LfD{LdLY?Z(k0he2LZmJD1mGZ&7|sWwxB!Wp~7@8#u6?>)ogw z6?poe;8LGqhZ(i$filbWXT3+qk2;q8IAV7MkxT%{bJ<9q*k^Ktdq|YLQi0!a_@~7Q z<7exrJAw)O`soX@!nj<%Dq5a@T6NVcZ4^MryPCsHD)%i{ei8}R*q?S3J7*JDx6W>w zrw|H=GxK46*nSC-mdg#`Ie8(Z5-!F1Vh~gvtsGPxM=|YVMI_0iU1NXowK@wS8QnFf zy#|`u1w4m82jw8nU6qM{)#`F%K&x|km!Q${Y8-ROFG<$$+N%Sz{nbmp*ViAmBdBbp zi*R_~&*U%lev zbN6e8W(~{0r1ImUQHJX|C6*)fEK0t=DvJSVyMj zFXlcdUaQ^lF!NVfDYA_0aX2OtOuuew@d0y@hyFSbupWxzwPtlNium7Up>VsW_eUfk zk$PB+tbvA6NAYfi!nqTtK;SbOuH_v4C4-NgxxCFZ(;6L%|3?vB~?UZ|LZ|%!8F72MU{o@ z`pmgU*~35xufIf+u~ER{?D4GrEk9g4%C0P^|GDDK0#8X>Z%V{Kjj}icErcDG#qN_I zUOayxz^MY@`hsTvs@=$-E)I3UiPqt$$Nm79lY0x7^wgXmP%f>(0{LJ*|J`Mw%*ipa znoV(hy7!Oel<8iA=jcVx!}hy))6RNqNJwFFQ;kyr3hm(I_hp$@TkXG{sTcdYqxxWR>Kl2tK0vu*BGzXtgx}p|hPwNj z}{RGeK5N0potT3Cie z5efVrP(+ou<+>)Of8H-~Vy?#iNDd*1ZTZdovpRNGt(p#eoGP3er<8#CY)tv}I z?TV5jZ$@z{%QRcGOK>Y3faCram9(#X*Kxn7@VSd&hym9XOx=D4%ef+0%dZMFvfqDE zW;m(TzpndCj}V@9`AvHOb=^IW#k_VpSbUa(8X9aP_dA9VjJ#pdX&W?{zjo zW>>zJJQuSzfPs$K8#o8K`xc7Xk2pnoRCCASbsz3I=>~v`GPipjBSSmTT9A&_uO>H& z^wwpv{#-~nv`P+zu4=I$eXj6l!e_5_hekOE{0GUzn{FA(W~>RhfZw%TAEO@r!LOWS zR{YO@X95_U5F1SQ0Ab$Os(~OH*rM5hhM#T#Nyu#qrjw9ApSJ)r&~t^ErsgNGVD_y? zW@z6gPf$43nY>@4swtP%l(w%fzm}(SN9-W@bt$C8=)3H^%EI3I=~@|4#)96(PA`8( z{9YG!Qsvr}>5L@aH!XbrX|}hijAY^LH36W(_$<~DG)$2_BT^Afr>g9>Wi;3+^51zBC6?LqWRF;@Q7kb{HM6LMgACq~zN^vY3 z!Fb$T{=Q#1T0UR1{>EYz0m+FtJ%4+hv1rKAT*ha{58EAmQ)v6d%eEB9@q2)*4{R`)rxvJD|1BMHlyf|hAYtzP>C)f&S2cC-Vdo%a09q~<} zj+H|of9LKD0pY@kzjLG~Bv^j23R_8f*S*Hv>RYn(`@R{oJ+#AX=oW8CKc``PN zxy!t1mLG{>klv1P{Vj_J-gCZ{>apl}24Emd*p6cq76gsGfp9OTGX%TLbawyho^<@Y$PSM-(`{ z2Z?P}tYy;Dx)oeDE1@MpjSPVbZh`tc4L$Py9w8qj(iyOi8V9}=(InV4fuBZ>e-4sG z*~vHlFuXyo@MoN%_eO;q{hY`os*o&a+MqW=vOg=Hv$gpj&!szGSoyccepM66MPP?#5=QcDv5psSDNU zctf35yM9CvINE>qaKB+c7$bs&7m-Rzx0@Z&O>8fG1NhIWo2&i<1|db@^Rsf*iX|!U zgqR&)Ny05|6riU*7^!x<+k!{7pHk>n0j1#NVciq-&dRdT%}}Pt`N5x?R;>j5J6X7U zi2c2ydjX#Vy+fevTkyH3{x+fR^97`$R&9K$v@RMsyN8v_U{OaSX;qsNC@aWp;@w00 zrAW}4#0vAH_q8W^UTOV(Ae92K^m0~wiZl}1BT17jBjBFOf=8A_78T;{XBL6L-31z- zTj-w2vvf_t23iB2L4sD*VaAl3nWgP@ZeT@&Tk^Yh<6dcx+<|!VQ7(E?1C%cr!AC;#UGGYzafpT9e zMm+;2_zasLH9q?;5`JB#roO8|ez_wn1oSb#!ShY+wm~mB5yzkAO ze?|Gd16JxeRyY>Sl>$TANw@q+jRaL|2?{PPKRx>n0EzQ`gsED8VVB-(Bkmm-)A4c_ zVes7b%K{6**Jd5cY1GrVEFv7w-AF_26$a(1^X)+ z{N*{1luwdVzt8I^nEEYmvqm3J?p<}QFu(%avz&tj_gK&tOL5Ji9mS3z32c8?O&=SG zYJ|gJpL0~NByQ=x`8c^6u$iCt8&G9&gYDc#8Gqa}sPR$kS+;>LoLTQMPM+XU5S~1v z;yI4d^UdOnqIJZKj^Li0`mjdw1gX8d+37VcsuZVX7$aXB;Q7lGRz5smq33`A;>?X< z!k5o?5JlqQ#)!>Mu@~1#<)RQ5meT+E2z2*aDfI6aRyqc*?ELu8R$%poG*s~dtHQ1< z<25HZaa7d1D-5PSkrC8homqZvt^Zd(L8q6I&Q$p3OlO2Q={k$36IQ$69iiTzaa3mw z3!gt~e_S%m5Wcrh-MaVS*!iEttbDz{LhUo~e0x;k3=GeG?4+VcuR} z2l?tk2a4UHwU%A^ntz2?L*O)}a&>-F%|rcgW0#MaP^Qj5*RA%P%Px0HEO5|`d%4!H zD}OJtqE7MtZ=qU3__5&WJo|S{3S3!t*I}?(lqGKZ!k;l5b9>W-uz~*&!O1DDkO&HGsCaxD%M`Nr&#q#zP_V2YJ$%u^6x{a_shtu=)-fgn=NMT;E>iQYb|yL zU(O^rUO~-){sVmUdu893!ZK&Rq`Hj#Pqa_ltuyq-W1=kAnY#zIoUII)mwutWw>B?Pc$ul+Su`B#FY=2*ZH%Q_q z3cF+dd*zX+5POAyGglsLV=gtK)$fifxhg{c?~|21@7wl<^Xd7p-BG25WyHDr|*1&+_d~k3%{-~G1p~{@5p<2AQRmB zVzwy;>3va2&6t2)Z5ceBA%7Qh3|VY%;K!lQ&xy?h@W|SY=t})O*x@TcywTS>Xp_GG z*;bu*8v41FFx<|zg9}PqjgGX^Mc|Hzpp9>#26=DWmZijFEc()Ovvd4?1{WK}Jl&2hC+@JOZ>367wCFZ;|uz%MT zB36>()INB+RJzRcl3jzu)9Yn{d)j3Q9rD9dGR4;y!aE60K2m9C8IE7eJyZau6C%c` zZZ&vUL~8p##}J#hPbM5WpTw81Q~`I2r|!zO0SkI?-T{=zaf9kEWifKm6~9B4&-GLO zULskXA9v@0s3yc4rQDcB+AE6Vc-U zLb(^`)B>ZCKCy`^yU_0m0_S^eN5-x#T^}4*x6GQ%)L$R!n!^`@yc*0e>qnw&}9;UP_hdR30)bzE*8%`4R;Y#dw0%AYPee9@h_f5~TqhoqN*EU}lo+?bL z&FFkL1W+Xj0N9Cfw6XYU_6vyWcS^{a&3(&lowe{#y# zc0Q#}X2l}PL)dkT-PVjhWCkN1I+FPpHn&3O9hSwHQ{)}ITMlx`(WTQLZBgq7&~;Pn z)}aRJ2AEZQ-eT8yaIuVl`lqovpqt*=mc}0j`XHVFw+<;~<8Y#9#|i$Pjf@xz(n!8Vp!C((|HQ!uqr>w!hm01H30nS?&5% z&~hG%_obPu_^5fu{uM#!f(dEqPmxs`v=K8>xB%31arpRm+Ydx`Um}=OT-CaqIOBDK zCYE9?_9I6S?4vm!rcaLSS|L>wOh}|`=YV{7l;{OvE4j+%S)#|RIM0`-=l%G}$#pvm#c=n;nvx#`QNKRZ zAf$c=h2Auzn=J_7lapT2pPkxCmhHrm0gzqx(reNOYhu^8CBH-ls~Z%`KK*`;=xzuy zXEtry2qq+CbC2G#!nUl0y`|l^F~K;C=_q4uj#2GO*IMJ7&=sL`gF@dDcgEH~vRAj^ zWZBU+|A#O`I(@Ssh7c`wkeK1;p5kNI>9-djp*hgOclGnUyKwfBub=1fu4__ zD9d|4*g;RnwBZ`!E@RobAZ&6SD^QjNP}c59pe!@au3&myaaHm!jkl=m=K8Mx;8u(3qJ!d;2e@<2XwFkP}l`vbb5>7Scz9{|9q9?T!-#vVIS3w{ctIC06^%f zNBwHBD0)U_r@&xrW1G^hxonp1Onad~l1LW^E7Lf#k`Qx6fD@c_S~4bmc#Pk`uU#LI ziXfnzCgG3AkTrm*U9~l**!tWQIk&%GR{=TF)8Fn`TVs5HfhuYCSb!NSmNR6#cvCIz zjDtTbn25S`NRTDg_2o9MgLU zL!U@e_M5_r0YcU%#?S0r=zIt>0lT6D;2k8bP6Y5c&FaLjwGvMSu!JE>ROVG$7|aTf z8taGw=8mSYZEt+-BXCT8ds^r zv|sUpzS84epc+l&lqA@(uzNYhe7CIw8|>)cz+@gz>uI)lvUzBM({6505Ik0XZZ!Q?0bacQwURW_)d_2XDwuUAas7tAe?{c^I%xL0MDM= z$YQ76zPIxwlfWhs2(=T(Z3__w&QQ7rS^mK(2j=O5bjIdYhyXHTXMRpOJ$PEuzgC~` zDEX7?BbXHcIE5M8EAMeJ!yx<$aPUZYrIH^C=!g@+lJ?nAe2fIw9%-isiS6zW0z|Y; z+#K63f_sH}u5=}>X)qT^6eJhw)rc7W#u z%{kjg-dFsfb%#b0T>*+-p)OEq00Ol(kt!$iw5tFycR0RVkBXKX{!=2V9$8)lSeIvf z6L-7s>A|^DKHwN;Xy7M6_L%k8OVtb=I2CI4FzqEk_C#XQ>UwsTh2u~BpWC~M){EfT zsHXrtk8-EgF#6_!8N?B83nApITfzDb2)IP*I&_3ulCR4)!AUrNIChe3Z=m5jPpQ>x%_Z4U-X`vM(MmE?y#Xmnx zamwR6rt>a6`m0tHxw`~_FNmAY_7(NRMzXz)A8O;sY^i zU`q^OUf`fezZ&XH)2+VMDM!RU`3WQPR}mKg?*(LUf#H3Z$CnT2%R=p^zSal1^Q}-6 zc}%a;xthG0ZgzviTqHnP=c_A}(NmtlK+doGbO_HfK5V;4WVcL(rGcV2m0=Kx^y6?A zkFPSYcxf{YnexC}KAIcX@hSit|;uZi7rJ_yKiwpMz~7(Jrovh9Ln&KAVW2f;oIUGR^}oe)>rsICq<+yb9GngbVms zc3ptJv(~;Y&IW963XAtn#BFsAE8FUDXfXV?d;9f|hZY}v?!?2HCUO8CRp+}c~lEsD&!zzUioOZ80y(>6F^;;0N zCvRc^ucQVuoCuhJky8O6yweNs9m{u$@aqB^^HN#D0A(TAczX)4PhlRP${Tx6YI}|T z1mNwqyYBM+3}Rase7ceB78!Zf*28tbZNW`Zv3Y9#s}`RhF9&vg0g55m9->~y=GwUN zshEj!V#goVWZZEK%~jAQKE(r>A%zE$fr9e8Fo&afp)e8v%u!f*aUP$zj`ze3n6&p? zZVeFSNWqguHX|fFE>VL}1R9mOThfaIO@j^%hdSktb`KWii0RiVOhpVZj(gfERHl5U z@JRsyF7&nf!H62*eA-TJlkX23*e>c;R#n&l3%PvkK5oK842Rs+WVI{5o6_dyl)(z{ z;sp4R)W_vppUX&tS8J}HFtRO(GXY#eQ|wMK3tziagM?d1S!Ct-piMz#8N$nd$QDl8 zJ?ho%4urUNyTlb`>-YXb{*PAOXk^_@)iUphq^T(5o#Wtn`9i*uf6lNpj#HP}h&UEv zT>Y@jv_2t^uLX7?K}gBASkE3tJny%O0mmnkyuIrLnrQF0@53dX*D}FkIG!G$h{SF0 z&)^G|xYdFM-6=M6So%=$RD_8kso?1%xA>cN7r1eDQ zY=rR+D3AdAbEC7kenzpnHv}UAA#8&LE^spVwDxVhWgcHU>}sX7+gD2gPV@)*#qVBO zn@;;&$iP+$E!*5z?cL)+KZEpl=%9%m=Z@WC?BmBE;rq0w72X^@4NtAjh(3Q;|H^3+ zI%mwb4j+8_B_a1L7uSS-Z6MnRLkHytm)-e{=BfZT4?3Ul`TlZ%MHDboenT*XPMmCr z817@XN5d3B~zxcJ{p$16y~V$eEa% z>$rcT?0DI`M5X<yGby`ZFD8@(j2wCam;a!eYylsJ;W$%)BLVh#=wsFI(l}mS54(z_l&PvQ z4`ukLmUG5(gQs)2Mz5rZFXZnx-bbh1Kp@uZy>g$^| zM^n_Y(m{S-DutMHv9D6DY{<-}<14YETvOJ>_bU}*$jwB|z1D#klU@4CoZ05semnI0 zeZPJEx%Xbz^Ywfk@6TfoAM0p5AI35FOaPb1g_JkyjE)C1CF+i+WqU$qNisN!&bQWH zJgf&N`-x64S8YeZyaO8&J%mMj6RX$hJjp?+s;|7&y;bbY1Q``&dcv*CiwzQE*Xle;9Z_dGt97!| z`OBYfioc0G$f-a*))KZi?a(wVMkiqG7(p=~WE?ragQgeO2Jy{oAn<`)n_bT1NsZh= z2;Y3XM9)$~d;d{&M&YI_-Zxs71qtQ#VbekwTw)~X-T*hJWAtEhyO>%r$o>BQ%mjt6Qh(!IKee~iOgur))*s1Q++4?)0 z<*qq940Ib<415DGhV8_ku9^Ax5v{Oje zn1U2!dvud%rJ!d)hq!u$Mb!v=68h={&5m5 zi1u$7eC;@SB<69PB=+spa+|J|z#eWyquU>2+bq!?kXzWbIz#6eEavvcwoWr}Q&7zQ zlbeISHaop6a9;f@L;CDc_@tOLj~N~H5C;qMF*{89Bv)q-3#t0vAHRGEP%qy_6iZxN zRh!QpVdE^lUo~i4(3>2%E%S5;$j#QodH3HNC`-{8cC5(yeFX%silRRPY#|yx#bnvH z_M8xm7En>19nwW|El=xo!Hlam&8dnhb$+wo-g0kf2jvpBA$*0AL1>8^V|MkN8AdkR zvFmhXx8=e)kaY|ytIP+h*LK=hypfHanI7+P4w_1{gcerF8p0&7DHNe~rm~PaN6LOy z7apsd``n7X`vgkrzEO=?;L51=&Z-|sI({I}X{s!V9uNUh9b2d4_a~`E-KFj*S>h1y z$oH#8#dE<29_pLKQ>VFFjU>1HD7@*tvs$DEbi%Zkm2?H8a#J#7p=~jzP9rtCR;?>N2d%vE zkTacp*-C1C_MC4N9op>fj$_${vD^l!c}F>8DPLc4s5 zNJXgGRnngq)cvH53#rz;F-3t;QK!M+a~haIIN8*m0VvOv7!DtaAILurH<+YBX{&%{ zeoyYTty$mkOJ?RNu%`P{r@DyXi`>f_$AGI%C>9(EYqJ;73H>c`h49WSc=ztZWRP`c zW=_Nlt#V+_2<7>xaH|#d?So>a-;P*5 zbe=KUy}e`kpN9~-sINW0%ngS_6QTkf#bnyVLqEqTM20c#@>=e=^W3ApE3@pnyWch} z5_$alM1L22y1~ki;~`D+s#=Jdo(xpsyQzJ5E~kuogCe2{>tGKX!~f9BYM->&tv&GM zhWVb|(7nkr#uO9*JnguIfh$2jx5JU-f-QI+#bZ}rp`q6;hKr?5CZGVFJu(I7g=*8Y z?tiwT&q}N@qiqXm7~^SAUM=S+ar##OLL71?6RQ7`8yka26_prqOaAHz zdpK<>)L*?GYI)(xXW$f+wxW5j9LnF6P?|7%UpcA$qCXf5)3DpPNbE3ehQ^0+)yF+8 zSNw69$3nMJBCR?~PS=ma68x5^x$Gyk$ysI7h_dMhxua-5Y}>^4+ppI;+BN5d=y;)-+1?oriXz?&CGx-SV$k`PQsZt4 zVgh~SHueuAyCdi}$b1Kv6?IQ6Y_6TZ9D9~?aiEIy9{u93M)xpjT3Zs{`k)pMklk(T z;fhjbC`vipXE5~<^Q9)x?sKGI8RyTFIH-?d`F*NpAwwF0YN6PL7&eXRdu$dAzTk`< z)U0$Z`6m#D-O={AyjTHcXrBV!uX1>QvtR@xvyT3cUCvOXaL>S_-f{L*p~0kyWlBnV zs?XJP5~;rD>I6(e@Wyy%zB>^ec_wx8wHpb2kxT^LlrB5jk&pD zEamv$BiQ>02`}p%V06ZUK3>pZb}wucb%y@j^az}Q?z+@sj495=w#1Hq_hv%j4VJ$Iumi>SMkE{KyL){DY`>! z9#ixPJJy9cGyb2DPtS}Sw24d13dI%PY6`nE3W~zAsjsn})5|pu@jNnYzvR8M91ZC} zM<)K5)3TWF_4d-PKQ7 z>{@I{QP5hfptbLvy0-(vJi^#P9_*2wLFmgSe{!`=Oy#A2ftR+kuXgnp8^N}x`{g~T zRYTr`3~go(Tu>W`ddg{m@afEk_dogXo!eFVW5F6W>03rSp~BS=Xx82w1@L$U@UF+R zG7?jnaL&3=Z5Q7fLmHI+N$dE7jDK+z9&d-Qb4G;+P*K#qujJCkDvHpj{y2Uh%r|Fd z2fsb(kDL6Y?Nd?rc62~TySXH?qi`_jJ??w*=IeB^PU_Wrjgxyw`(VY?WFzPI2q z;l(3}>^V2+dLHBpyW~GnA1kfgz4&lGW~&_R%AZu^iEiJD%c>4=grwV<7cSH@xFqI!ObdP6Y*YjZ-jz8AB z_ZcDy<}?+m7Rx+PYAR<=jEa0%yJoh-(lW}>WOwJh1;3EC=^Fj4w*wAh%3q(H5B!K^ z2dFRLyy=(r+Rut+<*`-)!nb${uk(c<3~cGFJH-q-7onCF^K_+P=Z|Fr^+Zj*O3FoA z@bFm*@)@sE(5K3iH*v9|aBpjlMzEekDFPXaRWtB)Ug})UFh>@h!Q-VaWJL9;dhK>&dDhG=N@-@KdsJ znSzZ*-s;Kv-~-GO&7H&%BOvr7^Chem;_emmVsf+5cV)Q^2r60mE1vJ|_SK z1BIJ3PB-nKZ2joSYchht#{$`DDd9yQY*3GivqB^0#J{LbV&~+T+EF*#4@1y_{+Jpp21u5`h)<$ldnNq_!jBd1CwQ} zKcx-}cM35z6L&^j^m(xAkC5A9d;#jrV^%V)z0OMd6AN8hsme^AvX0sa_U|#C8)f*<_oemiZS zjMTtMoyLQbu}90MAh*#E#l~jYwoxU)5K?Y_$C!AzBXc=u@d77 zy(!ki_Xu_y@}(=s?8Y~6<@wffA!$%|nsuW)Tl#uG>%_gW^!b>|wK^&n#&^FG$<;-;Zn@S1QBk>IFlW6{OuizgY5MyoswxpI?nS|dd2l50V_#0XTTq$? z^w*B@z@WC|)$V&DG8=alsi+(vnA`sqDP2!6^;1y^+Pnz7%VM(tG2CtSuRyf3@uHmc z=oVUgac!sjL+TXUirk+AMzpk5hPKdFs?_t_a86vHe?XzkV87fTliOU#^hg^PemM=& zH7QW>YIcl|_l;8P+vdcZ2@JAhU@wbZQXq@sV@>1)6%~zm{OhB2e4YM8rb$QOTNRa4 zCUc7^b{iMQk4H@EO1Hj|&W;vlv_0x+qk^JG>8!)e?$H>-uXZz)F7a*pCbkJF9^&nd zBpt_A);qcs1xZv_xlXgr$Q7?&a_Bm)D#}~DNh%RJq-4(&*s3nlspW^ZsXTcw0@%m7 zIn#^h;=R|bS|@+sV11R9G{wu-?r0TG0YP+QqjDRfdRC%x4ZnrhA`4_k~)Sno(;Z zd4W}OCU}~p{tgLt&x&frHNKP4O0J=7M4jZD7yrHqDnKyYC7xm-mm9+kPCYK#A*4-t z@V-=nn61q#rOoIpUJ16Que>9n#lmcm^QrSOIZBB3W=70i`WXHxKD#M?44ZQE8mPE0 z5A$m<`aa(`fW|a2{HO@@`fN5!W8MQ~ZhRipK=fJIp{M>n4j&dxCQwon`L7!Ercn1e61H@eUm3t$E#>)B%XJ7Su!D20Kx_%u39Flpn zw#PM93G(|r)^Fg=>iW57%l1-UV3!3`Iwye{fHTF1l$m+DdC_hg+B?MGR#kdG@$r0W zg!3>g1}WH<7NiVZB!k?p)HSYJ)3-3F-|Ox#eF1^f7D9FZy~>n$FaQ&J_2kYO~jVmp{ZI!>Iw{YpvBiS)BW_{77R!E%jM9^U)3lE|=M z$zEh|j8&v(0w9bLv_%LJuJbolcsYchoSCY1u;L)fj4B;UU7G@_q0Yfd2XV3h{d4ZL zyoJybqM%e%6eS4O}Q4X>YnlNJM_+EXH=)Z^mP5G}f^%^v^vxY3I&qDCN~IzXSgr1!l~zI5 zx+nt~Me*B!OR%98upQ;Bhn8W{ajz3~ljCY+Ce@WDqh4yR1zTGQO8Rk?CbYq+xa;GU z(Y-g7#M2|>5({M(h4X318UPV#=`sw7Dc;^jWLgF+F(A>pnz%yH1foS~7}EyM`#@41 z1$t#Z%CyjAX>pOIWf9NO8b4OrKYiVIP!ro40Pql0s)Q;6(j` z42U360i}v4B>@E#6hSGGa_Lecy+nGI;-!f+g&@-3hGCu|&->1QnaNis-=5u>%50Y(vET-#*%@0GF!4s+0x0;)(85RWe_C2obiw#T8y4dc^*sn)HT3}{ z&M8?odb=Pjp{nu0!b5-K=+GbSH9)5K+0_}=PeDX~=7?JzncZ~5b`;=?V_WNF5OmO zoqx;iH-ZTe$lZ>-S|y1x`Mv zKQolT*yaQmXc^ZE^M~TI3f)pTZmZOJ(;BelED#KB6>TOSSZ3&|2#Snas=W*Aw40%t ztmK98bkd$a=R^N)Jb|us9U+e~hS;bp7@BY)LEq`-wCf6{fm$FAyrpg|xzRR*W0GVO0fU3lg zX!XiWNsp#M@V(`W9eSyQmPK(VhUMli=}P57+6M{x^Ls~-9%^by16o>Z^vSgPpoec4 z+N>7c%{K1kV)`-{Hbd)uuPS@RWJ`BBEylqjb9Aa#g)qOm`J-5Pazz99oJoR0p;=$nb@h1zHBm0uhqw|^A#IEvU z5ZbfuH;(5_YM-pU#TWJ+)(kJLvCuZ?O~42ZKe^E?T|UfPxj20nE?$e8fzo~9?O2Os zRrciC)D2l3X!N5(E1qxoX=Chol29_b;gUL+$M#?~_*Gly2pTUS(2)PqgkeAtI%=16 zt2FZSnKJ%&f#Zf>g!$9wo4;ZaQcKn66MdCxXu~+=P|FbG@ME#Ur^Glq^ra`XYG%F$ zEZQLr6x@WxqJykGn!i4i36+VGNm&8k_p}@aYw~<(NcrfST?EUPQ!B^=o{uq+Nhe^u zFxPb0lDs~JHV!M=+`Xeoy_@EBf5&v8kn(*d7_u5XGdiKvBvoj16;adPhaSl?{%Y5a za7)q?Jg49P3?HI=BnwtLaZM!uk|6G4P#x?u2j@b2=hMu)bVda0GHNnr5%|zkkm8nZ|{3#yU7+zX>wK;;rPKw zMRorEuS?Jmv}LC~@Srlr(TNeRai&dFhxb1c%jSeWhM(_TroWwK#fxm0i@)iiuZmmr zHd+xmN1wo*+Awt5`IeAYoyCkg3&F{qGZpwm>8(Fgn)v2sl@yyMb(!bHtfhw|&I zlHCn#^3}Q4*Z5Yty1;u0VH`zE6{)Lu2|{4v1tGO!cbAp!&L;^M+AB6D8iO*G{Qcd` z6KAPRH+3m{)XsQ_oNIbGDjGc+{Ijh$vCKB2HPE`Uq4ex)wesCJ##Wn`LOXF3jNHYT ziejIJz7J~>Ii6N?338ll-66J4gW0D3R^~-2*LA8qlZQL)yVe@?Rtg<>*}`MXT~q9; zanZ^N7YGfLv+;~?E#3@L9(4EPh2_BsZ9?RKs*i ztv;UD%*q6Lt*s3OoDx&hF9llx|4?>u>Ep`&!C2ie^BY z8NtcoJiW24{n=TTVo!|K`LeRj_4R8h5kf(a&F3Spq)QG5iLwfHq3t^2^V8A-;+bw0 z&E+?66C5Zg}~U^oX52y*xTArM5*)mj4}-~pu2&NRRqj)W1d!oSU0 z01=9D2fWL_!X_(uic#G_;eCo_polTHG5Ph0F=xZ{ojXuH@e0kOT{Z$rUNax$rLQPg zz&KNb)FWDl9>HE~pzkM2T9mX8ju3pjJK`d6GwMoo9M%_|OM$l*e5d)L3GPmfGZDLC zt0J@Zn)<0!db(dim~=;sZc0ssiv-&-gj?7sM%(+`XQSeZT}o%9i)n$aR%hUozT1k6 zJ_+&>aBBG&SKH|F_bhintEu7`+M1)UT6{9AJFCNg0dj2~0fIHvm#_Q?8emQ@Fut8> zdo1zei_t)%NIV&WJy|K^*T$RSlH3t^1Uv|)bHHJCx_7dgGTHCfU zK5daZWdws}8WbOlj(ajceP(F6;CX0sxA6o9l6#yYbIgIO2 zs2`A%#AGAMu`h>_CklI))H@5dY@Uj1>=$Ja-J>fZqSgy~ScGVMV;67K5@L?izcP8E3mNjOmc z@&A;+PygTMJ$+3b9NqVgRPyqqx-{fac^zOX`|Trr1Ki<%EKbTV69MYq>p8GT|Ba(2 zZ-LYXCT{KDtCW>I%O9@)L8CrA_g2^1!8hLoQ@+>8r5DLK1OZU1Q?q}b}= zc}4+05#R$JxV{HwEqQ%Xb?|WbD96D(fE@qzS;@mmDLo=h_ 3.17.0' + gem 'docusign_esign', ' ~> 3.22.0' end class ESign diff --git a/quick_acg/Gemfile b/quick_acg/Gemfile index eafa580..0d43063 100644 --- a/quick_acg/Gemfile +++ b/quick_acg/Gemfile @@ -3,14 +3,14 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '~>3.0.2' +ruby '~>3.1.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 6.0.4.1' +gem 'rails', '~> 7.0.4.3' # Use sqlite3 as the database for Active Record -gem 'sqlite3', '~> 1.4.2' +gem 'sqlite3', '~> 1.6.1' # Use Puma as the app server -gem 'puma', '~> 4.3.9' +gem 'puma', '~> 6.1.1' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets @@ -23,7 +23,7 @@ gem 'coffee-rails', '~> 5.0.0' # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks gem 'turbolinks', '~> 5.2.1' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder -gem 'jbuilder', '~> 2.10.0' +gem 'jbuilder', '~> 2.11.5' # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 4.0' # Use ActiveModel has_secure_password @@ -44,32 +44,33 @@ end group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console - gem 'byebug', '~> 11.1.1', platforms: %i[mri mingw x64_mingw] + gem 'byebug', '~> 11.1.3', platforms: %i[mri mingw x64_mingw] end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. - gem 'listen', '~> 3.7.0' - gem 'web-console', '~> 4.0.1' + gem 'listen', '~> 3.8.0' + gem 'web-console', '~> 4.2.0' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring - gem 'pry-nav', '~> 0.3.0' + gem 'pry-nav', '~> 1.0.0' gem 'pry-rails', '~> 0.3.9' - gem 'spring', '~> 2.1.0' - gem 'spring-watcher-listen', '~> 2.0.1' + gem 'spring', '~> 4.1.1' + gem 'spring-watcher-listen', '~> 2.1.0' end group :test do # Adds support for Capybara system testing and selenium driver - gem 'capybara', '~> 3.31.0' - gem 'selenium-webdriver', '~> 3.142.7' + gem 'capybara', '~> 3.38.0' + gem 'selenium-webdriver', '~> 4.8.1' # Easy installation and use of chromedriver to run system tests with Chrome gem 'chromedriver-helper', '~> 2.1.1' + gem 'test-unit' end -gem 'docusign_esign', '~> 3.21.0' -gem 'omniauth-oauth2', '~> 1.7.1' +gem 'docusign_esign', '~> 3.22.0' +gem 'omniauth-oauth2', '~> 1.8.0' gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem 'tzinfo-data', '~> 1.2019.3', platforms: %i[mingw mswin x64_mingw jruby] -gem 'wdm', '>= 0.1.0', platforms: %i[mingw mswin x64_mingw] +gem 'tzinfo-data', '~> 1.2022.7', '>= 1.2022.7' +gem 'wdm', '>= 0.1.1', platforms: %i[mingw mswin x64_mingw] diff --git a/quick_acg/Gemfile.lock b/quick_acg/Gemfile.lock index 7602786..30e4a57 100644 --- a/quick_acg/Gemfile.lock +++ b/quick_acg/Gemfile.lock @@ -1,63 +1,73 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.4.8) - actionpack (= 6.0.4.8) + actioncable (7.0.4.3) + actionpack (= 7.0.4.3) + activesupport (= 7.0.4.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.4.8) - actionpack (= 6.0.4.8) - activejob (= 6.0.4.8) - activerecord (= 6.0.4.8) - activestorage (= 6.0.4.8) - activesupport (= 6.0.4.8) + actionmailbox (7.0.4.3) + actionpack (= 7.0.4.3) + activejob (= 7.0.4.3) + activerecord (= 7.0.4.3) + activestorage (= 7.0.4.3) + activesupport (= 7.0.4.3) mail (>= 2.7.1) - actionmailer (6.0.4.8) - actionpack (= 6.0.4.8) - actionview (= 6.0.4.8) - activejob (= 6.0.4.8) + net-imap + net-pop + net-smtp + actionmailer (7.0.4.3) + actionpack (= 7.0.4.3) + actionview (= 7.0.4.3) + activejob (= 7.0.4.3) + activesupport (= 7.0.4.3) mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp rails-dom-testing (~> 2.0) - actionpack (6.0.4.8) - actionview (= 6.0.4.8) - activesupport (= 6.0.4.8) - rack (~> 2.0, >= 2.0.8) + actionpack (7.0.4.3) + actionview (= 7.0.4.3) + activesupport (= 7.0.4.3) + rack (~> 2.0, >= 2.2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.4.8) - actionpack (= 6.0.4.8) - activerecord (= 6.0.4.8) - activestorage (= 6.0.4.8) - activesupport (= 6.0.4.8) + actiontext (7.0.4.3) + actionpack (= 7.0.4.3) + activerecord (= 7.0.4.3) + activestorage (= 7.0.4.3) + activesupport (= 7.0.4.3) + globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (6.0.4.8) - activesupport (= 6.0.4.8) + actionview (7.0.4.3) + activesupport (= 7.0.4.3) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.4.8) - activesupport (= 6.0.4.8) + activejob (7.0.4.3) + activesupport (= 7.0.4.3) globalid (>= 0.3.6) - activemodel (6.0.4.8) - activesupport (= 6.0.4.8) - activerecord (6.0.4.8) - activemodel (= 6.0.4.8) - activesupport (= 6.0.4.8) - activestorage (6.0.4.8) - actionpack (= 6.0.4.8) - activejob (= 6.0.4.8) - activerecord (= 6.0.4.8) - marcel (~> 1.0.0) - activesupport (6.0.4.8) + activemodel (7.0.4.3) + activesupport (= 7.0.4.3) + activerecord (7.0.4.3) + activemodel (= 7.0.4.3) + activesupport (= 7.0.4.3) + activestorage (7.0.4.3) + actionpack (= 7.0.4.3) + activejob (= 7.0.4.3) + activerecord (= 7.0.4.3) + activesupport (= 7.0.4.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.4.3) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - zeitwerk (~> 2.2, >= 2.2.2) - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) archive-zip (0.12.0) io-like (~> 0.3.0) bindex (0.8.1) @@ -65,15 +75,15 @@ GEM msgpack (~> 1.0) builder (3.2.4) byebug (11.1.3) - capybara (3.31.0) + capybara (3.38.0) addressable + matrix mini_mime (>= 0.1.3) nokogiri (~> 1.8) rack (>= 1.6.0) rack-test (>= 0.6.3) - regexp_parser (~> 1.5) + regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - childprocess (3.0.0) chromedriver-helper (2.1.1) archive-zip (~> 0.10) nokogiri (~> 1.8) @@ -85,210 +95,223 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.1.10) + concurrent-ruby (1.2.2) crass (1.0.6) - docusign_esign (3.19.0) + date (3.3.3) + docusign_esign (3.22.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - erubi (1.10.0) + erubi (1.12.0) ethon (0.16.0) ffi (>= 1.15.0) execjs (2.8.1) - faraday (2.3.0) - faraday-net_http (~> 2.0) + faraday (2.7.4) + faraday-net_http (>= 2.0, < 3.1) ruby2_keywords (>= 0.0.4) - faraday-net_http (2.0.3) - ffi (1.15.5) - ffi (1.15.5-x64-mingw32) - globalid (1.0.1) + faraday-net_http (3.0.2) + ffi (1.15.5-x64-mingw-ucrt) + globalid (1.1.0) activesupport (>= 5.0) hashie (5.0.0) i18n (1.12.0) concurrent-ruby (~> 1.0) io-like (0.3.1) - jbuilder (2.10.2) + jbuilder (2.11.5) + actionview (>= 5.0.0) activesupport (>= 5.0.0) - json (2.6.2) - jwt (2.4.1) - listen (3.7.1) + json (2.6.3) + jwt (2.7.0) + listen (3.8.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) loofah (2.19.1) crass (~> 1.0.2) nokogiri (>= 1.5.9) - mail (2.7.1) + mail (2.8.1) mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp marcel (1.0.2) - method_source (0.9.2) + matrix (0.4.2) + method_source (1.0.0) mini_mime (1.1.2) - minitest (5.17.0) - msgpack (1.5.3) + minitest (5.18.0) + msgpack (1.6.1) multi_xml (0.6.0) + net-imap (0.3.4) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.1) + timeout + net-smtp (0.3.3) + net-protocol nio4r (2.5.8) - nokogiri (1.13.10-x64-mingw32) + nokogiri (1.14.2-x64-mingw-ucrt) racc (~> 1.4) - nokogiri (1.13.10-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.13.10-x86_64-linux) - racc (~> 1.4) - oauth2 (2.0.5) + oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) jwt (>= 1.0, < 3.0) multi_xml (~> 0.5) - rack (>= 1.2, < 3) - rash_alt (>= 0.4, < 1) + rack (>= 1.2, < 4) + snaky_hash (~> 2.0) version_gem (~> 1.1) - omniauth (2.1.0) + omniauth (2.1.1) hashie (>= 3.4.6) rack (>= 2.2.3) rack-protection - omniauth-oauth2 (1.7.3) + omniauth-oauth2 (1.8.0) oauth2 (>= 1.4, < 3) - omniauth (>= 1.9, < 3) + omniauth (~> 2.0) omniauth-rails_csrf_protection (1.0.1) actionpack (>= 4.2) omniauth (~> 2.0) - pry (0.12.2) - coderay (~> 1.1.0) - method_source (~> 0.9.0) - pry-nav (0.3.0) - pry (>= 0.9.10, < 0.13.0) + power_assert (2.0.3) + pry (0.14.2) + coderay (~> 1.1) + method_source (~> 1.0) + pry-nav (1.0.0) + pry (>= 0.9.10, < 0.15) pry-rails (0.3.9) pry (>= 0.10.4) - public_suffix (4.0.7) - puma (4.3.12) + public_suffix (5.0.1) + puma (6.1.1) nio4r (~> 2.0) - racc (1.6.1) - rack (2.2.4) - rack-protection (2.2.0) + racc (1.6.2) + rack (2.2.6.4) + rack-protection (3.0.5) rack - rack-test (2.0.2) + rack-test (2.1.0) rack (>= 1.3) - rails (6.0.4.8) - actioncable (= 6.0.4.8) - actionmailbox (= 6.0.4.8) - actionmailer (= 6.0.4.8) - actionpack (= 6.0.4.8) - actiontext (= 6.0.4.8) - actionview (= 6.0.4.8) - activejob (= 6.0.4.8) - activemodel (= 6.0.4.8) - activerecord (= 6.0.4.8) - activestorage (= 6.0.4.8) - activesupport (= 6.0.4.8) - bundler (>= 1.3.0) - railties (= 6.0.4.8) - sprockets-rails (>= 2.0.0) + rails (7.0.4.3) + actioncable (= 7.0.4.3) + actionmailbox (= 7.0.4.3) + actionmailer (= 7.0.4.3) + actionpack (= 7.0.4.3) + actiontext (= 7.0.4.3) + actionview (= 7.0.4.3) + activejob (= 7.0.4.3) + activemodel (= 7.0.4.3) + activerecord (= 7.0.4.3) + activestorage (= 7.0.4.3) + activesupport (= 7.0.4.3) + bundler (>= 1.15.0) + railties (= 7.0.4.3) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.4.4) + rails-html-sanitizer (1.5.0) loofah (~> 2.19, >= 2.19.1) - railties (6.0.4.8) - actionpack (= 6.0.4.8) - activesupport (= 6.0.4.8) + railties (7.0.4.3) + actionpack (= 7.0.4.3) + activesupport (= 7.0.4.3) method_source - rake (>= 0.8.7) - thor (>= 0.20.3, < 2.0) + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) rake (13.0.6) - rash_alt (0.4.12) - hashie (>= 3.4) - rb-fsevent (0.11.1) + rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - regexp_parser (1.8.2) + regexp_parser (2.7.0) + rexml (3.2.5) ruby2_keywords (0.0.5) rubyzip (2.3.2) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) sassc (2.4.0) ffi (~> 1.9) - sassc (2.4.0-x64-mingw32) - ffi (~> 1.9) sassc-rails (2.1.2) railties (>= 4.0.0) sassc (>= 2.0) sprockets (> 3.0) sprockets-rails tilt - selenium-webdriver (3.142.7) - childprocess (>= 0.5, < 4.0) - rubyzip (>= 1.2.2) - spring (2.1.1) - spring-watcher-listen (2.0.1) + selenium-webdriver (4.8.1) + rexml (~> 3.2, >= 3.2.5) + rubyzip (>= 1.2.2, < 3.0) + websocket (~> 1.0) + snaky_hash (2.0.1) + hashie + version_gem (~> 1.1, >= 1.1.1) + spring (4.1.1) + spring-watcher-listen (2.1.0) listen (>= 2.7, < 4.0) - spring (>= 1.2, < 3.0) - sprockets (4.1.1) + spring (>= 4) + sprockets (4.2.0) concurrent-ruby (~> 1.0) - rack (> 1, < 3) + rack (>= 2.2.4, < 4) sprockets-rails (3.4.2) actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) - sqlite3 (1.4.4) + sqlite3 (1.6.1-x64-mingw-ucrt) + test-unit (3.5.7) + power_assert thor (1.2.1) - thread_safe (0.3.6) - tilt (2.0.10) + tilt (2.1.0) + timeout (0.3.2) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) typhoeus (1.4.0) ethon (>= 0.9.0) - tzinfo (1.2.10) - thread_safe (~> 0.1) - tzinfo-data (1.2019.3) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + tzinfo-data (1.2022.7) tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) - version_gem (1.1.0) - wdm (0.1.1) - web-console (4.0.4) + version_gem (1.1.2) + web-console (4.2.0) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) + websocket (1.2.9) websocket-driver (0.7.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.6) + zeitwerk (2.6.7) PLATFORMS - x64-mingw32 - x86_64-darwin-21 - x86_64-linux + x64-mingw-ucrt DEPENDENCIES bootsnap (~> 1.7.3) - byebug (~> 11.1.1) - capybara (~> 3.31.0) + byebug (~> 11.1.3) + capybara (~> 3.38.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_esign (~> 3.19.0) - jbuilder (~> 2.10.0) - listen (~> 3.7.0) - omniauth-oauth2 (~> 1.7.1) + docusign_esign (~> 3.22.0) + jbuilder (~> 2.11.5) + listen (~> 3.8.0) + omniauth-oauth2 (~> 1.8.0) omniauth-rails_csrf_protection - pry-nav (~> 0.3.0) + pry-nav (~> 1.0.0) pry-rails (~> 0.3.9) - puma (~> 4.3.9) - rails (~> 6.0.4.1) + puma (~> 6.1.1) + rails (~> 7.0.4.3) sass-rails (~> 6.0.0) - selenium-webdriver (~> 3.142.7) - spring (~> 2.1.0) - spring-watcher-listen (~> 2.0.1) - sqlite3 (~> 1.4.2) + selenium-webdriver (~> 4.8.1) + spring (~> 4.1.1) + spring-watcher-listen (~> 2.1.0) + sqlite3 (~> 1.6.1) + test-unit turbolinks (~> 5.2.1) - tzinfo-data (~> 1.2019.3) + tzinfo-data (~> 1.2022.7, >= 1.2022.7) uglifier (~> 4.2.0) - wdm (>= 0.1.0) - web-console (~> 4.0.1) + wdm (>= 0.1.1) + web-console (~> 4.2.0) RUBY VERSION - ruby 3.0.2p107 + ruby 3.1.2p20 BUNDLED WITH - 2.2.22 + 2.3.7 diff --git a/quick_acg/config/application.rb b/quick_acg/config/application.rb index bc611cc..cd7f547 100644 --- a/quick_acg/config/application.rb +++ b/quick_acg/config/application.rb @@ -12,7 +12,7 @@ class Application < Rails::Application # in config/environments/development.rb, production.rb, test.rb, etc config.app_url = 'http://localhost:3000' # The public url of the application. # Init DocuSign configuration, loaded from config/appsettings.yml file - DOCUSIGN_CONFIG = YAML.load_file(File.expand_path(File.join(Rails.root.to_s, '../config/appsettings.yml')))[Rails.env] + DOCUSIGN_CONFIG = YAML.load_file(File.join(Rails.root, '../config/appsettings.yml'), aliases: true)[Rails.env] DOCUSIGN_CONFIG.map do |k, v| config.send("#{k}=", v) end From 3cbc167129202ac80c78e5697fb91144ff785a6d Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 27 Apr 2023 11:10:01 -0700 Subject: [PATCH 190/363] Trying to see if we can have two snippets with the same code in Ruby for codeDepo (DEVDOCS-10346) --- app/services/api_creator.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/services/api_creator.rb b/app/services/api_creator.rb index 4f42a63..b9d5318 100644 --- a/app/services/api_creator.rb +++ b/app/services/api_creator.rb @@ -33,11 +33,15 @@ def create_template_api(args) def create_envelope_api(args) # Obtain your OAuth token # Step 2 start + #ds-snippet-start eSign29Step2 + #ds-snippet-start eSign28Step2 configuration = DocuSign_eSign::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_eSign::ApiClient.new configuration api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" + #ds-snippet-end eSign28Step2 + #ds-snippet-end eSign29Step2 # Step 2 end DocuSign_eSign::EnvelopesApi.new api_client end From 8e915734fc5c23100d6f295bd7b99251c0a1579f Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 27 Apr 2023 11:11:17 -0700 Subject: [PATCH 191/363] Fixing DEVDOCS-10346 --- app/services/api_creator.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/services/api_creator.rb b/app/services/api_creator.rb index b9d5318..d169000 100644 --- a/app/services/api_creator.rb +++ b/app/services/api_creator.rb @@ -34,13 +34,11 @@ def create_envelope_api(args) # Obtain your OAuth token # Step 2 start #ds-snippet-start eSign29Step2 - #ds-snippet-start eSign28Step2 configuration = DocuSign_eSign::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_eSign::ApiClient.new configuration api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" - #ds-snippet-end eSign28Step2 #ds-snippet-end eSign29Step2 # Step 2 end DocuSign_eSign::EnvelopesApi.new api_client From 9d2b66f08d97954c497acb87b853e58178488300 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Fri, 28 Apr 2023 09:58:05 -0700 Subject: [PATCH 192/363] Fixing codeDepot --- app/services/api_creator.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/api_creator.rb b/app/services/api_creator.rb index d169000..884829d 100644 --- a/app/services/api_creator.rb +++ b/app/services/api_creator.rb @@ -33,13 +33,13 @@ def create_template_api(args) def create_envelope_api(args) # Obtain your OAuth token # Step 2 start - #ds-snippet-start eSign29Step2 + #ds-snippet-start:eSign29Step2 configuration = DocuSign_eSign::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_eSign::ApiClient.new configuration api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" - #ds-snippet-end eSign29Step2 + #ds-snippet-end:eSign29Step2 # Step 2 end DocuSign_eSign::EnvelopesApi.new api_client end From 92736b99b4c23c73a709958d95ca9ad96a3011b9 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Wed, 3 May 2023 16:53:17 +0300 Subject: [PATCH 193/363] update rubocop config --- .rubocop.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.rubocop.yml b/.rubocop.yml index 33c44d9..acc84a5 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -10,6 +10,9 @@ AllCops: Layout/EndOfLine: Enabled: false +Layout/LeadingCommentSpace: + Enabled: false + Layout/LineLength: Enabled: false From 5ee0411f44a68a8bc9c4469f9136d5a0867acbac Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 4 May 2023 09:52:18 -0700 Subject: [PATCH 194/363] DEVDOCS-10618 adding codeDepot markets for Click1 for Ruby --- app/services/clickwrap/eg001_create_clickwrap_service.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/services/clickwrap/eg001_create_clickwrap_service.rb b/app/services/clickwrap/eg001_create_clickwrap_service.rb index 1203bca..ac63f09 100644 --- a/app/services/clickwrap/eg001_create_clickwrap_service.rb +++ b/app/services/clickwrap/eg001_create_clickwrap_service.rb @@ -9,13 +9,16 @@ def initialize(args) def worker # Step 2. Construct your API headers + #ds-snippet-start:click1Step2 configuration = DocuSign_Click::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_Click::ApiClient.new configuration api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:click1Step2 # Step 3. Construct the request body + #ds-snippet-start:click1Step3 # Create the display settings display_settings = DocuSign_Click::DisplaySettings.new( consentButtonText: 'I Agree', @@ -50,9 +53,12 @@ def worker name: args[:clickwrap_name], requireReacceptance: true ) + #ds-snippet-end:click1Step3 # Step 4. Call the Click API + #ds-snippet-start:click1Step4 account_api = DocuSign_Click::AccountsApi.new(api_client) account_api.create_clickwrap(args[:account_id], clickwrap_request) + #ds-snippet-end:click1Step4 end end From 33c1981cefe3c6501ff64a0e73ab1813c88a6a7f Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 4 May 2023 09:54:45 -0700 Subject: [PATCH 195/363] DEVDOCS-10618, fixing capitalization of snippet name --- .../clickwrap/eg001_create_clickwrap_service.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/services/clickwrap/eg001_create_clickwrap_service.rb b/app/services/clickwrap/eg001_create_clickwrap_service.rb index ac63f09..3b224bc 100644 --- a/app/services/clickwrap/eg001_create_clickwrap_service.rb +++ b/app/services/clickwrap/eg001_create_clickwrap_service.rb @@ -9,16 +9,16 @@ def initialize(args) def worker # Step 2. Construct your API headers - #ds-snippet-start:click1Step2 + #ds-snippet-start:Click1Step2 configuration = DocuSign_Click::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_Click::ApiClient.new configuration api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - #ds-snippet-end:click1Step2 + #ds-snippet-end:Click1Step2 # Step 3. Construct the request body - #ds-snippet-start:click1Step3 + #ds-snippet-start:Click1Step3 # Create the display settings display_settings = DocuSign_Click::DisplaySettings.new( consentButtonText: 'I Agree', @@ -53,12 +53,12 @@ def worker name: args[:clickwrap_name], requireReacceptance: true ) - #ds-snippet-end:click1Step3 + #ds-snippet-end:Click1Step3 # Step 4. Call the Click API - #ds-snippet-start:click1Step4 + #ds-snippet-start:Click1Step4 account_api = DocuSign_Click::AccountsApi.new(api_client) account_api.create_clickwrap(args[:account_id], clickwrap_request) - #ds-snippet-end:click1Step4 + #ds-snippet-end:Click1Step4 end end From ae0b8970c96df1d17e1b046a18dd153e471d08b9 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Thu, 4 May 2023 12:18:25 -0700 Subject: [PATCH 196/363] update SMS delivery code example (#125) * update SMS delivery code example --- app/services/e_sign/eg037_sms_delivery_service.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/services/e_sign/eg037_sms_delivery_service.rb b/app/services/e_sign/eg037_sms_delivery_service.rb index e2b6a9f..5a13ffd 100644 --- a/app/services/e_sign/eg037_sms_delivery_service.rb +++ b/app/services/e_sign/eg037_sms_delivery_service.rb @@ -88,6 +88,8 @@ def make_envelope(envelope_args) signer1.name = envelope_args[:signer_name] signer1.recipient_id = '1' signer1.routing_order = '1' + signer1.delivery_method = 'SMS' + ## 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 @@ -102,6 +104,7 @@ def make_envelope(envelope_args) cc1.routing_order = '2' cc1.recipient_id = '2' cc1.phone_number = cc_phone_number + cc1.delivery_method = 'SMS' # Create signHere fields (also known as tabs) on the documents # We're using anchor (autoPlace) positioning From d10542f30c92172e12c1daf43ba932f8bbcdd2a9 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Wed, 10 May 2023 11:46:35 -0700 Subject: [PATCH 197/363] DEVDOCS-10346, adding codeDepot markers --- .../e_sign/eg029_brands_apply_to_envelope_service.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb b/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb index fada571..7018124 100644 --- a/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb +++ b/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb @@ -15,14 +15,18 @@ def worker # Step 2. Construct your API headers envelope_api = create_envelope_api(args) # Step 3: Construct your envelope JSON body + #ds-snippet-start:eSign29Step3 envelope_definition = make_envelope(args[:envelope_args]) + #ds-snippet-end:eSign29Step3 # Step 4. Call the eSignature REST API + #ds-snippet-start:eSign29Step4 envelope_api.create_envelope args[:account_id], envelope_definition - # ***DS.snippet.0.end + #ds-snippet-end:eSign29Step4 end private + #ds-snippet-start:eSign29Step3 def make_envelope(envelope_args) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_blurb = 'Sample text for email body' @@ -80,4 +84,5 @@ def make_envelope(envelope_args) envelope_definition.status = envelope_args[:status] envelope_definition end + #ds-snippet-end:eSign29Step3 end From e9ebda5dbdf6eaa419072ae17120a855f51b9b97 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Wed, 10 May 2023 11:58:11 -0700 Subject: [PATCH 198/363] Adding comments --- .../e_sign/eg029_brands_apply_to_envelope_service.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb b/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb index fada571..7018124 100644 --- a/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb +++ b/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb @@ -15,14 +15,18 @@ def worker # Step 2. Construct your API headers envelope_api = create_envelope_api(args) # Step 3: Construct your envelope JSON body + #ds-snippet-start:eSign29Step3 envelope_definition = make_envelope(args[:envelope_args]) + #ds-snippet-end:eSign29Step3 # Step 4. Call the eSignature REST API + #ds-snippet-start:eSign29Step4 envelope_api.create_envelope args[:account_id], envelope_definition - # ***DS.snippet.0.end + #ds-snippet-end:eSign29Step4 end private + #ds-snippet-start:eSign29Step3 def make_envelope(envelope_args) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_blurb = 'Sample text for email body' @@ -80,4 +84,5 @@ def make_envelope(envelope_args) envelope_definition.status = envelope_args[:status] envelope_definition end + #ds-snippet-end:eSign29Step3 end From 98395d3bbbaf656e3219735bee711cb9965e2196 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Wed, 10 May 2023 23:37:36 +0300 Subject: [PATCH 199/363] added example (#126) shared access code example --- Gemfile | 2 +- Gemfile.lock | 4 +- .../e_sign/eeg043_shared_access_controller.rb | 107 ++++++++++++++++++ app/controllers/eg_controller.rb | 4 +- .../e_sign/eg043_shared_access_service.rb | 94 +++++++++++++++ app/services/utils.rb | 12 ++ app/views/ds_common/example_done.erb | 6 +- .../e_sign/eeg043_shared_access/get.html.erb | 30 +++++ config/routes.rb | 6 + 9 files changed, 259 insertions(+), 6 deletions(-) create mode 100644 app/controllers/e_sign/eeg043_shared_access_controller.rb create mode 100644 app/services/e_sign/eg043_shared_access_service.rb create mode 100644 app/views/e_sign/eeg043_shared_access/get.html.erb diff --git a/Gemfile b/Gemfile index 3099bf9..09cf495 100644 --- a/Gemfile +++ b/Gemfile @@ -70,7 +70,7 @@ end gem 'docusign_admin', '~> 1.1.0' gem 'docusign_click', '~> 1.3.0' -gem 'docusign_esign', '~> 3.22.0' +gem 'docusign_esign', '~> 3.23.0' gem 'docusign_monitor', '~> 1.1.0' gem 'docusign_rooms', '~> 1.3.0' gem 'omniauth-oauth2', '~> 1.8.0' diff --git a/Gemfile.lock b/Gemfile.lock index a0e96a0..968d6e3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -109,7 +109,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.22.0) + docusign_esign (3.23.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -335,7 +335,7 @@ DEPENDENCIES coffee-rails (~> 5.0.0) docusign_admin (~> 1.1.0) docusign_click (~> 1.3.0) - docusign_esign (~> 3.22.0) + docusign_esign (~> 3.23.0) docusign_monitor (~> 1.1.0) docusign_rooms (~> 1.3.0) jbuilder (~> 2.11.5) diff --git a/app/controllers/e_sign/eeg043_shared_access_controller.rb b/app/controllers/e_sign/eeg043_shared_access_controller.rb new file mode 100644 index 0000000..35ce36b --- /dev/null +++ b/app/controllers/e_sign/eeg043_shared_access_controller.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +require_relative '../../services/utils' + +class ESign::Eeg043SharedAccessController < EgController + before_action :authenticate_agent, only: [:list_envelopes] + before_action -> { check_auth('eSignature') }, except: %i[reauthenticate list_envelopes] + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 43, 'eSignature') } + + def create_agent + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + email: params['email'], + user_name: param_gsub(params['user_name']), + activation: param_gsub(params['activation']) + } + results = ESign::Eg043SharedAccessService.new(args).create_agent + session[:agent_user_id] = results.user_id + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json + @redirect_url = '/eeg043auth' + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end + + def create_authorization + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + agent_user_id: session['agent_user_id'] + } + args[:user_id] = Utils::DocuSignUtils.new.get_user_id args + session[:principal_user_id] = args[:user_id] + + ESign::Eg043SharedAccessService.new(args).create_authorization + + additional_page_data = @example['AdditionalPage'].find { |p| p['Name'] == 'authenticate_as_agent' } + @title = 'Authenticate as the agent' + @message = additional_page_data['ResultsPageText'] + @redirect_url = '/eeg043reauthenticate' + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + error = JSON.parse e.response_body + if error['errorCode'] == 'USER_NOT_FOUND' + additional_page_data = @example['AdditionalPage'].find { |p| p['Name'] == 'user_not_found' } + @title = 'Authenticate as the agent' + @message = additional_page_data['ResultsPageText'] + @redirect_url = '/eeg043auth' + return render 'ds_common/example_done' + end + handle_error(e) + end + + def reauthenticate + logout + redirect_to '/eeg043envelopes' + end + + def list_envelopes + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + user_id: session[:principal_user_id] + } + results = ESign::Eg043SharedAccessService.new(args).get_envelopes + + if results.result_set_size.to_i.positive? + additional_page_data = @example['AdditionalPage'].find { |p| p['Name'] == 'list_status_successful' } + @title = "Principal's envelopes visible in the agent's Shared Access UI" + @json = results.to_json.to_json + else + additional_page_data = @example['AdditionalPage'].find { |p| p['Name'] == 'list_status_unsuccessful' } + @title = "No envelopes in the principal user's account" + end + + @message = additional_page_data['ResultsPageText'] + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end + + private + + def logout + session.delete :ds_access_token + session.delete :ds_account_id + session.delete :ds_expires_at + session.delete 'omniauth.state' + session.delete 'omniauth.params' + session.delete 'omniauth.origin' + end + + def authenticate_agent + minimum_buffer_min = 10 + token_ok = check_token(minimum_buffer_min) + return if token_ok + + session[:eg] = 'eeg043envelopes' + redirect_to '/ds/mustAuthenticate' + end +end diff --git a/app/controllers/eg_controller.rb b/app/controllers/eg_controller.rb index 7534b52..3c45b3f 100644 --- a/app/controllers/eg_controller.rb +++ b/app/controllers/eg_controller.rb @@ -41,8 +41,6 @@ def set_meta @source_url = "#{Rails.application.config.github_example_url}#{@source_file}" end - private - def check_token(buffer_in_min = 10) buffer = buffer_in_min * 60 expires_at = session[:ds_expires_at] @@ -57,6 +55,8 @@ def check_token(buffer_in_min = 10) remaining_duration.positive? end + private + def time_in_words(duration) "#{Object.new.extend(ActionView::Helpers::DateHelper).distance_of_time_in_words(duration)}#{duration.negative? ? ' ago' : ''}" end diff --git a/app/services/e_sign/eg043_shared_access_service.rb b/app/services/e_sign/eg043_shared_access_service.rb new file mode 100644 index 0000000..8745b05 --- /dev/null +++ b/app/services/e_sign/eg043_shared_access_service.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +class ESign::Eg043SharedAccessService + attr_reader :args + + include ApiCreator + + def initialize(args) + @args = args + end + + def create_agent + configuration = DocuSign_eSign::Configuration.new + configuration.host = args[:base_path] + api_client = DocuSign_eSign::ApiClient.new configuration + api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" + + users_api = DocuSign_eSign::UsersApi.new api_client + + # Check if active user already exists + begin + options = DocuSign_eSign::ListOptions.new + options.email = args[:email] + users = users_api.list args[:account_id], options + + if users.result_set_size.to_i.positive? + user = users.users.find { |u| u.user_status == 'Active' } + return user unless user.nil? + end + rescue DocuSign_eSign::ApiError => e + error = JSON.parse e.response_body + raise unless error['errorCode'] == 'USER_LACKS_MEMBERSHIP' + end + + # Create new user + new_users = users_api.create args[:account_id], new_users_definition(args) + new_users.new_users[0] + end + + def create_authorization + configuration = DocuSign_eSign::Configuration.new + configuration.host = args[:base_path] + api_client = DocuSign_eSign::ApiClient.new configuration + api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" + + accounts_api = DocuSign_eSign::AccountsApi.new api_client + + # Check if authorization with manage permission already exists + options = DocuSign_eSign::GetAgentUserAuthorizationsOptions.new + options.permissions = 'manage' + + authorizations = accounts_api.get_agent_user_authorizations(args[:account_id], args[:agent_user_id], options) + return if authorizations.result_set_size.to_i.positive? + + # Create authorization + accounts_api.create_user_authorization( + args[:account_id], + args[:user_id], + user_authorization_request(args) + ) + end + + def new_users_definition(args) + agent = DocuSign_eSign::UserInformation.new( + userName: args[:user_name], + email: args[:email], + activationAccessCode: args[:activation] + ) + DocuSign_eSign::NewUsersDefinition.new(newUsers: [agent]) + end + + def user_authorization_request(args) + DocuSign_eSign::UserAuthorizationCreateRequest.new( + agentUser: DocuSign_eSign::AuthorizationUser.new( + accountId: args[:account_id], + userId: args[:agent_user_id] + ), + permission: 'manage' + ) + end + + def get_envelopes + configuration = DocuSign_eSign::Configuration.new + configuration.host = args[:base_path] + api_client = DocuSign_eSign::ApiClient.new configuration + api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" + api_client.set_default_header('X-DocuSign-Act-On-Behalf', args[:user_id]) + envelopes_api = DocuSign_eSign::EnvelopesApi.new api_client + + options = DocuSign_eSign::ListStatusChangesOptions.new + options.from_date = (Date.today - 10).strftime('%Y/%m/%d') + envelopes_api.list_status_changes args[:account_id], options + end +end diff --git a/app/services/utils.rb b/app/services/utils.rb index 0263c93..bec3d57 100644 --- a/app/services/utils.rb +++ b/app/services/utils.rb @@ -18,4 +18,16 @@ def get_example(manifest, number, api_name = 'eSignature') end end end + + class DocuSignUtils + def get_user_id(args) + configuration = DocuSign_eSign::Configuration.new + configuration.host = args[:base_path] + api_client = DocuSign_eSign::ApiClient.new configuration + api_client.set_base_path(args[:base_path]) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + user_info = api_client.get_user_info(args[:access_token]) + user_info.sub + end + end end diff --git a/app/views/ds_common/example_done.erb b/app/views/ds_common/example_done.erb index e599966..bb49251 100644 --- a/app/views/ds_common/example_done.erb +++ b/app/views/ds_common/example_done.erb @@ -15,4 +15,8 @@

    Check the request status

    <% end %> -

    Continue

    \ No newline at end of file +<% if @redirect_url %> +

    Continue

    +<% else %> +

    Continue

    +<% end %> diff --git a/app/views/e_sign/eeg043_shared_access/get.html.erb b/app/views/e_sign/eeg043_shared_access/get.html.erb new file mode 100644 index 0000000..494fe8f --- /dev/null +++ b/app/views/e_sign/eeg043_shared_access/get.html.erb @@ -0,0 +1,30 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% email_index = 0 %> +<% username_index = 1 %> +<% activation_index = 2 %> + +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + +
    +
    + + +
    +
    + + + <%= @manifest["SupportingTexts"]["HelpingTexts"]["SaveAgentActivationCode"] %> +
    + <%= render('partials/submit_button') %> +
    \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index dd2ce3d..50268f4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -212,6 +212,12 @@ get 'eeg042' => 'eeg042_document_generation#get' post 'eeg042' => 'eeg042_document_generation#create' + + post 'eeg043' => 'eeg043_shared_access#create_agent' + get 'eeg043' => 'eeg043_shared_access#get' + get 'eeg043auth' => 'eeg043_shared_access#create_authorization' + get 'eeg043reauthenticate' => 'eeg043_shared_access#reauthenticate' + get 'eeg043envelopes' => 'eeg043_shared_access#list_envelopes' end root 'ds_common#index' From 36f1ec37767489958da025867853cd7b8a59ab7d Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Mon, 22 May 2023 16:22:31 -0700 Subject: [PATCH 200/363] adding codeDepot snippets --- .../reg009_assign_form_to_form_group_controller.rb | 8 ++++---- .../eg009_assign_form_to_form_group_service.rb | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/controllers/room_api/reg009_assign_form_to_form_group_controller.rb b/app/controllers/room_api/reg009_assign_form_to_form_group_controller.rb index 761fb7b..9b36f1d 100644 --- a/app/controllers/room_api/reg009_assign_form_to_form_group_controller.rb +++ b/app/controllers/room_api/reg009_assign_form_to_form_group_controller.rb @@ -26,12 +26,12 @@ def create def get super - # Step 3 start + #ds-snippet-start:Rooms9Step3 @forms = RoomApi::GetDataService.new(session).get_form_libraries - # Step 3 end + #ds-snippet-end:Rooms9Step3 - # Step 4 start + #ds-snippet-start:Rooms9Step4 @form_groups = RoomApi::GetDataService.new(session).get_form_groups - # Step 4 end + #ds-snippet-end:Rooms9Step4 end end diff --git a/app/services/room_api/eg009_assign_form_to_form_group_service.rb b/app/services/room_api/eg009_assign_form_to_form_group_service.rb index 0248436..08788f3 100644 --- a/app/services/room_api/eg009_assign_form_to_form_group_service.rb +++ b/app/services/room_api/eg009_assign_form_to_form_group_service.rb @@ -8,34 +8,34 @@ def initialize(args) end def worker - # Step 2 start + #ds-snippet-start:Rooms9Step2 configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - # Step 2 end + #ds-snippet-end:Rooms9Step2 - # Step 6 start + #ds-snippet-start:Rooms9Step6 form_groups_api = DocuSign_Rooms::FormGroupsApi.new(api_client) begin response = form_groups_api.assign_form_group_form(args[:form_group_id], args[:account_id], body(args)) rescue Exception return { exception: 'Failed to assign a form to a form group' } end - # Step 6 end + #ds-snippet-end:Rooms9Step6 response end private def body(args) - # Step 5 start + #ds-snippet-start:Rooms9Step5 DocuSign_Rooms::FormGroupFormToAssign.new( { formId: args[:form_id] } ) - # Step 5 end + #ds-snippet-end:Rooms9Step5 end end From 618c1b5ee5f3c6a8b1d41721df20b4bc9437aa73 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Fri, 2 Jun 2023 19:50:48 +0300 Subject: [PATCH 201/363] Added new Admin API code examples (#127) * added admin examples 10 and 11 --- Gemfile | 2 +- Gemfile.lock | 46 +++++++++---------- ..._user_data_from_organization_controller.rb | 23 ++++++++++ ...elete_user_data_from_account_controller.rb | 21 +++++++++ ...ete_user_data_from_organization_service.rb | 41 +++++++++++++++++ ...1_delete_user_data_from_account_service.rb | 27 +++++++++++ app/services/jwt_auth/jwt_creator.rb | 4 +- .../get.html.erb | 19 ++++++++ .../get.html.erb | 19 ++++++++ config/initializers/omniauth.rb | 2 +- config/routes.rb | 6 +++ quick_acg/config/initializers/omniauth.rb | 2 +- test/test_helper.rb | 2 +- 13 files changed, 185 insertions(+), 29 deletions(-) create mode 100644 app/controllers/admin_api/aeg010_delete_user_data_from_organization_controller.rb create mode 100644 app/controllers/admin_api/aeg011_delete_user_data_from_account_controller.rb create mode 100644 app/services/admin_api/eg010_delete_user_data_from_organization_service.rb create mode 100644 app/services/admin_api/eg011_delete_user_data_from_account_service.rb create mode 100644 app/views/admin_api/aeg010_delete_user_data_from_organization/get.html.erb create mode 100644 app/views/admin_api/aeg011_delete_user_data_from_account/get.html.erb diff --git a/Gemfile b/Gemfile index 09cf495..5def594 100644 --- a/Gemfile +++ b/Gemfile @@ -68,7 +68,7 @@ group :test do gem 'test-unit' end -gem 'docusign_admin', '~> 1.1.0' +gem 'docusign_admin', '~> 1.2.0' gem 'docusign_click', '~> 1.3.0' gem 'docusign_esign', '~> 3.23.0' gem 'docusign_monitor', '~> 1.1.0' diff --git a/Gemfile.lock b/Gemfile.lock index 968d6e3..0cab288 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -66,7 +66,7 @@ GEM i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - addressable (2.8.1) + addressable (2.8.4) public_suffix (>= 2.0.2, < 6.0) archive-zip (0.12.0) io-like (~> 0.3.0) @@ -99,7 +99,7 @@ GEM concurrent-ruby (1.2.2) crass (1.0.6) date (3.3.3) - docusign_admin (1.1.0) + docusign_admin (1.2.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -128,7 +128,7 @@ GEM ethon (0.16.0) ffi (>= 1.15.0) execjs (2.8.1) - faraday (2.7.4) + faraday (2.7.5) faraday-net_http (>= 2.0, < 3.1) ruby2_keywords (>= 0.0.4) faraday-net_http (3.0.2) @@ -137,7 +137,7 @@ GEM globalid (1.1.0) activesupport (>= 5.0) hashie (5.0.0) - i18n (1.12.0) + i18n (1.13.0) concurrent-ruby (~> 1.0) io-like (0.3.1) jbuilder (2.11.5) @@ -148,9 +148,9 @@ GEM listen (3.8.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.19.1) + loofah (2.21.3) crass (~> 1.0.2) - nokogiri (>= 1.5.9) + nokogiri (>= 1.12.0) mail (2.8.1) mini_mime (>= 0.1.1) net-imap @@ -161,7 +161,7 @@ GEM method_source (1.0.0) mini_mime (1.1.2) minitest (5.18.0) - msgpack (1.6.1) + msgpack (1.7.1) multi_xml (0.6.0) net-imap (0.3.4) date @@ -172,10 +172,10 @@ GEM timeout net-smtp (0.3.3) net-protocol - nio4r (2.5.8) - nokogiri (1.14.2-x64-mingw-ucrt) + nio4r (2.5.9) + nokogiri (1.15.2-x64-mingw-ucrt) racc (~> 1.4) - nokogiri (1.14.2-x86_64-linux) + nokogiri (1.15.2-x86_64-linux) racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) @@ -194,8 +194,8 @@ GEM omniauth-rails_csrf_protection (1.0.1) actionpack (>= 4.2) omniauth (~> 2.0) - parallel (1.22.1) - parser (3.2.1.1) + parallel (1.23.0) + parser (3.2.2.1) ast (~> 2.4.1) power_assert (2.0.3) pry (0.14.2) @@ -209,8 +209,8 @@ GEM puma (6.1.1) nio4r (~> 2.0) racc (1.6.2) - rack (2.2.6.4) - rack-protection (3.0.5) + rack (2.2.7) + rack-protection (3.0.6) rack rack-test (2.1.0) rack (>= 1.3) @@ -245,7 +245,7 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - regexp_parser (2.7.0) + regexp_parser (2.8.0) rexml (3.2.5) rubocop (1.48.1) json (~> 2.3) @@ -257,7 +257,7 @@ GEM rubocop-ast (>= 1.26.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.27.0) + rubocop-ast (1.28.1) parser (>= 3.2.1.0) ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) @@ -272,7 +272,7 @@ GEM sprockets (> 3.0) sprockets-rails tilt - selenium-webdriver (4.8.1) + selenium-webdriver (4.8.6) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) @@ -290,11 +290,11 @@ GEM actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) - sqlite3 (1.6.1-x64-mingw-ucrt) - sqlite3 (1.6.1-x86_64-linux) - test-unit (3.5.7) + sqlite3 (1.6.3-x64-mingw-ucrt) + sqlite3 (1.6.3-x86_64-linux) + test-unit (3.5.9) power_assert - thor (1.2.1) + thor (1.2.2) tilt (2.1.0) timeout (0.3.2) turbolinks (5.2.1) @@ -321,7 +321,7 @@ GEM websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.7) + zeitwerk (2.6.8) PLATFORMS x64-mingw-ucrt @@ -333,7 +333,7 @@ DEPENDENCIES capybara (~> 3.38.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_admin (~> 1.1.0) + docusign_admin (~> 1.2.0) docusign_click (~> 1.3.0) docusign_esign (~> 3.23.0) docusign_monitor (~> 1.1.0) diff --git a/app/controllers/admin_api/aeg010_delete_user_data_from_organization_controller.rb b/app/controllers/admin_api/aeg010_delete_user_data_from_organization_controller.rb new file mode 100644 index 0000000..3ac5113 --- /dev/null +++ b/app/controllers/admin_api/aeg010_delete_user_data_from_organization_controller.rb @@ -0,0 +1,23 @@ +class AdminApi::Aeg010DeleteUserDataFromOrganizationController < EgController + before_action -> { check_auth('Admin') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 10, 'Admin') } + + def create + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? + + args = { + access_token: session['ds_access_token'], + email: param_gsub(params['email']), + organization_id: session['organization_id'] + } + + results = AdminApi::Eg010DeleteUserDataFromOrganizationService.new(args).worker + + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) + end +end diff --git a/app/controllers/admin_api/aeg011_delete_user_data_from_account_controller.rb b/app/controllers/admin_api/aeg011_delete_user_data_from_account_controller.rb new file mode 100644 index 0000000..1dd5273 --- /dev/null +++ b/app/controllers/admin_api/aeg011_delete_user_data_from_account_controller.rb @@ -0,0 +1,21 @@ +class AdminApi::Aeg011DeleteUserDataFromAccountController < EgController + before_action -> { check_auth('Admin') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 11, 'Admin') } + + def create + args = { + account_id: session['ds_account_id'], + access_token: session['ds_access_token'], + user_id: param_gsub(params['user_id']) + } + + results = AdminApi::Eg011DeleteUserDataFromAccountService.new(args).worker + + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) + end +end diff --git a/app/services/admin_api/eg010_delete_user_data_from_organization_service.rb b/app/services/admin_api/eg010_delete_user_data_from_organization_service.rb new file mode 100644 index 0000000..e387830 --- /dev/null +++ b/app/services/admin_api/eg010_delete_user_data_from_organization_service.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +class AdminApi::Eg010DeleteUserDataFromOrganizationService + attr_reader :args + + def initialize(args) + @args = args + end + + def worker + # Step 2 start + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + # Step 2 end + + # Step 3 start + users_api = DocuSign_Admin::UsersApi.new(api_client) + + options = DocuSign_Admin::GetUserDSProfilesByEmailOptions.new + options.email = args[:email] + result = users_api.get_user_ds_profiles_by_email(args[:organization_id], options) + user = result.users[0] + # Step 3 end + + # Step 4 start + organizations_api = DocuSign_Admin::OrganizationsApi.new(api_client) + user_data_redaction_request = DocuSign_Admin::IndividualUserDataRedactionRequest.new( + user_id: user.id, + memberships: [ + DocuSign_Admin::MembershipDataRedactionRequest.new( + account_id: user.memberships[0].account_id + ) + ] + ) + organizations_api.redact_individual_user_data(args[:organization_id], user_data_redaction_request) + # Step 4 end + end +end diff --git a/app/services/admin_api/eg011_delete_user_data_from_account_service.rb b/app/services/admin_api/eg011_delete_user_data_from_account_service.rb new file mode 100644 index 0000000..f709f28 --- /dev/null +++ b/app/services/admin_api/eg011_delete_user_data_from_account_service.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +class AdminApi::Eg011DeleteUserDataFromAccountService + attr_reader :args + + def initialize(args) + @args = args + end + + def worker + # Step 2 start + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + # Step 2 end + + # Step 3 start + accounts_api = DocuSign_Admin::AccountsApi.new(api_client) + membership_redaction_request = DocuSign_Admin::IndividualMembershipDataRedactionRequest.new( + user_id: args[:user_id] + ) + accounts_api.redact_individual_membership_data(args[:account_id], membership_redaction_request) + # Step 3 end + end +end diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index 0282cb2..dd9e96b 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -16,7 +16,7 @@ def self.consent_url(state, api) scope = 'signature impersonation' if %w[eSignature Monitor].include?(api) scope = 'signature impersonation 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' if api == 'Rooms' scope = 'signature impersonation click.manage click.send' if api == 'Click' - scope = 'signature impersonation organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' if api == 'Admin' + scope = 'signature impersonation organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact' if api == 'Admin' base_uri = "#{Rails.configuration.authorization_server}/oauth/auth" response_type = 'code' @@ -42,7 +42,7 @@ def initialize(session) end @client_module = DocuSign_Monitor if session[:api] == 'Monitor' if session[:api] == 'Admin' - scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' + scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact' @client_module = DocuSign_Admin end diff --git a/app/views/admin_api/aeg010_delete_user_data_from_organization/get.html.erb b/app/views/admin_api/aeg010_delete_user_data_from_organization/get.html.erb new file mode 100644 index 0000000..685e1c9 --- /dev/null +++ b/app/views/admin_api/aeg010_delete_user_data_from_organization/get.html.erb @@ -0,0 +1,19 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% email_index = 0 %> + +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + "> + <%= @manifest["SupportingTexts"]["HelpingTexts"]["EmailAddressOfUserToDelete"] %> +
    + <%= render('partials/submit_button') %> +
    diff --git a/app/views/admin_api/aeg011_delete_user_data_from_account/get.html.erb b/app/views/admin_api/aeg011_delete_user_data_from_account/get.html.erb new file mode 100644 index 0000000..88035e0 --- /dev/null +++ b/app/views/admin_api/aeg011_delete_user_data_from_account/get.html.erb @@ -0,0 +1,19 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% user_id_index = 0 %> + +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + " + required pattern="[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"> + <%= @manifest["SupportingTexts"]["HelpingTexts"]["UserIDOfUserToDelete"] %> +
    + <%= render('partials/submit_button') %> +
    diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 230fc11..0b6b207 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -45,7 +45,7 @@ when 'Click' strategy.options[:authorize_params].scope = 'signature click.manage click.send' when 'Admin' - strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' + strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact' end } end diff --git a/config/routes.rb b/config/routes.rb index 50268f4..a54187c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -86,6 +86,12 @@ get 'aeg009' => 'aeg009_delete_user_product_permission_profile#get' post 'aeg009' => 'aeg009_delete_user_product_permission_profile#create' + + get 'aeg010' => 'aeg010_delete_user_data_from_organization#get' + post 'aeg010' => 'aeg010_delete_user_data_from_organization#create' + + get 'aeg011' => 'aeg011_delete_user_data_from_account#get' + post 'aeg011' => 'aeg011_delete_user_data_from_account#create' end get '/eeg001' => 'eeg001_embedded_signing#get' diff --git a/quick_acg/config/initializers/omniauth.rb b/quick_acg/config/initializers/omniauth.rb index 230fc11..0b6b207 100644 --- a/quick_acg/config/initializers/omniauth.rb +++ b/quick_acg/config/initializers/omniauth.rb @@ -45,7 +45,7 @@ when 'Click' strategy.options[:authorize_params].scope = 'signature click.manage click.send' when 'Admin' - strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read' + strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact' end } end diff --git a/test/test_helper.rb b/test/test_helper.rb index 7cee366..0670721 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -8,7 +8,7 @@ $_scopes = %w[signature impersonation] $_click_scopes = %w[click.manage click.send] $_rooms_scopes = %w[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] -$_admin_scopes = %w[organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read] +$_admin_scopes = %w[organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact] class TestHelper < Test::Unit::TestCase From 6e3a6d195260369a15bf2921aa656299190f0c6f Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 2 Jun 2023 10:50:16 -0700 Subject: [PATCH 202/363] fix comments --- .../eg010_delete_user_data_from_organization_service.rb | 8 +++++--- .../eg011_delete_user_data_from_account_service.rb | 5 ++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/services/admin_api/eg010_delete_user_data_from_organization_service.rb b/app/services/admin_api/eg010_delete_user_data_from_organization_service.rb index e387830..1c0405a 100644 --- a/app/services/admin_api/eg010_delete_user_data_from_organization_service.rb +++ b/app/services/admin_api/eg010_delete_user_data_from_organization_service.rb @@ -16,16 +16,15 @@ def worker api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") # Step 2 end - # Step 3 start + # Get user users_api = DocuSign_Admin::UsersApi.new(api_client) options = DocuSign_Admin::GetUserDSProfilesByEmailOptions.new options.email = args[:email] result = users_api.get_user_ds_profiles_by_email(args[:organization_id], options) user = result.users[0] - # Step 3 end - # Step 4 start + # Step 3 start organizations_api = DocuSign_Admin::OrganizationsApi.new(api_client) user_data_redaction_request = DocuSign_Admin::IndividualUserDataRedactionRequest.new( user_id: user.id, @@ -35,6 +34,9 @@ def worker ) ] ) + # Step 3 end + + # Step 4 start organizations_api.redact_individual_user_data(args[:organization_id], user_data_redaction_request) # Step 4 end end diff --git a/app/services/admin_api/eg011_delete_user_data_from_account_service.rb b/app/services/admin_api/eg011_delete_user_data_from_account_service.rb index f709f28..d7b76e9 100644 --- a/app/services/admin_api/eg011_delete_user_data_from_account_service.rb +++ b/app/services/admin_api/eg011_delete_user_data_from_account_service.rb @@ -21,7 +21,10 @@ def worker membership_redaction_request = DocuSign_Admin::IndividualMembershipDataRedactionRequest.new( user_id: args[:user_id] ) - accounts_api.redact_individual_membership_data(args[:account_id], membership_redaction_request) # Step 3 end + + # Step 4 start + accounts_api.redact_individual_membership_data(args[:account_id], membership_redaction_request) + # Step 4 end end end From aade8528d7e792ddf575c493f4187e46c9913972 Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Tue, 6 Jun 2023 10:37:51 -0700 Subject: [PATCH 203/363] DEVDOCS-10501 adding codeDepot markers --- app/services/e_sign/eg006_envelope_docs_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/e_sign/eg006_envelope_docs_service.rb b/app/services/e_sign/eg006_envelope_docs_service.rb index 1708712..51e3595 100644 --- a/app/services/e_sign/eg006_envelope_docs_service.rb +++ b/app/services/e_sign/eg006_envelope_docs_service.rb @@ -9,10 +9,10 @@ def initialize(args) @args = args end - # ***DS.snippet.0.start def worker + #ds-snippet-start:eSign6Step3 envelope_api = create_envelope_api(args) envelope_api.list_documents args[:account_id], args[:envelope_id] + #ds-snippet-end:eSign6Step3 end - # ***DS.snippet.0.end end From 30827873340d554ed9444837a3a0ab41a7646800 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 9 Jun 2023 10:38:27 -0700 Subject: [PATCH 204/363] DEVDOCS-10391 --- .../eg003_bulk_export_user_data_service.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/services/admin_api/eg003_bulk_export_user_data_service.rb b/app/services/admin_api/eg003_bulk_export_user_data_service.rb index ba2652d..e4e240c 100644 --- a/app/services/admin_api/eg003_bulk_export_user_data_service.rb +++ b/app/services/admin_api/eg003_bulk_export_user_data_service.rb @@ -6,20 +6,20 @@ def initialize(args) end def worker - # Step 2 start + #ds-snippet-start:Admin3Step2 configuration = DocuSign_Admin::Configuration.new configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - # Step 2 end + #ds-snippet-end:Admin3Step2 - # Step 3 start + #ds-snippet-start:Admin3Step3 @bulk_exports_api = DocuSign_Admin::BulkExportsApi.new(api_client) response = bulk_exports_api.create_user_list_export(args[:organization_id], args[:request_body]) - # Step 3 end + #ds-snippet-end:Admin3Step3 - # Step 4 start + #ds-snippet-start:Admin3Step4 retry_count = 5 while retry_count >= 0 if response.results @@ -31,14 +31,14 @@ def worker response = bulk_exports_api.get_user_list_export(args[:organization_id], response.id) end end - # Step 4 end + #ds-snippet-end:Admin3Step4 response end private - # Step 5 start + #ds-snippet-start:Admin3Step5 def get_exported_user_data(args, export_id) bulk_export_response = bulk_exports_api.get_user_list_export(args[:organization_id], export_id) data_url = bulk_export_response.results[0].url @@ -59,5 +59,5 @@ def get_exported_user_data(args, export_id) end end end - # Step 5 end + #ds-snippet-end:Admin3Step5 end From 3251208cedd926279f309aaa96c937edd21da1ec Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 9 Jun 2023 10:40:32 -0700 Subject: [PATCH 205/363] DEVDOCS-10502 --- app/services/admin_api/eg004_import_user_service.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/services/admin_api/eg004_import_user_service.rb b/app/services/admin_api/eg004_import_user_service.rb index a6ac454..6a7a719 100644 --- a/app/services/admin_api/eg004_import_user_service.rb +++ b/app/services/admin_api/eg004_import_user_service.rb @@ -6,20 +6,20 @@ def initialize(args) end def worker - # Step 2 start + #ds-snippet-start:Admin4Step2 configuration = DocuSign_Admin::Configuration.new configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - # Step 2 end + #ds-snippet-end:Admin4Step2 - # Step 3 start + #ds-snippet-start:Admin4Step3 csv_file_data = File.open(args[:csv_file_path]).read csv_file_data = csv_file_data.gsub('{account_id}', args[:account_id]) @bulk_imports_api = DocuSign_Admin::BulkImportsApi.new(api_client) @bulk_imports_api.create_bulk_import_add_users_request(args[:organization_id], csv_file_data) - # Step 3 end + #ds-snippet-end:Admin4Step3 end end From fb045739a25ad0270d4156a4e5ccbd101ed5925a Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 9 Jun 2023 10:43:58 -0700 Subject: [PATCH 206/363] DEVDOCS-10390 --- .../admin_api/eg006_get_user_profile_by_email_service.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/services/admin_api/eg006_get_user_profile_by_email_service.rb b/app/services/admin_api/eg006_get_user_profile_by_email_service.rb index 5dc4b7b..ee00978 100644 --- a/app/services/admin_api/eg006_get_user_profile_by_email_service.rb +++ b/app/services/admin_api/eg006_get_user_profile_by_email_service.rb @@ -8,20 +8,20 @@ def initialize(args) end def worker - # Step 2 start + #ds-snippet-start:Admin6Step2 configuration = DocuSign_Admin::Configuration.new configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - # Step 2 end + #ds-snippet-end:Admin6Step2 - # Step 3 start + #ds-snippet-start:Admin6Step3 users_api = DocuSign_Admin::UsersApi.new(api_client) options = DocuSign_Admin::GetUserDSProfilesByEmailOptions.new options.email = args[:email] users_api.get_user_ds_profiles_by_email(args[:organization_id], options) - # Step 3 end + #ds-snippet-end:Admin6Step3 end end From 91135aa496066101e03147763fbf06cea8d644f1 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 9 Jun 2023 10:50:13 -0700 Subject: [PATCH 207/363] DEVDOCS-10396 --- .../eg007_get_user_profile_by_user_id_service.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/services/admin_api/eg007_get_user_profile_by_user_id_service.rb b/app/services/admin_api/eg007_get_user_profile_by_user_id_service.rb index 09afb34..8f20ca4 100644 --- a/app/services/admin_api/eg007_get_user_profile_by_user_id_service.rb +++ b/app/services/admin_api/eg007_get_user_profile_by_user_id_service.rb @@ -8,17 +8,17 @@ def initialize(args) end def worker - # Step 2 start + #ds-snippet-start:Admin7Step2 configuration = DocuSign_Admin::Configuration.new configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - # Step 2 end + #ds-snippet-end:Admin7Step2 - # Step 3 start + #ds-snippet-start:Admin7Step3 users_api = DocuSign_Admin::UsersApi.new(api_client) users_api.get_user_ds_profile(args[:organization_id], args[:user_id]) - # Step 3 end + #ds-snippet-end:Admin7Step3 end end From ee5e27ae3cb557f19058efb56e49de5aabcf8c6f Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 9 Jun 2023 10:55:40 -0700 Subject: [PATCH 208/363] DEVDOCS-10398 --- ...update_user_product_permission_profile_service.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/services/admin_api/eg008_update_user_product_permission_profile_service.rb b/app/services/admin_api/eg008_update_user_product_permission_profile_service.rb index c63b774..fe58f2b 100644 --- a/app/services/admin_api/eg008_update_user_product_permission_profile_service.rb +++ b/app/services/admin_api/eg008_update_user_product_permission_profile_service.rb @@ -8,22 +8,22 @@ def initialize(args) end def worker - # Step 2 start + #ds-snippet-start:Admin8Step2 configuration = DocuSign_Admin::Configuration.new configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - # Step 2 end + #ds-snippet-end:Admin8Step2 - # Step 3 start + #ds-snippet-start:Admin8Step3 product_permission_profile = DocuSign_Admin::ProductPermissionProfileRequest.new({ 'permission_profile_id' => args[:permission_profile_id], 'product_id' => args[:product_id] }) user_product_permission_profile_request = DocuSign_Admin::UserProductPermissionProfilesRequest.new({ 'email' => args[:email], 'product_permission_profiles' => [product_permission_profile] }) - # Step 3 end + #ds-snippet-end:Admin8Step3 - # Step 4 start + #ds-snippet-start:Admin8Step4 product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(api_client) product_permission_profiles_api.add_user_product_permission_profiles_by_email(args[:organization_id], args[:account_id], user_product_permission_profile_request) - # Step 4 end + #ds-snippet-end:Admin8Step4 end end From 69697de7b3319ef1275b1cac71d284385c7ff9d2 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 9 Jun 2023 11:07:25 -0700 Subject: [PATCH 209/363] DEVDOCS-10456 --- ...lete_user_product_permission_profile_service.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb b/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb index 413de64..baf16fd 100644 --- a/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb +++ b/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb @@ -8,22 +8,22 @@ def initialize(args) end def worker - # Step 2 start + #ds-snippet-start:Admin9Step2 configuration = DocuSign_Admin::Configuration.new configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - # Step 2 end + #ds-snippet-end:Admin9Step2 - # Step 3 start + #ds-snippet-start:Admin9Step4 user_product_profile_delete_request = DocuSign_Admin::UserProductProfileDeleteRequest.new({ 'user_email' => args[:email], 'product_ids' => [args[:product_id]] }) - # Step 3 end + #ds-snippet-end:Admin9Step4 - # Step 4 start + #ds-snippet-start:Admin9Step5 product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(api_client) product_permission_profiles_api.remove_user_product_permission(args[:organization_id], args[:account_id], user_product_profile_delete_request) - # Step 4 end + #ds-snippet-end:Admin9Step5 end def get_permission_profiles_by_email @@ -33,6 +33,7 @@ def get_permission_profiles_by_email api_client = DocuSign_Admin::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-start:Admin9Step3 product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(api_client) options = DocuSign_Admin::GetUserProductPermissionProfilesByEmailOptions.new @@ -40,5 +41,6 @@ def get_permission_profiles_by_email product_permission_profiles = product_permission_profiles_api.get_user_product_permission_profiles_by_email(args[:organization_id], args[:account_id], options) product_permission_profiles.as_json['product_permission_profiles'] + #ds-snippet-end:Admin9Step3 end end From c3d82ae0cdcbc36f1f4654d6f53c9e7840cc5f43 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 9 Jun 2023 11:21:31 -0700 Subject: [PATCH 210/363] DEVDOCS-10449 --- app/services/admin_api/eg005_audit_users_service.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/services/admin_api/eg005_audit_users_service.rb b/app/services/admin_api/eg005_audit_users_service.rb index dfb8496..a2c4b5a 100644 --- a/app/services/admin_api/eg005_audit_users_service.rb +++ b/app/services/admin_api/eg005_audit_users_service.rb @@ -8,24 +8,24 @@ def initialize(args) end def worker - # Step 2 start + #ds-snippet-start:Admin5Step2 configuration = DocuSign_Admin::Configuration.new configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - # Step 2 end + #ds-snippet-end:Admin5Step2 - # Step 3 start + #ds-snippet-start:Admin5Step3 options = DocuSign_Admin::GetUsersOptions.new options.account_id = args[:account_id] options.last_modified_since = (Date.today - 10).strftime('%Y/%m/%d') users_api = DocuSign_Admin::UsersApi.new(api_client) modified_users = users_api.get_users(args[:organization_id], options).as_json['users'] - # Step 3 end + #ds-snippet-end:Admin5Step3 - # Step 5 start + #ds-snippet-start:Admin5Step5 results = [] modified_users.each do |user| userProfilesOptions = DocuSign_Admin::GetUserProfilesOptions.new @@ -33,7 +33,7 @@ def worker result = users_api.get_user_profiles(args[:organization_id], userProfilesOptions) results.push(result) end - # Step 5 end + #ds-snippet-end:Admin5Step5 results end From 225fecff3a8eda94bace7326a0126e48b7bed3d6 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 9 Jun 2023 14:32:53 -0700 Subject: [PATCH 211/363] DEVDOCS-11409 - code depot markers --- .../eg011_delete_user_data_from_account_service.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/services/admin_api/eg011_delete_user_data_from_account_service.rb b/app/services/admin_api/eg011_delete_user_data_from_account_service.rb index d7b76e9..ba02f72 100644 --- a/app/services/admin_api/eg011_delete_user_data_from_account_service.rb +++ b/app/services/admin_api/eg011_delete_user_data_from_account_service.rb @@ -8,23 +8,23 @@ def initialize(args) end def worker - # Step 2 start + #ds-snippet-start:Admin11Step2 configuration = DocuSign_Admin::Configuration.new configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - # Step 2 end + #ds-snippet-end:Admin11Step2 - # Step 3 start + #ds-snippet-start:Admin11Step3 accounts_api = DocuSign_Admin::AccountsApi.new(api_client) membership_redaction_request = DocuSign_Admin::IndividualMembershipDataRedactionRequest.new( user_id: args[:user_id] ) - # Step 3 end + #ds-snippet-end:Admin11Step3 - # Step 4 start + #ds-snippet-start:Admin11Step4 accounts_api.redact_individual_membership_data(args[:account_id], membership_redaction_request) - # Step 4 end + #ds-snippet-end:Admin11Step4 end end From 2cd5284ecd61b046f1a7b99b4aeafe29ed4459ea Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 9 Jun 2023 14:34:11 -0700 Subject: [PATCH 212/363] DEVDOCS-11412 - code depot markers --- ...010_delete_user_data_from_organization_service.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/services/admin_api/eg010_delete_user_data_from_organization_service.rb b/app/services/admin_api/eg010_delete_user_data_from_organization_service.rb index 1c0405a..2ce8c20 100644 --- a/app/services/admin_api/eg010_delete_user_data_from_organization_service.rb +++ b/app/services/admin_api/eg010_delete_user_data_from_organization_service.rb @@ -8,13 +8,13 @@ def initialize(args) end def worker - # Step 2 start + #ds-snippet-start:Admin10Step2 configuration = DocuSign_Admin::Configuration.new configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - # Step 2 end + #ds-snippet-end:Admin10Step2 # Get user users_api = DocuSign_Admin::UsersApi.new(api_client) @@ -24,7 +24,7 @@ def worker result = users_api.get_user_ds_profiles_by_email(args[:organization_id], options) user = result.users[0] - # Step 3 start + #ds-snippet-start:Admin10Step3 organizations_api = DocuSign_Admin::OrganizationsApi.new(api_client) user_data_redaction_request = DocuSign_Admin::IndividualUserDataRedactionRequest.new( user_id: user.id, @@ -34,10 +34,10 @@ def worker ) ] ) - # Step 3 end + #ds-snippet-end:Admin10Step3 - # Step 4 start + #ds-snippet-start:Admin10Step4 organizations_api.redact_individual_user_data(args[:organization_id], user_data_redaction_request) - # Step 4 end + #ds-snippet-end:Admin10Step4 end end From 03aa7e0f43958442c92f1a54ce5038600d86b5f5 Mon Sep 17 00:00:00 2001 From: Mei Hsieh Date: Fri, 16 Jun 2023 14:59:09 -0700 Subject: [PATCH 213/363] DEVDOCS-10260 Rb eSign 1 cD mkrs --- .../eg001_embedded_signing_service.rb | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/app/services/eg001_embedded_signing_service.rb b/app/services/eg001_embedded_signing_service.rb index f9ce8a6..0b881f1 100644 --- a/app/services/eg001_embedded_signing_service.rb +++ b/app/services/eg001_embedded_signing_service.rb @@ -9,7 +9,6 @@ def initialize(args) @args = args end - # ***DS.snippet.0.start def worker ds_ping_url = args[:ds_ping_url] ds_return_url = "#{ds_ping_url}/ds_common-return" @@ -18,33 +17,37 @@ def worker signer_email = args[:signer_email] signer_name = args[:signer_name] - # Step 1. Create the envelope definition + # Create the envelope definition + #ds-snippet-start:eSign1Step3 envelope = make_envelope(args[:signer_client_id], pdf_filename, signer_email, signer_name) - # Step 2. Call DocuSign to create the envelope + # Call DocuSign to create the envelope envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope envelope_id = results.envelope_id + #ds-snippet-end # Save for future use within the example launcher # session[:envelope_id] = envelope_id - # Step 3. Create the recipient view for the embedded signing + # Create the recipient view for the embedded signing + #ds-snippet-start:eSign1Step5 view_request = make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, signer_email, signer_name) # Call the CreateRecipientView API results = envelope_api.create_recipient_view args[:account_id], envelope_id, view_request - # Step 4. Redirect the user to the embedded signing + # 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) # Redirect to results.url results.url + #ds-snippet-end end private - + #ds-snippet-start:eSign1Step4 def make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, signer_email, signer_name) view_request = DocuSign_eSign::RecipientViewRequest.new # Set the URL where you want the recipient to go once they are done signing @@ -77,7 +80,9 @@ def make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, si view_request end + #ds-snippet-end + #ds-snippet-start:eSign1Step2 def make_envelope(signer_client_id, pdf_filename, signer_email, signer_name) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document sent from Ruby SDK' @@ -118,5 +123,5 @@ def make_envelope(signer_client_id, pdf_filename, signer_email, signer_name) envelope_definition.status = 'sent' envelope_definition end - # ***DS.snippet.0.end + #ds-snippet-end end From 7a5414b673fc3feebab601ad9c12cdae455c8a24 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 22 Jun 2023 09:10:20 -0700 Subject: [PATCH 214/363] DEVDOCS-10533 - adding codeDepot markers --- app/services/clickwrap/eg005_clickwrap_responses_service.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/services/clickwrap/eg005_clickwrap_responses_service.rb b/app/services/clickwrap/eg005_clickwrap_responses_service.rb index 31b9e26..4a8abba 100644 --- a/app/services/clickwrap/eg005_clickwrap_responses_service.rb +++ b/app/services/clickwrap/eg005_clickwrap_responses_service.rb @@ -9,13 +9,16 @@ def initialize(args) def worker # Step 2. Construct your API headers + #ds-snippet-start:Click5Step2 configuration = DocuSign_Click::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_Click::ApiClient.new configuration api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:Click5Step2 # Step 3. Call the Click API + #ds-snippet-start:Click5Step3 # Set Clickwrap Agreements options agreements = DocuSign_Click::GetClickwrapAgreementsOptions.new agreements.client_user_id = args[:client_user_id] @@ -28,5 +31,6 @@ def worker args[:clickwrap_id], agreements ) + #ds-snippet-end:Click5Step3 end end From 2cf9db4398bf991f72b69c92abb32a8ab85f3ec0 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 22 Jun 2023 09:36:47 -0700 Subject: [PATCH 215/363] DEVDOCS-10231 - adding codeDepot markers --- app/services/clickwrap/eg004_list_clickwraps_service.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/services/clickwrap/eg004_list_clickwraps_service.rb b/app/services/clickwrap/eg004_list_clickwraps_service.rb index 8f25046..75c2375 100644 --- a/app/services/clickwrap/eg004_list_clickwraps_service.rb +++ b/app/services/clickwrap/eg004_list_clickwraps_service.rb @@ -9,16 +9,20 @@ def initialize(args) def worker # Step 2. Construct your API headers + #ds-snippet-start:Click4Step2 configuration = DocuSign_Click::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_Click::ApiClient.new configuration api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:Click4Step2 # Step 3. Call the Click API + #ds-snippet-start:Click4Step3 accounts_api = DocuSign_Click::AccountsApi.new(api_client) accounts_api.get_clickwraps( args[:account_id] ) + #ds-snippet-end:Click4Step3 end end From 665b5a602b29acaa0da8cc5d0e1167545300423b Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 22 Jun 2023 10:07:02 -0700 Subject: [PATCH 216/363] DEVDOCS-10553 - adding codeDepot markers --- .../clickwrap/eg003_create_new_clickwrap_version_service.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb b/app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb index ac53ab2..5272fbc 100644 --- a/app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb +++ b/app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb @@ -9,14 +9,17 @@ def initialize(args) def worker # Step 2. Construct your API headers + #ds-snippet-start:Click3Step2 configuration = DocuSign_Click::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_Click::ApiClient.new configuration api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:Click3Step2 # Step 3. Construct the request body # Create a display settings model + #ds-snippet-start:Click3Step3 display_settings = DocuSign_Click::DisplaySettings.new( consentButtonText: 'I Agree', displayName: "#{args[:clickwrap_name]} v2", @@ -49,13 +52,16 @@ def worker requireReacceptance: true, status: 'active' ) + #ds-snippet-end:Click3Step3 # Step 4. Call the Click API + #ds-snippet-start:Click3Step4 accounts_api = DocuSign_Click::AccountsApi.new(api_client) accounts_api.create_clickwrap_version( args[:account_id], args[:clickwrap_id], clickwrap_request ) + #ds-snippet-end:Click4Step4 end end From ab74bafa2a3b729f8bb343992044495df0fa8bc5 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Wed, 28 Jun 2023 11:03:54 -0700 Subject: [PATCH 217/363] adding codeDepot markers --- app/services/e_sign/eg011_embedded_sending_service.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/services/e_sign/eg011_embedded_sending_service.rb b/app/services/e_sign/eg011_embedded_sending_service.rb index dac2703..ce56b4f 100644 --- a/app/services/e_sign/eg011_embedded_sending_service.rb +++ b/app/services/e_sign/eg011_embedded_sending_service.rb @@ -10,19 +10,23 @@ def initialize(args) end def worker - # Step 1. Create the envelope as a draft using eg002's worker + # Create the envelope as a draft using eg002's worker # Exceptions will be caught by the calling function + #ds-snippet-start:eSign11Step2 results = create_envelope(args) envelope_id = results['envelope_id'] - # Step 2. Create the sender view + #ds-snippet-end:eSign11Step2 + + #ds-snippet-start:eSign11Step3 + # Create the sender view view_request = DocuSign_eSign::ReturnUrlRequest.new({ returnUrl: args[:ds_return_url] }) envelope_api = create_envelope_api(args) results = envelope_api.create_sender_view args[:account_id], envelope_id, view_request # Switch to the Recipients/Documents view if requested by the user in the form url = results.url url = url.sub! 'send=1', 'send=0' if args[:starting_view] == 'recipient' - { 'envelope_id' => envelope_id, 'redirect_url' => url } + #ds-snippet-end:eSign11Step3 end private From 69796a6cbc0007eb19cc5d5c2720bc657922fa19 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Wed, 28 Jun 2023 11:25:39 -0700 Subject: [PATCH 218/363] adding codeDepot markers --- app/services/e_sign/eg036_delayed_routing_service.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/services/e_sign/eg036_delayed_routing_service.rb b/app/services/e_sign/eg036_delayed_routing_service.rb index 6146392..b66e73a 100644 --- a/app/services/e_sign/eg036_delayed_routing_service.rb +++ b/app/services/e_sign/eg036_delayed_routing_service.rb @@ -16,9 +16,9 @@ def worker # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) - # Step 3 start + #ds-snippet-start:eSign36Step3 results = envelope_api.create_envelope args[:account_id], envelope_definition - # Step 3 end + #ds-snippet-end:eSign36Step3 envelope_id = results.envelope_id { 'envelope_id' => envelope_id } end @@ -26,8 +26,8 @@ def worker private def make_envelope(envelope_args) - # Step 2 start # Create the envelope definition + #ds-snippet-start:eSign36Step2 envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document' @@ -126,7 +126,7 @@ def make_envelope(envelope_args) # Request that the envelope be sent by setting status to "sent". # To request that the envelope be created as a draft, set status to "created" envelope_definition.status = envelope_args[:status] - # Step 2 end envelope_definition + #ds-snippet-end:eSign36Step2 end end From 6bc79d686f29357b5d55dcf890d6cf6e60d9a87c Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Fri, 7 Jul 2023 09:35:31 -0700 Subject: [PATCH 219/363] removing monitor example 2 (#128) * removing monitor example 2 * linting error --- .../meg002_post_web_query_controller.rb | 28 --------- .../eg001_embedded_signing_service.rb | 1 + .../eg002_post_web_query_service.rb | 60 ------------------- .../meg002_post_web_query/get.html.erb | 21 ------- config/routes.rb | 2 - 5 files changed, 1 insertion(+), 111 deletions(-) delete mode 100644 app/controllers/monitor_api/meg002_post_web_query_controller.rb delete mode 100644 app/services/monitor_api/eg002_post_web_query_service.rb delete mode 100644 app/views/monitor_api/meg002_post_web_query/get.html.erb diff --git a/app/controllers/monitor_api/meg002_post_web_query_controller.rb b/app/controllers/monitor_api/meg002_post_web_query_controller.rb deleted file mode 100644 index 0cb4c6a..0000000 --- a/app/controllers/monitor_api/meg002_post_web_query_controller.rb +++ /dev/null @@ -1,28 +0,0 @@ -class MonitorApi::Meg002PostWebQueryController < EgController - before_action -> { check_auth('Monitor') } - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2, 'Monitor') } - - def create - args = { - access_token: session[:ds_access_token], - data_set_name: 'monitor', - account_id: session['ds_account_id'], - version: '2.0', - start_date: params[:start_date], - end_date: params[:end_date] - } - - results = MonitorApi::Eg002PostWebQueryService.new(args).worker - - @title = @example['ExampleName'] - - if results != 'Monitor not enabled' - @message = @example['ResultsPageText'] - @json = results.to_json.to_json - else - @message = "You do not have Monitor enabled for your account, follow How to enable Monitor for your account to get it enabled." - end - - render 'ds_common/example_done' - end -end diff --git a/app/services/eg001_embedded_signing_service.rb b/app/services/eg001_embedded_signing_service.rb index 0b881f1..cfe56da 100644 --- a/app/services/eg001_embedded_signing_service.rb +++ b/app/services/eg001_embedded_signing_service.rb @@ -47,6 +47,7 @@ def worker end private + #ds-snippet-start:eSign1Step4 def make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, signer_email, signer_name) view_request = DocuSign_eSign::RecipientViewRequest.new diff --git a/app/services/monitor_api/eg002_post_web_query_service.rb b/app/services/monitor_api/eg002_post_web_query_service.rb deleted file mode 100644 index ef18699..0000000 --- a/app/services/monitor_api/eg002_post_web_query_service.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -class MonitorApi::Eg002PostWebQueryService - attr_reader :args - - def initialize(args) - @args = args - end - - def worker - # step 2 start - configuration = DocuSign_Monitor::Configuration.new - configuration.host = Rails.configuration.monitor_host - configuration.debugging = true - api_client = DocuSign_Monitor::ApiClient.new configuration - api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - # step 2 end - - # step 3 start - monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) - begin - @response = monitor_api.post_web_query(args[:data_set_name], args[:version], get_query) - # step 3 end - rescue StandardError - # error, probalby no Monitor enabled - @response = 'Monitor not enabled' - else - Rails.logger.info 'Responses for loops are displayed here. Only the final loop is displayed on the response page' - Rails.logger.info @response.inspect - ensure - return @response - end - end - - def get_query - { - "filters": [ - { - "FilterName": 'Time', - "BeginTime": args[:start_date], - "EndTime": args[:end_date] - }, - { - "FilterName": 'Has', - "ColumnName": 'AccountId', - "Value": args[:account_id] - } - ], - "aggregations": [ - { - "aggregationName": 'Raw', - "limit": '100', - "orderby": [ - 'Timestamp, desc' - ] - } - ] - } - end -end diff --git a/app/views/monitor_api/meg002_post_web_query/get.html.erb b/app/views/monitor_api/meg002_post_web_query/get.html.erb deleted file mode 100644 index 178593c..0000000 --- a/app/views/monitor_api/meg002_post_web_query/get.html.erb +++ /dev/null @@ -1,21 +0,0 @@ -<%= render('partials/example_info') %> - -<% form_index = 0 %> -<% start_index = 0 %> -<% end_name_index = 1 %> - -
    - <% if @example["Forms"][form_index]["FormName"] %> - <%= sanitize @example["Forms"][form_index]["FormName"] %> - <% end %> - -
    - - max=<%= Time.now %>> -
    -
    - - max=<%= Time.now %>> -
    - <%= render('partials/submit_button') %> -
    \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index a54187c..8ae2fad 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -54,8 +54,6 @@ scope module: 'monitor_api' do get 'meg001' => 'meg001_get_monitoring_dataset#get' post 'meg001' => 'meg001_get_monitoring_dataset#create' - get 'meg002' => 'meg002_post_web_query#get' - post 'meg002' => 'meg002_post_web_query#create' end scope module: 'admin_api' do From e72b578789f874223f4bb211fa69bbedcdb03dd4 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Fri, 7 Jul 2023 15:15:52 -0700 Subject: [PATCH 220/363] adding codeDepot markers --- .../e_sign/eg017_set_template_tab_values_service.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/services/e_sign/eg017_set_template_tab_values_service.rb b/app/services/e_sign/eg017_set_template_tab_values_service.rb index 3af1cb3..950d4a2 100644 --- a/app/services/e_sign/eg017_set_template_tab_values_service.rb +++ b/app/services/e_sign/eg017_set_template_tab_values_service.rb @@ -9,7 +9,6 @@ def initialize(args) @args = args end - # ***DS.snippet.0.start def worker signer_client_id = 1000 envelope_args = args[:envelope_args] @@ -17,14 +16,19 @@ def worker ds_return_url = "#{ds_ping_url}/ds_common-return" # Step 4. Construct the request body + #ds-snippet-start:eSign17Step4 envelope_definition = make_envelope(envelope_args) + #ds-snippet-end:eSign17Step4 # Step 5. Call the eSignature REST API + #ds-snippet-start:eSign17Step5 envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope_definition envelope_id = results.envelope_id + #ds-snippet-end:eSign17Step5 # Step 6. Create the View Request + #ds-snippet-start:eSign17Step6 view_request = make_recipient_view_request(envelope_args[:signer_email], envelope_args[:signer_name], signer_client_id, ds_return_url, ds_ping_url) # Call the CreateRecipientView API @@ -36,6 +40,7 @@ def worker # query parameter on the return URL (see the makeRecipientViewRequest method) # Redirect to results.url results.url + #ds-snippet-end:eSign17Step6 end private @@ -64,6 +69,7 @@ def make_envelope(args) # Step 3. Create Tabs and CustomFields # List item + #ds-snippet-start:eSign17Step3 list1 = DocuSign_eSign::List.new list1.value = 'Green' list1.document_id = '1' @@ -118,6 +124,7 @@ def make_envelope(args) # Add the TemplateRole objects to the envelope object envelope_definition.template_roles = [signer, cc] envelope_definition + #ds-snippet-end:eSign17Step3 end def make_recipient_view_request(signer_email, signer_name, signer_client_id, ds_return_url, ds_ping_url) @@ -148,5 +155,4 @@ def make_recipient_view_request(signer_email, signer_name, signer_client_id, ds_ view_request end - # ***DS.snippet.0.end end From a8934e2914375ac22dfcb842e5f6c9737bb7691e Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 11 Jul 2023 16:19:24 -0700 Subject: [PATCH 221/363] DEVDOCS-10513 - adding codeDepot markers --- app/services/clickwrap/eg002_activate_clickwrap_service.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/services/clickwrap/eg002_activate_clickwrap_service.rb b/app/services/clickwrap/eg002_activate_clickwrap_service.rb index a9079ff..51cf5f3 100644 --- a/app/services/clickwrap/eg002_activate_clickwrap_service.rb +++ b/app/services/clickwrap/eg002_activate_clickwrap_service.rb @@ -9,17 +9,22 @@ def initialize(args) def worker # Step 2. Construct your API headers + #ds-snippet-start:Click2Step2 configuration = DocuSign_Click::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_Click::ApiClient.new configuration api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:Click2Step2 # Step 3. Construct the request body # Create a clickwrap request model + #ds-snippet-start:Click2Step3 clickwrap_request = DocuSign_Click::ClickwrapRequest.new(status: 'active') + #ds-snippet-end:Click2Step3 # Step 4. Call the Click API + #ds-snippet-start:Click2Step4 accounts_api = DocuSign_Click::AccountsApi.new(api_client) accounts_api.update_clickwrap_version( args[:account_id], @@ -27,6 +32,7 @@ def worker 1, clickwrap_request ) + #ds-snippet-end:Click2Step4 end def get_inactive_clickwraps(statuses) From ea853a3532ae9f8f7e94481c73ea13cfdf0a7914 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 11 Jul 2023 16:22:40 -0700 Subject: [PATCH 222/363] DEVDOCS-10222 - adding codeDepot markers --- .../clickwrap/eg006_embed_clickwrap_service.rb | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/app/services/clickwrap/eg006_embed_clickwrap_service.rb b/app/services/clickwrap/eg006_embed_clickwrap_service.rb index b966aa6..de25785 100644 --- a/app/services/clickwrap/eg006_embed_clickwrap_service.rb +++ b/app/services/clickwrap/eg006_embed_clickwrap_service.rb @@ -9,21 +9,16 @@ def initialize(args) def worker # Step 2. Construct your API headers + #ds-snippet-start:Click6Step2 configuration = DocuSign_Click::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_Click::ApiClient.new configuration api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") api_client.config.debugging = true + #ds-snippet-end:Click6Step2 - # document_data = DocuSign_Click::DocumentData.new({ - # full_name: args[:full_name], - # email: args[:email], - # company: args[:company], - # title: args[:title], - # date: args[:date] - # }) - + #ds-snippet-start:Click6Step3 document_data = { 'fullName' => args[:full_name], 'email' => args[:email], @@ -37,11 +32,14 @@ def worker documentData: document_data }) + #ds-snippet-end:Click6Step3 + #ds-snippet-start:Click6Step4 accounts_api = DocuSign_Click::AccountsApi.new(api_client) response = accounts_api.create_has_agreed(args[:account_id], args[:clickwrap_id], userAgreementRequest) response.as_json + #ds-snippet-end:Click6Step4 end def get_active_clickwraps From a6b9a55ab22e05344352419e0554445e41dfbe51 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 13 Jul 2023 12:45:12 -0700 Subject: [PATCH 223/363] DEVDOCS-10346 - fixing codeDepot markers --- app/services/api_creator.rb | 6 ++---- .../e_sign/eg029_brands_apply_to_envelope_service.rb | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/services/api_creator.rb b/app/services/api_creator.rb index 884829d..7feb1f3 100644 --- a/app/services/api_creator.rb +++ b/app/services/api_creator.rb @@ -32,15 +32,13 @@ def create_template_api(args) def create_envelope_api(args) # Obtain your OAuth token - # Step 2 start - #ds-snippet-start:eSign29Step2 + #ds-snippet-start:eSignRubyStep2 configuration = DocuSign_eSign::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_eSign::ApiClient.new configuration api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" - #ds-snippet-end:eSign29Step2 - # Step 2 end + #ds-snippet-end:eSignRubyStep2 DocuSign_eSign::EnvelopesApi.new api_client end diff --git a/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb b/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb index 7018124..4aca19a 100644 --- a/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb +++ b/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb @@ -10,7 +10,6 @@ def initialize(args) end def worker - # ***DS.snippet.0.start # Step 1. Obtain your OAuth token # Step 2. Construct your API headers envelope_api = create_envelope_api(args) From 50d41b4ff86a100b0df0b27d1ca7c8ddffb42319 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 18 Jul 2023 10:19:03 -0700 Subject: [PATCH 224/363] DEVDOCS-10627 - adding codeDepot markers --- .../eg008_grant_office_access_to_form_group_service.rb | 8 ++++---- app/services/room_api/get_data_service.rb | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb b/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb index f2d4fe3..dae902a 100644 --- a/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb +++ b/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb @@ -8,22 +8,22 @@ def initialize(args) end def worker - # Step 2 start + #ds-snippet-start:Rooms1Step2 configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - # Step 2 end + #ds-snippet-end:Rooms1Step2 - # Step 5 start + #ds-snippet-start:Rooms1Step5 form_groups_api = DocuSign_Rooms::FormGroupsApi.new(api_client) begin response = form_groups_api.grant_office_access_to_form_group(args[:form_group_id], args[:office_id], args[:account_id]) rescue Exception return { exception: 'Failed to grant office access to a form group' } end - # Step 5 end + #ds-snippet-end:Rooms1Step5 response end end diff --git a/app/services/room_api/get_data_service.rb b/app/services/room_api/get_data_service.rb index f10b0e8..371e8bc 100644 --- a/app/services/room_api/get_data_service.rb +++ b/app/services/room_api/get_data_service.rb @@ -15,9 +15,11 @@ def initialize(session, options = {}) def get_offices worker + #ds-snippet-start:Rooms1Step3 offices_api = DocuSign_Rooms::OfficesApi.new(@api_client) offices = offices_api.get_offices(args[:account_id]) offices.as_json['officeSummaries'] + #ds-snippet-end:Rooms1Step3 end def get_default_admin_role_id @@ -73,9 +75,11 @@ def get_forms_from_room def get_form_groups worker + #ds-snippet-start:Rooms1Step4 form_groups_api = DocuSign_Rooms::FormGroupsApi.new(@api_client) form_groups = form_groups_api.get_form_groups(args[:account_id]) form_groups.as_json['formGroups'] + #ds-snippet-end:Rooms1Step4 end private From 4162e57504ed2a8cbc0ba8609a68c8a69f1007fb Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 18 Jul 2023 10:20:07 -0700 Subject: [PATCH 225/363] DEVDOCS-10627 - fixing --- .../eg008_grant_office_access_to_form_group_service.rb | 8 ++++---- app/services/room_api/get_data_service.rb | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb b/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb index dae902a..04930ad 100644 --- a/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb +++ b/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb @@ -8,22 +8,22 @@ def initialize(args) end def worker - #ds-snippet-start:Rooms1Step2 + #ds-snippet-start:Rooms8Step2 configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - #ds-snippet-end:Rooms1Step2 + #ds-snippet-end:Rooms8Step2 - #ds-snippet-start:Rooms1Step5 + #ds-snippet-start:Rooms8Step5 form_groups_api = DocuSign_Rooms::FormGroupsApi.new(api_client) begin response = form_groups_api.grant_office_access_to_form_group(args[:form_group_id], args[:office_id], args[:account_id]) rescue Exception return { exception: 'Failed to grant office access to a form group' } end - #ds-snippet-end:Rooms1Step5 + #ds-snippet-end:Rooms8Step5 response end end diff --git a/app/services/room_api/get_data_service.rb b/app/services/room_api/get_data_service.rb index 371e8bc..473be8c 100644 --- a/app/services/room_api/get_data_service.rb +++ b/app/services/room_api/get_data_service.rb @@ -15,11 +15,11 @@ def initialize(session, options = {}) def get_offices worker - #ds-snippet-start:Rooms1Step3 + #ds-snippet-start:Rooms8Step3 offices_api = DocuSign_Rooms::OfficesApi.new(@api_client) offices = offices_api.get_offices(args[:account_id]) offices.as_json['officeSummaries'] - #ds-snippet-end:Rooms1Step3 + #ds-snippet-end:Rooms8Step3 end def get_default_admin_role_id @@ -75,11 +75,11 @@ def get_forms_from_room def get_form_groups worker - #ds-snippet-start:Rooms1Step4 + #ds-snippet-start:Rooms8Step4 form_groups_api = DocuSign_Rooms::FormGroupsApi.new(@api_client) form_groups = form_groups_api.get_form_groups(args[:account_id]) form_groups.as_json['formGroups'] - #ds-snippet-end:Rooms1Step4 + #ds-snippet-end:Rooms8Step4 end private From 0513746dc74f035c09d755110490e751806b68e4 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 18 Jul 2023 11:29:02 -0700 Subject: [PATCH 226/363] DEVDOCS-11300 - adding codeDepot markers --- app/services/e_sign/eg012_embedded_console_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/e_sign/eg012_embedded_console_service.rb b/app/services/e_sign/eg012_embedded_console_service.rb index cca1ff1..95332fc 100644 --- a/app/services/e_sign/eg012_embedded_console_service.rb +++ b/app/services/e_sign/eg012_embedded_console_service.rb @@ -9,10 +9,10 @@ def initialize(args) @args = args end - # ***DS.snippet.0.start def worker # Step 1. Create the NDSE view request object # Exceptions will be caught by the calling function + #ds-snippet-start:eSign12Step2 view_request = DocuSign_eSign::ConsoleViewRequest.new({ returnUrl: args[:ds_return_url] }) @@ -20,7 +20,7 @@ def worker # Step 2. Call the API method envelope_api = create_envelope_api(args) results = envelope_api.create_console_view args[:account_id], view_request + #ds-snippet-end:eSign12Step2 { 'redirect_url' => results.url } end - # ***DS.snippet.0.end end From e2ef655eec9486857e518bc4839fd930206d5521 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 18 Jul 2023 11:37:02 -0700 Subject: [PATCH 227/363] DEVDOCS-11399 - adding codeDepot markers --- app/services/e_sign/eg043_shared_access_service.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/services/e_sign/eg043_shared_access_service.rb b/app/services/e_sign/eg043_shared_access_service.rb index 8745b05..a959392 100644 --- a/app/services/e_sign/eg043_shared_access_service.rb +++ b/app/services/e_sign/eg043_shared_access_service.rb @@ -10,12 +10,16 @@ def initialize(args) end def create_agent + #ds-snippet-start:eSign43Step2 configuration = DocuSign_eSign::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_eSign::ApiClient.new configuration api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" + #ds-snippet-end:eSign43Step2 + #ds-snippet-start:eSign43Step3 users_api = DocuSign_eSign::UsersApi.new api_client + #ds-snippet-end:eSign43Step3 # Check if active user already exists begin @@ -33,8 +37,10 @@ def create_agent end # Create new user + #ds-snippet-start:eSign43Step3 new_users = users_api.create args[:account_id], new_users_definition(args) new_users.new_users[0] + #ds-snippet-end:eSign43Step3 end def create_authorization @@ -43,6 +49,7 @@ def create_authorization api_client = DocuSign_eSign::ApiClient.new configuration api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" + #ds-snippet-start:eSign43Step4 accounts_api = DocuSign_eSign::AccountsApi.new api_client # Check if authorization with manage permission already exists @@ -58,8 +65,10 @@ def create_authorization args[:user_id], user_authorization_request(args) ) + #ds-snippet-end:eSign43Step4 end + #ds-snippet-start:eSign43Step3 def new_users_definition(args) agent = DocuSign_eSign::UserInformation.new( userName: args[:user_name], @@ -68,7 +77,9 @@ def new_users_definition(args) ) DocuSign_eSign::NewUsersDefinition.new(newUsers: [agent]) end + #ds-snippet-end:eSign43Step3 + #ds-snippet-start:eSign43Step4 def user_authorization_request(args) DocuSign_eSign::UserAuthorizationCreateRequest.new( agentUser: DocuSign_eSign::AuthorizationUser.new( @@ -78,8 +89,10 @@ def user_authorization_request(args) permission: 'manage' ) end + #ds-snippet-end:eSign43Step4 def get_envelopes + #ds-snippet-start:eSign43Step5 configuration = DocuSign_eSign::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_eSign::ApiClient.new configuration @@ -90,5 +103,6 @@ def get_envelopes options = DocuSign_eSign::ListStatusChangesOptions.new options.from_date = (Date.today - 10).strftime('%Y/%m/%d') envelopes_api.list_status_changes args[:account_id], options + #ds-snippet-end:eSign43Step5 end end From 20f964eedfe4f4c8b30f0bd473a722eb11b2cf13 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 20 Jul 2023 11:55:51 -0700 Subject: [PATCH 228/363] DEVDOCS-10304 - adding codeDepot markers --- .../room_api/eg005_get_rooms_with_filters_service.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/services/room_api/eg005_get_rooms_with_filters_service.rb b/app/services/room_api/eg005_get_rooms_with_filters_service.rb index efaf106..3ea0496 100644 --- a/app/services/room_api/eg005_get_rooms_with_filters_service.rb +++ b/app/services/room_api/eg005_get_rooms_with_filters_service.rb @@ -11,14 +11,20 @@ def worker configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host + #ds-snippet-start:Rooms5Step2 api_client = DocuSign_Rooms::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:Rooms5Step2 + #ds-snippet-start:Rooms5Step3 filters = DocuSign_Rooms::GetRoomsOptions.new filters.field_data_changed_start_date = args[:date_from] filters.field_data_changed_end_date = args[:date_to] + #ds-snippet-end:Rooms5Step3 + #ds-snippet-start:Rooms5Step4 rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) rooms_api.get_rooms(args[:account_id], filters) + #ds-snippet-end:Rooms5Step4 end end From 5d92711062782170728b383465c93dbaf9b3add0 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 20 Jul 2023 12:14:50 -0700 Subject: [PATCH 229/363] Updating comments --- .../room_api/eg005_get_rooms_with_filters_service.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/services/room_api/eg005_get_rooms_with_filters_service.rb b/app/services/room_api/eg005_get_rooms_with_filters_service.rb index efaf106..3ea0496 100644 --- a/app/services/room_api/eg005_get_rooms_with_filters_service.rb +++ b/app/services/room_api/eg005_get_rooms_with_filters_service.rb @@ -11,14 +11,20 @@ def worker configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host + #ds-snippet-start:Rooms5Step2 api_client = DocuSign_Rooms::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:Rooms5Step2 + #ds-snippet-start:Rooms5Step3 filters = DocuSign_Rooms::GetRoomsOptions.new filters.field_data_changed_start_date = args[:date_from] filters.field_data_changed_end_date = args[:date_to] + #ds-snippet-end:Rooms5Step3 + #ds-snippet-start:Rooms5Step4 rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) rooms_api.get_rooms(args[:account_id], filters) + #ds-snippet-end:Rooms5Step4 end end From 0894947eb7cb2c89f5adbd315a8d6b231d125cba Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Fri, 21 Jul 2023 13:50:25 -0700 Subject: [PATCH 230/363] DEVDOCS-10423 - adding codeDepot markers --- .../e_sign/eg026_permissions_change_single_setting_service.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/services/e_sign/eg026_permissions_change_single_setting_service.rb b/app/services/e_sign/eg026_permissions_change_single_setting_service.rb index cf97f2c..7dee3aa 100644 --- a/app/services/e_sign/eg026_permissions_change_single_setting_service.rb +++ b/app/services/e_sign/eg026_permissions_change_single_setting_service.rb @@ -10,16 +10,19 @@ def initialize(args) end def worker + #ds-snippet-start:eSign26Step4 accounts_api = create_account_api(args) permission_profile_settings = make_permission_profile_settings permission_profile_id = args[:permission_profile_id] accounts_api.update_permission_profile(args[:account_id], permission_profile_id, permission_profile_settings, DocuSign_eSign::UpdatePermissionProfileOptions.default) + #ds-snippet-end:eSign26Step4 end private def make_permission_profile_settings + #ds-snippet-start:eSign26Step3 permission_profile = DocuSign_eSign::PermissionProfile.new pr_settings = { useNewDocuSignExperienceInterface: 0, @@ -49,6 +52,7 @@ def make_permission_profile_settings vaultingMode: 'none' } permission_profile.settings = pr_settings + #ds-snippet-end:eSign26Step3 permission_profile end end From 2c8fc117e3345f77f06e3b5974c898ad9ba2dcd5 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Mon, 24 Jul 2023 10:08:29 -0700 Subject: [PATCH 231/363] DEVDOCS-10486 - adding codeDepot markers --- .../e_sign/eg034_use_conditional_recipients_service.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/services/e_sign/eg034_use_conditional_recipients_service.rb b/app/services/e_sign/eg034_use_conditional_recipients_service.rb index 1edc054..ee01a75 100644 --- a/app/services/e_sign/eg034_use_conditional_recipients_service.rb +++ b/app/services/e_sign/eg034_use_conditional_recipients_service.rb @@ -12,12 +12,15 @@ def initialize(args, signers) def worker # Step 2. Construct your API headers + #ds-snippet-start:eSign34Step2 configuration = DocuSign_eSign::Configuration.new configuration.host = args[:basePath] api_client = DocuSign_eSign::ApiClient.new configuration api_client.set_default_header('Authorization', "Bearer #{args[:accessToken]}") + #ds-snippet-end:eSign34Step2 # Step 3. Construct the request body + #ds-snippet-start:eSign34Step3 envelope_definition = DocuSign_eSign::EnvelopeDefinition.new(emailSubject: 'ApproveIfChecked') # Create the document model. @@ -174,13 +177,16 @@ def worker # 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_definition.status = 'sent' + #ds-snippet-end:eSign34Step3 # Step 4. Call the eSignature API + #ds-snippet-start:eSign34Step4 envelopes_api = DocuSign_eSign::EnvelopesApi.new(api_client) envelopes_api.create_envelope( args[:accountId], envelope_definition ) + #ds-snippet-end:eSign34Step4 end end From bebcf965d5dc38df9f268475e54af70a00205435 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 25 Jul 2023 16:28:45 -0700 Subject: [PATCH 232/363] DEVDOCS-10504 - adding codeDepot markers --- .../room_api/eg007_create_form_group_service.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/services/room_api/eg007_create_form_group_service.rb b/app/services/room_api/eg007_create_form_group_service.rb index 0d5dc5a..dcc1a22 100644 --- a/app/services/room_api/eg007_create_form_group_service.rb +++ b/app/services/room_api/eg007_create_form_group_service.rb @@ -8,29 +8,29 @@ def initialize(args) end def worker - # Step 2 start + #ds-snippet-start:Rooms7Step2 configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - # Step 2 end + #ds-snippet-end:Rooms7Step2 - # Step 4 start + #ds-snippet-start:Rooms7Step4 rooms_api = DocuSign_Rooms::FormGroupsApi.new(api_client) rooms_api.create_form_group(args[:account_id], body(args)) - # Step 4 end + #ds-snippet-end:Rooms7Step4 end private def body(args) - # Step 3 start + #ds-snippet-start:Rooms7Step3 DocuSign_Rooms::RoomForCreate.new( { name: args[:group_name] } ) - # Step 3 end + #ds-snippet-end:Rooms7Step3 end end From 55b104660fbe4cdbc6dc60eaa962147392ce9518 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 27 Jul 2023 11:40:11 -0700 Subject: [PATCH 233/363] DEVDOCS-10411 - adding codeDepot markers --- .../room_api/eg001_create_room_with_data_service.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/services/room_api/eg001_create_room_with_data_service.rb b/app/services/room_api/eg001_create_room_with_data_service.rb index 4f77533..aa9e717 100644 --- a/app/services/room_api/eg001_create_room_with_data_service.rb +++ b/app/services/room_api/eg001_create_room_with_data_service.rb @@ -11,17 +11,22 @@ def worker configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host + #ds-snippet-start:Rooms1Step2 api_client = DocuSign_Rooms::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:Rooms1Step2 + #ds-snippet-start:Rooms1Step4 rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) rooms_api.create_room(args[:account_id], body(args)) + #ds-snippet-end:Rooms1Step4 end private def body(args) + #ds-snippet-start:Rooms1Step3 DocuSign_Rooms::RoomForCreate.new( { name: args[:room_name], @@ -40,5 +45,6 @@ def body(args) ) } ) + #ds-snippet-end:Rooms1Step3 end end From 73b558412099c58897b02ad1d1bc4a23a4be0ddd Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Thu, 27 Jul 2023 12:07:58 -0700 Subject: [PATCH 234/363] DEVDOCS-10587 - adding codeDepot markers --- app/services/e_sign/eg035_scheduled_sending_service.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/services/e_sign/eg035_scheduled_sending_service.rb b/app/services/e_sign/eg035_scheduled_sending_service.rb index c7e3789..412e56e 100644 --- a/app/services/e_sign/eg035_scheduled_sending_service.rb +++ b/app/services/e_sign/eg035_scheduled_sending_service.rb @@ -17,7 +17,9 @@ def worker envelope_api = create_envelope_api(args) # Step 3 start + #ds-snippet-start:eSign35Step3 results = envelope_api.create_envelope args[:account_id], envelope_definition + #ds-snippet-end:eSign35Step3 # Step 3 end envelope_id = results.envelope_id @@ -31,6 +33,7 @@ def make_envelope(envelope_args) # The envelope has one recipient # Step 2 start + #ds-snippet-start:eSign35Step2 # Create the envelope definition envelope_definition = DocuSign_eSign::EnvelopeDefinition.new @@ -105,6 +108,7 @@ def make_envelope(envelope_args) # Request that the envelope be sent by setting status to "sent". # To request that the envelope be created as a draft, set status to "created" envelope_definition.status = envelope_args[:status] + #ds-snippet-end:eSign35Step2 # Step 2 end envelope_definition end From 6825189f8d70f517539dbb6f4092c2086a4c17f6 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 27 Jul 2023 14:18:16 -0700 Subject: [PATCH 235/363] DEVDOCS-10532 - adding codeDepot markers --- .../e_sign/eg020_phone_authentication_service.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/services/e_sign/eg020_phone_authentication_service.rb b/app/services/e_sign/eg020_phone_authentication_service.rb index 613fecb..6e5d952 100644 --- a/app/services/e_sign/eg020_phone_authentication_service.rb +++ b/app/services/e_sign/eg020_phone_authentication_service.rb @@ -10,13 +10,12 @@ def initialize(args) end def worker(workflow_id) - # ***DS.snippet.0.start envelope_args = args[:envelope_args] return 'phone_auth_not_enabled' if workflow_id.blank? # Construct your envelope JSON body - # Step 4 start + #ds-snippet-start:eSign20Step4 envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document set' @@ -81,7 +80,7 @@ def worker(workflow_id) # To request that the envelope be created as a draft, set to "created" envelope_definition.recipients = recipients envelope_definition.status = envelope_args[:status] - # Step 4 end + #ds-snippet-end:eSign20Step4 # Call the eSignature REST API # Step 5 start @@ -93,7 +92,7 @@ def worker(workflow_id) def get_workflow # Retrieve the workflow id - # Step 3 start + #ds-snippet-start:eSign20Step3 workflow_details = create_account_api(args) workflow_response = workflow_details.get_account_identity_verification(args[:account_id]) @@ -108,7 +107,7 @@ def get_workflow else '' end - # Step 3 end + #ds-snippet-end:eSign20Step3 rescue DocuSign_eSign::ApiError => e error = JSON.parse e.response_body @error_code = e.code From 1fc7e770b84eaf66ac1af77f37e44c6f7fcbdb4d Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Thu, 27 Jul 2023 14:20:21 -0700 Subject: [PATCH 236/363] DEVDOCS-10534 - missed one --- app/services/e_sign/eg020_phone_authentication_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/e_sign/eg020_phone_authentication_service.rb b/app/services/e_sign/eg020_phone_authentication_service.rb index 6e5d952..c4a591f 100644 --- a/app/services/e_sign/eg020_phone_authentication_service.rb +++ b/app/services/e_sign/eg020_phone_authentication_service.rb @@ -83,10 +83,10 @@ def worker(workflow_id) #ds-snippet-end:eSign20Step4 # Call the eSignature REST API - # Step 5 start + #ds-snippet-start:eSign20Step5 envelope_api = create_envelope_api(args) envelope_api.create_envelope args[:account_id], envelope_definition - # Step 5 end + #ds-snippet-end:eSign20Step5 end def get_workflow From f8ddfebb7bc8b989679990450b2540304554e4c3 Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Thu, 27 Jul 2023 14:34:48 -0700 Subject: [PATCH 237/363] DEVDOCS-10521 codeDepot markers --- .../monitor_api/eg001_get_monitoring_dataset_service.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb index f99acc7..7977774 100644 --- a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb +++ b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb @@ -8,19 +8,19 @@ def initialize(args) end def worker - # step 2 start + #ds-snippet-start:Monitor1Step2 configuration = DocuSign_Monitor::Configuration.new configuration.host = Rails.configuration.monitor_host configuration.debugging = true api_client = DocuSign_Monitor::ApiClient.new configuration api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - # step 2 end + #ds-snippet-end:Monitor1Step2 - # step 3 start + #ds-snippet-start:Monitor1Step3 monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) begin @response = monitor_api.get_stream(args[:data_set_name], args[:version]).data - # step 3 end + #ds-snippet-end:Monitor1Step3 rescue StandardError # error, probalby no Monitor enabled @response = 'Monitor not enabled' From 7554ed63951beb56d166ffb0c1b1dc5911db3624 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Fri, 28 Jul 2023 10:01:28 -0700 Subject: [PATCH 238/363] DEVDOCS-10394 - adding codeDepot markers --- .../admin_api/aeg001_create_user_controller.rb | 6 ++++++ app/services/admin_api/eg001_create_user_service.rb | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/controllers/admin_api/aeg001_create_user_controller.rb b/app/controllers/admin_api/aeg001_create_user_controller.rb index 757a133..9f8ceb0 100644 --- a/app/controllers/admin_api/aeg001_create_user_controller.rb +++ b/app/controllers/admin_api/aeg001_create_user_controller.rb @@ -10,6 +10,7 @@ def create access_token: session['ds_access_token'], organization_id: session['organization_id'] } + #ds-snippet-start:Admin1Step5 user_data = { user_name: param_gsub(params['user_name']), first_name: param_gsub(params['first_name']), @@ -30,6 +31,7 @@ def create } ] } + #ds-snippet-end:Admin1Step5 begin results = AdminApi::Eg001CreateUserService.new(args, user_data).worker @@ -52,10 +54,14 @@ def get access_token: session['ds_access_token'] } + #ds-snippet-start:Admin1Step3 accounts_api = create_account_api(args) @permission_profiles = accounts_api.list_permissions(args[:account_id]).permission_profiles + #ds-snippet-end:Admin1Step3 + #ds-snippet-start:Admin1Step4 groups_api = create_group_api(args) @groups = groups_api.list_groups(args[:account_id]).groups + #ds-snippet-end:Admin1Step4 end end diff --git a/app/services/admin_api/eg001_create_user_service.rb b/app/services/admin_api/eg001_create_user_service.rb index 3626cec..878120c 100644 --- a/app/services/admin_api/eg001_create_user_service.rb +++ b/app/services/admin_api/eg001_create_user_service.rb @@ -9,17 +9,17 @@ def initialize(args, user_data) end def worker - # Step 2 start + #ds-snippet-start:Admin1Step2 configuration = DocuSign_Admin::Configuration.new configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - # Step 2 end + #ds-snippet-end:Admin1Step2 - # Step 4 start + #ds-snippet-start:Admin1Step6 users_api = DocuSign_Admin::UsersApi.new(api_client) users_api.create_user(args[:organization_id], user_data) - # Step 4 end + #ds-snippet-end:Admin1Step6 end end From fb2d5b9a8a29c063266027205c1bf97dec1fc7f6 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Mon, 31 Jul 2023 14:59:06 -0700 Subject: [PATCH 239/363] DEVDOCS-10522 - adding codeDepot markers --- app/services/room_api/eg003_export_data_from_room_service.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/services/room_api/eg003_export_data_from_room_service.rb b/app/services/room_api/eg003_export_data_from_room_service.rb index a7c36f5..5107b2b 100644 --- a/app/services/room_api/eg003_export_data_from_room_service.rb +++ b/app/services/room_api/eg003_export_data_from_room_service.rb @@ -8,13 +8,17 @@ def initialize(args) end def worker + #ds-snippet-start:Rooms3Step2 configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:Rooms3Step2 + #ds-snippet-start:Rooms3Step3 rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) rooms_api.get_room_field_data(args[:room_id], args[:account_id]) + #ds-snippet-end:Rooms3Step3 end end From 8d58f9357d79250e8f25786f5a1c70cbd59cef36 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Mon, 31 Jul 2023 15:23:23 -0700 Subject: [PATCH 240/363] DEVDOCS-10393 - adding codeDepot markers --- Gemfile.lock | 33 ++++++++++--------- .../eg004_add_forms_to_room_service.rb | 6 ++++ 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 0cab288..7107a75 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -128,23 +128,22 @@ GEM ethon (0.16.0) ffi (>= 1.15.0) execjs (2.8.1) - faraday (2.7.5) + faraday (2.7.7) faraday-net_http (>= 2.0, < 3.1) ruby2_keywords (>= 0.0.4) faraday-net_http (3.0.2) ffi (1.15.5) - ffi (1.15.5-x64-mingw-ucrt) globalid (1.1.0) activesupport (>= 5.0) hashie (5.0.0) - i18n (1.13.0) + i18n (1.14.1) concurrent-ruby (~> 1.0) io-like (0.3.1) jbuilder (2.11.5) actionview (>= 5.0.0) activesupport (>= 5.0.0) json (2.6.3) - jwt (2.7.0) + jwt (2.7.1) listen (3.8.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) @@ -160,10 +159,10 @@ GEM matrix (0.4.2) method_source (1.0.0) mini_mime (1.1.2) - minitest (5.18.0) + minitest (5.18.1) msgpack (1.7.1) multi_xml (0.6.0) - net-imap (0.3.4) + net-imap (0.3.6) date net-protocol net-pop (0.1.2) @@ -195,8 +194,9 @@ GEM actionpack (>= 4.2) omniauth (~> 2.0) parallel (1.23.0) - parser (3.2.2.1) + parser (3.2.2.3) ast (~> 2.4.1) + racc power_assert (2.0.3) pry (0.14.2) coderay (~> 1.1) @@ -208,7 +208,7 @@ GEM public_suffix (5.0.1) puma (6.1.1) nio4r (~> 2.0) - racc (1.6.2) + racc (1.7.1) rack (2.2.7) rack-protection (3.0.6) rack @@ -231,8 +231,9 @@ GEM rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.5.0) - loofah (~> 2.19, >= 2.19.1) + rails-html-sanitizer (1.6.0) + loofah (~> 2.21) + nokogiri (~> 1.14) railties (7.0.4.3) actionpack (= 7.0.4.3) activesupport (= 7.0.4.3) @@ -245,7 +246,7 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - regexp_parser (2.8.0) + regexp_parser (2.8.1) rexml (3.2.5) rubocop (1.48.1) json (~> 2.3) @@ -257,7 +258,7 @@ GEM rubocop-ast (>= 1.26.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.28.1) + rubocop-ast (1.29.0) parser (>= 3.2.1.0) ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) @@ -292,10 +293,10 @@ GEM sprockets (>= 3.0.0) sqlite3 (1.6.3-x64-mingw-ucrt) sqlite3 (1.6.3-x86_64-linux) - test-unit (3.5.9) + test-unit (3.6.0) power_assert thor (1.2.2) - tilt (2.1.0) + tilt (2.2.0) timeout (0.3.2) turbolinks (5.2.1) turbolinks-source (~> 5.2) @@ -309,7 +310,7 @@ GEM uglifier (4.2.0) execjs (>= 0.3.0, < 3) unicode-display_width (2.4.2) - version_gem (1.1.2) + version_gem (1.1.3) web-console (4.2.0) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -361,7 +362,7 @@ DEPENDENCIES web-console (~> 4.2.0) RUBY VERSION - ruby 3.1.2p20 + ruby 3.2.0p0 BUNDLED WITH 2.3.7 diff --git a/app/services/room_api/eg004_add_forms_to_room_service.rb b/app/services/room_api/eg004_add_forms_to_room_service.rb index 0709c4f..9f0a932 100644 --- a/app/services/room_api/eg004_add_forms_to_room_service.rb +++ b/app/services/room_api/eg004_add_forms_to_room_service.rb @@ -8,20 +8,26 @@ def initialize(args) end def worker + #ds-snippet-start:Rooms4Step2 configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:Rooms4Step2 + #ds-snippet-start:Rooms4Step4 rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) rooms_api.add_form_to_room(args[:room_id], args[:account_id], body(args[:form_id])) + #ds-snippet-end:Rooms4Step4 end def body(form_id) + #ds-snippet-start:Rooms4Step3 DocuSign_Rooms::FormForAdd.new({ formId: form_id }) + #ds-snippet-end:Rooms4Step3 end end From 5fcbec3ddf89020a6c56998a774f1f048a6861bc Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 1 Aug 2023 14:53:28 -0700 Subject: [PATCH 241/363] DEVDOCS-10462 - adding codeDepot markers --- .../room_api/reg002_create_room_with_template_controller.rb | 2 ++ .../room_api/eg002_create_room_with_template_service.rb | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/app/controllers/room_api/reg002_create_room_with_template_controller.rb b/app/controllers/room_api/reg002_create_room_with_template_controller.rb index 6fc40bc..ac5e264 100644 --- a/app/controllers/room_api/reg002_create_room_with_template_controller.rb +++ b/app/controllers/room_api/reg002_create_room_with_template_controller.rb @@ -23,6 +23,8 @@ def create end def get + #ds-snippet-start:Rooms2Step3 @templates = RoomApi::GetDataService.new(session).get_templates + #ds-snippet-end:Rooms2Step3 end end diff --git a/app/services/room_api/eg002_create_room_with_template_service.rb b/app/services/room_api/eg002_create_room_with_template_service.rb index 2842654..f6015f4 100644 --- a/app/services/room_api/eg002_create_room_with_template_service.rb +++ b/app/services/room_api/eg002_create_room_with_template_service.rb @@ -8,19 +8,24 @@ def initialize(args) end def worker + #ds-snippet-start:Rooms2Step2 configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host api_client = DocuSign_Rooms::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:Rooms2Step2 + #ds-snippet-start:Rooms2Step5 rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) rooms_api.create_room(args[:account_id], body(args)) + #ds-snippet-end:Rooms2Step5 end private def body(args) + #ds-snippet-start:Rooms2Step4 DocuSign_Rooms::RoomForCreate.new( { name: args[:room_name], @@ -41,5 +46,6 @@ def body(args) ) } ) + #ds-snippet-end:Rooms2Step4 end end From dcff691ae06fe6ce08701cb8f117a4a2d7a63f84 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Wed, 9 Aug 2023 14:25:41 -0700 Subject: [PATCH 242/363] DEVDOCS-10549 - adding codeDepot markers --- app/services/e_sign/eg008_create_template_service.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/services/e_sign/eg008_create_template_service.rb b/app/services/e_sign/eg008_create_template_service.rb index 50d4a80..5647db7 100644 --- a/app/services/e_sign/eg008_create_template_service.rb +++ b/app/services/e_sign/eg008_create_template_service.rb @@ -9,7 +9,6 @@ def initialize(args) @args = args end - # ***DS.snippet.0.start def worker templates_api = create_template_api(args) # Step 1. Does the template exist? Try to look it up by name @@ -24,8 +23,10 @@ def worker else # Template not found -- so create it # Step 2 create the template + #ds-snippet-start:eSign8Step3 template_req_object = make_template_req result = templates_api.create_template(args[:account_id], template_req_object) + #ds-snippet-end:eSign8Step3 created_new_template = true # Retreive the new template ID @@ -39,6 +40,7 @@ def worker } end + #ds-snippet-start:eSign8Step2 def make_template_req # document 1 is a PDF # @@ -170,5 +172,5 @@ def make_template_req 'status' => 'created' ) end - # ***DS.snippet.0.end + #ds-snippet-end:eSign8Step2 end From cae358b6604968a4d2f495950eb3afd2696ee085 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Wed, 9 Aug 2023 14:28:06 -0700 Subject: [PATCH 243/363] DEVDOCS-10363 - adding codeDepot markers --- app/services/e_sign/eg028_brands_creating_service.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/services/e_sign/eg028_brands_creating_service.rb b/app/services/e_sign/eg028_brands_creating_service.rb index 944b4c5..afdef4c 100644 --- a/app/services/e_sign/eg028_brands_creating_service.rb +++ b/app/services/e_sign/eg028_brands_creating_service.rb @@ -19,10 +19,14 @@ def worker api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" # Step 3: Construct your request body + #ds-snippet-start:eSign28Step3 accounts_api = DocuSign_eSign::AccountsApi.new api_client params = { brandName: args[:brandName], defaultBrandLanguage: args[:defaultBrandLanguage] } + #ds-snippet-end:eSign28Step3 # Step 4: Call the eSignature API + #ds-snippet-start:eSign28Step4 accounts_api.create_brand(args[:account_id], params) + #ds-snippet-end:eSign28Step4 end end From ef73545482c24bd45b91912375c24ccbebc53263 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 22 Aug 2023 15:50:18 -0700 Subject: [PATCH 244/363] DEVDOCS-10419 - adding codeDepot markers --- app/services/e_sign/eg037_sms_delivery_service.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/services/e_sign/eg037_sms_delivery_service.rb b/app/services/e_sign/eg037_sms_delivery_service.rb index 5a13ffd..bcd6ecd 100644 --- a/app/services/e_sign/eg037_sms_delivery_service.rb +++ b/app/services/e_sign/eg037_sms_delivery_service.rb @@ -17,16 +17,16 @@ def worker # Call Envelopes::create API method # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) - # Step 3 start + #ds-snippet-start:eSign37Step3 results = envelope_api.create_envelope args[:account_id], envelope_definition - # Step 3 end + #ds-snippet-end:eSign37Step3 envelope_id = results.envelope_id { 'envelope_id' => envelope_id } end private - # Step 2 start + #ds-snippet-start:eSign37Step2 def make_envelope(envelope_args) # document 1 (HTML) has tag **signature_1** # document 2 (DOCX) has tag /sn1/ @@ -169,5 +169,5 @@ def create_document1(args) " end - # Step 2 end + #ds-snippet-end:eSign37Step2 end From c5266dbe5c71b799ba480cfb007a26a3d64dcc21 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Wed, 23 Aug 2023 20:30:18 +0000 Subject: [PATCH 245/363] fix page (#132) --- .../get.html.erb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/views/admin_api/aeg008_update_user_product_permission_profile/get.html.erb b/app/views/admin_api/aeg008_update_user_product_permission_profile/get.html.erb index 76ce3c1..2b5e65c 100644 --- a/app/views/admin_api/aeg008_update_user_product_permission_profile/get.html.erb +++ b/app/views/admin_api/aeg008_update_user_product_permission_profile/get.html.erb @@ -2,8 +2,7 @@ <% form_index = 0 %> <% product_index = 0 %> -<% esign_permission_index = 1 %> -<% clm_permission_index = 2 %> +<% permission_index = 1 %> <% redirect_to2_index = 0 %> <% if @email_ok %> @@ -19,7 +18,7 @@ <% if @clm_permission_profiles.present? %>
    - + <%= select_tag "clm_permission_profile_id", options_for_select(@clm_permission_profiles.map { |obj| [obj['permission_profile_name'], obj['permission_profile_id']] }), { :class => 'form-control' } %>
    <% else %> @@ -31,7 +30,7 @@ <% if @esign_permission_profiles.present? %> <% else %> From d2144a7aeb64f1d0de8024dcc27cacde20ad2693 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Mon, 28 Aug 2023 17:55:01 -0700 Subject: [PATCH 246/363] add whatsapp option (#133) * add whatsapp option to SMS delivery example --- .../e_sign/eeg037_sms_delivery_controller.rb | 1 + app/controllers/eg_controller.rb | 3 +++ app/services/e_sign/eg037_sms_delivery_service.rb | 4 ++-- app/views/e_sign/eeg037_sms_delivery/get.html.erb | 11 +++++++++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/controllers/e_sign/eeg037_sms_delivery_controller.rb b/app/controllers/e_sign/eeg037_sms_delivery_controller.rb index ac82553..dc82fa9 100644 --- a/app/controllers/e_sign/eeg037_sms_delivery_controller.rb +++ b/app/controllers/e_sign/eeg037_sms_delivery_controller.rb @@ -6,6 +6,7 @@ class ESign::Eeg037SmsDeliveryController < EgController def create envelope_args = { + delivery_method: param_gsub(params['delivery_method']), signer_name: param_gsub(params['signer_name']), cc_name: param_gsub(params['cc_name']), cc_phone_number: param_gsub(params['cc_phone_number']), diff --git a/app/controllers/eg_controller.rb b/app/controllers/eg_controller.rb index 3c45b3f..150361e 100644 --- a/app/controllers/eg_controller.rb +++ b/app/controllers/eg_controller.rb @@ -38,6 +38,9 @@ def get def set_meta @source_file = file_name.to_s + #remove extra character that doesn't exist in service file + index = @source_file.index('/') + @source_file[index + 1] = '' @source_url = "#{Rails.application.config.github_example_url}#{@source_file}" end diff --git a/app/services/e_sign/eg037_sms_delivery_service.rb b/app/services/e_sign/eg037_sms_delivery_service.rb index bcd6ecd..f3763ca 100644 --- a/app/services/e_sign/eg037_sms_delivery_service.rb +++ b/app/services/e_sign/eg037_sms_delivery_service.rb @@ -88,7 +88,7 @@ def make_envelope(envelope_args) signer1.name = envelope_args[:signer_name] signer1.recipient_id = '1' signer1.routing_order = '1' - signer1.delivery_method = 'SMS' + signer1.delivery_method = envelope_args[:delivery_method] ## routingOrder (lower means earlier) determines the order of deliveries # to the recipients. Parallel routing order is supported by using the @@ -104,7 +104,7 @@ def make_envelope(envelope_args) cc1.routing_order = '2' cc1.recipient_id = '2' cc1.phone_number = cc_phone_number - cc1.delivery_method = 'SMS' + cc1.delivery_method = envelope_args[:delivery_method] # Create signHere fields (also known as tabs) on the documents # We're using anchor (autoPlace) positioning diff --git a/app/views/e_sign/eeg037_sms_delivery/get.html.erb b/app/views/e_sign/eeg037_sms_delivery/get.html.erb index 59c8c9b..afa8ca9 100644 --- a/app/views/e_sign/eeg037_sms_delivery/get.html.erb +++ b/app/views/e_sign/eeg037_sms_delivery/get.html.erb @@ -7,12 +7,23 @@ <% cc_code_index = 3 %> <% cc_phone_index = 4 %> <% cc_name_index = 5 %> +<% delivery_method_index = 6 %> +<% sms_index = 7 %> +<% whatsapp_index = 8 %>
    <% if @example["Forms"][form_index]["FormName"] %> <%= sanitize @example["Forms"][form_index]["FormName"] %> <% end %> +
    +
    + + + + +
    +
    Date: Wed, 30 Aug 2023 13:08:02 -0700 Subject: [PATCH 247/363] DEVDOCS-10234 adding codeDepot markers --- app/services/e_sign/eg009_use_template_service.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/services/e_sign/eg009_use_template_service.rb b/app/services/e_sign/eg009_use_template_service.rb index 22c4a70..98b7721 100644 --- a/app/services/e_sign/eg009_use_template_service.rb +++ b/app/services/e_sign/eg009_use_template_service.rb @@ -9,19 +9,21 @@ def initialize(args) @args = args end - # ***DS.snippet.0.start + #ds-snippet-start:eSign9Step3 def worker envelope_args = args[:envelope_args] - # 1. Create the envelope request object + # Create the envelope request object envelope_definition = make_envelope(envelope_args) - # 2. Call Envelopes::create API method + # Call Envelopes::create API method # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope_definition envelope_id = results.envelope_id { envelope_id: envelope_id } end + #ds-snippet-end:eSign9Step3 + #ds-snippet-start:eSign9Step2 def make_envelope(args) # Create the envelope definition with the template_id envelope_definition = DocuSign_eSign::EnvelopeDefinition.new({ @@ -65,5 +67,5 @@ def make_envelope(args) envelope_definition.template_roles = [signer, cc] envelope_definition end - # ***DS.snippet.0.end + #ds-snippet-end:eSign9Step2 end From 8c357e266b0124723c54c9a0e5aa8c1b66a88307 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Wed, 30 Aug 2023 13:11:05 -0700 Subject: [PATCH 248/363] DEVDOCS-10508 adding codeDepot markers --- app/services/e_sign/eg002_signing_via_email_service.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/services/e_sign/eg002_signing_via_email_service.rb b/app/services/e_sign/eg002_signing_via_email_service.rb index ed5207b..3d5fa16 100644 --- a/app/services/e_sign/eg002_signing_via_email_service.rb +++ b/app/services/e_sign/eg002_signing_via_email_service.rb @@ -9,10 +9,11 @@ def initialize(args) @args = args end + #ds-snippet-start:eSign2Step3 def worker - # 1. Create the envelope request object + # Create the envelope request object envelope_definition = make_envelope args[:envelope_args] - # 2. Call Envelopes::create API method + # Call Envelopes::create API method # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) @@ -20,9 +21,11 @@ def worker envelope_id = results.envelope_id { 'envelope_id' => envelope_id } end + #ds-snippet-end:eSign2Step3 private + #ds-snippet-start:eSign2Step2 def make_envelope(envelope_args) # document 1 (HTML) has tag **signature_1** # document 2 (DOCX) has tag /sn1/ @@ -152,4 +155,5 @@ def create_document1(args) " end + #ds-snippet-end:eSign2Step2 end From 54c36c3019e189925d4bcc976c03ad57da0a17ae Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Tue, 5 Sep 2023 16:53:20 -0400 Subject: [PATCH 249/363] remove stage link from click example (#135) --- app/views/clickwrap/ceg006_embed_clickwrap/results.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/clickwrap/ceg006_embed_clickwrap/results.html.erb b/app/views/clickwrap/ceg006_embed_clickwrap/results.html.erb index 6b6f6eb..86c2e3f 100644 --- a/app/views/clickwrap/ceg006_embed_clickwrap/results.html.erb +++ b/app/views/clickwrap/ceg006_embed_clickwrap/results.html.erb @@ -16,7 +16,7 @@

    Continue

    - + <%= javascript_tag do %> docuSignClick.Clickwrap.render({ agreementUrl: "<%= @agreementUrl.html_safe %>", From 30931ba81d7fab1643556dc2ab6a8615c770dfb1 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Wed, 6 Sep 2023 14:59:59 -0700 Subject: [PATCH 250/363] DEVDOCS-10358 adding codeDepot markers --- .../eg031_bulk_sending_envelopes_service.rb | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb index bf796e5..3201220 100644 --- a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb +++ b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb @@ -12,45 +12,45 @@ def initialize(args, signers) def worker # Construct your API headers - # Step 2 start + #ds-snippet-start:eSign31Step2 configuration = DocuSign_eSign::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_eSign::ApiClient.new configuration construct_api_headers(api_client, args) - # Step end + #ds-snippet-end:eSign31Step2 # Create and submit the bulk sending list - # Step 3-1 start + #ds-snippet-start:eSign31Step3 bulk_envelopes_api = DocuSign_eSign::BulkEnvelopesApi.new api_client bulk_sending_list = create_bulk_sending_list(signers) bulk_list = bulk_envelopes_api.create_bulk_send_list(args[:account_id], bulk_sending_list) bulk_list_id = bulk_list.list_id - # Step 3-1 end + #ds-snippet-end:eSign31Step3 # Create the draft envelope - # Step 4-1 start + #ds-snippet-start:eSign31Step4 envelope_api = create_envelope_api(args) envelope_definition = make_envelope envelope = envelope_api.create_envelope(args[:account_id], envelope_definition, DocuSign_eSign::CreateEnvelopeOptions.default) envelope_id = envelope.envelope_id - # Step 4-1 end + #ds-snippet-end:eSign31Step4 # Attach your bulk list ID to the envelope - # Step 5-1 start + #ds-snippet-start:eSign31Step5 envelope_api.create_custom_fields(args[:account_id], envelope_id, custom_fields(bulk_list_id)) - # Step 5-1 end + #ds-snippet-end:eSign31Step5 # Initiate bulk send - # Step 6 start + #ds-snippet-start:eSign31Step6 bulk_send_request = DocuSign_eSign::BulkSendRequest.new(envelopeOrTemplateId: envelope_id) batch = bulk_envelopes_api.create_bulk_send_request(args[:account_id], bulk_list_id, bulk_send_request) batch_id = batch.batch_id - # Step 6 end + #ds-snippet-end:eSign31Step6 # Confirm successful batch send - # Step 7 start + #ds-snippet-start:eSign31Step7 bulk_envelopes_api.get_bulk_send_batch_status(args[:account_id], batch_id) - # Step 7 end + #ds-snippet-end:eSign31Step7 end private @@ -63,7 +63,6 @@ def construct_api_headers(api_client, args) api_client.default_headers['Accept-Language'] = 'en-US,en;q=0.9' end - # Step 3-2 start def create_bulk_sending_list(signers) bulk_copies = [] recipient1 = DocuSign_eSign::BulkSendingCopyRecipient.new( @@ -111,9 +110,7 @@ def create_bulk_sending_list(signers) bulkCopies: bulk_copies ) end - # Step 3-2 end - # Step 5-2 start def custom_fields(bulk_list_id) text_custom_fields = DocuSign_eSign::TextCustomField.new( name: 'mailingListId', @@ -126,9 +123,7 @@ def custom_fields(bulk_list_id) textCustomFields: [text_custom_fields] ) end - # Step 5-2 end - # Step 4-2 start def make_envelope # Create the envelope definition envelope_definition = DocuSign_eSign::EnvelopeDefinition.new @@ -192,5 +187,4 @@ def make_envelope envelope_definition.status = 'created' envelope_definition end - # Step 4-2 end end From d5468c2a1ea6407e31d312cbaf7ca625101e384d Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Wed, 6 Sep 2023 15:02:39 -0700 Subject: [PATCH 251/363] DEVDOCS-10571 adding codeDepot markers --- app/services/e_sign/eg005_envelope_recipients_service.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/services/e_sign/eg005_envelope_recipients_service.rb b/app/services/e_sign/eg005_envelope_recipients_service.rb index e78fb41..0107923 100644 --- a/app/services/e_sign/eg005_envelope_recipients_service.rb +++ b/app/services/e_sign/eg005_envelope_recipients_service.rb @@ -10,7 +10,9 @@ def initialize(args) end def worker + #ds-snippet-start:eSign5Step2 envelope_api = create_envelope_api(args) envelope_api.list_recipients args[:account_id], args[:envelope_id] + #ds-snippet-end:eSign5Step2 end end From 7c45c33f411990692c7b32f3bbcdb939fdd97ce7 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Wed, 13 Sep 2023 16:27:57 +0000 Subject: [PATCH 252/363] Account cloning code example (#134) * added code example --- Gemfile | 8 +-- Gemfile.lock | 62 ++++++++++--------- .../aeg012_clone_account_controller.rb | 35 +++++++++++ .../admin_api/eg012_clone_account_service.rb | 58 +++++++++++++++++ app/services/jwt_auth/jwt_creator.rb | 4 +- .../aeg012_clone_account/get.html.erb | 40 ++++++++++++ config/initializers/omniauth.rb | 2 +- config/routes.rb | 3 + quick_acg/config/initializers/omniauth.rb | 2 +- test/test_helper.rb | 2 +- 10 files changed, 177 insertions(+), 39 deletions(-) create mode 100644 app/controllers/admin_api/aeg012_clone_account_controller.rb create mode 100644 app/services/admin_api/eg012_clone_account_service.rb create mode 100644 app/views/admin_api/aeg012_clone_account/get.html.erb diff --git a/Gemfile b/Gemfile index 5def594..2b0c6ed 100644 --- a/Gemfile +++ b/Gemfile @@ -68,10 +68,10 @@ group :test do gem 'test-unit' end -gem 'docusign_admin', '~> 1.2.0' -gem 'docusign_click', '~> 1.3.0' -gem 'docusign_esign', '~> 3.23.0' -gem 'docusign_monitor', '~> 1.1.0' +gem 'docusign_admin', '~> 1.3.0' +gem 'docusign_click', '~> 1.4.0' +gem 'docusign_esign', '~> 3.24.0' +gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' gem 'omniauth-oauth2', '~> 1.8.0' gem 'omniauth-rails_csrf_protection' diff --git a/Gemfile.lock b/Gemfile.lock index 7107a75..abcabd2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -66,7 +66,7 @@ GEM i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - addressable (2.8.4) + addressable (2.8.5) public_suffix (>= 2.0.2, < 6.0) archive-zip (0.12.0) io-like (~> 0.3.0) @@ -99,22 +99,22 @@ GEM concurrent-ruby (1.2.2) crass (1.0.6) date (3.3.3) - docusign_admin (1.2.0) + docusign_admin (1.3.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_click (1.3.0) + docusign_click (1.4.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.23.0) + docusign_esign (3.24.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_monitor (1.1.0) + docusign_monitor (1.2.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -128,11 +128,12 @@ GEM ethon (0.16.0) ffi (>= 1.15.0) execjs (2.8.1) - faraday (2.7.7) + faraday (2.7.10) faraday-net_http (>= 2.0, < 3.1) ruby2_keywords (>= 0.0.4) faraday-net_http (3.0.2) ffi (1.15.5) + ffi (1.15.5-x64-mingw-ucrt) globalid (1.1.0) activesupport (>= 5.0) hashie (5.0.0) @@ -158,11 +159,11 @@ GEM marcel (1.0.2) matrix (0.4.2) method_source (1.0.0) - mini_mime (1.1.2) - minitest (5.18.1) - msgpack (1.7.1) + mini_mime (1.1.5) + minitest (5.19.0) + msgpack (1.7.2) multi_xml (0.6.0) - net-imap (0.3.6) + net-imap (0.3.7) date net-protocol net-pop (0.1.2) @@ -172,9 +173,9 @@ GEM net-smtp (0.3.3) net-protocol nio4r (2.5.9) - nokogiri (1.15.2-x64-mingw-ucrt) + nokogiri (1.15.4-x64-mingw-ucrt) racc (~> 1.4) - nokogiri (1.15.2-x86_64-linux) + nokogiri (1.15.4-x86_64-linux) racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) @@ -205,13 +206,13 @@ GEM pry (>= 0.9.10, < 0.15) pry-rails (0.3.9) pry (>= 0.10.4) - public_suffix (5.0.1) + public_suffix (5.0.3) puma (6.1.1) nio4r (~> 2.0) racc (1.7.1) - rack (2.2.7) - rack-protection (3.0.6) - rack + rack (2.2.8) + rack-protection (3.1.0) + rack (~> 2.2, >= 2.2.4) rack-test (2.1.0) rack (>= 1.3) rails (7.0.4.3) @@ -228,8 +229,9 @@ GEM activesupport (= 7.0.4.3) bundler (>= 1.15.0) railties (= 7.0.4.3) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest nokogiri (>= 1.6) rails-html-sanitizer (1.6.0) loofah (~> 2.21) @@ -247,7 +249,7 @@ GEM rb-inotify (0.10.1) ffi (~> 1.0) regexp_parser (2.8.1) - rexml (3.2.5) + rexml (3.2.6) rubocop (1.48.1) json (~> 2.3) parallel (~> 1.10) @@ -291,13 +293,13 @@ GEM actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) - sqlite3 (1.6.3-x64-mingw-ucrt) - sqlite3 (1.6.3-x86_64-linux) - test-unit (3.6.0) + sqlite3 (1.6.4-x64-mingw-ucrt) + sqlite3 (1.6.4-x86_64-linux) + test-unit (3.6.1) power_assert thor (1.2.2) tilt (2.2.0) - timeout (0.3.2) + timeout (0.4.0) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) @@ -317,12 +319,12 @@ GEM bindex (>= 0.4.0) railties (>= 6.0.0) websocket (1.2.9) - websocket-driver (0.7.5) + websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.8) + zeitwerk (2.6.11) PLATFORMS x64-mingw-ucrt @@ -334,10 +336,10 @@ DEPENDENCIES capybara (~> 3.38.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_admin (~> 1.2.0) - docusign_click (~> 1.3.0) - docusign_esign (~> 3.23.0) - docusign_monitor (~> 1.1.0) + docusign_admin (~> 1.3.0) + docusign_click (~> 1.4.0) + docusign_esign (~> 3.24.0) + docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) jbuilder (~> 2.11.5) listen (~> 3.8.0) @@ -362,7 +364,7 @@ DEPENDENCIES web-console (~> 4.2.0) RUBY VERSION - ruby 3.2.0p0 + ruby 3.1.2p20 BUNDLED WITH 2.3.7 diff --git a/app/controllers/admin_api/aeg012_clone_account_controller.rb b/app/controllers/admin_api/aeg012_clone_account_controller.rb new file mode 100644 index 0000000..80a7baf --- /dev/null +++ b/app/controllers/admin_api/aeg012_clone_account_controller.rb @@ -0,0 +1,35 @@ +class AdminApi::Aeg012CloneAccountController < EgController + before_action -> { check_auth('Admin') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 12, 'Admin') } + + def create + args = { + access_token: session['ds_access_token'], + organization_id: session['organization_id'], + source_account_id: param_gsub(params['source_account_id']), + target_account_name: param_gsub(params['target_account_name']), + target_account_first_name: param_gsub(params['target_account_first_name']), + target_account_last_name: param_gsub(params['target_account_last_name']), + target_account_email: param_gsub(params['target_account_email']) + } + + results = AdminApi::Eg012CloneAccountService.new(args).worker + + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) + end + + def get + super + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? + args = { + access_token: session['ds_access_token'], + organization_id: session['organization_id'] + } + @accounts = AdminApi::Eg012CloneAccountService.new(args).get_account.asset_group_accounts + end +end diff --git a/app/services/admin_api/eg012_clone_account_service.rb b/app/services/admin_api/eg012_clone_account_service.rb new file mode 100644 index 0000000..4d892c2 --- /dev/null +++ b/app/services/admin_api/eg012_clone_account_service.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +class AdminApi::Eg012CloneAccountService + attr_reader :args + + def initialize(args) + @args = args + end + + def worker + #ds-snippet-start:Admin12Step2 + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:Admin12Step2 + + #ds-snippet-start:Admin12Step4 + source_account = DocuSign_Admin::AssetGroupAccountCloneSourceAccount.new + source_account.id = args[:source_account_id] + + target_account_admin = DocuSign_Admin::AssetGroupAccountCloneTargetAccountAdmin.new + target_account_admin.first_name = args[:target_account_first_name] + target_account_admin.last_name = args[:target_account_last_name] + target_account_admin.email = args[:target_account_email] + + target_account = DocuSign_Admin::AssetGroupAccountCloneTargetAccount.new + target_account.name = args[:target_account_name] + target_account.admin = target_account_admin + target_account.country_code = 'US' + + account_data = DocuSign_Admin::AssetGroupAccountClone.new + account_data.source_account = source_account + account_data.target_account = target_account + #ds-snippet-end:Admin12Step4 + + #ds-snippet-start:Admin12Step5 + asset_group_api = DocuSign_Admin::ProvisionAssetGroupApi.new(api_client) + asset_group_api.clone_asset_group_account(args[:organization_id], account_data) + #ds-snippet-end:Admin12Step5 + end + + def get_account + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + + #ds-snippet-start:Admin12Step3 + asset_group_api = DocuSign_Admin::ProvisionAssetGroupApi.new(api_client) + options = DocuSign_Admin::GetAssetGroupAccountsOptions.new + options.compliant = true + asset_group_api.get_asset_group_accounts(args[:organization_id], options) + #ds-snippet-start:Admin12Step3 + end +end diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index dd9e96b..6f60b77 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -16,7 +16,7 @@ def self.consent_url(state, api) scope = 'signature impersonation' if %w[eSignature Monitor].include?(api) scope = 'signature impersonation 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' if api == 'Rooms' scope = 'signature impersonation click.manage click.send' if api == 'Click' - scope = 'signature impersonation organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact' if api == 'Admin' + scope = 'signature impersonation organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read' if api == 'Admin' base_uri = "#{Rails.configuration.authorization_server}/oauth/auth" response_type = 'code' @@ -42,7 +42,7 @@ def initialize(session) end @client_module = DocuSign_Monitor if session[:api] == 'Monitor' if session[:api] == 'Admin' - scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact' + scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read' @client_module = DocuSign_Admin end diff --git a/app/views/admin_api/aeg012_clone_account/get.html.erb b/app/views/admin_api/aeg012_clone_account/get.html.erb new file mode 100644 index 0000000..73eca05 --- /dev/null +++ b/app/views/admin_api/aeg012_clone_account/get.html.erb @@ -0,0 +1,40 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% source_account_id_index = 0 %> +<% target_account_name_index = 1 %> +<% target_account_first_name_index = 2 %> +<% target_account_last_name_index = 3 %> +<% target_account_email_index = 4 %> + + + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + <%= select_tag "source_account_id", options_for_select(@accounts.map { |obj| [obj.account_name, obj.account_id] }), { :class => 'form-control' } %> +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    + <%= render('partials/submit_button') %> + diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 0b6b207..ad1e5dd 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -45,7 +45,7 @@ when 'Click' strategy.options[:authorize_params].scope = 'signature click.manage click.send' when 'Admin' - strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact' + strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read' end } end diff --git a/config/routes.rb b/config/routes.rb index 8ae2fad..c20dfa0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -90,6 +90,9 @@ get 'aeg011' => 'aeg011_delete_user_data_from_account#get' post 'aeg011' => 'aeg011_delete_user_data_from_account#create' + + get 'aeg012' => 'aeg012_clone_account#get' + post 'aeg012' => 'aeg012_clone_account#create' end get '/eeg001' => 'eeg001_embedded_signing#get' diff --git a/quick_acg/config/initializers/omniauth.rb b/quick_acg/config/initializers/omniauth.rb index 0b6b207..ad1e5dd 100644 --- a/quick_acg/config/initializers/omniauth.rb +++ b/quick_acg/config/initializers/omniauth.rb @@ -45,7 +45,7 @@ when 'Click' strategy.options[:authorize_params].scope = 'signature click.manage click.send' when 'Admin' - strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact' + strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read' end } end diff --git a/test/test_helper.rb b/test/test_helper.rb index 0670721..6192f03 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -8,7 +8,7 @@ $_scopes = %w[signature impersonation] $_click_scopes = %w[click.manage click.send] $_rooms_scopes = %w[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] -$_admin_scopes = %w[organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact] +$_admin_scopes = %w[organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read] class TestHelper < Test::Unit::TestCase From 1ce99daa8477cc4e06df8787bd72de1b6a697b3e Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Wed, 13 Sep 2023 10:49:06 -0700 Subject: [PATCH 253/363] fix codeDepot snippet --- app/services/admin_api/eg012_clone_account_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/admin_api/eg012_clone_account_service.rb b/app/services/admin_api/eg012_clone_account_service.rb index 4d892c2..cb1ac61 100644 --- a/app/services/admin_api/eg012_clone_account_service.rb +++ b/app/services/admin_api/eg012_clone_account_service.rb @@ -53,6 +53,6 @@ def get_account options = DocuSign_Admin::GetAssetGroupAccountsOptions.new options.compliant = true asset_group_api.get_asset_group_accounts(args[:organization_id], options) - #ds-snippet-start:Admin12Step3 + #ds-snippet-end:Admin12Step3 end end From 2402c95e9f21eec8a77f6a52f29189ac07c068f2 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Thu, 21 Sep 2023 16:39:43 -0700 Subject: [PATCH 254/363] DEVDOCS-10621 adding codeDepot markers --- .../e_sign/eg041_cfr_embedded_signing_service.rb | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/services/e_sign/eg041_cfr_embedded_signing_service.rb b/app/services/e_sign/eg041_cfr_embedded_signing_service.rb index 4795a8b..b998635 100644 --- a/app/services/e_sign/eg041_cfr_embedded_signing_service.rb +++ b/app/services/e_sign/eg041_cfr_embedded_signing_service.rb @@ -9,9 +9,10 @@ def initialize(args) @args = args end - # ***DS.snippet.0.start def worker envelope_args = args[:envelope_args] + + #ds-snippet-start:eSign41Step2 accounts_api = create_account_api(args) # Obtain your workflow_id @@ -21,16 +22,20 @@ def worker workflow = workflow_results.identity_verification.find { |item| item.default_name == 'SMS for access & signatures' } workflow_id = workflow.workflow_id if workflow end + #ds-snippet-end:eSign41Step2 return 'invalid_workflow_id' if workflow_id.blank? + #ds-snippet-start:eSign41Step4 envelope_api = create_envelope_api(args) envelope_definition = make_envelope(args[:envelope_args], workflow_id) envelope = envelope_api.create_envelope(args[:account_id], envelope_definition) envelope_id = envelope.envelope_id + #ds-snippet-end:eSign41Step4 + #ds-snippet-start:eSign41Step5 view_request = DocuSign_eSign::RecipientViewRequest.new({ returnUrl: "#{envelope_args[:ds_return_url]}?state=123", authenticationMethod: 'none', @@ -40,14 +45,18 @@ def worker pingFrequency: 600, pingUrl: envelope_args[:ds_ping_url] }) + #ds-snippet-end:eSign41Step5 + #ds-snippet-start:eSign41Step6 results = envelope_api.create_recipient_view(args[:account_id], envelope_id, view_request) results.url + #ds-snippet-end:eSign41Step6 end private + #ds-snippet-start:eSign41Step3 def make_envelope(args, workflow_id) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document sent from Ruby SDK' @@ -106,5 +115,5 @@ def make_envelope(args, workflow_id) envelope_definition.status = 'sent' envelope_definition end - # ***DS.snippet.0.end + #ds-snippet-end:eSign41Step3 end From a37c3abcb9727064495fff0848ec99fe56e23d9c Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Thu, 21 Sep 2023 17:24:21 -0700 Subject: [PATCH 255/363] update text for order form --- data/order_form.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/order_form.html b/data/order_form.html index cddf370..15b87dd 100644 --- a/data/order_form.html +++ b/data/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 From a2ff0abd64ae4eadae21cc1e0a4f6699a17d74c5 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Thu, 28 Sep 2023 16:57:49 -0700 Subject: [PATCH 256/363] DEVDOCS-10254 adding codeDepot markers --- .../eg016_set_envelope_tab_data_service.rb | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/app/services/e_sign/eg016_set_envelope_tab_data_service.rb b/app/services/e_sign/eg016_set_envelope_tab_data_service.rb index a042cbe..8c8a132 100644 --- a/app/services/e_sign/eg016_set_envelope_tab_data_service.rb +++ b/app/services/e_sign/eg016_set_envelope_tab_data_service.rb @@ -9,27 +9,30 @@ def initialize(args) @args = args end - # ***DS.snippet.0.start def worker ds_ping_url = Rails.application.config.app_url ds_return_url = "#{ds_ping_url}/ds_common-return" signer_client_id = 1000 pdf_filename = 'World_Wide_Corp_salary.docx' - # Step 4. Construct the request body + # Construct the request body envelope = make_envelope(args[:signer_email], args[:signer_name], signer_client_id, pdf_filename) - # Step 5. Call the eSignature REST API + # Call the eSignature REST API + #ds-snippet-start:eSign16Step4 results = create_envelope_api(args).create_envelope args[:account_id], envelope envelope_id = results.envelope_id + #ds-snippet-end:eSign16Step4 - # Step 6. Create the View Request + # Create the View Request + #ds-snippet-start:eSign16Step5 view_request = make_recipient_view_request(args[:signer_email], args[:signer_name], signer_client_id, ds_return_url, ds_ping_url) - + #ds-snippet-end:eSign16Step5 + # Call the CreateRecipientView API results = create_envelope_api(args).create_recipient_view args[:account_id], envelope_id, view_request - # Step 4. Redirect the user to the embedded signing + # 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 return URL (see the makeRecipientViewRequest method) @@ -66,6 +69,7 @@ def make_recipient_view_request(signer_email, signer_name, signer_client_id, ds_ view_request end + #ds-snippet-start:eSign16Step3 def make_envelope(signer_email, signer_name, signer_client_id, pdf_filename) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document sent from Ruby SDK' @@ -85,7 +89,7 @@ def make_envelope(signer_email, signer_name, signer_client_id, pdf_filename) clientUserId: signer_client_id, recipientId: 1 }) - # Step 3. Create Tabs and CustomFields + # Create Tabs and CustomFields sign_here1 = DocuSign_eSign::SignHere.new sign_here1.anchor_string = '/sn1/' @@ -171,5 +175,5 @@ def make_envelope(signer_email, signer_name, signer_client_id, pdf_filename) envelope_definition.status = 'sent' envelope_definition end - # ***DS.snippet.0.end + #ds-snippet-end:eSign16Step3 end From 1c352c5477f3a85e30045e9221dc85b1b6d7e8b5 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Thu, 28 Sep 2023 17:01:52 -0700 Subject: [PATCH 257/363] DEVDOCS-10158 adding codeDepot markers --- app/services/e_sign/eg014_collect_payment_service.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/services/e_sign/eg014_collect_payment_service.rb b/app/services/e_sign/eg014_collect_payment_service.rb index 1286139..e614a57 100644 --- a/app/services/e_sign/eg014_collect_payment_service.rb +++ b/app/services/e_sign/eg014_collect_payment_service.rb @@ -9,19 +9,21 @@ def initialize(args) @args = args end - # ***DS.snippet.0.start + #ds-snippet-start:eSign14Step4 def worker envelope_definition = make_envelope(args[:envelope_args]) - # 2. Create and send the envelope + # Create and send the envelope # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope_definition envelope_id = results.envelope_id { envelope_id: envelope_id } end + #ds-snippet-end:eSign14Step4 private + #ds-snippet-start:eSign14Step3 def make_envelope(args) # This function creates the envelope definition for the order form # document 1 (html) has multiple tags: @@ -200,5 +202,5 @@ def make_envelope(args) envelope_definition.recipients = recipients envelope_definition end - # ***DS.snippet.0.end + #ds-snippet-end:eSign14Step3 end From 287bb1451677877ceee2b9b61d7a420153a5e3b3 Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Tue, 10 Oct 2023 11:20:05 -0700 Subject: [PATCH 258/363] DEVDOCS-10338 --- .../eg030_brands_apply_to_template_service.rb | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/app/services/e_sign/eg030_brands_apply_to_template_service.rb b/app/services/e_sign/eg030_brands_apply_to_template_service.rb index ea0e162..0644e7e 100644 --- a/app/services/e_sign/eg030_brands_apply_to_template_service.rb +++ b/app/services/e_sign/eg030_brands_apply_to_template_service.rb @@ -10,19 +10,22 @@ def initialize(args) end def worker - # ***DS.snippet.0.start - # Step 1. Obtain your OAuth token - # Step 2. Construct your API headers + # Obtain your OAuth token + # Construct your API headers envelope_api = create_envelope_api(args) - # Step 3. Construct your envelope JSON body + # Construct your envelope JSON body + #ds-snippet-start:eSign30Step3 envelope_definition = make_envelope(args[:envelope_args]) - # Step 4. Call the eSignature REST API + #ds-snippet-end:eSign30Step3 + # Call the eSignature REST API + #ds-snippet-start:eSign30Step4 envelope_api.create_envelope args[:account_id], envelope_definition - # ***DS.snippet.0.end + #ds-snippet-end:eSign30Step4 end private + #ds-snippet-start:eSign30Step3 def make_envelope(envelope_args) # Create the envelope definition with the template_id envelope_definition = DocuSign_eSign::EnvelopeDefinition.new @@ -33,18 +36,19 @@ def make_envelope(envelope_args) # Create the template role elements to connect the signer and cc recipients # to the template signer = DocuSign_eSign::TemplateRole.new({ - email: envelope_args[:signer_email], - name: envelope_args[:signer_name], - roleName: 'signer' - }) + email: envelope_args[:signer_email], + name: envelope_args[:signer_name], + roleName: 'signer' + }) # Create a cc template role cc = DocuSign_eSign::TemplateRole.new({ - email: envelope_args[:cc_email], - name: envelope_args[:cc_name], - roleName: 'cc' - }) + email: envelope_args[:cc_email], + name: envelope_args[:cc_name], + roleName: 'cc' + }) envelope_definition.template_roles = [signer, cc] envelope_definition end + #ds-snippet-end:eSign30Step3 end From 20e719d970d67709153a61191482b20168608add Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Tue, 10 Oct 2023 12:10:57 -0700 Subject: [PATCH 259/363] DEVDOCS-10596 adding codeDepot markers --- .../e_sign/eg010_send_binary_docs_service.rb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/services/e_sign/eg010_send_binary_docs_service.rb b/app/services/e_sign/eg010_send_binary_docs_service.rb index 2057c96..391e495 100644 --- a/app/services/e_sign/eg010_send_binary_docs_service.rb +++ b/app/services/e_sign/eg010_send_binary_docs_service.rb @@ -5,12 +5,11 @@ def initialize(args) @args = args end - # ***DS.snippet.0.start def worker envelope_args = args[:envelope_args] - # Step 1. Make the envelope JSON request body + # Make the envelope JSON request body envelopeJSON = make_envelope_json(envelope_args) - # Step 2. Gather documents and their headers + # Gather documents and their headers # Read files from a local directory # The reads could raise an exception if the file is not available! config = Rails.application.config @@ -33,7 +32,7 @@ def worker bytes: doc3_pdf_bytes } ] - # Step 3. Create and send the envelope + # Create and send the envelope crlf = "\r\n" boundary = 'multipartboundary_multipartboundary' hyphens = '--' @@ -81,11 +80,14 @@ def worker buffer << hyphens buffer << crlf + #ds-snippet-start:eSign10Step2 header = { "Accept": 'application/json', "Authorization": "Bearer #{args[:access_token]}" } + #ds-snippet-end:eSign10Step2 # Change your API version in the URL below to v2 for API version 2 + #ds-snippet-start:eSign10Step4 uri = URI.parse("#{args[:base_path]}/restapi/v2.1/accounts/#{args[:account_id]}/envelopes") http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = (uri.scheme == 'https') @@ -98,11 +100,12 @@ def worker obj = JSON.parse(response.body) raise Net::HTTPError.new(response.code, response.body) unless (response.code.to_i >= 200) && (response.code.to_i < 300) - + #ds-snippet-end:eSign10Step4 envelope_id = obj['envelopeId'] { 'envelope_id' => envelope_id } end + #ds-snippet-start:eSign10Step3 def make_envelope_json(envelope_args) # document 1 (HTML) has tag **signature_1** # document 2 (DOCX) has tag /sn1/ @@ -214,5 +217,5 @@ def create_document1(args) " end - # ***DS.snippet.0.end + #ds-snippet-end:eSign10Step3 end From 7bb026e4c84beb0c29ad560720038b9d181ae723 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 13 Oct 2023 14:01:14 -0700 Subject: [PATCH 260/363] DEVDOCS-10392 - adding codeDepot tags --- .../e_sign/eg019_access_code_authentication_service.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/services/e_sign/eg019_access_code_authentication_service.rb b/app/services/e_sign/eg019_access_code_authentication_service.rb index 364b717..1dfefcf 100644 --- a/app/services/e_sign/eg019_access_code_authentication_service.rb +++ b/app/services/e_sign/eg019_access_code_authentication_service.rb @@ -10,11 +10,11 @@ def initialize(args) end def worker - # ***DS.snippet.0.start + envelope_api = create_envelope_api(args) envelope_args = args[:envelope_args] - # Step 3: Construct your envelope JSON body + #ds-snippet-start:eSign19Step3 envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document set' @@ -59,8 +59,10 @@ def worker # To request that the envelope be created as a draft, set to "created" envelope_definition.recipients = recipients envelope_definition.status = envelope_args[:status] - # Step 4. Call the eSignature REST API + #ds-snippet-end:eSign19Step3 + + #ds-snippet-start:eSign19Step4 envelope_api.create_envelope(args[:account_id], envelope_definition) - # ***DS.snippet.0.end + #ds-snippet-end:eSign19Step4 end end From 132d2c90ac1a79f8b9c7c1fa4ac7467f2b19ab3e Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 13 Oct 2023 14:12:36 -0700 Subject: [PATCH 261/363] DEVDOCS-10395 - codeDepot tags --- .../e_sign/eg018_get_envelope_custom_field_data_service.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb b/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb index e7accc6..e0805a3 100644 --- a/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb +++ b/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb @@ -10,7 +10,8 @@ def initialize(args) end def worker - # Step 3. Call the eSignature REST API + #ds-snippet-start:eSign19Step3 create_envelope_api(args).list_custom_fields args[:account_id], args[:envelope_id] + #ds-snippet-end:eSign19Step3 end end From b50b862ad46ca2fdf0c428466860001be97390af Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 13 Oct 2023 14:15:16 -0700 Subject: [PATCH 262/363] DEVDOCS-10395 - codeDepot tags fix --- .../e_sign/eg018_get_envelope_custom_field_data_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb b/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb index e0805a3..fead846 100644 --- a/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb +++ b/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb @@ -10,8 +10,8 @@ def initialize(args) end def worker - #ds-snippet-start:eSign19Step3 + #ds-snippet-start:eSign18Step3 create_envelope_api(args).list_custom_fields args[:account_id], args[:envelope_id] - #ds-snippet-end:eSign19Step3 + #ds-snippet-end:eSign18Step3 end end From 7ccc58692059ce330c594a0b2ae4c3e9d521e676 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Fri, 13 Oct 2023 15:48:49 -0700 Subject: [PATCH 263/363] DEVDOCS-10273 adding codeDepot markers --- .../e_sign/eg023_idv_authentication_service.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/services/e_sign/eg023_idv_authentication_service.rb b/app/services/e_sign/eg023_idv_authentication_service.rb index 45547b8..0f80901 100644 --- a/app/services/e_sign/eg023_idv_authentication_service.rb +++ b/app/services/e_sign/eg023_idv_authentication_service.rb @@ -12,14 +12,15 @@ def initialize(args) def worker envelope_args = args[:envelope_args] - # Step 3. Obtain your workflow ID + # Obtain your workflow ID + #ds-snippet-start:eSign23Step3 accounts_api = create_account_api(args) workflow_response = accounts_api.get_account_identity_verification args[:account_id] if workflow_response.identity_verification idv_workflow = workflow_response.identity_verification.find { |item| item.default_name == 'DocuSign ID Verification' } workflow_id = idv_workflow.workflow_id if idv_workflow end - # Step 3 end + ##ds-snippet-end:eSign23Step3 return 'idv_not_enabled' if workflow_id.blank? @@ -27,7 +28,7 @@ def worker puts workflow_id # Construct your envelope JSON body - # Step 4 start + #ds-snippet-start:eSign23Step4 envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document set' @@ -77,12 +78,12 @@ def worker # To request that the envelope be created as a draft, set status to "created" envelope_definition.recipients = recipients envelope_definition.status = envelope_args[:status] - # Step 4 end + #ds-snippet-end:eSign23Step4 # Call the eSignature REST API - # Step 5 start + #ds-snippet-start:eSign23Step5 envelope_api = create_envelope_api(args) envelope_api.create_envelope args[:account_id], envelope_definition - # Step 5 end + #ds-snippet-end:eSign23Step5 end end From 66e86e776b61fccf5ff6a68010b36e5a484a7980 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Fri, 13 Oct 2023 15:54:39 -0700 Subject: [PATCH 264/363] DEVDOCS-10144 adding codeDepot markers --- app/services/e_sign/eg013_add_doc_to_template_service.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/services/e_sign/eg013_add_doc_to_template_service.rb b/app/services/e_sign/eg013_add_doc_to_template_service.rb index 749e4d5..4d777ea 100644 --- a/app/services/e_sign/eg013_add_doc_to_template_service.rb +++ b/app/services/e_sign/eg013_add_doc_to_template_service.rb @@ -9,6 +9,7 @@ def initialize(args) @args = args end + #ds-snippet-start:eSign13Step3 def worker envelope_args = args[:envelope_args] # 1. Create the envelope request object @@ -19,7 +20,9 @@ def worker results = envelope_api.create_envelope(args[:account_id], envelope_definition) envelope_id = results.envelope_id + #ds-snippet-end:eSign13Step3 # 3. Create the Recipient View request object + #ds-snippet-start:eSign13Step4 authentication_method = 'None' # How is this application authenticating # the signer? See the `authenticationMethod' definition # https://developers.docusign.com/docs/esign-rest-api/reference/envelopes/envelopeviews/createrecipient/ @@ -36,9 +39,11 @@ def worker envelope_id, recipient_view_request) { envelope_id: envelope_id, redirect_url: results.url } end + #ds-snippet-end:eSign13Step4 private + #ds-snippet-start:eSign13Step2 def make_envelope(args) # 1. Create recipients for server template. Note that the Recipients object # is used, not TemplateRole @@ -151,5 +156,5 @@ def create_document1(args) HEREDOC end - # ***DS.snippet.0.start + #ds-snippet-end:eSign13Step2 end From bd6780cc1bc2c17b9442907a07b77ccf16ed4ad1 Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Wed, 18 Oct 2023 10:27:20 -0700 Subject: [PATCH 265/363] DEVDOCS-10544 adding codeDepot markers --- app/services/e_sign/eg038_responsive_signing_service.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/services/e_sign/eg038_responsive_signing_service.rb b/app/services/e_sign/eg038_responsive_signing_service.rb index e0c5714..bc8e5d1 100644 --- a/app/services/e_sign/eg038_responsive_signing_service.rb +++ b/app/services/e_sign/eg038_responsive_signing_service.rb @@ -9,7 +9,7 @@ def initialize(args) @args = args end - # Step 3 start + #ds-snippet-start:eSign38Step3 def worker ds_return_url = "#{args[:ds_ping_url]}/ds_common-return" @@ -72,9 +72,9 @@ def make_recipient_view_request(args, ds_return_url) view_request end - # Step 3 end + #ds-snippet-start:eSign38Step3 - # Step 2 start + #ds-snippet-start:eSign38Step2 def make_envelope(args) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Example Signing Document' @@ -127,5 +127,5 @@ def get_html_content(args) .gsub('/l1q/', '') \ .gsub('/l2q/', '') end - # Step 2 end + #ds-snippet-end:eSign38Step2 end From 21638f05ced7b730b2e0db12490efaac538636a2 Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Wed, 18 Oct 2023 10:29:16 -0700 Subject: [PATCH 266/363] DEVDOCS-10544 fixing markers --- app/services/e_sign/eg038_responsive_signing_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/e_sign/eg038_responsive_signing_service.rb b/app/services/e_sign/eg038_responsive_signing_service.rb index bc8e5d1..6426079 100644 --- a/app/services/e_sign/eg038_responsive_signing_service.rb +++ b/app/services/e_sign/eg038_responsive_signing_service.rb @@ -72,7 +72,7 @@ def make_recipient_view_request(args, ds_return_url) view_request end - #ds-snippet-start:eSign38Step3 + #ds-snippet-end:eSign38Step3 #ds-snippet-start:eSign38Step2 def make_envelope(args) From 9814f001c58eea2fb7c1c1d512e8043ce5de1777 Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Wed, 18 Oct 2023 10:34:18 -0700 Subject: [PATCH 267/363] DEVDOCS-10424 adding codeDepot markers --- .../e_sign/eg033_unpauses_signature_workflow_service.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/services/e_sign/eg033_unpauses_signature_workflow_service.rb b/app/services/e_sign/eg033_unpauses_signature_workflow_service.rb index 9cdc21d..6e7e77d 100644 --- a/app/services/e_sign/eg033_unpauses_signature_workflow_service.rb +++ b/app/services/e_sign/eg033_unpauses_signature_workflow_service.rb @@ -10,19 +10,21 @@ def initialize(args) end def worker - # Step 2. Construct your API headers + #ds-snippet-start:eSign33Step2 configuration = DocuSign_eSign::Configuration.new configuration.host = args[:basePath] api_client = DocuSign_eSign::ApiClient.new configuration api_client.set_default_header('Authorization', "Bearer #{args[:accessToken]}") + #ds-snippet-end:eSign33Step2 - # Step 3. Construct the JSON body for your envelope + #ds-snippet-start:eSign33Step3 workflow = DocuSign_eSign::Workflow.new(status: args[:status]) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new(workflow: workflow) + #ds-snippet-end:eSign33Step3 - # Step 4. Call the eSignature API + #ds-snippet-start:eSign33Step4 envelopes_api = DocuSign_eSign::EnvelopesApi.new(api_client) update_options = DocuSign_eSign::UpdateOptions.new @@ -35,4 +37,5 @@ def worker update_options ) end + #ds-snippet-end:eSign33Step4 end From 34be557e1a6488025d0314b91d7276e9d8a8c830 Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Wed, 18 Oct 2023 10:40:31 -0700 Subject: [PATCH 268/363] DEVDOCS-10545 adding codeDepot markers --- .../e_sign/eg032_pauses_signature_workflow_service.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/services/e_sign/eg032_pauses_signature_workflow_service.rb b/app/services/e_sign/eg032_pauses_signature_workflow_service.rb index 98cd8e6..4ad7554 100644 --- a/app/services/e_sign/eg032_pauses_signature_workflow_service.rb +++ b/app/services/e_sign/eg032_pauses_signature_workflow_service.rb @@ -11,14 +11,15 @@ def initialize(args, signers) end def worker - # Step 2. Construct your API headers + #ds-snippet-start:eSign32Step2 configuration = DocuSign_eSign::Configuration.new configuration.host = args[:basePath] api_client = DocuSign_eSign::ApiClient.new configuration api_client.set_default_header('Authorization', "Bearer #{args[:accessToken]}") + #ds-snippet-end:eSign32Step2 - # Step 3. Construct the request body + #ds-snippet-start:eSign32Step3 envelope_definition = DocuSign_eSign::EnvelopeDefinition.new(emailSubject: 'EnvelopeWorkflowTest') # Create the document model. @@ -90,12 +91,14 @@ def worker # 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_definition.status = args[:status] + #ds-snippet-end:eSign32Step3 - # Step 4. Call the eSignature API + #ds-snippet-start:eSign32Step4 envelopes_api = DocuSign_eSign::EnvelopesApi.new(api_client) envelopes_api.create_envelope( args[:accountId], envelope_definition ) + #ds-snippet-end:eSign32Step4 end end From 9a18e058e3a864abf7c69b882cc9e82df3590620 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Fri, 20 Oct 2023 14:42:04 -0700 Subject: [PATCH 269/363] DEVDOCS-10324 adding codeDepot markers --- app/services/e_sign/eg007_envelope_get_doc_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/e_sign/eg007_envelope_get_doc_service.rb b/app/services/e_sign/eg007_envelope_get_doc_service.rb index 4d75784..059c7b8 100644 --- a/app/services/e_sign/eg007_envelope_get_doc_service.rb +++ b/app/services/e_sign/eg007_envelope_get_doc_service.rb @@ -10,13 +10,13 @@ def initialize(args) end def worker - # Step 3 start + #ds-snippet-start:eSign7Step3 envelope_api = create_envelope_api(args) document_id = args[:document_id] temp_file = envelope_api.get_document args[:account_id], document_id, args[:envelope_id] - # Step 3 end + #ds-snippet-end:eSign7Step3 # Find the matching document information item doc_item = args[:envelope_documents]['documents'].find { |item| item['document_id'] == document_id } From d53f8d51e93c5a8d102f35c4391bed7d07a0316b Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Fri, 20 Oct 2023 14:44:12 -0700 Subject: [PATCH 270/363] DEVDOCS-10294 adding codeDepot markers --- app/services/e_sign/eg003_list_envelopes_service.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/services/e_sign/eg003_list_envelopes_service.rb b/app/services/e_sign/eg003_list_envelopes_service.rb index 12c36cf..f153a88 100644 --- a/app/services/e_sign/eg003_list_envelopes_service.rb +++ b/app/services/e_sign/eg003_list_envelopes_service.rb @@ -10,17 +10,19 @@ def initialize(args) end def worker - # Step 1. List the envelopes + # List the envelopes # The Envelopes::listStatusChanges method has many options # See https://developers.docusign.com/esign-rest-api/reference/Envelopes/Envelopes/listStatusChange# # The list status changes call requires at least a from_date OR # a set of envelopeIds. Here we filter using a from_date. # Here we set the from_date to filter envelopes for the last month # Use ISO 8601 date format + #ds-snippet-start:eSign3Step2 envelope_api = create_envelope_api(args) options = DocuSign_eSign::ListStatusChangesOptions.new options.from_date = (Date.today - 30).strftime('%Y/%m/%d') # Exceptions will be caught by the calling function envelope_api.list_status_changes args[:account_id], options + #ds-snippet-end:eSign3Step2 end end From db5aee33d2efe2ccbd115c88a5f0be545522bb8c Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Fri, 20 Oct 2023 14:55:55 -0700 Subject: [PATCH 271/363] DEVDOCS-10311 adding codeDepot markers --- .../e_sign/eg039_signing_in_person_service.rb | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/app/services/e_sign/eg039_signing_in_person_service.rb b/app/services/e_sign/eg039_signing_in_person_service.rb index 072f01d..d3bda2a 100644 --- a/app/services/e_sign/eg039_signing_in_person_service.rb +++ b/app/services/e_sign/eg039_signing_in_person_service.rb @@ -9,7 +9,6 @@ def initialize(args) @args = args end - # ***DS.snippet.0.start def worker ds_ping_url = args[:ds_ping_url] ds_return_url = "#{ds_ping_url}/ds_common-return" @@ -20,20 +19,20 @@ def worker envelope = make_envelope(pdf_filename, host_email, host_name, signer_name) - # Step 3 start + #ds-snippet-start:eSign39Step3 envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope - # Step 3 end + #ds-snippet-end:eSign39Step3 envelope_id = results.envelope_id - # Step 5 start + #ds-snippet-start:eSign39Step5 view_request = make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_name) # Call the CreateRecipientView API results = envelope_api.create_recipient_view args[:account_id], envelope_id, view_request - # Step 5 end + #ds-snippet-end:eSign39Step5 # Redirect the user to the embedded signing # Don't use an iframe! @@ -45,7 +44,7 @@ def worker private - # Step 4 start + #ds-snippet-start:eSign39Step4 def make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_name) view_request = DocuSign_eSign::RecipientViewRequest.new # Set the URL where you want the recipient to go once they are done signing @@ -77,9 +76,9 @@ def make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_nam view_request end - # Step 4 end + #ds-snippet-end:eSign39Step4 - # Step 2 start + #ds-snippet-start:eSign39Step2 def make_envelope(pdf_filename, host_email, host_name, signer_name) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document sent from Ruby SDK' @@ -123,5 +122,5 @@ def make_envelope(pdf_filename, host_email, host_name, signer_name) envelope_definition.status = 'sent' envelope_definition end - # Step 2 end + #ds-snippet-end:eSign39Step2 end From d95db80ea49d4732eea0d2fd83e053631266397d Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Mon, 23 Oct 2023 22:57:11 +0300 Subject: [PATCH 272/363] Add focused view code example (#139) * added focused view example --- .../e_sign/eeg044_focused_view_controller.rb | 29 ++++ app/controllers/eg_controller.rb | 2 +- .../e_sign/eg010_send_binary_docs_service.rb | 1 + .../eg016_set_envelope_tab_data_service.rb | 2 +- ...g019_access_code_authentication_service.rb | 1 - .../eg030_brands_apply_to_template_service.rb | 16 +-- .../e_sign/eg044_focused_view_service.rb | 131 ++++++++++++++++++ .../e_sign/eeg044_focused_view/embed.html.erb | 79 +++++++++++ .../e_sign/eeg044_focused_view/get.html.erb | 27 ++++ config/routes.rb | 3 + 10 files changed, 280 insertions(+), 11 deletions(-) create mode 100644 app/controllers/e_sign/eeg044_focused_view_controller.rb create mode 100644 app/services/e_sign/eg044_focused_view_service.rb create mode 100644 app/views/e_sign/eeg044_focused_view/embed.html.erb create mode 100644 app/views/e_sign/eeg044_focused_view/get.html.erb diff --git a/app/controllers/e_sign/eeg044_focused_view_controller.rb b/app/controllers/e_sign/eeg044_focused_view_controller.rb new file mode 100644 index 0000000..a4f391c --- /dev/null +++ b/app/controllers/e_sign/eeg044_focused_view_controller.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class ESign::Eeg044FocusedViewController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 44) } + + def create + pdf_file_path = 'data/World_Wide_Corp_lorem.pdf' + + pdf_file_path = '../data/World_Wide_Corp_lorem.pdf' unless File.exist?(pdf_file_path) + + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + signer_email: param_gsub(params[:signerEmail]), + signer_name: param_gsub(params[:signerName]), + ds_ping_url: Rails.application.config.app_url, + signer_client_id: 1000, + pdf_filename: pdf_file_path + } + + @integration_key = Rails.application.config.integration_key + @url = ESign::Eg044FocusedViewService.new(args).worker + render 'e_sign/eeg044_focused_view/embed' + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end +end diff --git a/app/controllers/eg_controller.rb b/app/controllers/eg_controller.rb index 150361e..12f2dae 100644 --- a/app/controllers/eg_controller.rb +++ b/app/controllers/eg_controller.rb @@ -40,7 +40,7 @@ def set_meta @source_file = file_name.to_s #remove extra character that doesn't exist in service file index = @source_file.index('/') - @source_file[index + 1] = '' + index.nil? ? @source_file[0] = '' : @source_file[index + 1] = '' @source_url = "#{Rails.application.config.github_example_url}#{@source_file}" end diff --git a/app/services/e_sign/eg010_send_binary_docs_service.rb b/app/services/e_sign/eg010_send_binary_docs_service.rb index 391e495..2d41647 100644 --- a/app/services/e_sign/eg010_send_binary_docs_service.rb +++ b/app/services/e_sign/eg010_send_binary_docs_service.rb @@ -100,6 +100,7 @@ def worker obj = JSON.parse(response.body) raise Net::HTTPError.new(response.code, response.body) unless (response.code.to_i >= 200) && (response.code.to_i < 300) + #ds-snippet-end:eSign10Step4 envelope_id = obj['envelopeId'] { 'envelope_id' => envelope_id } diff --git a/app/services/e_sign/eg016_set_envelope_tab_data_service.rb b/app/services/e_sign/eg016_set_envelope_tab_data_service.rb index 8c8a132..6a56577 100644 --- a/app/services/e_sign/eg016_set_envelope_tab_data_service.rb +++ b/app/services/e_sign/eg016_set_envelope_tab_data_service.rb @@ -28,7 +28,7 @@ def worker #ds-snippet-start:eSign16Step5 view_request = make_recipient_view_request(args[:signer_email], args[:signer_name], signer_client_id, ds_return_url, ds_ping_url) #ds-snippet-end:eSign16Step5 - + # Call the CreateRecipientView API results = create_envelope_api(args).create_recipient_view args[:account_id], envelope_id, view_request diff --git a/app/services/e_sign/eg019_access_code_authentication_service.rb b/app/services/e_sign/eg019_access_code_authentication_service.rb index 1dfefcf..b0dd905 100644 --- a/app/services/e_sign/eg019_access_code_authentication_service.rb +++ b/app/services/e_sign/eg019_access_code_authentication_service.rb @@ -10,7 +10,6 @@ def initialize(args) end def worker - envelope_api = create_envelope_api(args) envelope_args = args[:envelope_args] diff --git a/app/services/e_sign/eg030_brands_apply_to_template_service.rb b/app/services/e_sign/eg030_brands_apply_to_template_service.rb index 0644e7e..5ea1928 100644 --- a/app/services/e_sign/eg030_brands_apply_to_template_service.rb +++ b/app/services/e_sign/eg030_brands_apply_to_template_service.rb @@ -36,16 +36,16 @@ def make_envelope(envelope_args) # Create the template role elements to connect the signer and cc recipients # to the template signer = DocuSign_eSign::TemplateRole.new({ - email: envelope_args[:signer_email], - name: envelope_args[:signer_name], - roleName: 'signer' - }) + email: envelope_args[:signer_email], + name: envelope_args[:signer_name], + roleName: 'signer' + }) # Create a cc template role cc = DocuSign_eSign::TemplateRole.new({ - email: envelope_args[:cc_email], - name: envelope_args[:cc_name], - roleName: 'cc' - }) + email: envelope_args[:cc_email], + name: envelope_args[:cc_name], + roleName: 'cc' + }) envelope_definition.template_roles = [signer, cc] envelope_definition diff --git a/app/services/e_sign/eg044_focused_view_service.rb b/app/services/e_sign/eg044_focused_view_service.rb new file mode 100644 index 0000000..633c777 --- /dev/null +++ b/app/services/e_sign/eg044_focused_view_service.rb @@ -0,0 +1,131 @@ +# frozen_string_literal: true + +class ESign::Eg044FocusedViewService + attr_reader :args + + include ApiCreator + + def initialize(args) + @args = args + end + + def worker + ds_ping_url = args[:ds_ping_url] + ds_return_url = "#{ds_ping_url}/ds_common-return" + signer_client_id = args[:signer_client_id] + pdf_filename = args[:pdf_filename] + signer_email = args[:signer_email] + signer_name = args[:signer_name] + + # Create the envelope definition + #ds-snippet-start:eSign44Step3 + envelope = make_envelope(args[:signer_client_id], pdf_filename, signer_email, signer_name) + + # Call DocuSign to create the envelope + envelope_api = create_envelope_api(args) + + results = envelope_api.create_envelope args[:account_id], envelope + envelope_id = results.envelope_id + #ds-snippet-end:eSign44Step3 + # Save for future use within the example launcher + # session[:envelope_id] = envelope_id + + # Create the recipient view for the embedded signing + #ds-snippet-start:eSign44Step5 + view_request = make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, signer_email, signer_name) + + # Call the CreateRecipientView API + results = envelope_api.create_recipient_view args[:account_id], envelope_id, view_request + + # 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) + # Redirect to results.url + results.url + #ds-snippet-end:eSign44Step5 + end + + private + + #ds-snippet-start:eSign44Step4 + def make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, signer_email, signer_name) + view_request = DocuSign_eSign::RecipientViewRequest.new + # 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. + view_request.return_url = "#{ds_return_url}?state=123" + + # How has your app authenticated the user? In addition to your app's + # authentication, you can include authenticate steps from DocuSign; + # e.g., SMS authentication + view_request.authentication_method = 'none' + + # Recipient information must match the embedded recipient info + # that was used to create the envelope + view_request.email = signer_email + view_request.user_name = signer_name + view_request.client_user_id = 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 + view_request.ping_frequency = '600' # seconds + # NOTE: The pings will only be sent if the pingUrl is an HTTPS address + view_request.ping_url = ds_ping_url # Optional setting + + view_request.frame_ancestors = ['http://localhost:3000', 'https://apps-d.docusign.com'] + view_request.message_origins = ['https://apps-d.docusign.com'] + + view_request + end + #ds-snippet-end:eSign44Step4 + + #ds-snippet-start:eSign44Step2 + def make_envelope(signer_client_id, pdf_filename, signer_email, signer_name) + envelope_definition = DocuSign_eSign::EnvelopeDefinition.new + envelope_definition.email_subject = 'Please sign this document sent from Ruby SDK' + + doc1 = DocuSign_eSign::Document.new + doc1.document_base64 = Base64.encode64(File.binread(pdf_filename)) + doc1.name = 'Lorem Ipsum' + doc1.file_extension = 'pdf' + doc1.document_id = '1' + + # The order in the docs array determines the order in the envelope + envelope_definition.documents = [doc1] + # Create a signer recipient to sign the document, identified by name and email + # We're setting the parameters via the object creation + signer1 = DocuSign_eSign::Signer.new({ + email: signer_email, name: signer_name, + clientUserId: signer_client_id, recipientId: 1 + }) + # The DocuSign platform searches throughout your envelope's documents for matching + # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 + # since they use the same anchor string for their "signer 1" tabs. + sign_here = DocuSign_eSign::SignHere.new + sign_here.anchor_string = '/sn1/' + sign_here.anchor_units = 'pixels' + sign_here.anchor_x_offset = '20' + sign_here.anchor_y_offset = '10' + # Tabs are set per recipient/signer + tabs = DocuSign_eSign::Tabs.new + tabs.sign_here_tabs = [sign_here] + signer1.tabs = tabs + # Add the recipients to the envelope object + recipients = DocuSign_eSign::Recipients.new + recipients.signers = [signer1] + + envelope_definition.recipients = recipients + # Request that the envelope be sent by setting status to "sent". + # To request that the envelope be created as a draft, set status to "created" + envelope_definition.status = 'sent' + envelope_definition + end + #ds-snippet-end:eSign44Step2 +end diff --git a/app/views/e_sign/eeg044_focused_view/embed.html.erb b/app/views/e_sign/eeg044_focused_view/embed.html.erb new file mode 100644 index 0000000..112c278 --- /dev/null +++ b/app/views/e_sign/eeg044_focused_view/embed.html.erb @@ -0,0 +1,79 @@ +
    +

    The document has been embedded with focused view.

    +
    + + + + + + + + Signing + + + +
    + + + + +

    Continue

    + + + + + diff --git a/app/views/e_sign/eeg044_focused_view/get.html.erb b/app/views/e_sign/eeg044_focused_view/get.html.erb new file mode 100644 index 0000000..94bca70 --- /dev/null +++ b/app/views/e_sign/eeg044_focused_view/get.html.erb @@ -0,0 +1,27 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %> + +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + " required + value="<%= @config.signer_email %>"> + <%= render('partials/email_will_not_be_shared') %> +
    +
    + + " + name="signerName" value="<%= @config.signer_name %>" required> +
    + <%= render('partials/submit_button') %> +
    \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index c20dfa0..f1bed2d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -225,6 +225,9 @@ get 'eeg043auth' => 'eeg043_shared_access#create_authorization' get 'eeg043reauthenticate' => 'eeg043_shared_access#reauthenticate' get 'eeg043envelopes' => 'eeg043_shared_access#list_envelopes' + + get 'eeg044' => 'eeg044_focused_view#get' + post 'eeg044' => 'eeg044_focused_view#create' end root 'ds_common#index' From 39550a6518fcaee11ec16ddd6ce2d0b311a11e94 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Mon, 23 Oct 2023 13:01:08 -0700 Subject: [PATCH 273/363] fix codeDepot tags on html.erb page --- app/views/e_sign/eeg044_focused_view/embed.html.erb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/views/e_sign/eeg044_focused_view/embed.html.erb b/app/views/e_sign/eeg044_focused_view/embed.html.erb index 112c278..251d481 100644 --- a/app/views/e_sign/eeg044_focused_view/embed.html.erb +++ b/app/views/e_sign/eeg044_focused_view/embed.html.erb @@ -2,9 +2,7 @@

    The document has been embedded with focused view.


    - +# ds-snippet-start:eSign44Step6 @@ -74,6 +72,4 @@ // Any configuration or API limits will be caught here }); - +# ds-snippet-end:eSign44Step6 From 2ba480029b18edf1f103546126f7a1aa4e89384e Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Mon, 23 Oct 2023 13:22:45 -0700 Subject: [PATCH 274/363] fix comment in html.erb file --- app/views/e_sign/eeg044_focused_view/embed.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/e_sign/eeg044_focused_view/embed.html.erb b/app/views/e_sign/eeg044_focused_view/embed.html.erb index 251d481..9bcec7f 100644 --- a/app/views/e_sign/eeg044_focused_view/embed.html.erb +++ b/app/views/e_sign/eeg044_focused_view/embed.html.erb @@ -2,7 +2,7 @@

    The document has been embedded with focused view.


    -# ds-snippet-start:eSign44Step6 +<%# ds-snippet-start:eSign44Step6 %> @@ -72,4 +72,4 @@ // Any configuration or API limits will be caught here }); -# ds-snippet-end:eSign44Step6 + <%# ds-snippet-end:eSign44Step6 %> From b34da56eaa750722483da8f331f7d2b77f1a24a3 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Mon, 23 Oct 2023 14:00:18 -0700 Subject: [PATCH 275/363] fix codeDepot tags --- app/views/e_sign/eeg044_focused_view/embed.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/e_sign/eeg044_focused_view/embed.html.erb b/app/views/e_sign/eeg044_focused_view/embed.html.erb index 9bcec7f..3ca900d 100644 --- a/app/views/e_sign/eeg044_focused_view/embed.html.erb +++ b/app/views/e_sign/eeg044_focused_view/embed.html.erb @@ -2,7 +2,7 @@

    The document has been embedded with focused view.


    -<%# ds-snippet-start:eSign44Step6 %> +/** ds-snippet-start:eSign44Step6 */ @@ -72,4 +72,4 @@ // Any configuration or API limits will be caught here }); - <%# ds-snippet-end:eSign44Step6 %> + /** ds-snippet-end:eSign44Step6 */ From d84a05c02f652d88c4e77317a549ad292ac993fa Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Thu, 26 Oct 2023 13:56:12 -0700 Subject: [PATCH 276/363] revert comments for codeDepot --- app/views/e_sign/eeg044_focused_view/embed.html.erb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/views/e_sign/eeg044_focused_view/embed.html.erb b/app/views/e_sign/eeg044_focused_view/embed.html.erb index 3ca900d..cd935da 100644 --- a/app/views/e_sign/eeg044_focused_view/embed.html.erb +++ b/app/views/e_sign/eeg044_focused_view/embed.html.erb @@ -2,7 +2,9 @@

    The document has been embedded with focused view.


    -/** ds-snippet-start:eSign44Step6 */ + @@ -72,4 +74,6 @@ // Any configuration or API limits will be caught here }); - /** ds-snippet-end:eSign44Step6 */ + \ No newline at end of file From 30258bcd49a0ab33c12883cb620dddd2466b90b2 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Thu, 26 Oct 2023 14:17:04 -0700 Subject: [PATCH 277/363] update erb comment type --- app/views/e_sign/eeg044_focused_view/embed.html.erb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/views/e_sign/eeg044_focused_view/embed.html.erb b/app/views/e_sign/eeg044_focused_view/embed.html.erb index cd935da..bf3f3b9 100644 --- a/app/views/e_sign/eeg044_focused_view/embed.html.erb +++ b/app/views/e_sign/eeg044_focused_view/embed.html.erb @@ -2,9 +2,7 @@

    The document has been embedded with focused view.


    - +#ds-snippet-start:eSign44Step6 @@ -74,6 +72,4 @@ // Any configuration or API limits will be caught here }); - \ No newline at end of file + #ds-snippet-end:eSign44Step6 \ No newline at end of file From 4c2fdded1746a415a854b9e5f14f3ad41efe99c8 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Thu, 26 Oct 2023 14:20:02 -0700 Subject: [PATCH 278/363] update codeDepot tags DEVDOCS-12659 --- app/views/e_sign/eeg044_focused_view/embed.html.erb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/views/e_sign/eeg044_focused_view/embed.html.erb b/app/views/e_sign/eeg044_focused_view/embed.html.erb index bf3f3b9..ebabf39 100644 --- a/app/views/e_sign/eeg044_focused_view/embed.html.erb +++ b/app/views/e_sign/eeg044_focused_view/embed.html.erb @@ -1,8 +1,9 @@

    The document has been embedded with focused view.


    - + @@ -72,4 +73,6 @@ // Any configuration or API limits will be caught here }); - #ds-snippet-end:eSign44Step6 \ No newline at end of file + \ No newline at end of file From 6de077a140c796dead41d633294f7e36edc46ab7 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Tue, 31 Oct 2023 00:01:57 +0200 Subject: [PATCH 279/363] Add formula tabs to responsive signing (#138) * add formula tabs --- Gemfile | 2 +- Gemfile.lock | 4 +- .../eg038_responsive_signing_service.rb | 61 ++++++++++++++++++- 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/Gemfile b/Gemfile index 2b0c6ed..7fb6de9 100644 --- a/Gemfile +++ b/Gemfile @@ -70,7 +70,7 @@ end gem 'docusign_admin', '~> 1.3.0' gem 'docusign_click', '~> 1.4.0' -gem 'docusign_esign', '~> 3.24.0' +gem 'docusign_esign', '~> 3.25.0' gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' gem 'omniauth-oauth2', '~> 1.8.0' diff --git a/Gemfile.lock b/Gemfile.lock index abcabd2..f560a05 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -109,7 +109,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.24.0) + docusign_esign (3.25.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -338,7 +338,7 @@ DEPENDENCIES coffee-rails (~> 5.0.0) docusign_admin (~> 1.3.0) docusign_click (~> 1.4.0) - docusign_esign (~> 3.24.0) + docusign_esign (~> 3.25.0) docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) jbuilder (~> 2.11.5) diff --git a/app/services/e_sign/eg038_responsive_signing_service.rb b/app/services/e_sign/eg038_responsive_signing_service.rb index 6426079..ad96038 100644 --- a/app/services/e_sign/eg038_responsive_signing_service.rb +++ b/app/services/e_sign/eg038_responsive_signing_service.rb @@ -91,12 +91,67 @@ def make_envelope(args) envelope_definition.documents = [doc] # Create a signer recipient to sign the document, identified by name and email # We're setting the parameters via the object creation + price_1 = 5 + formula_tab_1 = DocuSign_eSign::FormulaTab.new({ + font: 'helvetica', + fontSize: 'size11', + fontColor: 'black', + anchorString: '/l1e/', + anchorYOffset: '-8', + anchorUnits: 'pixels', + anchorXOffset: '105', + tabLabel: 'l1e', + formula: "[l1q] * #{price_1}", + roundDecimalPlaces: '0', + required: 'true', + locked: 'true', + disableAutoSize: 'false' + }) + + price_2 = 150 + formula_tab_2 = DocuSign_eSign::FormulaTab.new({ + font: 'helvetica', + fontSize: 'size11', + fontColor: 'black', + anchorString: '/l2e/', + anchorYOffset: '-8', + anchorUnits: 'pixels', + anchorXOffset: '105', + tabLabel: 'l2e', + formula: "[l2q] * #{price_2}", + roundDecimalPlaces: '0', + required: 'true', + locked: 'true', + disableAutoSize: 'false' + }) + + formula_tab_3 = DocuSign_eSign::FormulaTab.new({ + font: 'helvetica', + fontSize: 'size11', + fontColor: 'black', + anchorString: '/l3t/', + anchorYOffset: '-8', + anchorUnits: 'pixels', + anchorXOffset: '105', + tabLabel: 'l3t', + formula: '[l1e] + [l2e]', + roundDecimalPlaces: '0', + required: 'true', + locked: 'true', + disableAutoSize: 'false' + }) + + tabs = DocuSign_eSign::Tabs.new({ + formulaTabs: [formula_tab_1, formula_tab_2, formula_tab_3] + }) + signer = DocuSign_eSign::Signer.new({ email: args[:signer_email], name: args[:signer_name], clientUserId: args[:signer_client_id], recipientId: 1, - role_name: 'Signer' + role_name: 'Signer', + tabs: tabs }) cc = DocuSign_eSign::CarbonCopy.new({ @@ -124,8 +179,8 @@ def get_html_content(args) .gsub('{ccName}', args[:cc_name]) \ .gsub('{ccEmail}', args[:cc_email]) \ .gsub('/sn1/', '') \ - .gsub('/l1q/', '') \ - .gsub('/l2q/', '') + .gsub('/l1q/', '') \ + .gsub('/l2q/', '') end #ds-snippet-end:eSign38Step2 end From 61f0b30c1a498a3140c7cf692cd3732ea845fed7 Mon Sep 17 00:00:00 2001 From: inbargazit Date: Fri, 3 Nov 2023 11:15:10 -0700 Subject: [PATCH 280/363] DEVDOCS-10526 - adding :codeDepot markers --- app/services/e_sign/eg015_get_envelope_tab_data_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/e_sign/eg015_get_envelope_tab_data_service.rb b/app/services/e_sign/eg015_get_envelope_tab_data_service.rb index 4a16dff..d2d9883 100644 --- a/app/services/e_sign/eg015_get_envelope_tab_data_service.rb +++ b/app/services/e_sign/eg015_get_envelope_tab_data_service.rb @@ -9,7 +9,6 @@ def initialize(args) @args = args end - # ***DS.snippet.0.start def worker # Step 3. Call the eSignature REST API # The Envelopes::getEnvelopeFormData method has many options @@ -17,7 +16,8 @@ def worker # The get form data call requires an account ID and an envelope ID # Exceptions will be caught by the calling function + #ds-snippet-start:eSign15Step3 create_envelope_api(args).get_form_data args[:account_id], args[:envelope_id] + #ds-snippet-end:eSign15Step3 end - # ***DS.snippet.0.end end From 725e857418611c296e4881e6da832cf4ba726998 Mon Sep 17 00:00:00 2001 From: inbargazit Date: Fri, 3 Nov 2023 11:43:55 -0700 Subject: [PATCH 281/363] DEVDOCS-10369 - add :codeDepot markers --- app/services/e_sign/eg024_permission_create_service.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/services/e_sign/eg024_permission_create_service.rb b/app/services/e_sign/eg024_permission_create_service.rb index 9fdf010..fd6a625 100644 --- a/app/services/e_sign/eg024_permission_create_service.rb +++ b/app/services/e_sign/eg024_permission_create_service.rb @@ -10,16 +10,19 @@ def initialize(args) end def worker + #ds-snippet-start:eSign24Step4 accounts_api = create_account_api(args) permission_profile_name = args[:permission_profile_name] permission_profile_settings = make_permission_profile_settings accounts_api.create_permission_profile(args[:account_id], { permissionProfileName: permission_profile_name, settings: permission_profile_settings }, DocuSign_eSign::CreatePermissionProfileOptions.default) + #ds-snippet-end:eSign24Step4 end private + #ds-snippet-start:eSign24Step3 def make_permission_profile_settings { useNewDocuSignExperienceInterface: 0, @@ -49,4 +52,5 @@ def make_permission_profile_settings vaultingMode: 'none' } end + #ds-snippet-end:eSign24Step3 end From fcd62cad2e486fcf400c668c0ddde7d8b373947f Mon Sep 17 00:00:00 2001 From: Aaron Wilde <52012222+AaronWDS@users.noreply.github.com> Date: Wed, 8 Nov 2023 06:14:11 -0800 Subject: [PATCH 282/363] DEVDOCS-10452 cd tags Signed-off-by: Aaron Wilde <52012222+AaronWDS@users.noreply.github.com> --- .../e_sign/eg022_kba_authentication_service.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/services/e_sign/eg022_kba_authentication_service.rb b/app/services/e_sign/eg022_kba_authentication_service.rb index 6d6a881..3763e35 100644 --- a/app/services/e_sign/eg022_kba_authentication_service.rb +++ b/app/services/e_sign/eg022_kba_authentication_service.rb @@ -10,11 +10,10 @@ def initialize(args) end def worker - # ***DS.snippet.0.start envelope_api = create_envelope_api(args) envelope_args = args[:envelope_args] - # Step 3: Construct your envelope JSON body + #ds-snippet-start:eSign22Step3 envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document set' @@ -57,9 +56,10 @@ def worker # To request that the envelope be created as a draft, set to "created" envelope_definition.recipients = recipients envelope_definition.status = envelope_args[:status] - - # Step 4. Call the eSignature REST API + #ds-snippet-end:eSign22Step3 + + #ds-snippet-start:eSign22Step4 envelope_api.create_envelope args[:account_id], envelope_definition - # ***DS.snippet.0.end + #ds-snippet-end:eSign22Step4 end end From b44b104e09e82fa365094dd111fa10d23a8fc32e Mon Sep 17 00:00:00 2001 From: Aaron Wilde <52012222+AaronWDS@users.noreply.github.com> Date: Wed, 8 Nov 2023 06:21:16 -0800 Subject: [PATCH 283/363] DEVDOCS-10514 cd tags Signed-off-by: Aaron Wilde <52012222+AaronWDS@users.noreply.github.com> --- .../e_sign/eg040_set_document_visibility_service.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/services/e_sign/eg040_set_document_visibility_service.rb b/app/services/e_sign/eg040_set_document_visibility_service.rb index fa9acad..19957d1 100644 --- a/app/services/e_sign/eg040_set_document_visibility_service.rb +++ b/app/services/e_sign/eg040_set_document_visibility_service.rb @@ -10,24 +10,24 @@ def initialize(args) end def worker - # Step 3-1 start + #ds-snippet-start:eSign40Step3 envelope_definition = make_envelope args[:envelope_args] - # Step 3-1 end + #ds-snippet-end:eSign40Step3 # Exceptions will be caught by the calling function - # Step 4 start + #ds-snippet-start:eSign40Step4 envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope_definition envelope_id = results.envelope_id - # Step 4 end + #ds-snippet-end:eSign40Step4 { 'envelope_id' => envelope_id } end private - # Step 3-2 start + #ds-snippet-start:eSign40Step3 def make_envelope(envelope_args) # document 1 (HTML) has tag **signature_1** # document 2 (DOCX) has tag /sn1/ @@ -147,7 +147,7 @@ def make_envelope(envelope_args) envelope_definition.status = envelope_args[:status] envelope_definition end - # Step 3-2 end + #ds-snippet-end:eSign40Step3 def create_document1(args) " From a31118cfd587738696c8505232f4dd8ea81c1fc7 Mon Sep 17 00:00:00 2001 From: Aaron Wilde <52012222+AaronWDS@users.noreply.github.com> Date: Wed, 8 Nov 2023 06:22:13 -0800 Subject: [PATCH 284/363] Update eg040_set_document_visibility_service.rb Signed-off-by: Aaron Wilde <52012222+AaronWDS@users.noreply.github.com> --- app/services/e_sign/eg040_set_document_visibility_service.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/services/e_sign/eg040_set_document_visibility_service.rb b/app/services/e_sign/eg040_set_document_visibility_service.rb index 19957d1..905cb87 100644 --- a/app/services/e_sign/eg040_set_document_visibility_service.rb +++ b/app/services/e_sign/eg040_set_document_visibility_service.rb @@ -17,7 +17,6 @@ def worker # Exceptions will be caught by the calling function #ds-snippet-start:eSign40Step4 envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope args[:account_id], envelope_definition envelope_id = results.envelope_id #ds-snippet-end:eSign40Step4 From 098fe9bcba660d186b616bf9548f21c5ad141ff3 Mon Sep 17 00:00:00 2001 From: Aaron Wilde <52012222+AaronWDS@users.noreply.github.com> Date: Wed, 8 Nov 2023 06:26:26 -0800 Subject: [PATCH 285/363] DEVDOCS-10425 cd tags Signed-off-by: Aaron Wilde <52012222+AaronWDS@users.noreply.github.com> --- ...eg006_create_an_external_form_fill_session_service.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb b/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb index 912c862..571b8cf 100644 --- a/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb +++ b/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb @@ -8,19 +8,21 @@ def initialize(args) end def worker + #ds-snippet-start:Rooms6Step2 configuration = DocuSign_Rooms::Configuration.new configuration.host = Rails.configuration.rooms_host - api_client = DocuSign_Rooms::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:Rooms6Step2 + #ds-snippet-start:Rooms6Step4 rooms_api = DocuSign_Rooms::ExternalFormFillSessionsApi.new(api_client) - rooms_api.create_external_form_fill_session(args[:account_id], body(args)) + #ds-snippet-end:Rooms6Step4 end private - + #ds-snippet-start:Rooms6Step3 def body(args) DocuSign_Rooms::ExternalFormFillSessionForCreate.new({ formId: args[:form_id], @@ -28,4 +30,5 @@ def body(args) xFrameAllowedUrl: "http://#{args[:allowed_host]}" }) end + #ds-snippet-end:Rooms6Step3 end From c91c3e8489a25ebdfff533cf9697c642519cda81 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Wed, 8 Nov 2023 13:45:20 -0800 Subject: [PATCH 286/363] DEVDOCS-10536 adding codeDepot makers --- app/services/e_sign/eg004_envelope_info_service.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/services/e_sign/eg004_envelope_info_service.rb b/app/services/e_sign/eg004_envelope_info_service.rb index aca56f3..48b1827 100644 --- a/app/services/e_sign/eg004_envelope_info_service.rb +++ b/app/services/e_sign/eg004_envelope_info_service.rb @@ -10,7 +10,9 @@ def initialize(args) end def worker + #ds-snippet-start:eSign4Step2 envelope_api = create_envelope_api(args) envelope_api.get_envelope(args[:account_id], args[:envelope_id]) + #ds-snippet-end:eSign4Step2 end end From 55958ed005801ab8c11df369921815d18d5639cb Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Wed, 8 Nov 2023 13:48:46 -0800 Subject: [PATCH 287/363] DEVDOCS-10361 adding codeDepot markers --- app/services/e_sign/eg027_permissions_delete_service.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/services/e_sign/eg027_permissions_delete_service.rb b/app/services/e_sign/eg027_permissions_delete_service.rb index f1498d9..6d5df02 100644 --- a/app/services/e_sign/eg027_permissions_delete_service.rb +++ b/app/services/e_sign/eg027_permissions_delete_service.rb @@ -10,8 +10,10 @@ def initialize(args) end def worker - # Step 3: Call the eSignature REST API + # Call the eSignature REST API + #ds-snippet-start:eSign27Step3 accounts_api = create_account_api(args) accounts_api.delete_permission_profile(args[:account_id], args[:permission_profile_id]) + #ds-snippet-end:eSign27Step3 end end From 11784fc8819671186b5d5d5bafe910e7b054719c Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Wed, 8 Nov 2023 13:54:47 -0800 Subject: [PATCH 288/363] DEVDOCS-10528 adding codeDepot markers --- .../e_sign/eg025_permissions_set_user_group_service.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/services/e_sign/eg025_permissions_set_user_group_service.rb b/app/services/e_sign/eg025_permissions_set_user_group_service.rb index a18a84a..11005fb 100644 --- a/app/services/e_sign/eg025_permissions_set_user_group_service.rb +++ b/app/services/e_sign/eg025_permissions_set_user_group_service.rb @@ -12,10 +12,14 @@ def initialize(args) def worker group_api = create_group_api(args) - # Step 3: Construct the request body + # Construct the request body + #ds-snippet-start:eSign25Step3 params = { groups: [{ permissionProfileId: args[:permission_profile_id], groupId: args[:group_id] }] } + #ds-snippet-end:eSign25Step3 - # Step 4: Call the eSignature REST API + # Call the eSignature REST API + #ds-snippet-start:eSign25Step4 group_api.update_groups(args[:account_id], params) + #ds-snippet-end:eSign25Step4 end end From d9dd6a720dd9f6bb52118a39141eece7745a69df Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Thu, 30 Nov 2023 01:04:16 +0200 Subject: [PATCH 289/363] Add validate webhook message code example (#140) * added hmac code example --- app/assets/javascripts/search.js | 226 ++++++++++-------- ...001_validate_webhook_message_controller.rb | 20 ++ app/controllers/eg_controller.rb | 6 +- .../eg001_validate_webhook_message_service.rb | 25 ++ .../eg022_kba_authentication_service.rb | 2 +- ...e_an_external_form_fill_session_service.rb | 1 + .../get.html.erb | 24 ++ app/views/ds_common/index.html.erb | 20 +- app/views/partials/_example_info.erb | 16 +- config/routes.rb | 5 + 10 files changed, 223 insertions(+), 122 deletions(-) create mode 100644 app/controllers/connect/cneg001_validate_webhook_message_controller.rb create mode 100644 app/services/connect/eg001_validate_webhook_message_service.rb create mode 100644 app/views/connect/cneg001_validate_webhook_message/get.html.erb diff --git a/app/assets/javascripts/search.js b/app/assets/javascripts/search.js index dcdaacf..901fa7a 100644 --- a/app/assets/javascripts/search.js +++ b/app/assets/javascripts/search.js @@ -5,7 +5,8 @@ const DS_SEARCH = (function () { CLICK: "click", ROOMS: "rooms", ADMIN: "admin", - }; + CONNECT: "connect", + } const processJSONData = function () { const json_raw = $("#api_json_data").text(); @@ -14,22 +15,34 @@ const DS_SEARCH = (function () { return json; } - let processCFR11Value = function () { - let json_raw = $("#cfr11_data").text(); + const processCFR11Value = function () { + const cfr11_data = $("#cfr11_data"); + return cfr11_data.text(); + } + + function shouldAppendExample(element, example, cfrPart11) { + const isEsignature = element.Name.toLowerCase() === API_TYPES.ESIGNATURE.toLowerCase(); + const isCFREnabledForAll = example.CFREnabled === "AllAccounts"; + const isCFREnabledForCFROnly = cfrPart11 === "enabled" && example.CFREnabled === "CFROnly"; + const isCFREnabledForNonCFR = cfrPart11 !== "enabled" && example.CFREnabled === "NonCFR"; - return json_raw; -} + return !isEsignature || isCFREnabledForAll || isCFREnabledForCFROnly || isCFREnabledForNonCFR; + } function checkIfExampleMatches(example, matches) { const name = example.ExampleName; const description = example.ExampleDescription; - const pathNames = example.LinksToAPIMethod.map((a) => a.PathName); + + let pathNames = []; + if (example.LinksToAPIMethod) { + 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 + pathNames && pathNames.indexOf(matches[i].value) > -1 ) { return true; } @@ -62,6 +75,7 @@ const DS_SEARCH = (function () { const findCodeExamplesByKeywords = function(json, pattern) { const options = { isCaseSensitive: false, + minMatchCharLength: pattern.length, threshold: -0.0, includeMatches: true, ignoreLocation: true, @@ -73,16 +87,16 @@ const DS_SEARCH = (function () { ], }; - let clearJSON = JSON.stringify(json).replace(/<\/?[^>]+(>|$)/g, ""); - const fuse = new Fuse(JSON.parse(clearJSON), options); + const clearJSON = JSON.stringify(json).replace(/<\/?[^>]+(>|$)/g, ""); + const fuse = new Fuse(JSON.parse(clearJSON), options); - var searchResults = fuse.search(JSON.stringify(pattern)); + const searchResults = fuse.search(JSON.stringify(pattern)); - searchResults.forEach(searchResult => { - return clearResultsAfterMatching(searchResult.item, searchResult.matches) - }); + searchResults.forEach((searchResult) => + clearResultsAfterMatching(searchResult.item, searchResult.matches) + ); - return searchResults; + return searchResults; } const getExamplesByAPIType = function (apiType, codeExamples) { @@ -125,80 +139,85 @@ const DS_SEARCH = (function () { case API_TYPES.MONITOR: return "meg"; case API_TYPES.ESIGNATURE: - return "eeg"; + return "eg"; + case API_TYPES.CONNECT: + return "cneg"; } } - let addCodeExampleToHomepage = function (codeExamples) { + const 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("c#")) { - if (element.Name.toLowerCase() !== API_TYPES.ESIGNATURE.toLowerCase() || - ((example.CFREnabled == "AllAccounts") || - ((cfrPart11 == "enabled") && (example.CFREnabled == "CFROnly")) || - ((cfrPart11 != "enabled") && (example.CFREnabled == "NonCFR")))) { - $("#filtered_code_examples").append( - "

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

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

    " + example.ExampleDescription + "

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

    "); - - 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("

    "); - } - } - } - ); + 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("ruby") + ) { + if (shouldAppendExample(element, example, cfrPart11)) + { + $("#filtered_code_examples").append( + "

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

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

    " + example.ExampleDescription + "

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

    "); + const links = example.LinksToAPIMethod || []; + if (links.length > 0) { + if (links.length == 1) { + $("#filtered_code_examples").append( + processJSONData().SupportingTexts.APIMethodUsed + ); + } else { + $("#filtered_code_examples").append( + processJSONData().SupportingTexts.APIMethodUsedPlural + ); } - ); - } - ); -} + + links.forEach((link, index) => { + $("#filtered_code_examples").append(`${link.PathName}`); + + if (index + 1 === links.length) { + $("#filtered_code_examples").append(""); + } else if (index + 1 === links.length - 1) { + $("#filtered_code_examples").append(" and "); + } else { + $("#filtered_code_examples").append(", "); + } + }) + + } + + $("#filtered_code_examples").append("

    "); + } + } + }); + }); + }); + }; const textCouldNotBeFound = function () { $("#filtered_code_examples").append( @@ -207,12 +226,13 @@ const DS_SEARCH = (function () { }; return { - processJSONData: processJSONData, - getEnteredAPIType: getEnteredAPIType, - getExamplesByAPIType: getExamplesByAPIType, - findCodeExamplesByKeywords: findCodeExamplesByKeywords, - textCouldNotBeFound: textCouldNotBeFound, - addCodeExampleToHomepage: addCodeExampleToHomepage, + processJSONData, + getEnteredAPIType, + getExamplesByAPIType, + findCodeExamplesByKeywords, + textCouldNotBeFound, + addCodeExampleToHomepage, + shouldAppendExample, }; })(); @@ -240,27 +260,27 @@ function updateValue(esearchPattern) { if (result.length < 1) { DS_SEARCH.textCouldNotBeFound(); } else { - result.forEach(x => { - var api = json.filter(api => { - return api.Name === x.item.Name; + result.forEach((x) => { + const 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; - }); + const unfilteredGroup = api.Groups.filter((apiGroup) => { + return apiGroup.Name === group.Name; + })[0]; + + group.Examples.forEach((example, index) => { + const clearedExamples = unfilteredGroup.Examples.filter((apiExample) => { + return apiExample.ExampleNumber === example.ExampleNumber; + }) + x.item.Groups[groupIndex].Examples[index] = clearedExamples[0]; + }); }); DS_SEARCH.addCodeExampleToHomepage([x.item]); - }); + }); } } } -} \ No newline at end of file +} diff --git a/app/controllers/connect/cneg001_validate_webhook_message_controller.rb b/app/controllers/connect/cneg001_validate_webhook_message_controller.rb new file mode 100644 index 0000000..9da1522 --- /dev/null +++ b/app/controllers/connect/cneg001_validate_webhook_message_controller.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require_relative '../../services/utils' + +class Connect::Cneg001ValidateWebhookMessageController < EgController + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1, 'Connect') } + + def create + args = { + secret: params['secret'], + payload: params['payload'] + } + results = Connect::Eg001ValidateWebhookMessageService.new(args).worker + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end +end diff --git a/app/controllers/eg_controller.rb b/app/controllers/eg_controller.rb index 12f2dae..92c6c1f 100644 --- a/app/controllers/eg_controller.rb +++ b/app/controllers/eg_controller.rb @@ -13,7 +13,7 @@ def eg_name end def set_eg - session[:eg] = controller_name.to(5) + session[:eg] = controller_name.split('_', 2).first end def get @@ -22,7 +22,7 @@ def get # to have the user authenticate or re-authenticate. @token_ok = check_token @config = Rails.application.config - if @token_ok + if @token_ok || controller_name.include?('cneg') # addSpecialAttributes(model) @envelope_ok = session[:envelope_id].present? @documents_ok = session[:envelope_documents].present? @@ -40,7 +40,7 @@ def set_meta @source_file = file_name.to_s #remove extra character that doesn't exist in service file index = @source_file.index('/') - index.nil? ? @source_file[0] = '' : @source_file[index + 1] = '' + @source_file = index.nil? ? @source_file.sub(/^.*?eg/, 'eg') : @source_file.sub(%r{/.+?eg}, '/eg') @source_url = "#{Rails.application.config.github_example_url}#{@source_file}" end diff --git a/app/services/connect/eg001_validate_webhook_message_service.rb b/app/services/connect/eg001_validate_webhook_message_service.rb new file mode 100644 index 0000000..f8dc3d6 --- /dev/null +++ b/app/services/connect/eg001_validate_webhook_message_service.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'openssl' +require 'base64' + +class Connect::Eg001ValidateWebhookMessageService + attr_reader :args + + def initialize(args) + @args = args + end + + #ds-snippet-start:Connect1Step2 + def worker + digest = OpenSSL::Digest.new('sha256') + hashBytes = OpenSSL::HMAC.digest(digest, args[:secret], args[:payload]) + Base64.encode64(hashBytes) + end + + def hash_valid? + hash = worker(args[:secret], args[:payload]) + OpenSSL.secure_compare(hash.chomp, args[:signature]) + end + #ds-snippet-end:Connect1Step2 +end diff --git a/app/services/e_sign/eg022_kba_authentication_service.rb b/app/services/e_sign/eg022_kba_authentication_service.rb index 3763e35..2ba88c1 100644 --- a/app/services/e_sign/eg022_kba_authentication_service.rb +++ b/app/services/e_sign/eg022_kba_authentication_service.rb @@ -57,7 +57,7 @@ def worker envelope_definition.recipients = recipients envelope_definition.status = envelope_args[:status] #ds-snippet-end:eSign22Step3 - + #ds-snippet-start:eSign22Step4 envelope_api.create_envelope args[:account_id], envelope_definition #ds-snippet-end:eSign22Step4 diff --git a/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb b/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb index 571b8cf..762226c 100644 --- a/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb +++ b/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb @@ -22,6 +22,7 @@ def worker end private + #ds-snippet-start:Rooms6Step3 def body(args) DocuSign_Rooms::ExternalFormFillSessionForCreate.new({ diff --git a/app/views/connect/cneg001_validate_webhook_message/get.html.erb b/app/views/connect/cneg001_validate_webhook_message/get.html.erb new file mode 100644 index 0000000..8ad7e2e --- /dev/null +++ b/app/views/connect/cneg001_validate_webhook_message/get.html.erb @@ -0,0 +1,24 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% secret_index = 0 %> +<% payload_index = 1 %> + +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + " required> +
    +
    + + +
    + <%= render('partials/submit_button') %> +
    \ No newline at end of file diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index ef99678..526f370 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -51,6 +51,8 @@ "r" elsif api["Name"] == "Monitor" "m" + elsif api["Name"] == "Connect" + "cn" else "e" end %> @@ -63,16 +65,18 @@

    <%= sanitize example["ExampleDescription"] %>

    - <% if example["LinksToAPIMethod"].length > 1 %> - <%= sanitize @manifest["SupportingTexts"]["APIMethodUsedPlural"] %> - <% else %> - <%= sanitize @manifest["SupportingTexts"]["APIMethodUsed"] %> - <% end %> + <% if example["LinksToAPIMethod"] %> + <% if example["LinksToAPIMethod"].length > 1 %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsedPlural"] %> + <% else %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsed"] %> + <% end %> - <% example["LinksToAPIMethod"].each do |link| %> - "><%= link["PathName"] %> - <% end %> + <% example["LinksToAPIMethod"].each do |link| %> + "><%= link["PathName"] %> + <% end %>

    + <% end %> <% end %> <% end %> <% } %> diff --git a/app/views/partials/_example_info.erb b/app/views/partials/_example_info.erb index 4328ea9..bb91991 100644 --- a/app/views/partials/_example_info.erb +++ b/app/views/partials/_example_info.erb @@ -9,14 +9,16 @@ <%= sanitize @example["Note"] %> <% end %> -<% if @example["LinksToAPIMethod"].length > 1 %> - <%= sanitize @manifest["SupportingTexts"]["APIMethodUsedPlural"] %> -<% else %> - <%= sanitize @manifest["SupportingTexts"]["APIMethodUsed"] %> -<% end %> +<% if @example["LinksToAPIMethod"] %> + <% if @example["LinksToAPIMethod"].length > 1 %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsedPlural"] %> + <% else %> + <%= sanitize @manifest["SupportingTexts"]["APIMethodUsed"] %> + <% end %> -<% @example["LinksToAPIMethod"].each do |link| %> - "><%= link["PathName"] %> + <% @example["LinksToAPIMethod"].each do |link| %> + "><%= link["PathName"] %> + <% end %> <% end %>

    diff --git a/config/routes.rb b/config/routes.rb index f1bed2d..a8bf3c8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -230,6 +230,11 @@ post 'eeg044' => 'eeg044_focused_view#create' end + scope module: 'connect' do + get 'cneg001' => 'cneg001_validate_webhook_message#get' + post 'cneg001' => 'cneg001_validate_webhook_message#create' + end + root 'ds_common#index' # Login starts with POST'ing to: /auth/docusign From 3680066c66704632f3060a8487fb77d707a9aa10 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Wed, 29 Nov 2023 15:08:59 -0800 Subject: [PATCH 290/363] update codeDepot tags DEVDOCS-12873 --- .../connect/eg001_validate_webhook_message_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/connect/eg001_validate_webhook_message_service.rb b/app/services/connect/eg001_validate_webhook_message_service.rb index f8dc3d6..fbc6688 100644 --- a/app/services/connect/eg001_validate_webhook_message_service.rb +++ b/app/services/connect/eg001_validate_webhook_message_service.rb @@ -10,7 +10,7 @@ def initialize(args) @args = args end - #ds-snippet-start:Connect1Step2 + #ds-snippet-start:Connect1Step1 def worker digest = OpenSSL::Digest.new('sha256') hashBytes = OpenSSL::HMAC.digest(digest, args[:secret], args[:payload]) @@ -21,5 +21,5 @@ def hash_valid? hash = worker(args[:secret], args[:payload]) OpenSSL.secure_compare(hash.chomp, args[:signature]) end - #ds-snippet-end:Connect1Step2 + #ds-snippet-end:Connect1Step1 end From bb48ed5ec5ce3016a3ea6015e46c3351eb4b255a Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Tue, 5 Dec 2023 01:58:26 +0200 Subject: [PATCH 291/363] Fix sign-in issue (#142) * add redirect to auth page * linter issue --- app/controllers/ds_common_controller.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index f7825cc..fc98385 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -18,6 +18,8 @@ def handle_redirects session[:quickstarted] = true redirect_to '/auth/docusign' elsif session[:been_here].nil? + return redirect_to '/auth/docusign' if session[:ds_access_token].nil? || session[:ds_base_path].nil? + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) if enableCFR == 'enabled' session[:status_cfr] = 'enabled' From 0c8456cd625a49e25ae70c8735dc9bb4295cb0ba Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Mon, 4 Dec 2023 16:05:53 -0800 Subject: [PATCH 292/363] Add how to link in example_info.erb (#141) * Add how to link in example_info.erb --- app/views/partials/_example_info.erb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/views/partials/_example_info.erb b/app/views/partials/_example_info.erb index bb91991..8e18fdd 100644 --- a/app/views/partials/_example_info.erb +++ b/app/views/partials/_example_info.erb @@ -21,6 +21,10 @@ <% end %> <% end %> +<% if @example["LinkToHowTo"] %> +

    Prerequisite: See "><%= @example["LinkToHowTo"][0]["PathName"] %>

    +<% end %> +

    <%= sanitize format_string(@manifest["SupportingTexts"]["ViewSourceFile"], "#{@source_file}" ) %>

    \ No newline at end of file From bab87c6faeb879f561246e6e710403ea399cf724 Mon Sep 17 00:00:00 2001 From: meihDS <70775251+meihDS@users.noreply.github.com> Date: Thu, 7 Dec 2023 15:34:57 -0800 Subject: [PATCH 293/363] manually added hmac how-to link to get.html.erb --- .../connect/cneg001_validate_webhook_message/get.html.erb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/views/connect/cneg001_validate_webhook_message/get.html.erb b/app/views/connect/cneg001_validate_webhook_message/get.html.erb index 8ad7e2e..1ae1ede 100644 --- a/app/views/connect/cneg001_validate_webhook_message/get.html.erb +++ b/app/views/connect/cneg001_validate_webhook_message/get.html.erb @@ -1,5 +1,9 @@ <%= render('partials/example_info') %> +

    + Prerequisite: See How to validate an HMAC signature. +

    + <% form_index = 0 %> <% secret_index = 0 %> <% payload_index = 1 %> From f0e65fe856883a05b9b0bfcc0493294d4f0411a5 Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 15 Dec 2023 12:56:28 -0800 Subject: [PATCH 294/363] update readme for JWT and ACG projects --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 29382e1..cfc06d2 100644 --- a/README.md +++ b/README.md @@ -17,30 +17,30 @@ When the token expires, it updates automatically. ## 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 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. -## Rooms API +## Rooms API -**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/). +**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/). 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. -## 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) +## 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) 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. ## Monitor API -**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/). +**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/). -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/). +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/). 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. @@ -126,8 +126,8 @@ Also, in order to select JSON Web Token authentication in the launcher, in confi 1. From the picklist, select **JSON Web Token (JWT) grant** > **Authenticate with DocuSign**. 1. Select your desired code example. -## 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. +## JWT grant remote signing and Authorization Code Grant embedded signing projects +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 and the Authorization Code Grant embedded signing project. ### Troubleshooting Windows SSL issue From 822c9f7b7e0a0c541ffb54affda3d7d138edc86b Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Fri, 22 Dec 2023 14:04:51 +0200 Subject: [PATCH 295/363] fix monitor example --- .../eg001_get_monitoring_dataset_service.rb | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb index 7977774..7c3f1f7 100644 --- a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb +++ b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb @@ -19,11 +19,28 @@ def worker #ds-snippet-start:Monitor1Step3 monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) begin - @response = monitor_api.get_stream(args[:data_set_name], args[:version]).data + cursor_value = '' + limit = 100 + function_results = [] + options = DocuSign_Monitor::GetStreamOptions.new + options.limit = limit + + loop do + options.cursor = cursor_value unless cursor_value.empty? + + cursored_results = monitor_api.get_stream(args[:data_set_name], args[:version], options) + end_cursor = cursored_results.end_cursor + + break if cursor_value == end_cursor + + cursor_value = end_cursor + function_results.push(cursored_results.data) + end + @response = function_results #ds-snippet-end:Monitor1Step3 - rescue StandardError + rescue Exception => e # error, probalby no Monitor enabled - @response = 'Monitor not enabled' + @response = e else Rails.logger.info 'Responses for loops are displayed here. Only the final loop is displayed on the response page' Rails.logger.info @response.inspect From 7a989bb1115fed90d0359d5f05a4ffdc5d69bf9e Mon Sep 17 00:00:00 2001 From: AaronWDS Date: Wed, 10 Jan 2024 14:26:22 -0800 Subject: [PATCH 296/363] DEVDOCS-13477 code depot tags --- app/services/admin_api/eg005_audit_users_service.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/services/admin_api/eg005_audit_users_service.rb b/app/services/admin_api/eg005_audit_users_service.rb index a2c4b5a..f9c8b07 100644 --- a/app/services/admin_api/eg005_audit_users_service.rb +++ b/app/services/admin_api/eg005_audit_users_service.rb @@ -28,8 +28,12 @@ def worker #ds-snippet-start:Admin5Step5 results = [] modified_users.each do |user| + #ds-snippet-end:Admin5Step5 + #ds-snippet-start:Admin5Step4 userProfilesOptions = DocuSign_Admin::GetUserProfilesOptions.new userProfilesOptions.email = user['email'] + #ds-snippet-end:Admin5Step4 + #ds-snippet-start:Admin5Step5 result = users_api.get_user_profiles(args[:organization_id], userProfilesOptions) results.push(result) end From 8c8e411731def40792ed97c6c1ebf8547290acec Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Thu, 8 Feb 2024 15:21:11 +0200 Subject: [PATCH 297/363] add example --- Gemfile | 1 + Gemfile.lock | 6 + app/assets/javascripts/search.js | 3 + .../weg001_create_instance_controller.rb | 56 +++++++ app/services/jwt_auth/jwt_creator.rb | 5 + app/services/utils.rb | 10 ++ .../webforms/eg001_create_instance_service.rb | 153 ++++++++++++++++++ app/views/ds_common/index.html.erb | 2 + .../weg001_create_instance/get.html.erb | 5 + .../web_form_create.html.erb | 6 + .../web_form_embed.html.erb | 59 +++++++ config/appsettings.example.yml | 3 + config/initializers/omniauth.rb | 4 + config/routes.rb | 7 + data/World_Wide_Corp_Web_Form.pdf | Bin 0 -> 45823 bytes data/web-form-config.json | 1 + 16 files changed, 321 insertions(+) create mode 100644 app/controllers/webforms/weg001_create_instance_controller.rb create mode 100644 app/services/webforms/eg001_create_instance_service.rb create mode 100644 app/views/webforms/weg001_create_instance/get.html.erb create mode 100644 app/views/webforms/weg001_create_instance/web_form_create.html.erb create mode 100644 app/views/webforms/weg001_create_instance/web_form_embed.html.erb create mode 100644 data/World_Wide_Corp_Web_Form.pdf create mode 100644 data/web-form-config.json diff --git a/Gemfile b/Gemfile index 7fb6de9..b075c11 100644 --- a/Gemfile +++ b/Gemfile @@ -73,6 +73,7 @@ gem 'docusign_click', '~> 1.4.0' gem 'docusign_esign', '~> 3.25.0' gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' +gem 'docusign_webforms' gem 'omniauth-oauth2', '~> 1.8.0' gem 'omniauth-rails_csrf_protection' diff --git a/Gemfile.lock b/Gemfile.lock index f560a05..68590fa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -124,6 +124,11 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) + docusign_webforms (1.0.1.rc10) + addressable (~> 2.7, >= 2.7.0) + json (~> 2.1, >= 2.1.0) + jwt (~> 2.2, >= 2.2.1) + typhoeus (~> 1.0, >= 1.0.1) erubi (1.12.0) ethon (0.16.0) ffi (>= 1.15.0) @@ -341,6 +346,7 @@ DEPENDENCIES docusign_esign (~> 3.25.0) docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) + docusign_webforms jbuilder (~> 2.11.5) listen (~> 3.8.0) matrix (~> 0.4.2) diff --git a/app/assets/javascripts/search.js b/app/assets/javascripts/search.js index 901fa7a..cdbd0e4 100644 --- a/app/assets/javascripts/search.js +++ b/app/assets/javascripts/search.js @@ -6,6 +6,7 @@ const DS_SEARCH = (function () { ROOMS: "rooms", ADMIN: "admin", CONNECT: "connect", + WEBFORMS: "webforms", } const processJSONData = function () { @@ -142,6 +143,8 @@ const DS_SEARCH = (function () { return "eg"; case API_TYPES.CONNECT: return "cneg"; + case API_TYPES.WEBFORMS: + return "weg"; } } diff --git a/app/controllers/webforms/weg001_create_instance_controller.rb b/app/controllers/webforms/weg001_create_instance_controller.rb new file mode 100644 index 0000000..642c318 --- /dev/null +++ b/app/controllers/webforms/weg001_create_instance_controller.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +class Webforms::Weg001CreateInstanceController < EgController + before_action -> { check_auth('WebForms') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1, 'WebForms') } + + def create_web_form_template + args = { + template_name: 'Web Form Example Template', + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } + + web_form_template_id = Webforms::Eg001CreateInstanceService.new(args).create_web_form_template + Utils::FileUtils.new.replace_template_id(File.join('data', Rails.application.config.web_form_config_file), web_form_template_id) + session[:web_form_template_id] = web_form_template_id + + redirect_to '/weg001webForm' + end + + def create_web_form_instance + args = { + form_name: 'Web Form Example Template', + client_user_id: '1234-5678-abcd-ijkl', + account_id: session[:ds_account_id], + base_path: Rails.application.config.webforms_host, + access_token: session[:ds_access_token] + } + create_instance_service = Webforms::Eg001CreateInstanceService.new(args) + web_forms = create_instance_service.list_web_forms + results = create_instance_service.create_web_form_instance web_forms.items.first.id + + @integration_key = Rails.application.config.integration_key + @form_url = results.form_url + @instance_token = results.instance_token + render 'webforms/weg001_create_instance/web_form_embed' + end + + def get + additional_page = @example['AdditionalPage'].find { |p| p['Name'] == 'create_web_form_template' } + @example['ExampleDescription'] = additional_page['ResultsPageText'] + + render 'webforms/weg001_create_instance/get' + end + + def get_web_form_create_view + redirect_to '/weg001' if session[:web_form_template_id].nil? + + additional_page = @example['AdditionalPage'].find { |p| p['Name'] == 'create_web_form' } + @title = @example['ExampleName'] + @description = additional_page['ResultsPageText'] + + render 'webforms/weg001_create_instance/web_form_create' + end +end diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index 6f60b77..59fd2ea 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -17,6 +17,7 @@ def self.consent_url(state, api) scope = 'signature impersonation 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' if api == 'Rooms' scope = 'signature impersonation click.manage click.send' if api == 'Click' scope = 'signature impersonation organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read' if api == 'Admin' + scope = 'signature webforms_manage' if api == 'WebForms' base_uri = "#{Rails.configuration.authorization_server}/oauth/auth" response_type = 'code' @@ -45,6 +46,10 @@ def initialize(session) scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read' @client_module = DocuSign_Admin end + if session[:api] == 'WebForms' + scope = 'signature webforms_manage' + @client_module = DocuSign_WebForms + end @scope = scope @api_client = create_initial_api_client(host: Rails.configuration.aud, client_module: @client_module, debugging: false) diff --git a/app/services/utils.rb b/app/services/utils.rb index bec3d57..23b8254 100644 --- a/app/services/utils.rb +++ b/app/services/utils.rb @@ -30,4 +30,14 @@ def get_user_id(args) user_info.sub end end + + class FileUtils + def replace_template_id(file_path, template_id) + content = File.read(file_path) + + content.gsub!('template-id', template_id) + + File.write(file_path, content) + end + end end diff --git a/app/services/webforms/eg001_create_instance_service.rb b/app/services/webforms/eg001_create_instance_service.rb new file mode 100644 index 0000000..cb75aaf --- /dev/null +++ b/app/services/webforms/eg001_create_instance_service.rb @@ -0,0 +1,153 @@ +# frozen_string_literal: true + +class Webforms::Eg001CreateInstanceService + attr_reader :args + + include ApiCreator + + def initialize(args) + @args = args + end + + def create_web_form_template + templates_api = create_template_api args + + options = DocuSign_eSign::ListTemplatesOptions.new + options.search_text = args[:template_name] + web_forms_templates = templates_api.list_templates(args[:account_id], options) + + if web_forms_templates.result_set_size.to_i.positive? + template_id = web_forms_templates.envelope_templates[0].template_id + else + template_req_object = make_web_forms_template + template = templates_api.create_template(args[:account_id], template_req_object) + template_id = template.template_id + end + + template_id + end + + def list_web_forms + configuration = DocuSign_WebForms::Configuration.new + configuration.host = Rails.configuration.webforms_host + + api_client = DocuSign_WebForms::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + + webforms_api = DocuSign_WebForms::FormManagementApi.new(api_client) + + options = DocuSign_WebForms::ListFormsOptions.new + options.search = args[:form_name] + + webforms_api.list_forms(args[:account_id], options) + end + + def create_web_form_instance(form_id) + configuration = DocuSign_WebForms::Configuration.new + configuration.host = Rails.configuration.webforms_host + + api_client = DocuSign_WebForms::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + + webforms_api = DocuSign_WebForms::FormInstanceManagementApi.new(api_client) + + web_form_values = { + 'PhoneNumber' => '555-555-5555', + 'Yes' => ['Yes'], + 'Company' => 'Tally', + 'JobTitle' => 'Programmer Writer' + } + web_form_req_object = DocuSign_WebForms::CreateInstanceRequestBody.new({ + 'clientUserId' => args[:client_user_id], + 'formValues' => web_form_values, + 'expirationOffset' => '3600' + }) + webforms_api.create_instance(args[:account_id], form_id, web_form_req_object) + end + + private + + def make_web_forms_template + template_name = args[:template_name] + doc_file = 'World_Wide_Corp_Web_Form.pdf' + base64_file_content = Base64.encode64(File.binread(File.join('data', doc_file))) + + # Create the document model + document = DocuSign_eSign::Document.new({ + # Create the DocuSign document object + 'documentBase64' => base64_file_content, + 'name' => 'World_Wide_Web_Form', # Can be different from actual file name + 'fileExtension' => 'pdf', # Many different document types are accepted + 'documentId' => '1' # A label used to reference the doc + }) + + # Create the signer recipient model + # Since these are role definitions, no name/email: + signer = DocuSign_eSign::Signer.new({ + 'roleName' => 'signer', 'recipientId' => '1', 'routingOrder' => '1' + }) + # Create fields using absolute positioning + # Create a sign_here tab (field on the document) + sign_here = DocuSign_eSign::SignHere.new( + 'documentId' => '1', 'tabLabel' => 'Signature', + 'anchorString' => '/SignHere/', 'anchorUnits' => 'pixel', + 'anchorXOffset' => '20', 'anchorYOffset' => '10' + ) + check = DocuSign_eSign::Checkbox.new( + 'documentId' => '1', 'tabLabel' => 'Yes', + 'anchorString' => '/SMS/', 'anchorUnits' => 'pixel', + 'anchorXOffset' => '20', 'anchorYOffset' => '10' + ) + text1 = DocuSign_eSign::Text.new( + 'documentId' => '1', 'tabLabel' => 'FullName', + 'anchorString' => '/FullName/', 'anchorUnits' => 'pixel', + 'anchorXOffset' => '20', 'anchorYOffset' => '10' + ) + text2 = DocuSign_eSign::Text.new( + 'documentId' => '1', 'tabLabel' => 'PhoneNumber', + 'anchorString' => '/PhoneNumber/', 'anchorUnits' => 'pixel', + 'anchorXOffset' => '20', 'anchorYOffset' => '10' + ) + text3 = DocuSign_eSign::Text.new( + 'documentId' => '1', 'tabLabel' => 'Company', + 'anchorString' => '/Company/', 'anchorUnits' => 'pixel', + 'anchorXOffset' => '20', 'anchorYOffset' => '10' + ) + text4 = DocuSign_eSign::Text.new( + 'documentId' => '1', 'tabLabel' => 'JobTitle', + 'anchorString' => '/JobTitle/', 'anchorUnits' => 'pixel', + 'anchorXOffset' => '20', 'anchorYOffset' => '10' + ) + date_signed = DocuSign_eSign::DateSigned.new( + 'documentId' => '1', 'tabLabel' => 'DateSigned', + 'anchorString' => '/Date/', 'anchorUnits' => 'pixel', + 'anchorXOffset' => '20', 'anchorYOffset' => '10' + ) + + # Add the tabs model to the signer + # The Tabs object takes arrays of the different field/tab types + signer.tabs = DocuSign_eSign::Tabs.new( + 'signHereTabs' => [sign_here], + 'checkboxTabs' => [check], + 'textTabs' => [text1, text2, text3, text4], + 'dateSignedTabs' => [date_signed] + ) + # Create top two objects + envelope_template_definition = DocuSign_eSign::EnvelopeTemplate.new( + 'description' => 'Example template created via the API', + 'shared' => 'false' + ) + + # Top object: + DocuSign_eSign::EnvelopeTemplate.new( + 'documents' => [document], + 'name' => template_name, + 'emailSubject' => 'Please sign this document', + 'envelopeTemplateDefinition' => envelope_template_definition, + 'recipients' => DocuSign_eSign::Recipients.new( + 'signers' => [signer] + ), + 'status' => 'created' + ) + end +end diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index 526f370..35cb5ae 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -53,6 +53,8 @@ "m" elsif api["Name"] == "Connect" "cn" + elsif api["Name"] == "WebForms" + "w" else "e" end %> diff --git a/app/views/webforms/weg001_create_instance/get.html.erb b/app/views/webforms/weg001_create_instance/get.html.erb new file mode 100644 index 0000000..a56f414 --- /dev/null +++ b/app/views/webforms/weg001_create_instance/get.html.erb @@ -0,0 +1,5 @@ +<%= render('partials/example_info') %> + +
    + <%= render('partials/submit_button') %> +
    \ No newline at end of file diff --git a/app/views/webforms/weg001_create_instance/web_form_create.html.erb b/app/views/webforms/weg001_create_instance/web_form_create.html.erb new file mode 100644 index 0000000..6c5af78 --- /dev/null +++ b/app/views/webforms/weg001_create_instance/web_form_create.html.erb @@ -0,0 +1,6 @@ +

    <%= @title %>

    +

    <%= sanitize @description %>

    + +
    + <%= render('partials/submit_button') %> +
    \ No newline at end of file diff --git a/app/views/webforms/weg001_create_instance/web_form_embed.html.erb b/app/views/webforms/weg001_create_instance/web_form_embed.html.erb new file mode 100644 index 0000000..1354b92 --- /dev/null +++ b/app/views/webforms/weg001_create_instance/web_form_embed.html.erb @@ -0,0 +1,59 @@ + + + + + + + +
    +
    +

    Embedded Webform Example

    +
    +

    Web Form will render here

    +
    +
    +
    + + + +

    Continue

    + + + \ No newline at end of file diff --git a/config/appsettings.example.yml b/config/appsettings.example.yml index c6526d4..ac83a2c 100644 --- a/config/appsettings.example.yml +++ b/config/appsettings.example.yml @@ -23,6 +23,7 @@ default: &default rooms_host: "https://demo.rooms.docusign.com/restapi" monitor_host: "https://lens-d.docusign.net" admin_host: "https://api-d.docusign.net/management" + webforms_host: ".services.docusign.net/webforms/v1.1" allow_silent_authentication: true # A user can be silently authenticated if they have an # Active login session on another tab of the same browser # Set if you want a specific DocuSign AccountId, If false, the users default account will be used. @@ -34,6 +35,8 @@ default: &default doc_pdf: World_Wide_Corp_lorem.pdf doc_terms_pdf: Term_Of_Service.pdf doc_offer_letter: Offer_Letter_Demo.docx + web_form_template_file: World_Wide_Corp_Form.pdf + web_form_config_file: web-form-config.json gateway_name: "stripe" gateway_display_name: "Stripe" github_example_url: https://github.com/docusign/code-examples-ruby/tree/master/app/services/ diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index ad1e5dd..0a6c88c 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -40,12 +40,16 @@ session = strategy.session case session[:api] + when 'eSignature' + strategy.options[:authorize_params].scope = 'signature' when 'Rooms' strategy.options[:authorize_params].scope = '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' when 'Click' strategy.options[:authorize_params].scope = 'signature click.manage click.send' when 'Admin' strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read' + when 'WebForms' + strategy.options[:authorize_params].scope = 'signature webforms_read webforms_instance_read webforms_instance_write' end } end diff --git a/config/routes.rb b/config/routes.rb index a8bf3c8..80a483b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -235,6 +235,13 @@ post 'cneg001' => 'cneg001_validate_webhook_message#create' end + scope module: 'webforms' do + get 'weg001' => 'weg001_create_instance#get' + get 'weg001webForm' => 'weg001_create_instance#get_web_form_create_view' + post 'weg001' => 'weg001_create_instance#create_web_form_template' + post 'weg001webForm' => 'weg001_create_instance#create_web_form_instance' + end + root 'ds_common#index' # Login starts with POST'ing to: /auth/docusign diff --git a/data/World_Wide_Corp_Web_Form.pdf b/data/World_Wide_Corp_Web_Form.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d6b952766a08335d2116f0f8f746622473d4c6fa GIT binary patch literal 45823 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\"adm\":{\"path\":\"ADM.Form.SignerName\"}}","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":"9bcf6cba-05cf-4088-8c85-e5a905ca1efb","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":"d2d23949-ce13-48de-9043-ce1b4d7d594a","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":"6308de2e-cea9-48aa-ab03-25d53a54cc5a","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":"d1d70d31-d7d4-462b-b41a-cc1f55698ae2","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","allowComments":"true","disableResponsiveDocument":"true","anySigner":null,"envelopeLocation":"current_site"}]} From 0936c5e8cae122c25248fcbbe864ea0b07f53e6a Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Tue, 13 Feb 2024 13:29:33 -0800 Subject: [PATCH 298/363] DEVDOCS-13760 codeDepot markers --- .../eg042_document_generation_service.rb | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/app/services/e_sign/eg042_document_generation_service.rb b/app/services/e_sign/eg042_document_generation_service.rb index 81faf17..f91a6db 100644 --- a/app/services/e_sign/eg042_document_generation_service.rb +++ b/app/services/e_sign/eg042_document_generation_service.rb @@ -16,43 +16,52 @@ def worker account_id = args[:account_id] envelope_args = args[:envelope_args] - # Step 1. Create the template + #ds-snippet-start:eSign42Step2 template = template_api.create_template(account_id, template_data) template_id = template.template_id + #ds-snippet-end:eSign42Step2 - # Step 2. Update template document + #ds-snippet-start:eSign42Step3 document_id = '1' template_api.update_document(account_id, document_id, template_id, template_document(envelope_args)) + #ds-snippet-end:eSign42Step3 - # Step 3. Update recipient tabs + #ds-snippet-start:eSign42Step4 recipient_id = '1' template_api.create_tabs(account_id, recipient_id, template_id, recipient_tabs) + #ds-snippet-end:eSign42Step4 - # Step 4. Create draft envelope + #ds-snippet-start:eSign42Step5 envelope_definition = make_envelope(template_id, envelope_args) envelope = envelope_api.create_envelope(account_id, envelope_definition) envelope_id = envelope.envelope_id + #ds-snippet-end:eSign42Step5 - # Step 5: Get the document id + #ds-snippet-start:eSign42Step6 doc_gen_form_fields_response = envelope_api.get_envelope_doc_gen_form_fields(account_id, envelope_id) document_id_guid = doc_gen_form_fields_response.doc_gen_form_fields[0].document_id + #ds-snippet-end:eSign42Step6 - # Step 6: Merge the data fields + #ds-snippet-start:eSign42Step7 form_fields_request = form_fields(envelope_args, document_id_guid) envelope_api.update_envelope_doc_gen_form_fields( account_id, envelope_id, form_fields_request ) + #ds-snippet-end:eSign42Step7 - # Step 7. Send the envelope + #ds-snippet-start:eSign42Step8 send_envelope_req = DocuSign_eSign::Envelope.new(status: 'sent') envelope = envelope_api.update(account_id, envelope_id, send_envelope_req) + #ds-snippet-end:eSign42Step8 + { 'envelope_id' => envelope.envelope_id } end private + #ds-snippet-start:eSign42Step2 def template_data # Create recipients signer = DocuSign_eSign::Signer.new( @@ -74,7 +83,9 @@ def template_data status: 'created' ) end + #ds-snippet-end:eSign42Step2 + #ds-snippet-start:eSign42Step3 def template_document(args) # Create the document model document = DocuSign_eSign::Document.new( @@ -90,7 +101,9 @@ def template_document(args) documents: [document] ) end + #ds-snippet-end:eSign42Step3 + #ds-snippet-start:eSign42Step4 def recipient_tabs # Create tabs sign_here = DocuSign_eSign::SignHere.new( @@ -109,7 +122,9 @@ def recipient_tabs dateSignedTabs: [date_signed] ) end + #ds-snippet-end:eSign42Step4 + #ds-snippet-start:eSign42Step5 def make_envelope(template_id, args) # Create the signer model signer = DocuSign_eSign::TemplateRole.new( @@ -125,7 +140,9 @@ def make_envelope(template_id, args) templateId: template_id ) end + #ds-snippet-end:eSign42Step5 + #ds-snippet-start:eSign42Step7 def form_fields(args, document_id_guid) candidate_name_field = DocuSign_eSign::DocGenFormField.new( name: 'Candidate_Name', @@ -160,4 +177,5 @@ def form_fields(args, document_id_guid) docGenFormFields: [doc_gen_form_fields] ) end + #ds-snippet-end:eSign42Step7 end From 681be18e0c89f392aca5479b6f7c0b29de8f8d1f Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Wed, 14 Feb 2024 12:34:23 +0200 Subject: [PATCH 299/363] specify webforms gem version & change js events --- Gemfile | 2 +- Gemfile.lock | 4 +- .../web_form_embed.html.erb | 51 +++++++++++++++---- 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/Gemfile b/Gemfile index b075c11..9568be4 100644 --- a/Gemfile +++ b/Gemfile @@ -73,7 +73,7 @@ gem 'docusign_click', '~> 1.4.0' gem 'docusign_esign', '~> 3.25.0' gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' -gem 'docusign_webforms' +gem 'docusign_webforms', '~> 1.0.2.rc12' gem 'omniauth-oauth2', '~> 1.8.0' gem 'omniauth-rails_csrf_protection' diff --git a/Gemfile.lock b/Gemfile.lock index 68590fa..68fd76a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -124,7 +124,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_webforms (1.0.1.rc10) + docusign_webforms (1.0.2.rc12) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -346,7 +346,7 @@ DEPENDENCIES docusign_esign (~> 3.25.0) docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) - docusign_webforms + docusign_webforms (~> 1.0.2.rc12) jbuilder (~> 2.11.5) listen (~> 3.8.0) matrix (~> 0.4.2) diff --git a/app/views/webforms/weg001_create_instance/web_form_embed.html.erb b/app/views/webforms/weg001_create_instance/web_form_embed.html.erb index 1354b92..9586072 100644 --- a/app/views/webforms/weg001_create_instance/web_form_embed.html.erb +++ b/app/views/webforms/weg001_create_instance/web_form_embed.html.erb @@ -39,20 +39,51 @@ minHeight: "1500px", }, //Controls the auto resize behavior of the iframe - autoResizeHeight: true, - //These values are passed to the iframe URL as query params - tracking: { - "tracking-field": "tracking-value", - }, - //These values are passed to the iframe URL as hash params - hidden: { - "hidden-field": "hidden-value", - }, + autoResizeHeight: true }; + const webFormWidget = docusign.webforms({ url: '<%= @form_url %>', options: webFormOptions, - }) + }); + + //Basic milestones in this workflow + webFormWidget.on('ready', (event) => { + // event = { type: 'ready' }; + console.log('debug form loaded', event); + }); + + webFormWidget.on('submitted', (event) => { + // event = { type: 'submitted', envelopeId: 'abcd1234' }; + console.log('debug form submitted', event); + }); + + webFormWidget.on('signingReady', (event) => { + // event = { type: 'submitted', envelopeId: 'abcd1234' }; + console.log('debug form signingReady', event); + }); + + webFormWidget.on('sessionEnd', (event) => { + //There are 3 sessionEnd types sessionTimeout, remoteSigningInitiated, signingResult + + // event = { type: 'sessionEnd', sessionEndType: 'sessionTimeout' }; + // event = { + // type: 'sessionEnd', + // sessionEndType: 'signingResult', + // signingResultType: 'signing_complete', + // returnUrl: 'bigcorp.com', + // envelopeId: 'abcd1234', + // }; + // event = { type: 'sessionEnd', sessionEndType: 'remoteSigningInitiated', envelopeId: 'abcd1234' }; + console.log('debug form signingResult', event); + }); + + //Less commonly used events + webFormWidget.on('userActivity', (event) => { + // event = { type: 'userActivity', activityType: 'click' | 'keydown' }; + console.log('debug form userActivity', event); + }); + webFormWidget.mount("#docusign"); } loadWebform(); From 676c91b730f3797b0e011835b6e2cd600a534d1a Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Wed, 14 Feb 2024 11:53:50 -0800 Subject: [PATCH 300/363] fixing base path and scopes --- app/services/jwt_auth/jwt_creator.rb | 4 ++-- config/appsettings.example.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index 59fd2ea..708ca2f 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -17,7 +17,7 @@ def self.consent_url(state, api) scope = 'signature impersonation 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' if api == 'Rooms' scope = 'signature impersonation click.manage click.send' if api == 'Click' scope = 'signature impersonation organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read' if api == 'Admin' - scope = 'signature webforms_manage' if api == 'WebForms' + scope = 'signature webforms_read webforms_instance_read webforms_instance_write' if api == 'WebForms' base_uri = "#{Rails.configuration.authorization_server}/oauth/auth" response_type = 'code' @@ -47,7 +47,7 @@ def initialize(session) @client_module = DocuSign_Admin end if session[:api] == 'WebForms' - scope = 'signature webforms_manage' + scope = 'signature webforms_read webforms_instance_read webforms_instance_write' @client_module = DocuSign_WebForms end diff --git a/config/appsettings.example.yml b/config/appsettings.example.yml index ac83a2c..067b8b9 100644 --- a/config/appsettings.example.yml +++ b/config/appsettings.example.yml @@ -23,7 +23,7 @@ default: &default rooms_host: "https://demo.rooms.docusign.com/restapi" monitor_host: "https://lens-d.docusign.net" admin_host: "https://api-d.docusign.net/management" - webforms_host: ".services.docusign.net/webforms/v1.1" + webforms_host: "https://apps-d.docusign.com/api/webforms/v1.1" allow_silent_authentication: true # A user can be silently authenticated if they have an # Active login session on another tab of the same browser # Set if you want a specific DocuSign AccountId, If false, the users default account will be used. From b4760dcfa6c3061d246b96346ccb274248969c39 Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Thu, 15 Feb 2024 14:29:37 -0800 Subject: [PATCH 301/363] latest SDK and other changes --- Gemfile | 2 +- Gemfile.lock | 15 ++++------- .../webforms/eg001_create_instance_service.rb | 26 +++++++++---------- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/Gemfile b/Gemfile index 9568be4..c87beb2 100644 --- a/Gemfile +++ b/Gemfile @@ -73,7 +73,7 @@ gem 'docusign_click', '~> 1.4.0' gem 'docusign_esign', '~> 3.25.0' gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' -gem 'docusign_webforms', '~> 1.0.2.rc12' +gem 'docusign_webforms', '~> 1.0.0' gem 'omniauth-oauth2', '~> 1.8.0' gem 'omniauth-rails_csrf_protection' diff --git a/Gemfile.lock b/Gemfile.lock index 68fd76a..832c8c5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -124,7 +124,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_webforms (1.0.2.rc12) + docusign_webforms (1.0.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -138,7 +138,6 @@ GEM ruby2_keywords (>= 0.0.4) faraday-net_http (3.0.2) ffi (1.15.5) - ffi (1.15.5-x64-mingw-ucrt) globalid (1.1.0) activesupport (>= 5.0) hashie (5.0.0) @@ -178,9 +177,7 @@ GEM net-smtp (0.3.3) net-protocol nio4r (2.5.9) - nokogiri (1.15.4-x64-mingw-ucrt) - racc (~> 1.4) - nokogiri (1.15.4-x86_64-linux) + nokogiri (1.15.4-x86_64-darwin) racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) @@ -298,8 +295,7 @@ GEM actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) - sqlite3 (1.6.4-x64-mingw-ucrt) - sqlite3 (1.6.4-x86_64-linux) + sqlite3 (1.6.4-x86_64-darwin) test-unit (3.6.1) power_assert thor (1.2.2) @@ -332,8 +328,7 @@ GEM zeitwerk (2.6.11) PLATFORMS - x64-mingw-ucrt - x86_64-linux + x86_64-darwin-21 DEPENDENCIES bootsnap (~> 1.7.3) @@ -346,7 +341,7 @@ DEPENDENCIES docusign_esign (~> 3.25.0) docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) - docusign_webforms (~> 1.0.2.rc12) + docusign_webforms (~> 1.0.0) jbuilder (~> 2.11.5) listen (~> 3.8.0) matrix (~> 0.4.2) diff --git a/app/services/webforms/eg001_create_instance_service.rb b/app/services/webforms/eg001_create_instance_service.rb index cb75aaf..09a9f6d 100644 --- a/app/services/webforms/eg001_create_instance_service.rb +++ b/app/services/webforms/eg001_create_instance_service.rb @@ -29,7 +29,6 @@ def create_web_form_template def list_web_forms configuration = DocuSign_WebForms::Configuration.new - configuration.host = Rails.configuration.webforms_host api_client = DocuSign_WebForms::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") @@ -44,7 +43,6 @@ def list_web_forms def create_web_form_instance(form_id) configuration = DocuSign_WebForms::Configuration.new - configuration.host = Rails.configuration.webforms_host api_client = DocuSign_WebForms::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") @@ -58,10 +56,10 @@ def create_web_form_instance(form_id) 'JobTitle' => 'Programmer Writer' } web_form_req_object = DocuSign_WebForms::CreateInstanceRequestBody.new({ - 'clientUserId' => args[:client_user_id], - 'formValues' => web_form_values, - 'expirationOffset' => '3600' - }) + 'clientUserId' => args[:client_user_id], + 'formValues' => web_form_values, + 'expirationOffset' => '3600' + }) webforms_api.create_instance(args[:account_id], form_id, web_form_req_object) end @@ -74,18 +72,18 @@ def make_web_forms_template # Create the document model document = DocuSign_eSign::Document.new({ - # Create the DocuSign document object - 'documentBase64' => base64_file_content, - 'name' => 'World_Wide_Web_Form', # Can be different from actual file name - 'fileExtension' => 'pdf', # Many different document types are accepted - 'documentId' => '1' # A label used to reference the doc - }) + # Create the DocuSign document object + 'documentBase64' => base64_file_content, + 'name' => 'World_Wide_Web_Form', # Can be different from actual file name + 'fileExtension' => 'pdf', # Many different document types are accepted + 'documentId' => '1' # A label used to reference the doc + }) # Create the signer recipient model # Since these are role definitions, no name/email: signer = DocuSign_eSign::Signer.new({ - 'roleName' => 'signer', 'recipientId' => '1', 'routingOrder' => '1' - }) + 'roleName' => 'signer', 'recipientId' => '1', 'routingOrder' => '1' + }) # Create fields using absolute positioning # Create a sign_here tab (field on the document) sign_here = DocuSign_eSign::SignHere.new( From d714bb56963ae8d8d8fd706ab44597df0c90d6ff Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Thu, 15 Feb 2024 14:36:25 -0800 Subject: [PATCH 302/363] codeDepot markers --- .../webforms/eg001_create_instance_service.rb | 13 ++++++++++--- .../weg001_create_instance/web_form_embed.html.erb | 10 +++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/app/services/webforms/eg001_create_instance_service.rb b/app/services/webforms/eg001_create_instance_service.rb index 09a9f6d..c904568 100644 --- a/app/services/webforms/eg001_create_instance_service.rb +++ b/app/services/webforms/eg001_create_instance_service.rb @@ -28,17 +28,20 @@ def create_web_form_template end def list_web_forms + #ds-snippet-start:WebForms1Step2 configuration = DocuSign_WebForms::Configuration.new - api_client = DocuSign_WebForms::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:WebForms1Step2 + #ds-snippet-start:WebForms1Step3 webforms_api = DocuSign_WebForms::FormManagementApi.new(api_client) options = DocuSign_WebForms::ListFormsOptions.new options.search = args[:form_name] webforms_api.list_forms(args[:account_id], options) + #ds-snippet-end:WebForms1Step3 end def create_web_form_instance(form_id) @@ -47,8 +50,7 @@ def create_web_form_instance(form_id) api_client = DocuSign_WebForms::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - webforms_api = DocuSign_WebForms::FormInstanceManagementApi.new(api_client) - + #ds-snippet-start:WebForms1Step4 web_form_values = { 'PhoneNumber' => '555-555-5555', 'Yes' => ['Yes'], @@ -60,7 +62,12 @@ def create_web_form_instance(form_id) 'formValues' => web_form_values, 'expirationOffset' => '3600' }) + #ds-snippet-end:WebForms1Step4 + + #ds-snippet-start:WebForms1Step5 + webforms_api = DocuSign_WebForms::FormInstanceManagementApi.new(api_client) webforms_api.create_instance(args[:account_id], form_id, web_form_req_object) + #ds-snippet-end:WebForms1Step5 end private diff --git a/app/views/webforms/weg001_create_instance/web_form_embed.html.erb b/app/views/webforms/weg001_create_instance/web_form_embed.html.erb index 9586072..ce23ef0 100644 --- a/app/views/webforms/weg001_create_instance/web_form_embed.html.erb +++ b/app/views/webforms/weg001_create_instance/web_form_embed.html.erb @@ -18,6 +18,10 @@

    Continue

    + + \ No newline at end of file + + + \ No newline at end of file From 24774b72cd309faa119041293b3f3d3a1e54459f Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Tue, 20 Feb 2024 14:43:07 -0800 Subject: [PATCH 303/363] adding codeDepot markers --- .../eg002_create_active_clm_esign_user_service.rb | 10 ++++------ app/services/admin_api/get_data_service.rb | 12 ++++++------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb b/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb index ebc5cc1..9b6d9e4 100644 --- a/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb +++ b/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb @@ -8,23 +8,21 @@ def initialize(args) end def worker - # Step 2 start configuration = DocuSign_Admin::Configuration.new configuration.host = Rails.configuration.admin_host api_client = DocuSign_Admin::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - # Step 2 end - # Step 6 start + #ds-snippet-start:Admin2Step6 users_api = DocuSign_Admin::UsersApi.new(api_client) users_api.add_or_update_user(args[:organization_id], args[:account_id], body(args)) - # Step 6 end + #ds-snippet-end:Admin2Step6 end private - # Step 5 start + #ds-snippet-start:Admin2Step5 def body(args) { user_name: args[:user_name], @@ -49,5 +47,5 @@ def body(args) ] } end - # Step 5 end + #ds-snippet-end:Admin2Step5 end diff --git a/app/services/admin_api/get_data_service.rb b/app/services/admin_api/get_data_service.rb index fd0e441..0af56ef 100644 --- a/app/services/admin_api/get_data_service.rb +++ b/app/services/admin_api/get_data_service.rb @@ -13,21 +13,21 @@ def initialize(session, _options = {}) def get_product_permission_profiles worker - # Step 3 start + #ds-snippet-start:Admin2Step3 product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(@api_client) product_permission_profiles = product_permission_profiles_api.get_product_permission_profiles(args[:organization_id], args[:account_id]) product_permission_profiles.as_json['product_permission_profiles'] - # Step 3 end + #ds-snippet-end:Admin2Step3 end def get_ds_groups worker - # Step 4 start + #ds-snippet-start:Admin2Step4 ds_groups_api = DocuSign_Admin::DSGroupsApi.new(@api_client) ds_groups = ds_groups_api.get_ds_groups(args[:organization_id], args[:account_id]) ds_groups.as_json['ds_groups'] - # Step 4 end + #ds-snippet-end:Admin2Step4 end def get_organization_id @@ -39,9 +39,7 @@ def get_organization_id def check_import_status(import_id) worker bulk_imports_api = DocuSign_Admin::BulkImportsApi.new(@api_client) - # Step 4 start bulk_imports_api.get_bulk_user_import_request(args[:organization_id], import_id) - # Step 4 end end def check_user_exists_by_email(email) @@ -59,9 +57,11 @@ def check_user_exists_by_email(email) private def worker + #ds-snippet-start:AdminRubyStep2 configuration = DocuSign_Admin::Configuration.new configuration.host = Rails.configuration.admin_host @api_client = DocuSign_Admin::ApiClient.new(configuration) @api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:AdminRubyStep2 end end From ae1124606f24dd11bdf2ffdff3112952df90561b Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Thu, 22 Feb 2024 14:34:07 +0200 Subject: [PATCH 304/363] fix date filter --- app/services/e_sign/eg003_list_envelopes_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/e_sign/eg003_list_envelopes_service.rb b/app/services/e_sign/eg003_list_envelopes_service.rb index f153a88..cf56d34 100644 --- a/app/services/e_sign/eg003_list_envelopes_service.rb +++ b/app/services/e_sign/eg003_list_envelopes_service.rb @@ -20,7 +20,7 @@ def worker #ds-snippet-start:eSign3Step2 envelope_api = create_envelope_api(args) options = DocuSign_eSign::ListStatusChangesOptions.new - options.from_date = (Date.today - 30).strftime('%Y/%m/%d') + options.from_date = (Date.today - 30).strftime('%Y-%m-%d') # Exceptions will be caught by the calling function envelope_api.list_status_changes args[:account_id], options #ds-snippet-end:eSign3Step2 From 8744f6b51deb2d11ea7cb30b8e6cbe75fd3d49b6 Mon Sep 17 00:00:00 2001 From: inbargazit Date: Thu, 22 Feb 2024 15:12:00 -0800 Subject: [PATCH 305/363] Fixing date format in eg003_list_envelopes_service.rb --- app/services/e_sign/eg003_list_envelopes_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/e_sign/eg003_list_envelopes_service.rb b/app/services/e_sign/eg003_list_envelopes_service.rb index f153a88..cf56d34 100644 --- a/app/services/e_sign/eg003_list_envelopes_service.rb +++ b/app/services/e_sign/eg003_list_envelopes_service.rb @@ -20,7 +20,7 @@ def worker #ds-snippet-start:eSign3Step2 envelope_api = create_envelope_api(args) options = DocuSign_eSign::ListStatusChangesOptions.new - options.from_date = (Date.today - 30).strftime('%Y/%m/%d') + options.from_date = (Date.today - 30).strftime('%Y-%m-%d') # Exceptions will be caught by the calling function envelope_api.list_status_changes args[:account_id], options #ds-snippet-end:eSign3Step2 From 6e2c9c172e272b1e77cd163bbea7cffbc8701373 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Thu, 7 Mar 2024 14:24:40 -0800 Subject: [PATCH 306/363] adding step 5 codeDepot markers --- .../results.html.erb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/views/room_api/reg006_create_an_external_form_fill_session/results.html.erb b/app/views/room_api/reg006_create_an_external_form_fill_session/results.html.erb index f6cefe1..3ed56ad 100644 --- a/app/views/room_api/reg006_create_an_external_form_fill_session/results.html.erb +++ b/app/views/room_api/reg006_create_an_external_form_fill_session/results.html.erb @@ -5,8 +5,13 @@ <%= @json %> + - +

    Continue

    From 041d8acb480bcc7c41b3105f30787a79e3174215 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Thu, 7 Mar 2024 15:44:35 -0800 Subject: [PATCH 307/363] adding admin 4 step 4 codeDepot marker --- app/services/admin_api/get_data_service.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/services/admin_api/get_data_service.rb b/app/services/admin_api/get_data_service.rb index 0af56ef..dd7b326 100644 --- a/app/services/admin_api/get_data_service.rb +++ b/app/services/admin_api/get_data_service.rb @@ -38,8 +38,10 @@ def get_organization_id def check_import_status(import_id) worker + #ds-snippet-start:Admin4Step4 bulk_imports_api = DocuSign_Admin::BulkImportsApi.new(@api_client) bulk_imports_api.get_bulk_user_import_request(args[:organization_id], import_id) + #ds-snippet-end:Admin4Step4 end def check_user_exists_by_email(email) From d0b51c7459ab0c88a0bdff352bed6185a78c2c62 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Thu, 7 Mar 2024 15:50:44 -0800 Subject: [PATCH 308/363] fixing codeDepot marker --- app/services/admin_api/get_data_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/admin_api/get_data_service.rb b/app/services/admin_api/get_data_service.rb index dd7b326..8235f3a 100644 --- a/app/services/admin_api/get_data_service.rb +++ b/app/services/admin_api/get_data_service.rb @@ -23,11 +23,11 @@ def get_product_permission_profiles def get_ds_groups worker - #ds-snippet-start:Admin2Step4 + #ds-snippet-start:Admin4Step4 ds_groups_api = DocuSign_Admin::DSGroupsApi.new(@api_client) ds_groups = ds_groups_api.get_ds_groups(args[:organization_id], args[:account_id]) ds_groups.as_json['ds_groups'] - #ds-snippet-end:Admin2Step4 + #ds-snippet-end:Admin4Step4 end def get_organization_id From f091e390bdb5ba4c68ae1cf5785721a3626aa808 Mon Sep 17 00:00:00 2001 From: Raileen Del Rosario Date: Thu, 7 Mar 2024 15:54:16 -0800 Subject: [PATCH 309/363] fixing admin 2 codeDepot markers --- app/services/admin_api/get_data_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/admin_api/get_data_service.rb b/app/services/admin_api/get_data_service.rb index 8235f3a..dd7b326 100644 --- a/app/services/admin_api/get_data_service.rb +++ b/app/services/admin_api/get_data_service.rb @@ -23,11 +23,11 @@ def get_product_permission_profiles def get_ds_groups worker - #ds-snippet-start:Admin4Step4 + #ds-snippet-start:Admin2Step4 ds_groups_api = DocuSign_Admin::DSGroupsApi.new(@api_client) ds_groups = ds_groups_api.get_ds_groups(args[:organization_id], args[:account_id]) ds_groups.as_json['ds_groups'] - #ds-snippet-end:Admin4Step4 + #ds-snippet-end:Admin2Step4 end def get_organization_id From 12f1b84305b6a1cf8e97aca1677be9b4058be55a Mon Sep 17 00:00:00 2001 From: Karissa Jacobsen Date: Fri, 8 Mar 2024 15:39:24 -0800 Subject: [PATCH 310/363] azure pipeline --- azure-pipelines.yml | 120 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 azure-pipelines.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000..bea1d09 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,120 @@ +# 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: ruby_dockerfile + displayName: 'download Dockerfile' + inputs: + secureFile: 'ruby.Dockerfile' + +- script: | + echo "place ruby.Dockerfile" + echo $(ruby_dockerfile.secureFilePath) + cp $(ruby_Dockerfile.secureFilePath) code-examples-ruby-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: 'tests_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: ruby_appsettings + displayName: 'download appsettings.yml' + inputs: + secureFile: 'ruby.appsettings.yml' + + +- script: | + echo "place appsettings.yml" + cp $(ruby_appsettings.secureFilePath) code-examples-ruby-private/config/appsettings.yml + displayName: 'place appsettings.yml' + + +- task: DownloadSecureFile@1 + name: ruby_private_key + displayName: 'download private.key' + inputs: + secureFile: 'private.key' + + +- script: | + echo "place private.key" + cp $(ruby_private_key.secureFilePath) code-examples-ruby-private/config/docusign_private_key.txt + displayName: 'place docusign_private_key.txt' + +- script: dir $(Build.SourcesDirectory) + +- script: dir $(Build.SourcesDirectory)/code-examples-ruby-private + +- task: Docker@2 + displayName: Build ruby image + inputs: + command: build + repository: 'launcher-automation-ruby' + dockerfile: '$(Build.SourcesDirectory)/code-examples-ruby-private/Dockerfile' + buildContext: '$(Build.SourcesDirectory)/code-examples-ruby-private ' + tags: | + latest + +- script: | + docker run -p 3000:3000 -d launcher-automation-ruby:latest + displayName: 'start ruby app' + +- script: | + cd launcher-automation + mvn clean test -DsuiteXmlFile="ruby_suite.xml" + displayName: 'Ruby app tests' + +- script: | + docker stop $(docker ps -a -q) + docker rm $(docker ps -a -q) + displayName: 'stop ruby app' + +- script: | + allure generate --clean --output $(Build.SourcesDirectory)/ruby-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)/ruby-allure-output' From 505bee78080b6ef6db7fd2e35b2667e011bc85e3 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Thu, 28 Mar 2024 00:17:51 +0200 Subject: [PATCH 311/363] Enforce signer visibility (#155) * add enforce_signer_visibility & fix search for esign --- Gemfile.lock | 9 +++++++ app/assets/javascripts/search.js | 2 +- .../admin_api/eg005_audit_users_service.rb | 4 ++-- .../eg040_set_document_visibility_service.rb | 1 + .../webforms/eg001_create_instance_service.rb | 24 +++++++++---------- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 832c8c5..71e12a2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -138,6 +138,7 @@ GEM ruby2_keywords (>= 0.0.4) faraday-net_http (3.0.2) ffi (1.15.5) + ffi (1.15.5-x64-mingw-ucrt) globalid (1.1.0) activesupport (>= 5.0) hashie (5.0.0) @@ -177,8 +178,12 @@ GEM net-smtp (0.3.3) net-protocol nio4r (2.5.9) + nokogiri (1.15.4-x64-mingw-ucrt) + racc (~> 1.4) nokogiri (1.15.4-x86_64-darwin) racc (~> 1.4) + nokogiri (1.15.4-x86_64-linux) + racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) jwt (>= 1.0, < 3.0) @@ -295,7 +300,9 @@ GEM actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) + sqlite3 (1.6.4-x64-mingw-ucrt) sqlite3 (1.6.4-x86_64-darwin) + sqlite3 (1.6.4-x86_64-linux) test-unit (3.6.1) power_assert thor (1.2.2) @@ -328,7 +335,9 @@ GEM zeitwerk (2.6.11) PLATFORMS + x64-mingw-ucrt x86_64-darwin-21 + x86_64-linux DEPENDENCIES bootsnap (~> 1.7.3) diff --git a/app/assets/javascripts/search.js b/app/assets/javascripts/search.js index cdbd0e4..9668b39 100644 --- a/app/assets/javascripts/search.js +++ b/app/assets/javascripts/search.js @@ -140,7 +140,7 @@ const DS_SEARCH = (function () { case API_TYPES.MONITOR: return "meg"; case API_TYPES.ESIGNATURE: - return "eg"; + return "eeg"; case API_TYPES.CONNECT: return "cneg"; case API_TYPES.WEBFORMS: diff --git a/app/services/admin_api/eg005_audit_users_service.rb b/app/services/admin_api/eg005_audit_users_service.rb index f9c8b07..c2a612e 100644 --- a/app/services/admin_api/eg005_audit_users_service.rb +++ b/app/services/admin_api/eg005_audit_users_service.rb @@ -28,8 +28,8 @@ def worker #ds-snippet-start:Admin5Step5 results = [] modified_users.each do |user| - #ds-snippet-end:Admin5Step5 - #ds-snippet-start:Admin5Step4 + #ds-snippet-end:Admin5Step5 + #ds-snippet-start:Admin5Step4 userProfilesOptions = DocuSign_Admin::GetUserProfilesOptions.new userProfilesOptions.email = user['email'] #ds-snippet-end:Admin5Step4 diff --git a/app/services/e_sign/eg040_set_document_visibility_service.rb b/app/services/e_sign/eg040_set_document_visibility_service.rb index 905cb87..db601ca 100644 --- a/app/services/e_sign/eg040_set_document_visibility_service.rb +++ b/app/services/e_sign/eg040_set_document_visibility_service.rb @@ -43,6 +43,7 @@ def make_envelope(envelope_args) envelope_definition = DocuSign_eSign::EnvelopeDefinition.new envelope_definition.email_subject = 'Please sign this document set' + envelope_definition.enforce_signer_visibility = 'true' # Add the documents doc1_b64 = Base64.encode64(create_document1(envelope_args)) diff --git a/app/services/webforms/eg001_create_instance_service.rb b/app/services/webforms/eg001_create_instance_service.rb index c904568..3114d3a 100644 --- a/app/services/webforms/eg001_create_instance_service.rb +++ b/app/services/webforms/eg001_create_instance_service.rb @@ -58,10 +58,10 @@ def create_web_form_instance(form_id) 'JobTitle' => 'Programmer Writer' } web_form_req_object = DocuSign_WebForms::CreateInstanceRequestBody.new({ - 'clientUserId' => args[:client_user_id], - 'formValues' => web_form_values, - 'expirationOffset' => '3600' - }) + 'clientUserId' => args[:client_user_id], + 'formValues' => web_form_values, + 'expirationOffset' => '3600' + }) #ds-snippet-end:WebForms1Step4 #ds-snippet-start:WebForms1Step5 @@ -79,18 +79,18 @@ def make_web_forms_template # Create the document model document = DocuSign_eSign::Document.new({ - # Create the DocuSign document object - 'documentBase64' => base64_file_content, - 'name' => 'World_Wide_Web_Form', # Can be different from actual file name - 'fileExtension' => 'pdf', # Many different document types are accepted - 'documentId' => '1' # A label used to reference the doc - }) + # Create the DocuSign document object + 'documentBase64' => base64_file_content, + 'name' => 'World_Wide_Web_Form', # Can be different from actual file name + 'fileExtension' => 'pdf', # Many different document types are accepted + 'documentId' => '1' # A label used to reference the doc + }) # Create the signer recipient model # Since these are role definitions, no name/email: signer = DocuSign_eSign::Signer.new({ - 'roleName' => 'signer', 'recipientId' => '1', 'routingOrder' => '1' - }) + 'roleName' => 'signer', 'recipientId' => '1', 'routingOrder' => '1' + }) # Create fields using absolute positioning # Create a sign_here tab (field on the document) sign_here = DocuSign_eSign::SignHere.new( From 1c6f153247967de4f2b2609de362895d077ce1d8 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Wed, 10 Apr 2024 19:06:31 +0300 Subject: [PATCH 312/363] Maestro API code examples (#156) * added Maestro code examples --- Gemfile | 2 +- Gemfile.lock | 120 ++-- app/assets/javascripts/search.js | 3 + .../eeg008_create_template_controller.rb | 1 + .../mseg001_trigger_workflow_controller.rb | 112 ++++ .../mseg002_cancel_workflow_controller.rb | 52 ++ .../mseg003_get_workflow_status_controller.rb | 34 + app/controllers/session_controller.rb | 1 + app/services/jwt_auth/jwt_creator.rb | 1 + .../mseg001_trigger_workflow_service.rb | 71 ++ .../mseg002_cancel_workflow_service.rb | 41 ++ .../mseg003_get_workflow_status_service.rb | 29 + app/services/maestro_api/utils.rb | 621 ++++++++++++++++++ app/services/utils.rb | 13 + app/views/ds_common/index.html.erb | 2 + .../mseg001_trigger_workflow/get.html.erb | 54 ++ .../publish_workflow.html.erb | 7 + .../mseg002_cancel_workflow/get.html.erb | 33 + .../mseg003_get_workflow_status/get.html.erb | 33 + config/appsettings.example.yml | 1 + config/initializers/omniauth.rb | 2 + config/routes.rb | 12 + 22 files changed, 1185 insertions(+), 60 deletions(-) create mode 100644 app/controllers/maestro_api/mseg001_trigger_workflow_controller.rb create mode 100644 app/controllers/maestro_api/mseg002_cancel_workflow_controller.rb create mode 100644 app/controllers/maestro_api/mseg003_get_workflow_status_controller.rb create mode 100644 app/services/maestro_api/mseg001_trigger_workflow_service.rb create mode 100644 app/services/maestro_api/mseg002_cancel_workflow_service.rb create mode 100644 app/services/maestro_api/mseg003_get_workflow_status_service.rb create mode 100644 app/services/maestro_api/utils.rb create mode 100644 app/views/maestro_api/mseg001_trigger_workflow/get.html.erb create mode 100644 app/views/maestro_api/mseg001_trigger_workflow/publish_workflow.html.erb create mode 100644 app/views/maestro_api/mseg002_cancel_workflow/get.html.erb create mode 100644 app/views/maestro_api/mseg003_get_workflow_status/get.html.erb diff --git a/Gemfile b/Gemfile index c87beb2..3a3e8cb 100644 --- a/Gemfile +++ b/Gemfile @@ -71,9 +71,9 @@ end gem 'docusign_admin', '~> 1.3.0' gem 'docusign_click', '~> 1.4.0' gem 'docusign_esign', '~> 3.25.0' +gem 'docusign_maestro', '~> 1.0.0.rc1' gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' -gem 'docusign_webforms', '~> 1.0.0' gem 'omniauth-oauth2', '~> 1.8.0' gem 'omniauth-rails_csrf_protection' diff --git a/Gemfile.lock b/Gemfile.lock index 71e12a2..aa7bfb2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -66,11 +66,12 @@ GEM i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - addressable (2.8.5) + addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) archive-zip (0.12.0) io-like (~> 0.3.0) ast (2.4.2) + base64 (0.2.0) bindex (0.8.1) bootsnap (1.7.7) msgpack (~> 1.0) @@ -96,9 +97,9 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.2.2) + concurrent-ruby (1.2.3) crass (1.0.6) - date (3.3.3) + date (3.3.4) docusign_admin (1.3.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) @@ -114,17 +115,17 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_monitor (1.2.0) + docusign_maestro (1.0.0.rc1) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_rooms (1.3.0) + docusign_monitor (1.2.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_webforms (1.0.0) + docusign_rooms (1.3.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -132,28 +133,29 @@ GEM erubi (1.12.0) ethon (0.16.0) ffi (>= 1.15.0) - execjs (2.8.1) - faraday (2.7.10) - faraday-net_http (>= 2.0, < 3.1) - ruby2_keywords (>= 0.0.4) - faraday-net_http (3.0.2) - ffi (1.15.5) - ffi (1.15.5-x64-mingw-ucrt) - globalid (1.1.0) - activesupport (>= 5.0) + execjs (2.9.1) + faraday (2.9.0) + faraday-net_http (>= 2.0, < 3.2) + faraday-net_http (3.1.0) + net-http + ffi (1.16.3) + ffi (1.16.3-x64-mingw-ucrt) + globalid (1.2.1) + activesupport (>= 6.1) hashie (5.0.0) - i18n (1.14.1) + i18n (1.14.4) concurrent-ruby (~> 1.0) io-like (0.3.1) jbuilder (2.11.5) actionview (>= 5.0.0) activesupport (>= 5.0.0) - json (2.6.3) - jwt (2.7.1) + json (2.7.2) + jwt (2.8.1) + base64 listen (3.8.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.21.3) + loofah (2.22.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) mail (2.8.1) @@ -161,28 +163,28 @@ GEM net-imap net-pop net-smtp - marcel (1.0.2) + marcel (1.0.4) matrix (0.4.2) method_source (1.0.0) mini_mime (1.1.5) - minitest (5.19.0) + minitest (5.22.3) msgpack (1.7.2) multi_xml (0.6.0) - net-imap (0.3.7) + net-http (0.4.1) + uri + net-imap (0.4.10) date net-protocol net-pop (0.1.2) net-protocol - net-protocol (0.2.1) + net-protocol (0.2.2) timeout - net-smtp (0.3.3) + net-smtp (0.5.0) net-protocol - nio4r (2.5.9) - nokogiri (1.15.4-x64-mingw-ucrt) - racc (~> 1.4) - nokogiri (1.15.4-x86_64-darwin) + nio4r (2.7.1) + nokogiri (1.16.3-x64-mingw-ucrt) racc (~> 1.4) - nokogiri (1.15.4-x86_64-linux) + nokogiri (1.16.3-x86_64-linux) racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) @@ -191,7 +193,7 @@ GEM rack (>= 1.2, < 4) snaky_hash (~> 2.0) version_gem (~> 1.1) - omniauth (2.1.1) + omniauth (2.1.2) hashie (>= 3.4.6) rack (>= 2.2.3) rack-protection @@ -201,8 +203,8 @@ GEM omniauth-rails_csrf_protection (1.0.1) actionpack (>= 4.2) omniauth (~> 2.0) - parallel (1.23.0) - parser (3.2.2.3) + parallel (1.24.0) + parser (3.3.0.5) ast (~> 2.4.1) racc power_assert (2.0.3) @@ -213,12 +215,13 @@ GEM pry (>= 0.9.10, < 0.15) pry-rails (0.3.9) pry (>= 0.10.4) - public_suffix (5.0.3) + public_suffix (5.0.5) puma (6.1.1) nio4r (~> 2.0) - racc (1.7.1) - rack (2.2.8) - rack-protection (3.1.0) + racc (1.7.3) + rack (2.2.9) + rack-protection (3.2.0) + base64 (>= 0.1.0) rack (~> 2.2, >= 2.2.4) rack-test (2.1.0) rack (>= 1.3) @@ -251,11 +254,11 @@ GEM thor (~> 1.0) zeitwerk (~> 2.5) rainbow (3.1.1) - rake (13.0.6) + rake (13.2.1) rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - regexp_parser (2.8.1) + regexp_parser (2.9.0) rexml (3.2.6) rubocop (1.48.1) json (~> 2.3) @@ -267,10 +270,9 @@ GEM rubocop-ast (>= 1.26.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.29.0) - parser (>= 3.2.1.0) + rubocop-ast (1.31.2) + parser (>= 3.3.0.4) ruby-progressbar (1.13.0) - ruby2_keywords (0.0.5) rubyzip (2.3.2) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) @@ -289,29 +291,28 @@ GEM snaky_hash (2.0.1) hashie version_gem (~> 1.1, >= 1.1.1) - spring (4.1.1) + spring (4.1.3) spring-watcher-listen (2.1.0) listen (>= 2.7, < 4.0) spring (>= 4) - sprockets (4.2.0) + sprockets (4.2.1) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) sprockets-rails (3.4.2) actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) - sqlite3 (1.6.4-x64-mingw-ucrt) - sqlite3 (1.6.4-x86_64-darwin) - sqlite3 (1.6.4-x86_64-linux) - test-unit (3.6.1) + sqlite3 (1.6.9-x64-mingw-ucrt) + sqlite3 (1.6.9-x86_64-linux) + test-unit (3.6.2) power_assert - thor (1.2.2) - tilt (2.2.0) - timeout (0.4.0) + thor (1.3.1) + tilt (2.3.0) + timeout (0.4.1) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) - typhoeus (1.4.0) + typhoeus (1.4.1) ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) @@ -319,24 +320,25 @@ GEM tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) - unicode-display_width (2.4.2) - version_gem (1.1.3) - web-console (4.2.0) + unicode-display_width (2.5.0) + uri (0.13.0) + version_gem (1.1.4) + wdm (0.1.1) + web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - websocket (1.2.9) + websocket (1.2.10) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.11) + zeitwerk (2.6.13) PLATFORMS x64-mingw-ucrt - x86_64-darwin-21 x86_64-linux DEPENDENCIES @@ -348,9 +350,9 @@ DEPENDENCIES docusign_admin (~> 1.3.0) docusign_click (~> 1.4.0) docusign_esign (~> 3.25.0) + docusign_maestro (~> 1.0.0.rc1) docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) - docusign_webforms (~> 1.0.0) jbuilder (~> 2.11.5) listen (~> 3.8.0) matrix (~> 0.4.2) @@ -377,4 +379,4 @@ RUBY VERSION ruby 3.1.2p20 BUNDLED WITH - 2.3.7 + 2.4.22 diff --git a/app/assets/javascripts/search.js b/app/assets/javascripts/search.js index 9668b39..612e088 100644 --- a/app/assets/javascripts/search.js +++ b/app/assets/javascripts/search.js @@ -7,6 +7,7 @@ const DS_SEARCH = (function () { ADMIN: "admin", CONNECT: "connect", WEBFORMS: "webforms", + MAESTRO: "maestro", } const processJSONData = function () { @@ -145,6 +146,8 @@ const DS_SEARCH = (function () { return "cneg"; case API_TYPES.WEBFORMS: return "weg"; + case API_TYPES.MAESTRO: + return "mseg"; } } diff --git a/app/controllers/e_sign/eeg008_create_template_controller.rb b/app/controllers/e_sign/eeg008_create_template_controller.rb index 43b08fd..4a38528 100644 --- a/app/controllers/e_sign/eeg008_create_template_controller.rb +++ b/app/controllers/e_sign/eeg008_create_template_controller.rb @@ -13,6 +13,7 @@ def create } results = ESign::Eg008CreateTemplateService.new(args).worker session[:template_id] = results[:template_id] + session[:workflow_template_id] = results[:template_id] msg = if results.fetch(:created_new_template) 'The template has been created!' else diff --git a/app/controllers/maestro_api/mseg001_trigger_workflow_controller.rb b/app/controllers/maestro_api/mseg001_trigger_workflow_controller.rb new file mode 100644 index 0000000..db30552 --- /dev/null +++ b/app/controllers/maestro_api/mseg001_trigger_workflow_controller.rb @@ -0,0 +1,112 @@ +class MaestroApi::Mseg001TriggerWorkflowController < EgController + before_action -> { check_auth('Maestro') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1, 'Maestro') } + + def create + args = { + instance_name: params[:instance_name], + signer_email: params[:signer_email], + signer_name: params[:signer_name], + cc_email: params[:cc_email], + cc_name: params[:cc_name], + workflow_id: session[:workflow_id], + account_id: session[:ds_account_id], + access_token: session[:ds_access_token], + base_path: Rails.application.config.maestro_client_host + } + + trigger_workflow_service = MaestroApi::Mseg001TriggerWorkflowService.new args + workflow = trigger_workflow_service.get_workflow_definition + results = trigger_workflow_service.trigger_workflow workflow + + session[:instance_id] = results.instance_id + + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results.instance_id) + @json = results.to_json.to_json + + render 'ds_common/example_done' + rescue DocuSign_Maestro::ApiError => e + @error_code = e.code || error['errorCode'] + if e.to_s == '403' + @error_message = format_string(@manifest['SupportingTexts']['ContactSupportToEnableFeature'], 'Maestro') + return render 'ds_common/error' + end + handle_error(e) + end + + def get + args = { + template_id: session[:workflow_template_id], + account_id: session[:ds_account_id], + access_token: session[:ds_access_token], + base_path: Rails.application.config.maestro_client_host + } + + trigger_workflow_service = MaestroApi::Mseg001TriggerWorkflowService.new args + workflows = trigger_workflow_service.get_workflow_definitions + + if workflows.count.positive? + sorted_workflows = workflows.value.sort_by(&:last_updated_date).reverse + + session[:workflow_id] = sorted_workflows[0].id if sorted_workflows + session[:is_workflow_published] = true + end + + unless session[:workflow_id] + unless session[:workflow_template_id] + @show_template_not_ok = true + return render 'maestro_api/mseg001_trigger_workflow/get' + end + + session[:workflow_id] = MaestroApi::Utils.new.create_workflow args + end + unless session[:is_workflow_published] + consent_url = MaestroApi::Utils.new.publish_workflow args, session[:workflow_id] + if consent_url + additional_page_data = @example['AdditionalPage'].find { |p| p['Name'] == 'publish_workflow' } + @title = @example['ExampleName'] + @message = additional_page_data['ResultsPageText'] + @consent_url = consent_url + + render 'maestro_api/mseg001_trigger_workflow/publish_workflow' + end + end + rescue DocuSign_Maestro::ApiError => e + @error_code = e.code || error['errorCode'] + if e.to_s == '403' + @error_message = format_string(@manifest['SupportingTexts']['ContactSupportToEnableFeature'], 'Maestro') + return render 'ds_common/error' + end + handle_error(e) + end + + def publish + args = { + account_id: session[:ds_account_id], + access_token: session[:ds_access_token], + base_path: Rails.application.config.maestro_client_host + } + + consent_url = MaestroApi::Utils.new.publish_workflow args, session[:workflow_id] + + if consent_url + additional_page_data = @example['AdditionalPage'].find { |p| p['Name'] == 'publish_workflow' } + @title = @example['ExampleName'] + @message = additional_page_data['ResultsPageText'] + @consent_url = consent_url + + return render 'maestro_api/mseg001_trigger_workflow/publish_workflow' + end + + session[:is_workflow_published] = true + render 'maestro_api/mseg001_trigger_workflow/get' + rescue DocuSign_Maestro::ApiError => e + @error_code = e.code || error['errorCode'] + if e.to_s == '403' + @error_message = format_string(@manifest['SupportingTexts']['ContactSupportToEnableFeature'], 'Maestro') + return render 'ds_common/error' + end + handle_error(e) + end +end diff --git a/app/controllers/maestro_api/mseg002_cancel_workflow_controller.rb b/app/controllers/maestro_api/mseg002_cancel_workflow_controller.rb new file mode 100644 index 0000000..673ab8c --- /dev/null +++ b/app/controllers/maestro_api/mseg002_cancel_workflow_controller.rb @@ -0,0 +1,52 @@ +class MaestroApi::Mseg002CancelWorkflowController < EgController + before_action -> { check_auth('Maestro') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2, 'Maestro') } + + def create + args = { + workflow_id: session[:workflow_id], + instance_id: session[:instance_id], + account_id: session[:ds_account_id], + access_token: session[:ds_access_token], + base_path: Rails.application.config.maestro_client_host + } + + results = MaestroApi::Mseg002CancelWorkflowService.new(args).cancel_workflow_instance + + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], session[:instance_id]) + @json = results.to_json.to_json + + render 'ds_common/example_done' + rescue DocuSign_Maestro::ApiError => e + @error_code = e.code || error['errorCode'] + if e.to_s == '403' + @error_message = format_string(@manifest['SupportingTexts']['ContactSupportToEnableFeature'], 'Maestro') + return render 'ds_common/error' + end + handle_error(e) + end + + def get + args = { + workflow_id: session[:workflow_id], + instance_id: session[:instance_id], + account_id: session[:ds_account_id], + access_token: session[:ds_access_token], + base_path: Rails.application.config.maestro_client_host + } + + state = MaestroApi::Mseg002CancelWorkflowService.new(args).get_instance_state + @instance_ok = state.downcase == 'in progress' + + @workflow_id = session[:workflow_id] + @instance_id = session[:instance_id] + rescue DocuSign_Maestro::ApiError => e + @error_code = e.code || error['errorCode'] + if e.to_s == '403' + @error_message = format_string(@manifest['SupportingTexts']['ContactSupportToEnableFeature'], 'Maestro') + return render 'ds_common/error' + end + handle_error(e) + end +end diff --git a/app/controllers/maestro_api/mseg003_get_workflow_status_controller.rb b/app/controllers/maestro_api/mseg003_get_workflow_status_controller.rb new file mode 100644 index 0000000..43bcd2e --- /dev/null +++ b/app/controllers/maestro_api/mseg003_get_workflow_status_controller.rb @@ -0,0 +1,34 @@ +class MaestroApi::Mseg003GetWorkflowStatusController < EgController + before_action -> { check_auth('Maestro') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 3, 'Maestro') } + + def create + args = { + workflow_id: session[:workflow_id], + instance_id: session[:instance_id], + account_id: session[:ds_account_id], + access_token: session[:ds_access_token], + base_path: Rails.application.config.maestro_client_host + } + + results = MaestroApi::Mseg003GetWorkflowStatusService.new(args).get_instance_state + + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results.instance_state) + @json = results.to_json.to_json + + render 'ds_common/example_done' + rescue DocuSign_Maestro::ApiError => e + @error_code = e.code || error['errorCode'] + if e.to_s == '403' + @error_message = format_string(@manifest['SupportingTexts']['ContactSupportToEnableFeature'], 'Maestro') + return render 'ds_common/error' + end + handle_error(e) + end + + def get + @workflow_id = session[:workflow_id] + @instance_id = session[:instance_id] + end +end diff --git a/app/controllers/session_controller.rb b/app/controllers/session_controller.rb index 97a70eb..466fa6b 100644 --- a/app/controllers/session_controller.rb +++ b/app/controllers/session_controller.rb @@ -59,6 +59,7 @@ def internal_destroy session.delete :eg session.delete :manifest session.delete :status_cfr + session.delete :is_workflow_published end def store_auth_hash_from_docusign_callback diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index 708ca2f..8dbbc72 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -18,6 +18,7 @@ def self.consent_url(state, api) scope = 'signature impersonation click.manage click.send' if api == 'Click' scope = 'signature impersonation organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read' if api == 'Admin' scope = 'signature webforms_read webforms_instance_read webforms_instance_write' if api == 'WebForms' + scope = 'signature aow_manage' if api == 'Maestro' base_uri = "#{Rails.configuration.authorization_server}/oauth/auth" response_type = 'code' diff --git a/app/services/maestro_api/mseg001_trigger_workflow_service.rb b/app/services/maestro_api/mseg001_trigger_workflow_service.rb new file mode 100644 index 0000000..bf7262d --- /dev/null +++ b/app/services/maestro_api/mseg001_trigger_workflow_service.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +class MaestroApi::Mseg001TriggerWorkflowService + include Utils + attr_reader :args + + def initialize(args) + @args = args + end + + def get_workflow_definitions + #ds-snippet-start:Maestro1Step2 + configuration = DocuSign_Maestro::Configuration.new + configuration.host = args[:base_path] + + api_client = DocuSign_Maestro::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:Maestro1Step2 + + workflow_management_api = DocuSign_Maestro::WorkflowManagementApi.new(api_client) + + options = DocuSign_Maestro::GetWorkflowDefinitionsOptions.new + options.status = 'active' + workflow_management_api.get_workflow_definitions(args[:account_id], options) + end + + def get_workflow_definition + configuration = DocuSign_Maestro::Configuration.new + configuration.host = args[:base_path] + + api_client = DocuSign_Maestro::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + + #ds-snippet-start:Maestro1Step3 + workflow_management_api = DocuSign_Maestro::WorkflowManagementApi.new(api_client) + workflow_management_api.get_workflow_definition(args[:account_id], args[:workflow_id]) + #ds-snippet-end:Maestro1Step3 + end + + def trigger_workflow(workflow) + configuration = DocuSign_Maestro::Configuration.new + configuration.host = args[:base_path] + + api_client = DocuSign_Maestro::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + + #ds-snippet-start:Maestro1Step4 + trigger_payload = DocuSign_Maestro::TriggerPayload.new + trigger_payload.instance_name = args[:instance_name] + trigger_payload.participants = {} + trigger_payload.payload = { + signerEmail: args[:signer_email], + signerName: args[:signer_name], + ccEmail: args[:cc_email], + ccName: args[:cc_name] + } + trigger_payload.metadata = {} + + mtid = URLUtils.new.get_parameter_value_from_url(workflow.trigger_url, 'mtid') + mtsec = URLUtils.new.get_parameter_value_from_url(workflow.trigger_url, 'mtsec') + trigger_options = DocuSign_Maestro::TriggerWorkflowOptions.new + trigger_options.mtid = mtid + trigger_options.mtsec = mtsec + #ds-snippet-end:Maestro1Step4 + + #ds-snippet-start:Maestro1Step5 + workflow_trigger_api = DocuSign_Maestro::WorkflowTriggerApi.new(api_client) + workflow_trigger_api.trigger_workflow(args[:account_id], trigger_payload, trigger_options) + #ds-snippet-end:Maestro1Step5 + end +end diff --git a/app/services/maestro_api/mseg002_cancel_workflow_service.rb b/app/services/maestro_api/mseg002_cancel_workflow_service.rb new file mode 100644 index 0000000..1717e49 --- /dev/null +++ b/app/services/maestro_api/mseg002_cancel_workflow_service.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +class MaestroApi::Mseg002CancelWorkflowService + attr_reader :args + + def initialize(args) + @args = args + end + + def get_instance_state + configuration = DocuSign_Maestro::Configuration.new + configuration.host = args[:base_path] + + api_client = DocuSign_Maestro::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + + workflow_instance_management_api = DocuSign_Maestro::WorkflowInstanceManagementApi.new(api_client) + + workflow_instance_management_api.get_workflow_instance( + args[:account_id], + args[:workflow_id], + args[:instance_id] + ).instance_state + end + + def cancel_workflow_instance + #ds-snippet-start:Maestro2Step2 + configuration = DocuSign_Maestro::Configuration.new + configuration.host = args[:base_path] + + api_client = DocuSign_Maestro::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:Maestro2Step2 + + #ds-snippet-start:Maestro2Step3 + workflow_instance_management_api = DocuSign_Maestro::WorkflowInstanceManagementApi.new(api_client) + + workflow_instance_management_api.cancel_workflow_instance(args[:account_id], args[:instance_id]) + #ds-snippet-end:Maestro2Step3 + end +end diff --git a/app/services/maestro_api/mseg003_get_workflow_status_service.rb b/app/services/maestro_api/mseg003_get_workflow_status_service.rb new file mode 100644 index 0000000..47e1c06 --- /dev/null +++ b/app/services/maestro_api/mseg003_get_workflow_status_service.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class MaestroApi::Mseg003GetWorkflowStatusService + attr_reader :args + + def initialize(args) + @args = args + end + + def get_instance_state + #ds-snippet-start:Maestro3Step2 + configuration = DocuSign_Maestro::Configuration.new + configuration.host = args[:base_path] + + api_client = DocuSign_Maestro::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:Maestro3Step2 + + #ds-snippet-start:Maestro3Step3 + workflow_instance_management_api = DocuSign_Maestro::WorkflowInstanceManagementApi.new(api_client) + + workflow_instance_management_api.get_workflow_instance( + args[:account_id], + args[:workflow_id], + args[:instance_id] + ) + #ds-snippet-end:Maestro3Step3 + end +end diff --git a/app/services/maestro_api/utils.rb b/app/services/maestro_api/utils.rb new file mode 100644 index 0000000..58a9f02 --- /dev/null +++ b/app/services/maestro_api/utils.rb @@ -0,0 +1,621 @@ +# frozen_string_literal: true + +require 'securerandom' + +class MaestroApi::Utils + def create_workflow(args) + signer_id = SecureRandom.uuid + cc_id = SecureRandom.uuid + trigger_id = 'wfTrigger' + + participants = { + signer_id => { + 'participantRole' => 'Signer' + }, + cc_id => { + 'participantRole' => 'CC' + } + } + + dac_id_field = "dacId_#{trigger_id}" + id_field = "id_#{trigger_id}" + signer_name_field = "signerName_#{trigger_id}" + signer_email_field = "signerEmail_#{trigger_id}" + cc_name_field = "ccName_#{trigger_id}" + cc_email_field = "ccEmail_#{trigger_id}" + + trigger = DocuSign_Maestro::DSWorkflowTrigger.new({ + name: 'Get_URL', + type: 'Http', + httpType: 'Get', + id: trigger_id, + input: { + metadata: { + customAttributes: {} + }, + payload: { + "#{dac_id_field}": { + source: 'step', + propertyName: 'dacId', + stepId: trigger_id + }, + "#{id_field}": { + source: 'step', + propertyName: 'id', + stepId: trigger_id + }, + "#{signer_name_field}": { + source: 'step', + propertyName: 'signerName', + stepId: trigger_id + }, + "#{signer_email_field}": { + source: 'step', + propertyName: 'signerEmail', + stepId: trigger_id + }, + "#{cc_name_field}": { + source: 'step', + propertyName: 'ccName', + stepId: trigger_id + }, + "#{cc_email_field}": { + source: 'step', + propertyName: 'ccEmail', + stepId: trigger_id + } + }, + participants: {} + }, + output: { + "#{dac_id_field}": { + source: 'step', + propertyName: 'dacId', + stepId: trigger_id + } + } + }) + + variables = { + "#{dac_id_field}": DocuSign_Maestro::DSWorkflowVariableFromVariable.new({ + source: 'step', + propertyName: 'dacId', + stepId: trigger_id + }), + "#{id_field}": DocuSign_Maestro::DSWorkflowVariableFromVariable.new({ + source: 'step', + propertyName: 'id', + stepId: trigger_id + }), + "#{signer_name_field}": DocuSign_Maestro::DSWorkflowVariableFromVariable.new({ + source: 'step', + propertyName: 'signerName', + stepId: trigger_id + }), + "#{signer_email_field}": DocuSign_Maestro::DSWorkflowVariableFromVariable.new({ + source: 'step', + propertyName: 'signerEmail', + stepId: trigger_id + }), + "#{cc_name_field}": DocuSign_Maestro::DSWorkflowVariableFromVariable.new({ + source: 'step', + propertyName: 'ccName', + stepId: trigger_id + }), + "#{cc_email_field}": DocuSign_Maestro::DSWorkflowVariableFromVariable.new({ + 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' + } + } + + step1 = { + 'id': 'step1', + 'name': 'Set Up Invite', + 'moduleName': 'Notification-SendEmail', + 'configurationProgress': 'Completed', + 'type': 'DS-EmailNotification', + 'config': { + 'templateType': 'WorkflowParticipantNotification', + 'templateVersion': 1, + 'language': 'en', + 'sender_name': 'DocuSign Orchestration', + 'sender_alias': 'Orchestration', + 'participantId': signer_id + }, + 'input': { + 'recipients': [ + { + 'name': { + 'source': 'step', + 'propertyName': 'signerName', + 'stepId': trigger_id + }, + 'email': { + 'source': 'step', + 'propertyName': 'signerEmail', + 'stepId': trigger_id + } + } + ], + 'mergeValues': { + 'CustomMessage': 'Follow this link to access and complete the workflow.', + 'ParticipantFullName': { + 'source': 'step', + 'propertyName': 'signerName', + 'stepId': trigger_id + } + } + }, + 'output': {} + } + + step2 = { + "id": 'step2', + "name": 'Get Signatures', + "moduleName": 'ESign', + "configurationProgress": 'Completed', + "type": 'DS-Sign', + "config": { + "participantId": signer_id + }, + "input": { + "isEmbeddedSign": true, + "documents": [ + { + "type": 'FromDSTemplate', + "eSignTemplateId": args[: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' + } + } + } + + step3 = { + "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": {} + } + + workflow_definition = DocuSign_Maestro::WorkflowDefinition.new({ + workflowName: 'Example workflow - send invite to signer', + workflowDescription: '', + documentVersion: '1.0.0', + schemaVersion: '1.0.0', + accountId: args[:account_id], + participants: participants, + trigger: trigger, + variables: variables, + steps: [step1, step2, step3] + }) + + configuration = DocuSign_Maestro::Configuration.new + configuration.host = args[:base_path] + + api_client = DocuSign_Maestro::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + + workflow_management_api = DocuSign_Maestro::WorkflowManagementApi.new(api_client) + workflow_management_api.create_workflow_definition( + args[:account_id], + { "workflowDefinition": workflow_definition } + ).workflow_definition_id + end + + def publish_workflow(args, workflow_id) + configuration = DocuSign_Maestro::Configuration.new + configuration.host = args[:base_path] + + api_client = DocuSign_Maestro::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + + workflow_management_api = DocuSign_Maestro::WorkflowManagementApi.new(api_client) + + deploy_request = DocuSign_Maestro::DeployRequest.new({ + deploymentStatus: DocuSign_Maestro::DeployStatus::PUBLISH + }) + begin + workflow_management_api.publish_or_un_publish_workflow_definition( + args[:account_id], + workflow_id, + deploy_request + ) + + # return false if workflow does not require a consent to be published + false + rescue Exception => e + return raise e unless e.respond_to?(:response_body) + + response_body = JSON.parse(e.response_body) + return raise e unless response_body.key?('responseType') + + is_consent_required = response_body['responseType'] == 'NeedConsent' + return response_body['consentUrl'] if is_consent_required + + raise e + end + end +end diff --git a/app/services/utils.rb b/app/services/utils.rb index 23b8254..43af62a 100644 --- a/app/services/utils.rb +++ b/app/services/utils.rb @@ -40,4 +40,17 @@ def replace_template_id(file_path, template_id) File.write(file_path, content) end end + + class URLUtils + def get_parameter_value_from_url(url, param_name) + parsed_url = URI.parse(url) + query_params = URI.decode_www_form(parsed_url.query || '') + + # Access the parameter value (returns a list) + param_value_list = query_params.assoc(param_name) + + # If the parameter exists, return the first value; otherwise, return nil + param_value_list ? param_value_list[1] : nil + end + end end diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index 35cb5ae..cb5221e 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -55,6 +55,8 @@ "cn" elsif api["Name"] == "WebForms" "w" + elsif api["Name"] == "Maestro" + "ms" else "e" end %> diff --git a/app/views/maestro_api/mseg001_trigger_workflow/get.html.erb b/app/views/maestro_api/mseg001_trigger_workflow/get.html.erb new file mode 100644 index 0000000..0a76846 --- /dev/null +++ b/app/views/maestro_api/mseg001_trigger_workflow/get.html.erb @@ -0,0 +1,54 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% instance_name_index = 0 %> +<% signer_email_index = 1 %> +<% signer_name_index = 2 %> +<% cc_email_index = 3 %> +<% cc_name_index = 4 %> +<% redirect_to8_index = 0 %> + +<% unless @show_template_not_ok %> +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + +
    +
    + + + <%= render('partials/email_will_not_be_shared') %> +
    +
    + + +
    +
    + + + The email for the cc recipient must be different from the signer's email. +
    +
    + + +
    + + <%= render('partials/submit_button') %> +
    +<% else %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to8_index]["RedirectText"], 'href="eeg008"') %> + +
    + <%= render('partials/continue_button') %> +
    +<% end %> diff --git a/app/views/maestro_api/mseg001_trigger_workflow/publish_workflow.html.erb b/app/views/maestro_api/mseg001_trigger_workflow/publish_workflow.html.erb new file mode 100644 index 0000000..0ea0ec4 --- /dev/null +++ b/app/views/maestro_api/mseg001_trigger_workflow/publish_workflow.html.erb @@ -0,0 +1,7 @@ +

    <%= @title %>

    +<%= format_string(@message, @consent_url).html_safe %> + +
    + + <%= render('partials/submit_button') %> +
    diff --git a/app/views/maestro_api/mseg002_cancel_workflow/get.html.erb b/app/views/maestro_api/mseg002_cancel_workflow/get.html.erb new file mode 100644 index 0000000..5ad3a90 --- /dev/null +++ b/app/views/maestro_api/mseg002_cancel_workflow/get.html.erb @@ -0,0 +1,33 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% workflow_id_index = 0 %> +<% instance_id_index = 1 %> +<% redirect_to1_index = 0 %> + +<% if @instance_ok %> +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + +
    +
    + + +
    + + <%= render('partials/submit_button') %> +
    +<% else %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="mseg001"') %> + +
    + <%= render('partials/continue_button') %> +
    +<% end %> diff --git a/app/views/maestro_api/mseg003_get_workflow_status/get.html.erb b/app/views/maestro_api/mseg003_get_workflow_status/get.html.erb new file mode 100644 index 0000000..9e536b8 --- /dev/null +++ b/app/views/maestro_api/mseg003_get_workflow_status/get.html.erb @@ -0,0 +1,33 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% workflow_id_index = 0 %> +<% instance_id_index = 1 %> +<% redirect_to1_index = 0 %> + +<% if @workflow_id && @instance_id %> +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + +
    +
    + + +
    + + <%= render('partials/submit_button') %> +
    +<% else %> + <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="mseg001"') %> + +
    + <%= render('partials/continue_button') %> +
    +<% end %> diff --git a/config/appsettings.example.yml b/config/appsettings.example.yml index 067b8b9..c6f9fcb 100644 --- a/config/appsettings.example.yml +++ b/config/appsettings.example.yml @@ -24,6 +24,7 @@ default: &default monitor_host: "https://lens-d.docusign.net" admin_host: "https://api-d.docusign.net/management" webforms_host: "https://apps-d.docusign.com/api/webforms/v1.1" + maestro_client_host: "https://demo.services.docusign.net/" allow_silent_authentication: true # A user can be silently authenticated if they have an # Active login session on another tab of the same browser # Set if you want a specific DocuSign AccountId, If false, the users default account will be used. diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 0a6c88c..65c5b37 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -50,6 +50,8 @@ strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read' when 'WebForms' strategy.options[:authorize_params].scope = 'signature webforms_read webforms_instance_read webforms_instance_write' + when 'Maestro' + strategy.options[:authorize_params].scope = 'signature aow_manage' end } end diff --git a/config/routes.rb b/config/routes.rb index 80a483b..a1078c3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -242,6 +242,18 @@ post 'weg001webForm' => 'weg001_create_instance#create_web_form_instance' end + scope module: 'maestro_api' do + get 'mseg001' => 'mseg001_trigger_workflow#get' + post 'mseg001' => 'mseg001_trigger_workflow#create' + post 'mseg001publish' => 'mseg001_trigger_workflow#publish' + + get 'mseg002' => 'mseg002_cancel_workflow#get' + post 'mseg002' => 'mseg002_cancel_workflow#create' + + get 'mseg003' => 'mseg003_get_workflow_status#get' + post 'mseg003' => 'mseg003_get_workflow_status#create' + end + root 'ds_common#index' # Login starts with POST'ing to: /auth/docusign From 4acad7078634e1327c4ac56c8682323358ee4cd0 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Thu, 11 Apr 2024 23:43:34 +0000 Subject: [PATCH 313/363] add cleanup commands to azure pipeline --- azure-pipelines.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index bea1d09..965975a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -86,6 +86,15 @@ steps: - script: dir $(Build.SourcesDirectory)/code-examples-ruby-private +- task: CmdLine@2 + inputs: + script: 'docker rm -f $(docker ps -a -q)' + continueOnError: true + +- script: | + docker system prune -a --force + displayName: "cleanup docker files" + - task: Docker@2 displayName: Build ruby image inputs: From 326b32561c28c3f9279a909f95232511b7b5ddac Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Fri, 12 Apr 2024 15:19:22 +0000 Subject: [PATCH 314/363] add check for running containers --- azure-pipelines.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 965975a..3aebf0b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -86,10 +86,16 @@ steps: - script: dir $(Build.SourcesDirectory)/code-examples-ruby-private -- task: CmdLine@2 - inputs: - script: 'docker rm -f $(docker ps -a -q)' - continueOnError: true +- 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 From 49e1783117fbab223564b317e0ceb960eb040a2c Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Tue, 16 Apr 2024 02:52:26 +0300 Subject: [PATCH 315/363] DocGen example updates to use Dynamic Tables (#158) * update doc gen example --- Gemfile | 2 +- Gemfile.lock | 4 +- .../eeg042_document_generation_controller.rb | 3 +- .../eg042_document_generation_service.rb | 52 ++++++++++++++++-- .../eeg042_document_generation/get.html.erb | 9 ++- config/appsettings.example.yml | 2 +- data/Offer_Letter_Dynamic_Table.docx | Bin 0 -> 36681 bytes 7 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 data/Offer_Letter_Dynamic_Table.docx diff --git a/Gemfile b/Gemfile index 3a3e8cb..b7a21de 100644 --- a/Gemfile +++ b/Gemfile @@ -70,7 +70,7 @@ end gem 'docusign_admin', '~> 1.3.0' gem 'docusign_click', '~> 1.4.0' -gem 'docusign_esign', '~> 3.25.0' +gem 'docusign_esign', '~> 3.27.0.rc1' gem 'docusign_maestro', '~> 1.0.0.rc1' gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' diff --git a/Gemfile.lock b/Gemfile.lock index aa7bfb2..8df3efd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -110,7 +110,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.25.0) + docusign_esign (3.27.0.rc1) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -349,7 +349,7 @@ DEPENDENCIES coffee-rails (~> 5.0.0) docusign_admin (~> 1.3.0) docusign_click (~> 1.4.0) - docusign_esign (~> 3.25.0) + docusign_esign (~> 3.27.0.rc1) docusign_maestro (~> 1.0.0.rc1) docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) diff --git a/app/controllers/e_sign/eeg042_document_generation_controller.rb b/app/controllers/e_sign/eeg042_document_generation_controller.rb index 5e1d502..3a12f3f 100644 --- a/app/controllers/e_sign/eeg042_document_generation_controller.rb +++ b/app/controllers/e_sign/eeg042_document_generation_controller.rb @@ -13,8 +13,9 @@ def create manager_name: param_gsub(params['manager_name']), job_title: param_gsub(params['job_title']), salary: param_gsub(params['salary']), + rsus: param_gsub(params['rsus']), start_date: param_gsub(params['start_date']), - doc_file: File.join('data', Rails.application.config.doc_offer_letter) + doc_file: File.join('data', Rails.application.config.offer_letter_dynamic_table) } args = { account_id: session['ds_account_id'], diff --git a/app/services/e_sign/eg042_document_generation_service.rb b/app/services/e_sign/eg042_document_generation_service.rb index f91a6db..0b2a3c1 100644 --- a/app/services/e_sign/eg042_document_generation_service.rb +++ b/app/services/e_sign/eg042_document_generation_service.rb @@ -113,7 +113,7 @@ def recipient_tabs anchorYOffset: '-22' ) date_signed = DocuSign_eSign::DateSigned.new( - anchorString: 'Date', + anchorString: 'Date Signed', anchorUnits: 'pixels', anchorYOffset: '-22' ) @@ -144,6 +144,8 @@ def make_envelope(template_id, args) #ds-snippet-start:eSign42Step7 def form_fields(args, document_id_guid) + bonus_value = '20%' + candidate_name_field = DocuSign_eSign::DocGenFormField.new( name: 'Candidate_Name', value: args[:candidate_name] @@ -156,16 +158,54 @@ def form_fields(args, document_id_guid) name: 'Job_Title', value: args[:job_title] ) - salary_field = DocuSign_eSign::DocGenFormField.new( - name: 'Salary', - value: args[:salary] - ) start_date_field = DocuSign_eSign::DocGenFormField.new( name: 'Start_Date', value: args[:start_date] ) + + salary_row = DocuSign_eSign::DocGenFormFieldRowValue.new( + docGenFormFieldList: [ + DocuSign_eSign::DocGenFormField.new( + name: 'Compensation_Component', + value: 'Salary' + ), + DocuSign_eSign::DocGenFormField.new( + name: 'Details', + value: "$#{args[:salary]}" + ) + ] + ) + bonus_row = DocuSign_eSign::DocGenFormFieldRowValue.new( + docGenFormFieldList: [ + DocuSign_eSign::DocGenFormField.new( + name: 'Compensation_Component', + value: 'Bonus' + ), + DocuSign_eSign::DocGenFormField.new( + name: 'Details', + value: bonus_value + ) + ] + ) + rsus_row = DocuSign_eSign::DocGenFormFieldRowValue.new( + docGenFormFieldList: [ + DocuSign_eSign::DocGenFormField.new( + name: 'Compensation_Component', + value: 'RSUs' + ), + DocuSign_eSign::DocGenFormField.new( + name: 'Details', + value: args[:rsus] + ) + ] + ) + compensation_package = DocuSign_eSign::DocGenFormField.new( + name: 'Compensation_Package', + type: 'TableRow', + rowValues: [salary_row, bonus_row, rsus_row] + ) doc_gen_form_fields_list = [ - candidate_name_field, manager_name_field, salary_field, job_title_field, start_date_field + candidate_name_field, manager_name_field, job_title_field, start_date_field, compensation_package ] doc_gen_form_fields = DocuSign_eSign::DocGenFormFields.new( diff --git a/app/views/e_sign/eeg042_document_generation/get.html.erb b/app/views/e_sign/eeg042_document_generation/get.html.erb index d20f81d..9ba7f3e 100644 --- a/app/views/e_sign/eeg042_document_generation/get.html.erb +++ b/app/views/e_sign/eeg042_document_generation/get.html.erb @@ -7,6 +7,7 @@ <% job_title_index = 3 %> <% salary_index = 4 %> <% start_date_index = 5 %> +<% rsus_index = 6 %>
    <% if @example["Forms"][form_index]["FormName"] %> @@ -34,8 +35,7 @@
    @@ -43,6 +43,11 @@
    +
    + + +
    Kz_CZ-Nd^lkv_OO17#eRibJ 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%0Av6P|nqe-e0Nb-m$v0QIe1hA` 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 Date: Fri, 19 Apr 2024 23:23:48 +0000 Subject: [PATCH 316/363] update branding (#159) * update branding --- LICENSE | 2 +- PAYMENTS_INSTALLATION.md | 8 ++-- README.md | 40 +++++++++--------- app/assets/images/favicon.ico | Bin 33310 -> 0 bytes app/assets/images/favicon.png | Bin 0 -> 1221 bytes app/controllers/ds_common_controller.rb | 4 +- app/controllers/session_controller.rb | 2 +- .../e_sign/eg002_signing_via_email_service.rb | 8 ++-- .../e_sign/eg008_create_template_service.rb | 2 +- .../e_sign/eg010_send_binary_docs_service.rb | 2 +- .../e_sign/eg011_embedded_sending_service.rb | 8 ++-- .../e_sign/eg014_collect_payment_service.rb | 2 +- .../eg016_set_envelope_tab_data_service.rb | 8 ++-- .../eg017_set_template_tab_values_service.rb | 8 ++-- ...g019_access_code_authentication_service.rb | 2 +- .../eg020_phone_authentication_service.rb | 2 +- .../eg022_kba_authentication_service.rb | 2 +- .../eg023_idv_authentication_service.rb | 2 +- .../eg029_brands_apply_to_envelope_service.rb | 2 +- .../eg031_bulk_sending_envelopes_service.rb | 2 +- .../e_sign/eg035_scheduled_sending_service.rb | 4 +- .../e_sign/eg036_delayed_routing_service.rb | 4 +- .../e_sign/eg037_sms_delivery_service.rb | 8 ++-- .../eg038_responsive_signing_service.rb | 10 ++--- .../e_sign/eg039_signing_in_person_service.rb | 10 ++--- .../eg040_set_document_visibility_service.rb | 8 ++-- .../eg041_cfr_embedded_signing_service.rb | 2 +- .../e_sign/eg044_focused_view_service.rb | 12 +++--- .../eg001_embedded_signing_service.rb | 12 +++--- app/services/jwt_auth/jwt_creator.rb | 4 +- .../webforms/eg001_create_instance_service.rb | 2 +- .../admin_api/aeg001_create_user/get.html.erb | 2 +- .../get.html.erb | 2 +- app/views/admin_api/index.html.erb | 2 +- app/views/ds_common/ds_return.html.erb | 12 +++--- app/views/layouts/_head.erb | 6 +-- app/views/room_api/index.html.erb | 4 +- .../reg004_add_forms_to_room/get.html.erb | 4 +- config/application.rb | 4 +- config/appsettings.example.yml | 2 +- lib/docusign.rb | 4 +- quick_acg/app/views/ds_common/error.erb | 2 +- .../eeg041_cfr_embedded_signing/get.html.erb | 4 +- .../eeg001_embedded_signing/get.html.erb | 4 +- quick_acg/config/application.rb | 4 +- quick_acg/lib/docusign.rb | 4 +- 46 files changed, 121 insertions(+), 121 deletions(-) delete mode 100644 app/assets/images/favicon.ico create mode 100644 app/assets/images/favicon.png diff --git a/LICENSE b/LICENSE index 390a206..652162e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2018 DocuSign, Inc. (https://www.docusign.com) +Copyright (c) 2024 Docusign, Inc. (https://www.docusign.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/PAYMENTS_INSTALLATION.md b/PAYMENTS_INSTALLATION.md index d575c2c..311a410 100644 --- a/PAYMENTS_INSTALLATION.md +++ b/PAYMENTS_INSTALLATION.md @@ -1,6 +1,6 @@ # Configure a payment gateway -DocuSign offers built-in connections to multiple payment gateways. The payments code example uses a developer 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. ## Create a Stripe payment gateway @@ -9,13 +9,13 @@ DocuSign offers built-in connections to multiple payment gateways. The payments 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) + ![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**. + 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. ## Additional 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) +* [How to send a request for payment](https://developers.docusign.com/docs/esign-rest-api/how-to/request-a-payment) diff --git a/README.md b/README.md index cfc06d2..103eb10 100644 --- a/README.md +++ b/README.md @@ -2,64 +2,64 @@ ### GitHub repo: [code-examples-ruby](./README.md) -This GitHub repo includes code examples for the DocuSign Admin API, Click API, eSignature REST API, Monitor API, and Rooms API. To switch between API code examples, modify the `examples_API` setting in the appsettings.yml file. Set only one API type to `true` and set the remaining to `false`. +This GitHub repo includes code examples for the Docusign Admin API, Click API, eSignature REST API, Monitor API, and Rooms API. To switch between API code examples, modify the `examples_API` setting in the appsettings.yml file. Set only one API type to `true` and set the remaining to `false`. -If none of the API types are set to `true`, the DocuSign eSignature REST API code examples will be shown. If multiple API types are set to `true`, only the first will be shown. +If none of the API types are set to `true`, the Docusign eSignature REST API code examples will be shown. If multiple API types are set to `true`, only the first will be shown. ## Introduction This repo is a Ruby on Rails application that supports the following authentication workflows: -* Authentication with DocuSign via [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode). +* 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/). +* Authentication with Docusign via [JSON Web Token (JWT) Grant](https://developers.docusign.com/platform/auth/jwt/). When the token expires, it updates automatically. ## 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. +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. ## Rooms API -**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. +**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/). -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. +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. ## 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) -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. +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. ## Monitor API -**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/). +**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/). 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/). -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. +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. ## Admin API -**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). +**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). 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/). -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. +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. ## 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. +**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 for authentication to use either [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) or [JWT Grant](https://developers.docusign.com/platform/auth/jwt/). +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 for authentication to use either [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) or [JWT Grant](https://developers.docusign.com/platform/auth/jwt/). This [video](https://www.youtube.com/watch?v=eiRI4fe5HgM) demonstrates how to obtain an integration key. @@ -89,7 +89,7 @@ For a list of code examples that use the Admin API, see the [How-to guides overv ### 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. +**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-ruby repository. 1. In your command-line environment, switch to the folder: @@ -106,7 +106,7 @@ For a list of code examples that use the Admin API, see the [How-to guides overv ### 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. +**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 config/appsettings.yml, change `quickstart` to `false`. 1. Extract the Quickstart ZIP file or download or clone the code-examples-ruby repository. @@ -123,11 +123,11 @@ Also, in order to select JSON Web Token authentication in the launcher, in confi 1. Run the launcher: `rails s` 1. Open a browser to http://localhost:3000 1. If it is your first time using the app, grant consent by selecting **Accept**. On the black navigation bar, select **Logout**, then **Login**. -1. From the picklist, select **JSON Web Token (JWT) grant** > **Authenticate with DocuSign**. +1. From the picklist, select **JSON Web Token (JWT) grant** > **Authenticate with Docusign**. 1. Select your desired code example. ## JWT grant remote signing and Authorization Code Grant embedded signing projects -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 and the Authorization Code Grant embedded 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 and the Authorization Code Grant embedded signing project. ### Troubleshooting Windows SSL issue @@ -147,7 +147,7 @@ Find the root folder for your Ruby gems (in this case, a 64-bit version of Ruby C:\Ruby27-x64\lib\ruby\gems\2.7.0\gems\ -Find the relevant DocuSign Ruby SDK you are using. The name always starts with “docusign”; for instance, DocuSign Click SDK version 1.0.0: +Find the relevant Docusign Ruby SDK you are using. The name always starts with “docusign”; for instance, Docusign Click SDK version 1.0.0: C:\Ruby27-x64\lib\ruby\gems\2.7.0\gems\docusign_click-1.0.0\lib\docusign_click diff --git a/app/assets/images/favicon.ico b/app/assets/images/favicon.ico deleted file mode 100644 index fd990b6942f717e57af521d6c65eb20998282e55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33310 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 RZ?k$1)N`Po1HQ_E{{uWiH2VMm diff --git a/app/assets/images/favicon.png b/app/assets/images/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..fefff5520d83a3686f8d1a411a24582bf40717b0 GIT binary patch literal 1221 zcmV;$1UmbPP)*vk@IiGJN#SJqlwialH6qg2vEMmTZGeX}RZT&bcjZ z`O^~8uqNM}d;919KIi-UopXK#4tep_tKi$W!NbGgOy*@Knqny@m}s(rK4K{yw(S8X z>f&rR#8XpX#{o+TCIU}Rg41cRZ66jM`iqwNGEtO?X4!F=9mgw;^+i+}iS8;Xud!`M z41jGzX_!Eu0f3a2`GJ%jOf;__sE7)RNO2uif36%yu`gDRb6-jM7Q61Q6H3Yk4(tJ7 zqT&%9@B>$%c1rI*X4@W8+SwzeKpqpIR>lD)(&^JMYfN;(JR3L>0G&EN4HYM5Scrgr zK0X9PfUPmGC8~7uwV41K0To)p@E=0bpyb$>ZV`KRzsZ^d_*VyY-0_=wGF$lMaT-?tGXttS4a7LP-O?w>9frMsDU^g2$*zCoHmAAko>myqQi{04h77S30IA z%wg1I04@WJ#$tDC04lRDvXnU{YBguUi2?Xc%D=`1qHCPVn4SP91fZAXQxjauId+^g z+Ww=aV50@E-qE|Dg-{U)c=Z%S&@9E#Sl7~KI=!aPh^kd^i-|f-OEx|Z-5oUqxPr9@ zr_u3SqnTH2$!3hlqAQ!}R8c$N5&gwPpDEXknjRw__nT9yn*wF-1&Z5mV&;!lymO}= z!%I;N)l~tOU4EfZuJR j-cEwUNw9XfZVLVf6}&j39e`aL00000NkvXXu0mjfO4u@9 literal 0 HcmV?d00001 diff --git a/app/controllers/ds_common_controller.rb b/app/controllers/ds_common_controller.rb index fc98385..dc350a3 100644 --- a/app/controllers/ds_common_controller.rb +++ b/app/controllers/ds_common_controller.rb @@ -58,7 +58,7 @@ def render_examples def ds_return # To break out of the Quickstart loop an example has been completed session[:been_here] = true - @title = 'Return from DocuSign' + @title = 'Return from Docusign' @event = request.params['event'] @state = request.params['state'] @envelope_id = request.params['envelopeId'] @@ -69,7 +69,7 @@ def ds_must_authenticate jwt_auth if session[:api] == 'Monitor' redirect_to '/auth/docusign' if Rails.configuration.quickstart && session[:been_here].nil? - @title = 'Authenticate with DocuSign' + @title = 'Authenticate with Docusign' @show_doc = Rails.application.config.documentation case params[:auth] diff --git a/app/controllers/session_controller.rb b/app/controllers/session_controller.rb index 466fa6b..e9791cd 100644 --- a/app/controllers/session_controller.rb +++ b/app/controllers/session_controller.rb @@ -12,7 +12,7 @@ def create # reset the session internal_destroy - Rails.logger.debug "\n==> DocuSign callback Authentication response:\n#{auth_hash.to_yaml}\n" + Rails.logger.debug "\n==> Docusign callback Authentication response:\n#{auth_hash.to_yaml}\n" Rails.logger.info "==> Login: New token for admin user which will expire at: #{Time.at(auth_hash.credentials['expires_at'])}" store_auth_hash_from_docusign_callback redirect_to redirect_url diff --git a/app/services/e_sign/eg002_signing_via_email_service.rb b/app/services/e_sign/eg002_signing_via_email_service.rb index 3d5fa16..9aae9f4 100644 --- a/app/services/e_sign/eg002_signing_via_email_service.rb +++ b/app/services/e_sign/eg002_signing_via_email_service.rb @@ -51,21 +51,21 @@ def make_envelope(envelope_args) # Create the document models document1 = DocuSign_eSign::Document.new( - # Create the DocuSign document object + # Create the Docusign document object documentBase64: doc1_b64, name: 'Order acknowledgement', # Can be different from actual file name fileExtension: 'html', # Many different document types are accepted documentId: '1' # A label used to reference the doc ) document2 = DocuSign_eSign::Document.new( - # Create the DocuSign document object + # Create the Docusign document object documentBase64: doc2_b64, name: 'Battle Plan', # Can be different from actual file name fileExtension: 'docx', # Many different document types are accepted documentId: '2' # A label used to reference the do ) document3 = DocuSign_eSign::Document.new( - # Create the DocuSign document object + # Create the Docusign document object documentBase64: doc3_b64, name: 'Lorem Ipsum', # Can be different from actual file name fileExtension: 'pdf', # Many different document types are accepted @@ -95,7 +95,7 @@ def make_envelope(envelope_args) # Create signHere fields (also known as tabs) on the documents # We're using anchor (autoPlace) positioning # - # The DocuSign platform searches throughout your envelope's documents for matching + # The Docusign platform searches throughout your envelope's documents for matching # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 # since they use the same anchor string for their "signer 1" tabs. sign_here1 = DocuSign_eSign::SignHere.new( diff --git a/app/services/e_sign/eg008_create_template_service.rb b/app/services/e_sign/eg008_create_template_service.rb index 5647db7..fee6169 100644 --- a/app/services/e_sign/eg008_create_template_service.rb +++ b/app/services/e_sign/eg008_create_template_service.rb @@ -57,7 +57,7 @@ def make_template_req # Create the document model document = DocuSign_eSign::Document.new({ - # Create the DocuSign document object + # Create the Docusign document object 'documentBase64' => base64_file_content, 'name' => 'Lorem Ipsum', # Can be different from actual file name 'fileExtension' => 'pdf', # Many different document types are accepted diff --git a/app/services/e_sign/eg010_send_binary_docs_service.rb b/app/services/e_sign/eg010_send_binary_docs_service.rb index 2d41647..3dfd6e4 100644 --- a/app/services/e_sign/eg010_send_binary_docs_service.rb +++ b/app/services/e_sign/eg010_send_binary_docs_service.rb @@ -161,7 +161,7 @@ def make_envelope_json(envelope_args) # Create signHere fields (also known as tabs) on the documents, # We're using anchor (autoPlace) positioning # - # The DocuSign platform searches throughout your envelope's documents for matching + # The Docusign platform searches throughout your envelope's documents for matching # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 # since they use the same anchor string for their "signer 1" tabs. sign_here1 = DocuSign_eSign::SignHere.new({ diff --git a/app/services/e_sign/eg011_embedded_sending_service.rb b/app/services/e_sign/eg011_embedded_sending_service.rb index ce56b4f..2a6e36d 100644 --- a/app/services/e_sign/eg011_embedded_sending_service.rb +++ b/app/services/e_sign/eg011_embedded_sending_service.rb @@ -68,21 +68,21 @@ def make_envelope(envelope_args) # Create the document models document1 = DocuSign_eSign::Document.new( - # Create the DocuSign document object + # Create the Docusign document object documentBase64: doc1_b64, name: 'Order acknowledgement', # Can be different from actual file name fileExtension: 'html', # Many different document types are accepted documentId: '1' # A label used to reference the doc ) document2 = DocuSign_eSign::Document.new( - # Create the DocuSign document object + # Create the Docusign document object documentBase64: doc2_b64, name: 'Battle Plan', # Can be different from actual file name fileExtension: 'docx', # Many different document types are accepted documentId: '2' # A label used to reference the do ) document3 = DocuSign_eSign::Document.new( - # Create the DocuSign document object + # Create the Docusign document object documentBase64: doc3_b64, name: 'Lorem Ipsum', # Can be different from actual file name fileExtension: 'pdf', # Many different document types are accepted @@ -112,7 +112,7 @@ def make_envelope(envelope_args) # Create signHere fields (also known as tabs) on the documents # We're using anchor (autoPlace) positioning # - # The DocuSign platform searches throughout your envelope's documents for matching + # The Docusign platform searches throughout your envelope's documents for matching # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 # since they use the same anchor string for their "signer 1" tabs. sign_here1 = DocuSign_eSign::SignHere.new( diff --git a/app/services/e_sign/eg014_collect_payment_service.rb b/app/services/e_sign/eg014_collect_payment_service.rb index e614a57..a0687e4 100644 --- a/app/services/e_sign/eg014_collect_payment_service.rb +++ b/app/services/e_sign/eg014_collect_payment_service.rb @@ -42,7 +42,7 @@ def make_envelope(args) # # NOTA BENE: This method 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 WYSIWYG + # # using the Docusign web tool as WYSIWYG # # form designer. # # # ################################################################# diff --git a/app/services/e_sign/eg016_set_envelope_tab_data_service.rb b/app/services/e_sign/eg016_set_envelope_tab_data_service.rb index 6a56577..4196bbb 100644 --- a/app/services/e_sign/eg016_set_envelope_tab_data_service.rb +++ b/app/services/e_sign/eg016_set_envelope_tab_data_service.rb @@ -45,12 +45,12 @@ def make_recipient_view_request(signer_email, signer_name, signer_client_id, ds_ # Set the URL where you want the recipient to go once they are done signing; this # 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 + # 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 view_request.return_url = "#{ds_return_url}?state=123" # How has your app authenticated the user? In addition to your app's authentication, - # you can include authenticate steps from DocuSign; e.g., SMS authentication + # you can include authenticate steps from Docusign; e.g., SMS authentication view_request.authentication_method = 'none' # Recipient information must match embedded recipient info we used to create the envelope @@ -58,9 +58,9 @@ def make_recipient_view_request(signer_email, signer_name, signer_client_id, ds_ view_request.user_name = signer_name view_request.client_user_id = signer_client_id - # DocuSign recommends that you redirect to DocuSign for the embedded signing. There are + # 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) + # parameter. It causes the Docusign Signing web page (not the Docusign server) # to send pings via AJAX to your app view_request.ping_frequency = '600' # seconds # NOTE: The pings will only be sent if the pingUrl is an HTTPS address diff --git a/app/services/e_sign/eg017_set_template_tab_values_service.rb b/app/services/e_sign/eg017_set_template_tab_values_service.rb index 950d4a2..647103e 100644 --- a/app/services/e_sign/eg017_set_template_tab_values_service.rb +++ b/app/services/e_sign/eg017_set_template_tab_values_service.rb @@ -132,12 +132,12 @@ def make_recipient_view_request(signer_email, signer_name, signer_client_id, ds_ # Set the URL where you want the recipient to go once they are done signing; this # 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 + # 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 view_request.return_url = "#{ds_return_url}?state=123" # How has your app authenticated the user? In addition to your app's authentication, - # you can include authenticate steps from DocuSign; e.g., SMS authentication + # you can include authenticate steps from Docusign; e.g., SMS authentication view_request.authentication_method = 'none' # Recipient information must match embedded recipient info we used to create the envelope @@ -145,9 +145,9 @@ def make_recipient_view_request(signer_email, signer_name, signer_client_id, ds_ view_request.user_name = signer_name view_request.client_user_id = signer_client_id - # DocuSign recommends that you redirect to DocuSign for the embedded signing. There are + # 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) + # parameter. It causes the Docusign signing web page (not the Docusign server) # to send pings via AJAX to your app view_request.ping_frequency = '600' # seconds # NOTE: The pings will only be sent if the pingUrl is an HTTPS address diff --git a/app/services/e_sign/eg019_access_code_authentication_service.rb b/app/services/e_sign/eg019_access_code_authentication_service.rb index b0dd905..0bd9a8f 100644 --- a/app/services/e_sign/eg019_access_code_authentication_service.rb +++ b/app/services/e_sign/eg019_access_code_authentication_service.rb @@ -20,7 +20,7 @@ def worker # Add the documents and create the document models pdf_filename = 'World_Wide_Corp_lorem.pdf' document1 = DocuSign_eSign::Document.new( - # Create the DocuSign Document object + # Create the Docusign Document object documentBase64: Base64.encode64(File.binread(File.join('data', pdf_filename))), name: 'NDA', # Can be different from actual file name fileExtension: 'pdf', # Many different document types are accepted diff --git a/app/services/e_sign/eg020_phone_authentication_service.rb b/app/services/e_sign/eg020_phone_authentication_service.rb index c4a591f..676175a 100644 --- a/app/services/e_sign/eg020_phone_authentication_service.rb +++ b/app/services/e_sign/eg020_phone_authentication_service.rb @@ -22,7 +22,7 @@ def worker(workflow_id) # Add the documents and create the document models pdf_filename = 'World_Wide_Corp_lorem.pdf' document1 = DocuSign_eSign::Document.new( - # Create the DocuSign Document object + # Create the Docusign Document object documentBase64: Base64.encode64(File.binread(File.join('data', pdf_filename))), name: 'Lorem', # Can be different from actual file name fileExtension: 'pdf', # Many different document types are accepted diff --git a/app/services/e_sign/eg022_kba_authentication_service.rb b/app/services/e_sign/eg022_kba_authentication_service.rb index 2ba88c1..abfce8a 100644 --- a/app/services/e_sign/eg022_kba_authentication_service.rb +++ b/app/services/e_sign/eg022_kba_authentication_service.rb @@ -20,7 +20,7 @@ def worker # Add the documents and create the document models pdf_filename = 'World_Wide_Corp_lorem.pdf' document1 = DocuSign_eSign::Document.new( - # Create the DocuSign Document object + # Create the Docusign Document object documentBase64: Base64.encode64(File.binread(File.join('data', pdf_filename))), name: 'NDA', # Can be different from actual file name fileExtension: 'pdf', # Many different document types are accepted diff --git a/app/services/e_sign/eg023_idv_authentication_service.rb b/app/services/e_sign/eg023_idv_authentication_service.rb index 0f80901..21f4875 100644 --- a/app/services/e_sign/eg023_idv_authentication_service.rb +++ b/app/services/e_sign/eg023_idv_authentication_service.rb @@ -37,7 +37,7 @@ def worker # Create the document models document1 = DocuSign_eSign::Document.new( - # Create the DocuSign Document object + # Create the Docusign Document object documentBase64: Base64.encode64(File.binread(File.join('data', pdf_filename))), name: 'Lorem', # Can be different from the actual file name fileExtension: 'pdf', # Many different document types are accepted diff --git a/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb b/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb index 4aca19a..cf97a85 100644 --- a/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb +++ b/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb @@ -36,7 +36,7 @@ def make_envelope(envelope_args) # Add the documents and create the document models pdf_filename = 'World_Wide_Corp_lorem.pdf' document1 = DocuSign_eSign::Document.new( - # Create the DocuSign Document object + # Create the Docusign Document object documentBase64: Base64.encode64(File.binread(File.join('data', pdf_filename))), name: 'NDA', # Can be different from actual file name fileExtension: 'pdf', # Many different document types are accepted diff --git a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb index 3201220..7ef43fb 100644 --- a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb +++ b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb @@ -161,7 +161,7 @@ def make_envelope recipientType: 'cc' ) - # The DocuSign platform searches throughout your envelope's documents for matching + # The Docusign platform searches throughout your envelope's documents for matching # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 # since they use the same anchor string for their "signer 1" tabs. sign_here = DocuSign_eSign::SignHere.new diff --git a/app/services/e_sign/eg035_scheduled_sending_service.rb b/app/services/e_sign/eg035_scheduled_sending_service.rb index 412e56e..36d626a 100644 --- a/app/services/e_sign/eg035_scheduled_sending_service.rb +++ b/app/services/e_sign/eg035_scheduled_sending_service.rb @@ -47,7 +47,7 @@ def make_envelope(envelope_args) # Create the document model document = DocuSign_eSign::Document.new( - # Create the DocuSign document object + # Create the Docusign document object documentBase64: doc_b64, name: 'Lorem Ipsum', # Can be different from actual file name fileExtension: 'pdf', # Many different document types are accepted @@ -70,7 +70,7 @@ def make_envelope(envelope_args) # Create a signHere field (also known as a tab) on the document # We're using anchor (autoPlace) positioning # - # The DocuSign platform searches throughout your envelope's documents for matching + # The Docusign platform searches throughout your envelope's documents for matching # anchor strings. sign_here = DocuSign_eSign::SignHere.new( anchorString: '/sn1/', diff --git a/app/services/e_sign/eg036_delayed_routing_service.rb b/app/services/e_sign/eg036_delayed_routing_service.rb index b66e73a..9551f48 100644 --- a/app/services/e_sign/eg036_delayed_routing_service.rb +++ b/app/services/e_sign/eg036_delayed_routing_service.rb @@ -40,7 +40,7 @@ def make_envelope(envelope_args) # Create the document model document = DocuSign_eSign::Document.new( - # Create the DocuSign document object + # Create the Docusign document object documentBase64: doc_b64, name: 'Lorem Ipsum', # Can be different from actual file name fileExtension: 'pdf', # Many different document types are accepted @@ -70,7 +70,7 @@ def make_envelope(envelope_args) # We're using anchor (autoPlace) positioning for the sign_here1 tab # and we're using absolute positioning for the sign_here2 tab. # - # The DocuSign platform searches throughout your envelope's documents for matching + # The Docusign platform searches throughout your envelope's documents for matching # anchor strings. sign_here1 = DocuSign_eSign::SignHere.new( anchorString: '/sn1/', diff --git a/app/services/e_sign/eg037_sms_delivery_service.rb b/app/services/e_sign/eg037_sms_delivery_service.rb index f3763ca..79edddb 100644 --- a/app/services/e_sign/eg037_sms_delivery_service.rb +++ b/app/services/e_sign/eg037_sms_delivery_service.rb @@ -54,21 +54,21 @@ def make_envelope(envelope_args) # Create the document models document1 = DocuSign_eSign::Document.new( - # Create the DocuSign document object + # Create the Docusign document object documentBase64: doc1_b64, name: 'Order acknowledgement', # Can be different from actual file name fileExtension: 'html', # Many different document types are accepted documentId: '1' # A label used to reference the doc ) document2 = DocuSign_eSign::Document.new( - # Create the DocuSign document object + # Create the Docusign document object documentBase64: doc2_b64, name: 'Battle Plan', # Can be different from actual file name fileExtension: 'docx', # Many different document types are accepted documentId: '2' # A label used to reference the do ) document3 = DocuSign_eSign::Document.new( - # Create the DocuSign document object + # Create the Docusign document object documentBase64: doc3_b64, name: 'Lorem Ipsum', # Can be different from actual file name fileExtension: 'pdf', # Many different document types are accepted @@ -109,7 +109,7 @@ def make_envelope(envelope_args) # Create signHere fields (also known as tabs) on the documents # We're using anchor (autoPlace) positioning # - # The DocuSign platform searches throughout your envelope's documents for matching + # The Docusign platform searches throughout your envelope's documents for matching # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 # since they use the same anchor string for their "signer 1" tabs. sign_here1 = DocuSign_eSign::SignHere.new( diff --git a/app/services/e_sign/eg038_responsive_signing_service.rb b/app/services/e_sign/eg038_responsive_signing_service.rb index ad96038..0cd1a4c 100644 --- a/app/services/e_sign/eg038_responsive_signing_service.rb +++ b/app/services/e_sign/eg038_responsive_signing_service.rb @@ -16,7 +16,7 @@ def worker # Create the envelope definition envelope = make_envelope(args) - # Call DocuSign to create the envelope + # Call Docusign to create the envelope envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope @@ -46,13 +46,13 @@ def make_recipient_view_request(args, ds_return_url) # 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 Docusign signing. It's usually better to use # the session mechanism of your web framework. Query parameters # can be changed/spoofed very easily. view_request.return_url = "#{ds_return_url}?state=123" # How has your app authenticated the user? In addition to your app's - # authentication, you can include authenticate steps from DocuSign; + # authentication, you can include authenticate steps from Docusign; # e.g., SMS authentication view_request.authentication_method = 'none' @@ -62,9 +62,9 @@ def make_recipient_view_request(args, ds_return_url) view_request.user_name = args[:signer_name] view_request.client_user_id = args[:signer_client_id] - # DocuSign recommends that you redirect to DocuSign for the embedded signing. There are + # 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) + # parameter. It causes the Docusign signing web page (not the Docusign server) # to send pings via AJAX to your app view_request.ping_frequency = '600' # seconds # NOTE: The pings will only be sent if the pingUrl is an HTTPS address diff --git a/app/services/e_sign/eg039_signing_in_person_service.rb b/app/services/e_sign/eg039_signing_in_person_service.rb index d3bda2a..2ba99d5 100644 --- a/app/services/e_sign/eg039_signing_in_person_service.rb +++ b/app/services/e_sign/eg039_signing_in_person_service.rb @@ -51,13 +51,13 @@ def make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_nam # 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 Docusign signing. It's usually better to use # the session mechanism of your web framework. Query parameters # can be changed/spoofed very easily. view_request.return_url = "#{ds_return_url}?state=123" # How has your app authenticated the user? In addition to your app's - # authentication, you can include authenticate steps from DocuSign; + # authentication, you can include authenticate steps from Docusign; # e.g., SMS authentication view_request.authentication_method = 'none' @@ -66,9 +66,9 @@ def make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_nam view_request.email = host_email view_request.user_name = host_name - # DocuSign recommends that you redirect to DocuSign for the embedded signing. There are + # 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) + # parameter. It causes the Docusign signing web page (not the Docusign server) # to send pings via AJAX to your app view_request.ping_frequency = '600' # seconds # NOTE: The pings will only be sent if the pingUrl is an HTTPS address @@ -101,7 +101,7 @@ def make_envelope(pdf_filename, host_email, host_name, signer_name) in_person_signer.recipient_id = '1' in_person_signer.routing_order = '1' - # The DocuSign platform searches throughout your envelope's documents for matching + # The Docusign platform searches throughout your envelope's documents for matching # anchor strings. sign_here = DocuSign_eSign::SignHere.new sign_here.anchor_string = '/sn1/' diff --git a/app/services/e_sign/eg040_set_document_visibility_service.rb b/app/services/e_sign/eg040_set_document_visibility_service.rb index db601ca..0049c20 100644 --- a/app/services/e_sign/eg040_set_document_visibility_service.rb +++ b/app/services/e_sign/eg040_set_document_visibility_service.rb @@ -54,21 +54,21 @@ def make_envelope(envelope_args) # Create the document models document1 = DocuSign_eSign::Document.new( - # Create the DocuSign document object + # Create the Docusign document object documentBase64: doc1_b64, name: 'Order acknowledgement', # Can be different from actual file name fileExtension: 'html', # Many different document types are accepted documentId: '1' # A label used to reference the doc ) document2 = DocuSign_eSign::Document.new( - # Create the DocuSign document object + # Create the Docusign document object documentBase64: doc2_b64, name: 'Battle Plan', # Can be different from actual file name fileExtension: 'docx', # Many different document types are accepted documentId: '2' # A label used to reference the do ) document3 = DocuSign_eSign::Document.new( - # Create the DocuSign document object + # Create the Docusign document object documentBase64: doc3_b64, name: 'Lorem Ipsum', # Can be different from actual file name fileExtension: 'pdf', # Many different document types are accepted @@ -106,7 +106,7 @@ def make_envelope(envelope_args) # Create signHere fields (also known as tabs) on the documents # We're using anchor (autoPlace) positioning # - # The DocuSign platform searches throughout your envelope's documents for matching + # The Docusign platform searches throughout your envelope's documents for matching # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 # since they use the same anchor string for their "signer 1" tabs. sign_here1 = DocuSign_eSign::SignHere.new( diff --git a/app/services/e_sign/eg041_cfr_embedded_signing_service.rb b/app/services/e_sign/eg041_cfr_embedded_signing_service.rb index b998635..95585c9 100644 --- a/app/services/e_sign/eg041_cfr_embedded_signing_service.rb +++ b/app/services/e_sign/eg041_cfr_embedded_signing_service.rb @@ -93,7 +93,7 @@ def make_envelope(args, workflow_id) recipientId: 1, identityVerification: identity_verification }) - # The DocuSign platform searches throughout your envelope's documents for matching + # The Docusign platform searches throughout your envelope's documents for matching # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 # since they use the same anchor string for their "signer 1" tabs. sign_here = DocuSign_eSign::SignHere.new diff --git a/app/services/e_sign/eg044_focused_view_service.rb b/app/services/e_sign/eg044_focused_view_service.rb index 633c777..5750f7a 100644 --- a/app/services/e_sign/eg044_focused_view_service.rb +++ b/app/services/e_sign/eg044_focused_view_service.rb @@ -21,7 +21,7 @@ def worker #ds-snippet-start:eSign44Step3 envelope = make_envelope(args[:signer_client_id], pdf_filename, signer_email, signer_name) - # Call DocuSign to create the envelope + # Call Docusign to create the envelope envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope @@ -55,13 +55,13 @@ def make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, si # 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 Docusign signing. It's usually better to use # the session mechanism of your web framework. Query parameters # can be changed/spoofed very easily. view_request.return_url = "#{ds_return_url}?state=123" # How has your app authenticated the user? In addition to your app's - # authentication, you can include authenticate steps from DocuSign; + # authentication, you can include authenticate steps from Docusign; # e.g., SMS authentication view_request.authentication_method = 'none' @@ -71,9 +71,9 @@ def make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, si view_request.user_name = signer_name view_request.client_user_id = signer_client_id - # DocuSign recommends that you redirect to DocuSign for the embedded signing. There are + # 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) + # parameter. It causes the Docusign signing web page (not the Docusign server) # to send pings via AJAX to your app view_request.ping_frequency = '600' # seconds # NOTE: The pings will only be sent if the pingUrl is an HTTPS address @@ -105,7 +105,7 @@ def make_envelope(signer_client_id, pdf_filename, signer_email, signer_name) email: signer_email, name: signer_name, clientUserId: signer_client_id, recipientId: 1 }) - # The DocuSign platform searches throughout your envelope's documents for matching + # The Docusign platform searches throughout your envelope's documents for matching # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 # since they use the same anchor string for their "signer 1" tabs. sign_here = DocuSign_eSign::SignHere.new diff --git a/app/services/eg001_embedded_signing_service.rb b/app/services/eg001_embedded_signing_service.rb index cfe56da..24a999b 100644 --- a/app/services/eg001_embedded_signing_service.rb +++ b/app/services/eg001_embedded_signing_service.rb @@ -21,7 +21,7 @@ def worker #ds-snippet-start:eSign1Step3 envelope = make_envelope(args[:signer_client_id], pdf_filename, signer_email, signer_name) - # Call DocuSign to create the envelope + # Call Docusign to create the envelope envelope_api = create_envelope_api(args) results = envelope_api.create_envelope args[:account_id], envelope @@ -55,13 +55,13 @@ def make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, si # 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 Docusign signing. It's usually better to use # the session mechanism of your web framework. Query parameters # can be changed/spoofed very easily. view_request.return_url = "#{ds_return_url}?state=123" # How has your app authenticated the user? In addition to your app's - # authentication, you can include authenticate steps from DocuSign; + # authentication, you can include authenticate steps from Docusign; # e.g., SMS authentication view_request.authentication_method = 'none' @@ -71,9 +71,9 @@ def make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, si view_request.user_name = signer_name view_request.client_user_id = signer_client_id - # DocuSign recommends that you redirect to DocuSign for the embedded signing. There are + # 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) + # parameter. It causes the Docusign signing web page (not the Docusign server) # to send pings via AJAX to your app view_request.ping_frequency = '600' # seconds # NOTE: The pings will only be sent if the pingUrl is an HTTPS address @@ -102,7 +102,7 @@ def make_envelope(signer_client_id, pdf_filename, signer_email, signer_name) email: signer_email, name: signer_name, clientUserId: signer_client_id, recipientId: 1 }) - # The DocuSign platform searches throughout your envelope's documents for matching + # The Docusign platform searches throughout your envelope's documents for matching # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 # since they use the same anchor string for their "signer 1" tabs. sign_here = DocuSign_eSign::SignHere.new diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index 8dbbc72..88598fe 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -6,7 +6,7 @@ class JwtCreator attr_reader :session, :api_client, :state - # DocuSign authorization URI to obtain individual consent + # Docusign authorization URI to obtain individual consent # https://developers.docusign.com/platform/auth/jwt/jwt-get-token # https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/ def self.consent_url(state, api) @@ -97,7 +97,7 @@ def check_jwt_token def update_account_info(token) # docusign_esign: GET /oauth/userinfo # This endpoint returns information on the caller, including their name, email, account, and organizational information. - # The response includes the base_uri needed to interact with the DocuSign APIs. + # The response includes the base_uri needed to interact with the Docusign APIs. # https://developers.docusign.com/platform/auth/reference/user-info user_info_response = api_client.get_user_info(token.access_token) accounts = user_info_response.accounts diff --git a/app/services/webforms/eg001_create_instance_service.rb b/app/services/webforms/eg001_create_instance_service.rb index 3114d3a..23b282b 100644 --- a/app/services/webforms/eg001_create_instance_service.rb +++ b/app/services/webforms/eg001_create_instance_service.rb @@ -79,7 +79,7 @@ def make_web_forms_template # Create the document model document = DocuSign_eSign::Document.new({ - # Create the DocuSign document object + # Create the Docusign document object 'documentBase64' => base64_file_content, 'name' => 'World_Wide_Web_Form', # Can be different from actual file name 'fileExtension' => 'pdf', # Many different document types are accepted diff --git a/app/views/admin_api/aeg001_create_user/get.html.erb b/app/views/admin_api/aeg001_create_user/get.html.erb index abd0081..27be449 100644 --- a/app/views/admin_api/aeg001_create_user/get.html.erb +++ b/app/views/admin_api/aeg001_create_user/get.html.erb @@ -42,7 +42,7 @@
    <% else %>
    -

    Problem: Please first create a DocuSign permission profile. +

    Problem: Please first create a Docusign permission profile.
    Thank you.

    <% end %> diff --git a/app/views/admin_api/aeg002_create_active_clm_esign_user/get.html.erb b/app/views/admin_api/aeg002_create_active_clm_esign_user/get.html.erb index efbf319..efce466 100644 --- a/app/views/admin_api/aeg002_create_active_clm_esign_user/get.html.erb +++ b/app/views/admin_api/aeg002_create_active_clm_esign_user/get.html.erb @@ -65,7 +65,7 @@ <% else %>
    -

    Problem: Please first create a DocuSign Admin group. +

    Problem: Please first create a Docusign Admin group.
    Thank you.

    <% end %> diff --git a/app/views/admin_api/index.html.erb b/app/views/admin_api/index.html.erb index f7c8a5e..0747ff9 100644 --- a/app/views/admin_api/index.html.erb +++ b/app/views/admin_api/index.html.erb @@ -5,7 +5,7 @@

    Ruby Launcher

    -

    Run and explore DocuSign Admin API code examples with Authorization Code Grant or JWT Grant authentication

    +

    Run and explore Docusign Admin API code examples with Authorization Code Grant or JWT Grant authentication

    diff --git a/app/views/ds_common/ds_return.html.erb b/app/views/ds_common/ds_return.html.erb index 428965e..7a96b0e 100644 --- a/app/views/ds_common/ds_return.html.erb +++ b/app/views/ds_common/ds_return.html.erb @@ -1,20 +1,20 @@ -

    Returned data from DocuSign!

    +

    Returned data from Docusign!

    Data:

    <% if @event %> -

    event: <%= @event %>. This event parameter is supplied by DocuSign. +

    event: <%= @event %>. This event parameter is supplied by Docusign. Since it could have been spoofed, don't make business decisions based on - its value. Instead, query DocuSign as appropriate.

    + its value. Instead, query Docusign as appropriate.

    <% end %> <% if @envelope_id %> -

    envelopeId: <%= @envelope_id %>. The envelopeId parameter is supplied by DocuSign. +

    envelopeId: <%= @envelope_id %>. The envelopeId parameter is supplied by Docusign. Since it could have been spoofed, don't make business decisions based on - its value. Instead, query DocuSign as appropriate.

    + its value. Instead, query Docusign as appropriate.

    <% end %> <% if @state %> -

    state: <%= @state %>. This example state was sent to DocuSign and has now been received back. +

    state: <%= @state %>. This example state was sent to Docusign and has now been received back. It is usually better to store state in your web framework's session.

    <% end %> diff --git a/app/views/layouts/_head.erb b/app/views/layouts/_head.erb index e984b57..bc7b30a 100644 --- a/app/views/layouts/_head.erb +++ b/app/views/layouts/_head.erb @@ -5,13 +5,13 @@ - + <% if @title %> <%= @title %> <% else %> - DocuSign Ruby Code Examples + Docusign Ruby Code Examples <% end %> @@ -24,7 +24,7 @@

    Ruby Launcher

    -

    Welcome to the DocuSign Ruby examples using multiple OAuth flows (JWT and Authorization +

    Welcome to the Docusign Ruby examples using multiple OAuth flows (JWT and Authorization Code Grant).

    @@ -21,7 +21,7 @@

    Welcome

    This launcher both demonstrates use of JWT and OAuth Authorization Code Grant flow and includes multiple usage - examples for the DocuSign Rooms API.

    + examples for the Docusign Rooms API.

    <% if @show_doc %>

    Documentation on using JWT or OAuth Authorization Code Grant diff --git a/app/views/room_api/reg004_add_forms_to_room/get.html.erb b/app/views/room_api/reg004_add_forms_to_room/get.html.erb index 21316c2..fd40618 100644 --- a/app/views/room_api/reg004_add_forms_to_room/get.html.erb +++ b/app/views/room_api/reg004_add_forms_to_room/get.html.erb @@ -37,8 +37,8 @@

    - Problem: DocuSign Forms is not enabled for this company. Please contact - DocuSign Rooms Support + Problem: Docusign Forms is not enabled for this company. Please contact + Docusign Rooms Support to enable Forms.
    Thank you. diff --git a/config/application.rb b/config/application.rb index 4a2b8ba..4930ccd 100644 --- a/config/application.rb +++ b/config/application.rb @@ -7,11 +7,11 @@ module CodeExamplesRuby class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 5.2 - # Configuration for DocuSign example. + # Configuration for Docusign example. # For a production application, you will store the credentials # in config/environments/development.rb, production.rb, test.rb, etc config.app_url = 'http://localhost:3000' # The public url of the application. - # Init DocuSign configuration, loaded from config/appsettings.yml file + # Init Docusign configuration, loaded from config/appsettings.yml file DOCUSIGN_CONFIG = YAML.load_file("#{Rails.root}/config/appsettings.yml")[Rails.env] DOCUSIGN_CONFIG.map do |k, v| config.send("#{k}=", v) diff --git a/config/appsettings.example.yml b/config/appsettings.example.yml index e09319e..0b88d2b 100644 --- a/config/appsettings.example.yml +++ b/config/appsettings.example.yml @@ -27,7 +27,7 @@ default: &default maestro_client_host: "https://demo.services.docusign.net/" allow_silent_authentication: true # A user can be silently authenticated if they have an # Active login session on another tab of the same browser - # Set if you want a specific DocuSign AccountId, If false, the users default account will be used. + # Set if you want a specific Docusign AccountId, If false, the users default account will be used. target_account_id: false # Payment gateway information is optional. It is only needed for Send a request for Accept Payments. # See the PAYMENTS_INSTALLATION.md file for instructions gateway_account_id: {DS_PAYMENT_GATEWAY_ID} # The remainder of this file is already configured. diff --git a/lib/docusign.rb b/lib/docusign.rb index b37d692..3617969 100644 --- a/lib/docusign.rb +++ b/lib/docusign.rb @@ -9,8 +9,8 @@ class Docusign < OmniAuth::Strategies::OAuth2 # The name of the strategy, used in config/initializer/omniauth.rb option :name, 'docusign' - # These are called after the OAuth2 login authentication has succeeded and are part of the DocuSign callback response message: - # transforms the DocuSign login response from the raw_info https://github.com/omniauth/omniauth/wiki/Strategy-Contribution-Guide#defining-the-callback-phase + # These are called after the OAuth2 login authentication has succeeded and are part of the Docusign callback response message: + # transforms the Docusign login response from the raw_info https://github.com/omniauth/omniauth/wiki/Strategy-Contribution-Guide#defining-the-callback-phase # into the standardized schema required by OmniAuth https://github.com/omniauth/omniauth/wiki/Auth-Hash-Schema # and gets exposed through the "request.env[omniauth.auth]" to the SessionController#create uid { raw_info['sub'] } diff --git a/quick_acg/app/views/ds_common/error.erb b/quick_acg/app/views/ds_common/error.erb index 9eae50e..b431df0 100644 --- a/quick_acg/app/views/ds_common/error.erb +++ b/quick_acg/app/views/ds_common/error.erb @@ -9,7 +9,7 @@ <% if @title %> <%= @title %> <% else %> - DocuSign Ruby Code Examples + Docusign Ruby Code Examples <% end %> diff --git a/quick_acg/app/views/e_sign/eeg041_cfr_embedded_signing/get.html.erb b/quick_acg/app/views/e_sign/eeg041_cfr_embedded_signing/get.html.erb index 7507806..0d0dcd9 100644 --- a/quick_acg/app/views/e_sign/eeg041_cfr_embedded_signing/get.html.erb +++ b/quick_acg/app/views/e_sign/eeg041_cfr_embedded_signing/get.html.erb @@ -9,7 +9,7 @@ <% if @title %> <%= @title %> <% else %> - DocuSign Ruby Code Examples + Docusign Ruby Code Examples <% end %> @@ -50,7 +50,7 @@

    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 +

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

    <% if @show_doc %> diff --git a/quick_acg/app/views/eeg001_embedded_signing/get.html.erb b/quick_acg/app/views/eeg001_embedded_signing/get.html.erb index 230e534..52f1ded 100644 --- a/quick_acg/app/views/eeg001_embedded_signing/get.html.erb +++ b/quick_acg/app/views/eeg001_embedded_signing/get.html.erb @@ -9,7 +9,7 @@ <% if @title %> <%= @title %> <% else %> - DocuSign Ruby Code Examples + Docusign Ruby Code Examples <% end %> @@ -50,7 +50,7 @@

    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 +

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

    <% if @show_doc %> diff --git a/quick_acg/config/application.rb b/quick_acg/config/application.rb index cd7f547..973b98b 100644 --- a/quick_acg/config/application.rb +++ b/quick_acg/config/application.rb @@ -7,11 +7,11 @@ module CodeExamplesRuby class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 5.2 - # Configuration for DocuSign example. + # Configuration for Docusign example. # For a production application, you will store the credentials # in config/environments/development.rb, production.rb, test.rb, etc config.app_url = 'http://localhost:3000' # The public url of the application. - # Init DocuSign configuration, loaded from config/appsettings.yml file + # Init Docusign configuration, loaded from config/appsettings.yml file DOCUSIGN_CONFIG = YAML.load_file(File.join(Rails.root, '../config/appsettings.yml'), aliases: true)[Rails.env] DOCUSIGN_CONFIG.map do |k, v| config.send("#{k}=", v) diff --git a/quick_acg/lib/docusign.rb b/quick_acg/lib/docusign.rb index b37d692..3617969 100644 --- a/quick_acg/lib/docusign.rb +++ b/quick_acg/lib/docusign.rb @@ -9,8 +9,8 @@ class Docusign < OmniAuth::Strategies::OAuth2 # The name of the strategy, used in config/initializer/omniauth.rb option :name, 'docusign' - # These are called after the OAuth2 login authentication has succeeded and are part of the DocuSign callback response message: - # transforms the DocuSign login response from the raw_info https://github.com/omniauth/omniauth/wiki/Strategy-Contribution-Guide#defining-the-callback-phase + # These are called after the OAuth2 login authentication has succeeded and are part of the Docusign callback response message: + # transforms the Docusign login response from the raw_info https://github.com/omniauth/omniauth/wiki/Strategy-Contribution-Guide#defining-the-callback-phase # into the standardized schema required by OmniAuth https://github.com/omniauth/omniauth/wiki/Auth-Hash-Schema # and gets exposed through the "request.env[omniauth.auth]" to the SessionController#create uid { raw_info['sub'] } From 4fdb6a074f3db608d86e7a61a36ce4b2f097cb23 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Wed, 1 May 2024 13:41:46 +0300 Subject: [PATCH 317/363] maintenance --- Gemfile | 18 +- Gemfile.lock | 202 +++++++++++-------- jwt_console_project/jwt_console.rb | 2 +- quick_acg/Gemfile | 18 +- quick_acg/Gemfile.lock | 306 ++++++++++++++++------------- 5 files changed, 310 insertions(+), 236 deletions(-) diff --git a/Gemfile b/Gemfile index b7a21de..c038607 100644 --- a/Gemfile +++ b/Gemfile @@ -6,11 +6,11 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '~>3.1.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 7.0.4.3' +gem 'rails', '~> 7.1.3.2' # Use sqlite3 as the database for Active Record -gem 'sqlite3', '~> 1.6.1' +gem 'sqlite3', '~> 1.7.3' # Use Puma as the app server -gem 'puma', '~> 6.1.1' +gem 'puma', '~> 6.4.2' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets @@ -49,20 +49,20 @@ end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. - gem 'listen', '~> 3.8.0' - gem 'web-console', '~> 4.2.0' + gem 'listen', '~> 3.9.0' + gem 'web-console', '~> 4.2.1' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'pry-nav', '~> 1.0.0' gem 'pry-rails', '~> 0.3.9' - gem 'rubocop', '~> 1.48.1', require: false - gem 'spring', '~> 4.1.1' + gem 'rubocop', '~> 1.63.3', require: false + gem 'spring', '~> 4.2.1' gem 'spring-watcher-listen', '~> 2.1.0' end group :test do # Adds support for Capybara system testing and selenium driver - gem 'capybara', '~> 3.38.0' - gem 'selenium-webdriver', '~> 4.8.1' + gem 'capybara', '~> 3.40.0' + gem 'selenium-webdriver', '~> 4.19.0' # Easy installation and use of chromedriver to run system tests with Chrome gem 'chromedriver-helper', '~> 2.1.1' gem 'test-unit' diff --git a/Gemfile.lock b/Gemfile.lock index 8df3efd..8773fae 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,70 +1,79 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.0.4.3) - actionpack (= 7.0.4.3) - activesupport (= 7.0.4.3) + actioncable (7.1.3.2) + actionpack (= 7.1.3.2) + activesupport (= 7.1.3.2) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.4.3) - actionpack (= 7.0.4.3) - activejob (= 7.0.4.3) - activerecord (= 7.0.4.3) - activestorage (= 7.0.4.3) - activesupport (= 7.0.4.3) + zeitwerk (~> 2.6) + actionmailbox (7.1.3.2) + actionpack (= 7.1.3.2) + activejob (= 7.1.3.2) + activerecord (= 7.1.3.2) + activestorage (= 7.1.3.2) + activesupport (= 7.1.3.2) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.0.4.3) - actionpack (= 7.0.4.3) - actionview (= 7.0.4.3) - activejob (= 7.0.4.3) - activesupport (= 7.0.4.3) + actionmailer (7.1.3.2) + actionpack (= 7.1.3.2) + actionview (= 7.1.3.2) + activejob (= 7.1.3.2) + activesupport (= 7.1.3.2) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp - rails-dom-testing (~> 2.0) - actionpack (7.0.4.3) - actionview (= 7.0.4.3) - activesupport (= 7.0.4.3) - rack (~> 2.0, >= 2.2.0) + rails-dom-testing (~> 2.2) + actionpack (7.1.3.2) + actionview (= 7.1.3.2) + activesupport (= 7.1.3.2) + nokogiri (>= 1.8.5) + racc + rack (>= 2.2.4) + rack-session (>= 1.0.1) rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.4.3) - actionpack (= 7.0.4.3) - activerecord (= 7.0.4.3) - activestorage (= 7.0.4.3) - activesupport (= 7.0.4.3) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + actiontext (7.1.3.2) + actionpack (= 7.1.3.2) + activerecord (= 7.1.3.2) + activestorage (= 7.1.3.2) + activesupport (= 7.1.3.2) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.4.3) - activesupport (= 7.0.4.3) + actionview (7.1.3.2) + activesupport (= 7.1.3.2) builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (7.0.4.3) - activesupport (= 7.0.4.3) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (7.1.3.2) + activesupport (= 7.1.3.2) globalid (>= 0.3.6) - activemodel (7.0.4.3) - activesupport (= 7.0.4.3) - activerecord (7.0.4.3) - activemodel (= 7.0.4.3) - activesupport (= 7.0.4.3) - activestorage (7.0.4.3) - actionpack (= 7.0.4.3) - activejob (= 7.0.4.3) - activerecord (= 7.0.4.3) - activesupport (= 7.0.4.3) + activemodel (7.1.3.2) + activesupport (= 7.1.3.2) + activerecord (7.1.3.2) + activemodel (= 7.1.3.2) + activesupport (= 7.1.3.2) + timeout (>= 0.4.0) + activestorage (7.1.3.2) + actionpack (= 7.1.3.2) + activejob (= 7.1.3.2) + activerecord (= 7.1.3.2) + activesupport (= 7.1.3.2) marcel (~> 1.0) - mini_mime (>= 1.1.0) - activesupport (7.0.4.3) + activesupport (7.1.3.2) + base64 + bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) minitest (>= 5.1) + mutex_m tzinfo (~> 2.0) addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) @@ -72,16 +81,17 @@ GEM io-like (~> 0.3.0) ast (2.4.2) base64 (0.2.0) + bigdecimal (3.1.7) bindex (0.8.1) bootsnap (1.7.7) msgpack (~> 1.0) builder (3.2.4) byebug (11.1.3) - capybara (3.38.0) + capybara (3.40.0) addressable matrix mini_mime (>= 0.1.3) - nokogiri (~> 1.8) + nokogiri (~> 1.11) rack (>= 1.6.0) rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) @@ -98,6 +108,7 @@ GEM execjs coffee-script-source (1.12.2) concurrent-ruby (1.2.3) + connection_pool (2.4.1) crass (1.0.6) date (3.3.4) docusign_admin (1.3.0) @@ -130,6 +141,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) + drb (2.2.1) erubi (1.12.0) ethon (0.16.0) ffi (>= 1.15.0) @@ -145,14 +157,19 @@ GEM hashie (5.0.0) i18n (1.14.4) concurrent-ruby (~> 1.0) + io-console (0.7.2) io-like (0.3.1) + irb (1.12.0) + rdoc + reline (>= 0.4.2) jbuilder (2.11.5) actionview (>= 5.0.0) activesupport (>= 5.0.0) json (2.7.2) jwt (2.8.1) base64 - listen (3.8.0) + language_server-protocol (3.17.0.3) + listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) loofah (2.22.0) @@ -170,6 +187,7 @@ GEM minitest (5.22.3) msgpack (1.7.2) multi_xml (0.6.0) + mutex_m (0.2.0) net-http (0.4.1) uri net-imap (0.4.10) @@ -215,30 +233,37 @@ GEM pry (>= 0.9.10, < 0.15) pry-rails (0.3.9) pry (>= 0.10.4) + psych (5.1.2) + stringio public_suffix (5.0.5) - puma (6.1.1) + puma (6.4.2) nio4r (~> 2.0) racc (1.7.3) rack (2.2.9) rack-protection (3.2.0) base64 (>= 0.1.0) rack (~> 2.2, >= 2.2.4) + rack-session (1.0.2) + rack (< 3) rack-test (2.1.0) rack (>= 1.3) - rails (7.0.4.3) - actioncable (= 7.0.4.3) - actionmailbox (= 7.0.4.3) - actionmailer (= 7.0.4.3) - actionpack (= 7.0.4.3) - actiontext (= 7.0.4.3) - actionview (= 7.0.4.3) - activejob (= 7.0.4.3) - activemodel (= 7.0.4.3) - activerecord (= 7.0.4.3) - activestorage (= 7.0.4.3) - activesupport (= 7.0.4.3) + rackup (1.0.0) + rack (< 3) + webrick + rails (7.1.3.2) + actioncable (= 7.1.3.2) + actionmailbox (= 7.1.3.2) + actionmailer (= 7.1.3.2) + actionpack (= 7.1.3.2) + actiontext (= 7.1.3.2) + actionview (= 7.1.3.2) + activejob (= 7.1.3.2) + activemodel (= 7.1.3.2) + activerecord (= 7.1.3.2) + activestorage (= 7.1.3.2) + activesupport (= 7.1.3.2) bundler (>= 1.15.0) - railties (= 7.0.4.3) + railties (= 7.1.3.2) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -246,28 +271,34 @@ GEM rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) - railties (7.0.4.3) - actionpack (= 7.0.4.3) - activesupport (= 7.0.4.3) - method_source + railties (7.1.3.2) + actionpack (= 7.1.3.2) + activesupport (= 7.1.3.2) + irb + rackup (>= 1.0.0) rake (>= 12.2) - thor (~> 1.0) - zeitwerk (~> 2.5) + thor (~> 1.0, >= 1.2.2) + zeitwerk (~> 2.6) rainbow (3.1.1) rake (13.2.1) rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) + rdoc (6.6.3.1) + psych (>= 4.0.0) regexp_parser (2.9.0) + reline (0.5.2) + io-console (~> 0.5) rexml (3.2.6) - rubocop (1.48.1) + rubocop (1.63.3) json (~> 2.3) + language_server-protocol (>= 3.17.0) parallel (~> 1.10) - parser (>= 3.2.0.0) + parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.26.0, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) rubocop-ast (1.31.2) @@ -284,14 +315,15 @@ GEM sprockets (> 3.0) sprockets-rails tilt - selenium-webdriver (4.8.6) + selenium-webdriver (4.19.0) + base64 (~> 0.2) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) snaky_hash (2.0.1) hashie version_gem (~> 1.1, >= 1.1.1) - spring (4.1.3) + spring (4.2.1) spring-watcher-listen (2.1.0) listen (>= 2.7, < 4.0) spring (>= 4) @@ -302,8 +334,9 @@ GEM actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) - sqlite3 (1.6.9-x64-mingw-ucrt) - sqlite3 (1.6.9-x86_64-linux) + sqlite3 (1.7.3-x64-mingw-ucrt) + sqlite3 (1.7.3-x86_64-linux) + stringio (3.1.0) test-unit (3.6.2) power_assert thor (1.3.1) @@ -329,6 +362,7 @@ GEM activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) + webrick (1.8.1) websocket (1.2.10) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) @@ -344,7 +378,7 @@ PLATFORMS DEPENDENCIES bootsnap (~> 1.7.3) byebug (~> 11.1.3) - capybara (~> 3.38.0) + capybara (~> 3.40.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) docusign_admin (~> 1.3.0) @@ -354,26 +388,26 @@ DEPENDENCIES docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) jbuilder (~> 2.11.5) - listen (~> 3.8.0) + listen (~> 3.9.0) matrix (~> 0.4.2) omniauth-oauth2 (~> 1.8.0) omniauth-rails_csrf_protection pry-nav (~> 1.0.0) pry-rails (~> 0.3.9) - puma (~> 6.1.1) - rails (~> 7.0.4.3) - rubocop (~> 1.48.1) + puma (~> 6.4.2) + rails (~> 7.1.3.2) + rubocop (~> 1.63.3) sass-rails (~> 6.0.0) - selenium-webdriver (~> 4.8.1) - spring (~> 4.1.1) + selenium-webdriver (~> 4.19.0) + spring (~> 4.2.1) spring-watcher-listen (~> 2.1.0) - sqlite3 (~> 1.6.1) + sqlite3 (~> 1.7.3) test-unit turbolinks (~> 5.2.1) tzinfo-data (~> 1.2022.7, >= 1.2022.7) uglifier (~> 4.2.0) wdm (>= 0.1.1) - web-console (~> 4.2.0) + web-console (~> 4.2.1) RUBY VERSION ruby 3.1.2p20 diff --git a/jwt_console_project/jwt_console.rb b/jwt_console_project/jwt_console.rb index 820fba6..501a768 100644 --- a/jwt_console_project/jwt_console.rb +++ b/jwt_console_project/jwt_console.rb @@ -2,7 +2,7 @@ gemfile do source 'https://rubygems.org' - gem 'docusign_esign', ' ~> 3.22.0' + gem 'docusign_esign', ' ~> 3.27.0.rc1' end class ESign diff --git a/quick_acg/Gemfile b/quick_acg/Gemfile index 0d43063..9f14b3f 100644 --- a/quick_acg/Gemfile +++ b/quick_acg/Gemfile @@ -6,11 +6,11 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '~>3.1.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 7.0.4.3' +gem 'rails', '~> 7.1.3.2' # Use sqlite3 as the database for Active Record -gem 'sqlite3', '~> 1.6.1' +gem 'sqlite3', '~> 1.7.3' # Use Puma as the app server -gem 'puma', '~> 6.1.1' +gem 'puma', '~> 6.4.2' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets @@ -49,25 +49,25 @@ end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. - gem 'listen', '~> 3.8.0' - gem 'web-console', '~> 4.2.0' + gem 'listen', '~> 3.9.0' + gem 'web-console', '~> 4.2.1' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'pry-nav', '~> 1.0.0' gem 'pry-rails', '~> 0.3.9' - gem 'spring', '~> 4.1.1' + gem 'spring', '~> 4.2.1' gem 'spring-watcher-listen', '~> 2.1.0' end group :test do # Adds support for Capybara system testing and selenium driver - gem 'capybara', '~> 3.38.0' - gem 'selenium-webdriver', '~> 4.8.1' + gem 'capybara', '~> 3.40.0' + gem 'selenium-webdriver', '~> 4.19.0' # Easy installation and use of chromedriver to run system tests with Chrome gem 'chromedriver-helper', '~> 2.1.1' gem 'test-unit' end -gem 'docusign_esign', '~> 3.22.0' +gem 'docusign_esign', '~> 3.27.0.rc1' gem 'omniauth-oauth2', '~> 1.8.0' gem 'omniauth-rails_csrf_protection' diff --git a/quick_acg/Gemfile.lock b/quick_acg/Gemfile.lock index 30e4a57..80a99ff 100644 --- a/quick_acg/Gemfile.lock +++ b/quick_acg/Gemfile.lock @@ -1,85 +1,96 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.0.4.3) - actionpack (= 7.0.4.3) - activesupport (= 7.0.4.3) + actioncable (7.1.3.2) + actionpack (= 7.1.3.2) + activesupport (= 7.1.3.2) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.4.3) - actionpack (= 7.0.4.3) - activejob (= 7.0.4.3) - activerecord (= 7.0.4.3) - activestorage (= 7.0.4.3) - activesupport (= 7.0.4.3) + zeitwerk (~> 2.6) + actionmailbox (7.1.3.2) + actionpack (= 7.1.3.2) + activejob (= 7.1.3.2) + activerecord (= 7.1.3.2) + activestorage (= 7.1.3.2) + activesupport (= 7.1.3.2) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.0.4.3) - actionpack (= 7.0.4.3) - actionview (= 7.0.4.3) - activejob (= 7.0.4.3) - activesupport (= 7.0.4.3) + actionmailer (7.1.3.2) + actionpack (= 7.1.3.2) + actionview (= 7.1.3.2) + activejob (= 7.1.3.2) + activesupport (= 7.1.3.2) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp - rails-dom-testing (~> 2.0) - actionpack (7.0.4.3) - actionview (= 7.0.4.3) - activesupport (= 7.0.4.3) - rack (~> 2.0, >= 2.2.0) + rails-dom-testing (~> 2.2) + actionpack (7.1.3.2) + actionview (= 7.1.3.2) + activesupport (= 7.1.3.2) + nokogiri (>= 1.8.5) + racc + rack (>= 2.2.4) + rack-session (>= 1.0.1) rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.4.3) - actionpack (= 7.0.4.3) - activerecord (= 7.0.4.3) - activestorage (= 7.0.4.3) - activesupport (= 7.0.4.3) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + actiontext (7.1.3.2) + actionpack (= 7.1.3.2) + activerecord (= 7.1.3.2) + activestorage (= 7.1.3.2) + activesupport (= 7.1.3.2) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.4.3) - activesupport (= 7.0.4.3) + actionview (7.1.3.2) + activesupport (= 7.1.3.2) builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (7.0.4.3) - activesupport (= 7.0.4.3) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (7.1.3.2) + activesupport (= 7.1.3.2) globalid (>= 0.3.6) - activemodel (7.0.4.3) - activesupport (= 7.0.4.3) - activerecord (7.0.4.3) - activemodel (= 7.0.4.3) - activesupport (= 7.0.4.3) - activestorage (7.0.4.3) - actionpack (= 7.0.4.3) - activejob (= 7.0.4.3) - activerecord (= 7.0.4.3) - activesupport (= 7.0.4.3) + activemodel (7.1.3.2) + activesupport (= 7.1.3.2) + activerecord (7.1.3.2) + activemodel (= 7.1.3.2) + activesupport (= 7.1.3.2) + timeout (>= 0.4.0) + activestorage (7.1.3.2) + actionpack (= 7.1.3.2) + activejob (= 7.1.3.2) + activerecord (= 7.1.3.2) + activesupport (= 7.1.3.2) marcel (~> 1.0) - mini_mime (>= 1.1.0) - activesupport (7.0.4.3) + activesupport (7.1.3.2) + base64 + bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) minitest (>= 5.1) + mutex_m tzinfo (~> 2.0) - addressable (2.8.1) + addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) archive-zip (0.12.0) io-like (~> 0.3.0) + base64 (0.2.0) + bigdecimal (3.1.7) bindex (0.8.1) bootsnap (1.7.7) msgpack (~> 1.0) builder (3.2.4) byebug (11.1.3) - capybara (3.38.0) + capybara (3.40.0) addressable matrix mini_mime (>= 0.1.3) - nokogiri (~> 1.8) + nokogiri (~> 1.11) rack (>= 1.6.0) rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) @@ -95,63 +106,73 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.2.2) + concurrent-ruby (1.2.3) + connection_pool (2.4.1) crass (1.0.6) - date (3.3.3) - docusign_esign (3.22.0) + date (3.3.4) + docusign_esign (3.27.0.rc1) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) + drb (2.2.1) erubi (1.12.0) ethon (0.16.0) ffi (>= 1.15.0) - execjs (2.8.1) - faraday (2.7.4) - faraday-net_http (>= 2.0, < 3.1) - ruby2_keywords (>= 0.0.4) - faraday-net_http (3.0.2) - ffi (1.15.5-x64-mingw-ucrt) - globalid (1.1.0) - activesupport (>= 5.0) + execjs (2.9.1) + faraday (2.9.0) + faraday-net_http (>= 2.0, < 3.2) + faraday-net_http (3.1.0) + net-http + ffi (1.16.3-x64-mingw-ucrt) + globalid (1.2.1) + activesupport (>= 6.1) hashie (5.0.0) - i18n (1.12.0) + i18n (1.14.4) concurrent-ruby (~> 1.0) + io-console (0.7.2) io-like (0.3.1) + irb (1.12.0) + rdoc + reline (>= 0.4.2) jbuilder (2.11.5) actionview (>= 5.0.0) activesupport (>= 5.0.0) - json (2.6.3) - jwt (2.7.0) - listen (3.8.0) + json (2.7.2) + jwt (2.8.1) + base64 + listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.19.1) + loofah (2.22.0) crass (~> 1.0.2) - nokogiri (>= 1.5.9) + nokogiri (>= 1.12.0) mail (2.8.1) mini_mime (>= 0.1.1) net-imap net-pop net-smtp - marcel (1.0.2) + marcel (1.0.4) matrix (0.4.2) - method_source (1.0.0) - mini_mime (1.1.2) - minitest (5.18.0) - msgpack (1.6.1) + method_source (1.1.0) + mini_mime (1.1.5) + minitest (5.22.3) + msgpack (1.7.2) multi_xml (0.6.0) - net-imap (0.3.4) + mutex_m (0.2.0) + net-http (0.4.1) + uri + net-imap (0.4.10) date net-protocol net-pop (0.1.2) net-protocol - net-protocol (0.2.1) + net-protocol (0.2.2) timeout - net-smtp (0.3.3) + net-smtp (0.5.0) net-protocol - nio4r (2.5.8) - nokogiri (1.14.2-x64-mingw-ucrt) + nio4r (2.7.1) + nokogiri (1.16.4-x64-mingw-ucrt) racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) @@ -160,7 +181,7 @@ GEM rack (>= 1.2, < 4) snaky_hash (~> 2.0) version_gem (~> 1.1) - omniauth (2.1.1) + omniauth (2.1.2) hashie (>= 3.4.6) rack (>= 2.2.3) rack-protection @@ -178,48 +199,62 @@ GEM pry (>= 0.9.10, < 0.15) pry-rails (0.3.9) pry (>= 0.10.4) - public_suffix (5.0.1) - puma (6.1.1) + psych (5.1.2) + stringio + public_suffix (5.0.5) + puma (6.4.2) nio4r (~> 2.0) - racc (1.6.2) - rack (2.2.6.4) - rack-protection (3.0.5) - rack + racc (1.7.3) + rack (3.0.10) + rack-protection (4.0.0) + base64 (>= 0.1.0) + rack (>= 3.0.0, < 4) + rack-session (2.0.0) + rack (>= 3.0.0) rack-test (2.1.0) rack (>= 1.3) - rails (7.0.4.3) - actioncable (= 7.0.4.3) - actionmailbox (= 7.0.4.3) - actionmailer (= 7.0.4.3) - actionpack (= 7.0.4.3) - actiontext (= 7.0.4.3) - actionview (= 7.0.4.3) - activejob (= 7.0.4.3) - activemodel (= 7.0.4.3) - activerecord (= 7.0.4.3) - activestorage (= 7.0.4.3) - activesupport (= 7.0.4.3) + rackup (2.1.0) + rack (>= 3) + webrick (~> 1.8) + rails (7.1.3.2) + actioncable (= 7.1.3.2) + actionmailbox (= 7.1.3.2) + actionmailer (= 7.1.3.2) + actionpack (= 7.1.3.2) + actiontext (= 7.1.3.2) + actionview (= 7.1.3.2) + activejob (= 7.1.3.2) + activemodel (= 7.1.3.2) + activerecord (= 7.1.3.2) + activestorage (= 7.1.3.2) + activesupport (= 7.1.3.2) bundler (>= 1.15.0) - railties (= 7.0.4.3) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) + railties (= 7.1.3.2) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.5.0) - loofah (~> 2.19, >= 2.19.1) - railties (7.0.4.3) - actionpack (= 7.0.4.3) - activesupport (= 7.0.4.3) - method_source + rails-html-sanitizer (1.6.0) + loofah (~> 2.21) + nokogiri (~> 1.14) + railties (7.1.3.2) + actionpack (= 7.1.3.2) + activesupport (= 7.1.3.2) + irb + rackup (>= 1.0.0) rake (>= 12.2) - thor (~> 1.0) - zeitwerk (~> 2.5) - rake (13.0.6) + thor (~> 1.0, >= 1.2.2) + zeitwerk (~> 2.6) + rake (13.2.1) rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - regexp_parser (2.7.0) - rexml (3.2.5) - ruby2_keywords (0.0.5) + rdoc (6.6.3.1) + psych (>= 4.0.0) + regexp_parser (2.9.0) + reline (0.5.2) + io-console (~> 0.5) + rexml (3.2.6) rubyzip (2.3.2) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) @@ -231,34 +266,36 @@ GEM sprockets (> 3.0) sprockets-rails tilt - selenium-webdriver (4.8.1) + selenium-webdriver (4.19.0) + base64 (~> 0.2) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) snaky_hash (2.0.1) hashie version_gem (~> 1.1, >= 1.1.1) - spring (4.1.1) + spring (4.2.1) spring-watcher-listen (2.1.0) listen (>= 2.7, < 4.0) spring (>= 4) - sprockets (4.2.0) + sprockets (4.2.1) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) sprockets-rails (3.4.2) actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) - sqlite3 (1.6.1-x64-mingw-ucrt) - test-unit (3.5.7) + sqlite3 (1.7.3-x64-mingw-ucrt) + stringio (3.1.0) + test-unit (3.6.2) power_assert - thor (1.2.1) - tilt (2.1.0) - timeout (0.3.2) + thor (1.3.1) + tilt (2.3.0) + timeout (0.4.1) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) - typhoeus (1.4.0) + typhoeus (1.4.1) ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) @@ -266,19 +303,22 @@ GEM tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) - version_gem (1.1.2) - web-console (4.2.0) + uri (0.13.0) + version_gem (1.1.4) + wdm (0.1.1) + web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - websocket (1.2.9) - websocket-driver (0.7.5) + webrick (1.8.1) + websocket (1.2.10) + websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.7) + zeitwerk (2.6.13) PLATFORMS x64-mingw-ucrt @@ -286,32 +326,32 @@ PLATFORMS DEPENDENCIES bootsnap (~> 1.7.3) byebug (~> 11.1.3) - capybara (~> 3.38.0) + capybara (~> 3.40.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_esign (~> 3.22.0) + docusign_esign (~> 3.27.0.rc1) jbuilder (~> 2.11.5) - listen (~> 3.8.0) + listen (~> 3.9.0) omniauth-oauth2 (~> 1.8.0) omniauth-rails_csrf_protection pry-nav (~> 1.0.0) pry-rails (~> 0.3.9) - puma (~> 6.1.1) - rails (~> 7.0.4.3) + puma (~> 6.4.2) + rails (~> 7.1.3.2) sass-rails (~> 6.0.0) - selenium-webdriver (~> 4.8.1) - spring (~> 4.1.1) + selenium-webdriver (~> 4.19.0) + spring (~> 4.2.1) spring-watcher-listen (~> 2.1.0) - sqlite3 (~> 1.6.1) + sqlite3 (~> 1.7.3) test-unit turbolinks (~> 5.2.1) tzinfo-data (~> 1.2022.7, >= 1.2022.7) uglifier (~> 4.2.0) wdm (>= 0.1.1) - web-console (~> 4.2.0) + web-console (~> 4.2.1) RUBY VERSION ruby 3.1.2p20 BUNDLED WITH - 2.3.7 + 2.4.22 From bc76ef1b08742e6a37444e9452dd30ecab24526c Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Wed, 15 May 2024 12:04:45 +0300 Subject: [PATCH 318/363] update example --- Gemfile | 2 +- Gemfile.lock | 34 +++++++++--------- .../e_sign/eg011_embedded_sending_service.rb | 36 +++++++++++++++++-- .../eeg011_embedded_sending/get.html.erb | 4 +-- 4 files changed, 54 insertions(+), 22 deletions(-) diff --git a/Gemfile b/Gemfile index b7a21de..fb610f1 100644 --- a/Gemfile +++ b/Gemfile @@ -70,7 +70,7 @@ end gem 'docusign_admin', '~> 1.3.0' gem 'docusign_click', '~> 1.4.0' -gem 'docusign_esign', '~> 3.27.0.rc1' +gem 'docusign_esign', '~> 4.0.0.rc1' gem 'docusign_maestro', '~> 1.0.0.rc1' gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' diff --git a/Gemfile.lock b/Gemfile.lock index 8df3efd..038a1a5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -72,6 +72,7 @@ GEM io-like (~> 0.3.0) ast (2.4.2) base64 (0.2.0) + bigdecimal (3.1.8) bindex (0.8.1) bootsnap (1.7.7) msgpack (~> 1.0) @@ -110,12 +111,12 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (3.27.0.rc1) + docusign_esign (4.0.0.rc1) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_maestro (1.0.0.rc1) + docusign_maestro (1.0.1.rc2) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -143,7 +144,7 @@ GEM globalid (1.2.1) activesupport (>= 6.1) hashie (5.0.0) - i18n (1.14.4) + i18n (1.14.5) concurrent-ruby (~> 1.0) io-like (0.3.1) jbuilder (2.11.5) @@ -165,14 +166,15 @@ GEM net-smtp marcel (1.0.4) matrix (0.4.2) - method_source (1.0.0) + method_source (1.1.0) mini_mime (1.1.5) minitest (5.22.3) msgpack (1.7.2) - multi_xml (0.6.0) + multi_xml (0.7.1) + bigdecimal (~> 3.1) net-http (0.4.1) uri - net-imap (0.4.10) + net-imap (0.4.11) date net-protocol net-pop (0.1.2) @@ -181,10 +183,10 @@ GEM timeout net-smtp (0.5.0) net-protocol - nio4r (2.7.1) - nokogiri (1.16.3-x64-mingw-ucrt) + nio4r (2.7.3) + nokogiri (1.16.5-x64-mingw-ucrt) racc (~> 1.4) - nokogiri (1.16.3-x86_64-linux) + nokogiri (1.16.5-x86_64-linux) racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) @@ -200,11 +202,11 @@ GEM omniauth-oauth2 (1.8.0) oauth2 (>= 1.4, < 3) omniauth (~> 2.0) - omniauth-rails_csrf_protection (1.0.1) + omniauth-rails_csrf_protection (1.0.2) actionpack (>= 4.2) omniauth (~> 2.0) parallel (1.24.0) - parser (3.3.0.5) + parser (3.3.1.0) ast (~> 2.4.1) racc power_assert (2.0.3) @@ -258,7 +260,7 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - regexp_parser (2.9.0) + regexp_parser (2.9.1) rexml (3.2.6) rubocop (1.48.1) json (~> 2.3) @@ -270,8 +272,8 @@ GEM rubocop-ast (>= 1.26.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.31.2) - parser (>= 3.3.0.4) + rubocop-ast (1.31.3) + parser (>= 3.3.1.0) ruby-progressbar (1.13.0) rubyzip (2.3.2) sass-rails (6.0.0) @@ -335,7 +337,7 @@ GEM websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.13) + zeitwerk (2.6.14) PLATFORMS x64-mingw-ucrt @@ -349,7 +351,7 @@ DEPENDENCIES coffee-rails (~> 5.0.0) docusign_admin (~> 1.3.0) docusign_click (~> 1.4.0) - docusign_esign (~> 3.27.0.rc1) + docusign_esign (~> 4.0.0.rc1) docusign_maestro (~> 1.0.0.rc1) docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) diff --git a/app/services/e_sign/eg011_embedded_sending_service.rb b/app/services/e_sign/eg011_embedded_sending_service.rb index 2a6e36d..6ff7042 100644 --- a/app/services/e_sign/eg011_embedded_sending_service.rb +++ b/app/services/e_sign/eg011_embedded_sending_service.rb @@ -19,12 +19,10 @@ def worker #ds-snippet-start:eSign11Step3 # Create the sender view - view_request = DocuSign_eSign::ReturnUrlRequest.new({ returnUrl: args[:ds_return_url] }) + view_request = envelope_view_request(args) envelope_api = create_envelope_api(args) results = envelope_api.create_sender_view args[:account_id], envelope_id, view_request - # Switch to the Recipients/Documents view if requested by the user in the form url = results.url - url = url.sub! 'send=1', 'send=0' if args[:starting_view] == 'recipient' { 'envelope_id' => envelope_id, 'redirect_url' => url } #ds-snippet-end:eSign11Step3 end @@ -148,6 +146,38 @@ def make_envelope(envelope_args) envelope_definition end + def envelope_view_request(args) + DocuSign_eSign::EnvelopeViewRequest.new( + returnUrl: args[:ds_return_url], + viewAccess: 'envelope', + settings: DocuSign_eSign::EnvelopeViewSettings.new( + startingScreen: args[:starting_view], + sendButtonAction: 'send', + showBackButton: 'false', + backButtonAction: 'previousPage', + showHeaderActions: 'false', + showDiscardAction: 'false', + lockToken: '', + recipientSettings: DocuSign_eSign::EnvelopeViewRecipientSettings.new( + showEditRecipients: 'false', + showContactsList: 'false' + ), + documentSettings: DocuSign_eSign::EnvelopeViewDocumentSettings.new( + showEditDocuments: 'false', + showEditDocumentVisibility: 'false', + showEditPages: 'false' + ), + taggerSettings: DocuSign_eSign::EnvelopeViewTaggerSettings.new( + paletteSections: 'default', + paletteDefault: 'custom' + ), + templateSettings: DocuSign_eSign::EnvelopeViewTemplateSettings.new( + showMatchingTemplatesPrompt: 'true' + ) + ) + ) + end + def create_document1(args) " diff --git a/app/views/e_sign/eeg011_embedded_sending/get.html.erb b/app/views/e_sign/eeg011_embedded_sending/get.html.erb index 0bb3890..912ff17 100644 --- a/app/views/e_sign/eeg011_embedded_sending/get.html.erb +++ b/app/views/e_sign/eeg011_embedded_sending/get.html.erb @@ -15,8 +15,8 @@
    From b2f4a3cbc5b6c27620036450f20eb7381a5dae5e Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Wed, 15 May 2024 17:01:45 +0300 Subject: [PATCH 319/363] fix package version --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 038a1a5..9453977 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -116,7 +116,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_maestro (1.0.1.rc2) + docusign_maestro (1.0.0.rc1) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) From c82942aec898fda287374524316adb20b33e58af Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Thu, 16 May 2024 11:32:01 -0700 Subject: [PATCH 320/363] updating codeDepot markers --- app/services/e_sign/eg011_embedded_sending_service.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/services/e_sign/eg011_embedded_sending_service.rb b/app/services/e_sign/eg011_embedded_sending_service.rb index 6ff7042..63b0352 100644 --- a/app/services/e_sign/eg011_embedded_sending_service.rb +++ b/app/services/e_sign/eg011_embedded_sending_service.rb @@ -146,6 +146,7 @@ def make_envelope(envelope_args) envelope_definition end + #ds-snippet-start:eSign11Step3 def envelope_view_request(args) DocuSign_eSign::EnvelopeViewRequest.new( returnUrl: args[:ds_return_url], @@ -177,6 +178,7 @@ def envelope_view_request(args) ) ) end + #ds-snippet-end:eSign11Step3 def create_document1(args) " From 374258ec71bcb5963db40469aa5c969cc7b54070 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Mon, 3 Jun 2024 17:26:21 +0300 Subject: [PATCH 321/363] fix error display and add webforms gem --- Gemfile | 1 + Gemfile.lock | 34 ++++++++++++++++++++------------ app/controllers/eg_controller.rb | 2 +- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Gemfile b/Gemfile index fb610f1..e8846ab 100644 --- a/Gemfile +++ b/Gemfile @@ -75,6 +75,7 @@ gem 'docusign_maestro', '~> 1.0.0.rc1' gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' gem 'omniauth-oauth2', '~> 1.8.0' +gem 'docusign_webforms', '~> 1.0.0' gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem diff --git a/Gemfile.lock b/Gemfile.lock index 9453977..c47cf2e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -98,7 +98,7 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.2.3) + concurrent-ruby (1.3.1) crass (1.0.6) date (3.3.4) docusign_admin (1.3.0) @@ -111,12 +111,12 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (4.0.0.rc1) + docusign_esign (4.0.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_maestro (1.0.0.rc1) + docusign_maestro (1.0.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -131,6 +131,11 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) + docusign_webforms (1.0.0) + addressable (~> 2.7, >= 2.7.0) + json (~> 2.1, >= 2.1.0) + jwt (~> 2.2, >= 2.2.1) + typhoeus (~> 1.0, >= 1.0.1) erubi (1.12.0) ethon (0.16.0) ffi (>= 1.15.0) @@ -139,8 +144,8 @@ GEM faraday-net_http (>= 2.0, < 3.2) faraday-net_http (3.1.0) net-http - ffi (1.16.3) - ffi (1.16.3-x64-mingw-ucrt) + ffi (1.17.0-x64-mingw-ucrt) + ffi (1.17.0-x86_64-linux-gnu) globalid (1.2.1) activesupport (>= 6.1) hashie (5.0.0) @@ -168,13 +173,13 @@ GEM matrix (0.4.2) method_source (1.1.0) mini_mime (1.1.5) - minitest (5.22.3) + minitest (5.23.1) msgpack (1.7.2) multi_xml (0.7.1) bigdecimal (~> 3.1) net-http (0.4.1) uri - net-imap (0.4.11) + net-imap (0.4.12) date net-protocol net-pop (0.1.2) @@ -206,7 +211,7 @@ GEM actionpack (>= 4.2) omniauth (~> 2.0) parallel (1.24.0) - parser (3.3.1.0) + parser (3.3.2.0) ast (~> 2.4.1) racc power_assert (2.0.3) @@ -220,7 +225,7 @@ GEM public_suffix (5.0.5) puma (6.1.1) nio4r (~> 2.0) - racc (1.7.3) + racc (1.8.0) rack (2.2.9) rack-protection (3.2.0) base64 (>= 0.1.0) @@ -258,10 +263,11 @@ GEM rainbow (3.1.1) rake (13.2.1) rb-fsevent (0.11.2) - rb-inotify (0.10.1) + rb-inotify (0.11.1) ffi (~> 1.0) - regexp_parser (2.9.1) - rexml (3.2.6) + regexp_parser (2.9.2) + rexml (3.2.8) + strscan (>= 3.0.9) rubocop (1.48.1) json (~> 2.3) parallel (~> 1.10) @@ -306,6 +312,7 @@ GEM sprockets (>= 3.0.0) sqlite3 (1.6.9-x64-mingw-ucrt) sqlite3 (1.6.9-x86_64-linux) + strscan (3.1.0) test-unit (3.6.2) power_assert thor (1.3.1) @@ -337,7 +344,7 @@ GEM websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.14) + zeitwerk (2.6.15) PLATFORMS x64-mingw-ucrt @@ -355,6 +362,7 @@ DEPENDENCIES docusign_maestro (~> 1.0.0.rc1) docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) + docusign_webforms (~> 1.0.0) jbuilder (~> 2.11.5) listen (~> 3.8.0) matrix (~> 0.4.2) diff --git a/app/controllers/eg_controller.rb b/app/controllers/eg_controller.rb index 92c6c1f..cfaeef0 100644 --- a/app/controllers/eg_controller.rb +++ b/app/controllers/eg_controller.rb @@ -92,7 +92,7 @@ def check_auth(api) def handle_error(e) error = JSON.parse e.response_body @error_code = e.code || error['errorCode'] - @error_message = error['error_description'] || error['message'] + @error_message = error['error_description'] || error['message'] || error['error'] render 'ds_common/error' end From db955e237614323641ff1feda286c6b3d0d6b578 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Mon, 3 Jun 2024 17:35:15 +0300 Subject: [PATCH 322/363] update gemfile.lock --- Gemfile.lock | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index c47cf2e..6109f1a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -98,7 +98,7 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.3.1) + concurrent-ruby (1.2.3) crass (1.0.6) date (3.3.4) docusign_admin (1.3.0) @@ -111,12 +111,12 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (4.0.0) + docusign_esign (4.0.0.rc1) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_maestro (1.0.0) + docusign_maestro (1.0.0.rc1) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -144,8 +144,8 @@ GEM faraday-net_http (>= 2.0, < 3.2) faraday-net_http (3.1.0) net-http - ffi (1.17.0-x64-mingw-ucrt) - ffi (1.17.0-x86_64-linux-gnu) + ffi (1.16.3) + ffi (1.16.3-x64-mingw-ucrt) globalid (1.2.1) activesupport (>= 6.1) hashie (5.0.0) @@ -173,13 +173,13 @@ GEM matrix (0.4.2) method_source (1.1.0) mini_mime (1.1.5) - minitest (5.23.1) + minitest (5.22.3) msgpack (1.7.2) multi_xml (0.7.1) bigdecimal (~> 3.1) net-http (0.4.1) uri - net-imap (0.4.12) + net-imap (0.4.11) date net-protocol net-pop (0.1.2) @@ -211,7 +211,7 @@ GEM actionpack (>= 4.2) omniauth (~> 2.0) parallel (1.24.0) - parser (3.3.2.0) + parser (3.3.1.0) ast (~> 2.4.1) racc power_assert (2.0.3) @@ -225,7 +225,7 @@ GEM public_suffix (5.0.5) puma (6.1.1) nio4r (~> 2.0) - racc (1.8.0) + racc (1.7.3) rack (2.2.9) rack-protection (3.2.0) base64 (>= 0.1.0) @@ -263,11 +263,10 @@ GEM rainbow (3.1.1) rake (13.2.1) rb-fsevent (0.11.2) - rb-inotify (0.11.1) + rb-inotify (0.10.1) ffi (~> 1.0) - regexp_parser (2.9.2) - rexml (3.2.8) - strscan (>= 3.0.9) + regexp_parser (2.9.1) + rexml (3.2.6) rubocop (1.48.1) json (~> 2.3) parallel (~> 1.10) @@ -312,7 +311,6 @@ GEM sprockets (>= 3.0.0) sqlite3 (1.6.9-x64-mingw-ucrt) sqlite3 (1.6.9-x86_64-linux) - strscan (3.1.0) test-unit (3.6.2) power_assert thor (1.3.1) @@ -344,7 +342,7 @@ GEM websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.15) + zeitwerk (2.6.14) PLATFORMS x64-mingw-ucrt From ad28a8840af01e49973853b9a4708035cac602a7 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Mon, 3 Jun 2024 17:39:28 +0300 Subject: [PATCH 323/363] fix linter issues --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index e8846ab..84d57d3 100644 --- a/Gemfile +++ b/Gemfile @@ -74,8 +74,8 @@ gem 'docusign_esign', '~> 4.0.0.rc1' gem 'docusign_maestro', '~> 1.0.0.rc1' gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' -gem 'omniauth-oauth2', '~> 1.8.0' gem 'docusign_webforms', '~> 1.0.0' +gem 'omniauth-oauth2', '~> 1.8.0' gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem From fa9a96a8a06a92846b1d98b1ab0ce67d48fc54dd Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Tue, 11 Jun 2024 18:25:54 +0300 Subject: [PATCH 324/363] fix for new maestro sdk --- app/services/maestro_api/mseg001_trigger_workflow_service.rb | 2 +- config/appsettings.example.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/maestro_api/mseg001_trigger_workflow_service.rb b/app/services/maestro_api/mseg001_trigger_workflow_service.rb index bf7262d..4fcdd2e 100644 --- a/app/services/maestro_api/mseg001_trigger_workflow_service.rb +++ b/app/services/maestro_api/mseg001_trigger_workflow_service.rb @@ -65,7 +65,7 @@ def trigger_workflow(workflow) #ds-snippet-start:Maestro1Step5 workflow_trigger_api = DocuSign_Maestro::WorkflowTriggerApi.new(api_client) - workflow_trigger_api.trigger_workflow(args[:account_id], trigger_payload, trigger_options) + workflow_trigger_api.trigger_workflow(args[:account_id], args[:workflow_id], trigger_payload, trigger_options) #ds-snippet-end:Maestro1Step5 end end diff --git a/config/appsettings.example.yml b/config/appsettings.example.yml index 0b88d2b..9dac446 100644 --- a/config/appsettings.example.yml +++ b/config/appsettings.example.yml @@ -24,7 +24,7 @@ default: &default monitor_host: "https://lens-d.docusign.net" admin_host: "https://api-d.docusign.net/management" webforms_host: "https://apps-d.docusign.com/api/webforms/v1.1" - maestro_client_host: "https://demo.services.docusign.net/" + maestro_client_host: "https://apps-d.docusign.com/api/maestro" allow_silent_authentication: true # A user can be silently authenticated if they have an # Active login session on another tab of the same browser # Set if you want a specific Docusign AccountId, If false, the users default account will be used. From 26c82ab9eeb4229d70565f8ed1f2f79d4946d4d2 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Wed, 12 Jun 2024 15:51:00 +0300 Subject: [PATCH 325/363] added custom error messages --- .../e_sign/eeg020_phone_authentication_controller.rb | 6 ++++++ .../e_sign/eeg022_kba_authentication_controller.rb | 6 ++++++ .../e_sign/eeg023_idv_authentication_controller.rb | 6 ++++++ app/views/e_sign/eeg020_phone_authentication/get.html.erb | 4 ++-- app/views/e_sign/eeg022_kba_authentication/get.html.erb | 5 ++--- app/views/e_sign/eeg023_idv_authentication/get.html.erb | 5 ++--- 6 files changed, 24 insertions(+), 8 deletions(-) diff --git a/app/controllers/e_sign/eeg020_phone_authentication_controller.rb b/app/controllers/e_sign/eeg020_phone_authentication_controller.rb index d6ad9a5..92aa261 100644 --- a/app/controllers/e_sign/eeg020_phone_authentication_controller.rb +++ b/app/controllers/e_sign/eeg020_phone_authentication_controller.rb @@ -19,6 +19,12 @@ def create envelope_args: envelope_args } + if Rails.application.config.signer_email == envelope_args[:signer_email] + @error_code = 400 + @error_message = @manifest['SupportingTexts']['IdenticalEmailsNotAllowedErrorMessage'] + return render 'ds_common/error' + end + phone_auth_service = ESign::Eg020PhoneAuthenticationService.new(args) # Retrieve the workflow id diff --git a/app/controllers/e_sign/eeg022_kba_authentication_controller.rb b/app/controllers/e_sign/eeg022_kba_authentication_controller.rb index 25da5a1..3601b79 100644 --- a/app/controllers/e_sign/eeg022_kba_authentication_controller.rb +++ b/app/controllers/e_sign/eeg022_kba_authentication_controller.rb @@ -17,6 +17,12 @@ def create envelope_args: envelope_args } + if Rails.application.config.signer_email == envelope_args[:signer_email] + @error_code = 400 + @error_message = @manifest['SupportingTexts']['IdenticalEmailsNotAllowedErrorMessage'] + return render 'ds_common/error' + end + results = ESign::Eg022KbaAuthenticationService.new(args).worker session[:envelope_id] = results.envelope_id diff --git a/app/controllers/e_sign/eeg023_idv_authentication_controller.rb b/app/controllers/e_sign/eeg023_idv_authentication_controller.rb index 9620368..ccc50c2 100644 --- a/app/controllers/e_sign/eeg023_idv_authentication_controller.rb +++ b/app/controllers/e_sign/eeg023_idv_authentication_controller.rb @@ -17,6 +17,12 @@ def create envelope_args: envelope_args } + if Rails.application.config.signer_email == envelope_args[:signer_email] + @error_code = 400 + @error_message = @manifest['SupportingTexts']['IdenticalEmailsNotAllowedErrorMessage'] + return render 'ds_common/error' + end + results = ESign::Eg023IdvAuthenticationService.new(args).worker if results.to_s == 'idv_not_enabled' diff --git a/app/views/e_sign/eeg020_phone_authentication/get.html.erb b/app/views/e_sign/eeg020_phone_authentication/get.html.erb index 05f636b..2e930df 100644 --- a/app/views/e_sign/eeg020_phone_authentication/get.html.erb +++ b/app/views/e_sign/eeg020_phone_authentication/get.html.erb @@ -30,14 +30,14 @@ " required - value="<%= @config.signer_email %>" required> + required> <%= render('partials/email_will_not_be_shared') %>
    " name="signer_name" - value="<%= @config.signer_name %>" required> + required>
    <%= render('partials/submit_button') %> diff --git a/app/views/e_sign/eeg022_kba_authentication/get.html.erb b/app/views/e_sign/eeg022_kba_authentication/get.html.erb index 2fdf193..ac89ee5 100644 --- a/app/views/e_sign/eeg022_kba_authentication/get.html.erb +++ b/app/views/e_sign/eeg022_kba_authentication/get.html.erb @@ -13,15 +13,14 @@ " required - value="<%= @config.signer_email %>"> + placeholder="<%= @example["Forms"][form_index]["Inputs"][signer_email_index]["InputPlaceholder"] %>" required> <%= render('partials/email_will_not_be_shared') %>
    " name="signerName" - value="<%= @config.signer_name %>" required> + required>
    <%= render('partials/submit_button') %> \ No newline at end of file diff --git a/app/views/e_sign/eeg023_idv_authentication/get.html.erb b/app/views/e_sign/eeg023_idv_authentication/get.html.erb index 51ef8c1..90272df 100644 --- a/app/views/e_sign/eeg023_idv_authentication/get.html.erb +++ b/app/views/e_sign/eeg023_idv_authentication/get.html.erb @@ -13,15 +13,14 @@ " required - value="<%= @config.signer_email %>"> + placeholder="<%= @example["Forms"][form_index]["Inputs"][signer_email_index]["InputPlaceholder"] %>" required> <%= render('partials/email_will_not_be_shared') %>
    " name="signerName" - value="<%= @config.signer_name %>" required> + required>
    <%= render('partials/submit_button') %> From 8eb5ae1b428898eba039fbf4d8c8b9fafc6445de Mon Sep 17 00:00:00 2001 From: inbargazit Date: Mon, 24 Jun 2024 14:28:43 -0700 Subject: [PATCH 326/363] DEVDOCS-14769 - updating the banner/header image for the Ruby launcher --- app/views/admin_api/index.html.erb | 4 ++-- app/views/clickwrap/index.html.erb | 4 ++-- app/views/ds_common/index.html.erb | 4 ++-- app/views/monitor_api/index.html.erb | 4 ++-- app/views/room_api/index.html.erb | 4 ++-- public/banner-code.png | Bin 53558 -> 0 bytes public/header.png | Bin 0 -> 74963 bytes 7 files changed, 10 insertions(+), 10 deletions(-) delete mode 100644 public/banner-code.png create mode 100644 public/header.png diff --git a/app/views/admin_api/index.html.erb b/app/views/admin_api/index.html.erb index 0747ff9..9ffac1e 100644 --- a/app/views/admin_api/index.html.erb +++ b/app/views/admin_api/index.html.erb @@ -1,5 +1,5 @@
    -
    +
    @@ -8,7 +8,7 @@

    Run and explore Docusign Admin API code examples with Authorization Code Grant or JWT Grant authentication

    diff --git a/app/views/clickwrap/index.html.erb b/app/views/clickwrap/index.html.erb index 2e8574f..5057376 100644 --- a/app/views/clickwrap/index.html.erb +++ b/app/views/clickwrap/index.html.erb @@ -1,6 +1,6 @@
    -
    +
    - +
    @@ -9,7 +9,7 @@

    Run and explore Click API code examples with Authorization Code Grant or JWT Grant authentication

    diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index cb5221e..86f2b79 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -1,6 +1,6 @@
    -
    - +
    +
    diff --git a/app/views/monitor_api/index.html.erb b/app/views/monitor_api/index.html.erb index ce443c2..ad3cc1d 100644 --- a/app/views/monitor_api/index.html.erb +++ b/app/views/monitor_api/index.html.erb @@ -1,5 +1,5 @@
    -
    +
    @@ -8,7 +8,7 @@

    Run and explore eSignature REST API code examples with Authorization Code Grant or JWT Grant authentication

    - +
    @@ -8,7 +8,7 @@

    Run and explore Monitor API code examples with JWT Grant authentication

    diff --git a/app/views/room_api/index.html.erb b/app/views/room_api/index.html.erb index 3665763..fe0840f 100644 --- a/app/views/room_api/index.html.erb +++ b/app/views/room_api/index.html.erb @@ -1,6 +1,6 @@
    -
    +
    - +
    @@ -10,7 +10,7 @@ Code Grant).

    diff --git a/public/banner-code.png b/public/banner-code.png deleted file mode 100644 index 292d14e9eb8e14c7fdb570f769ae5d95af3829b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53558 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 LdK`IxC8YiX2lGP* diff --git a/public/header.png b/public/header.png new file mode 100644 index 0000000000000000000000000000000000000000..a7fcac18ebfa670cf77bdde4bc32105d9749596d GIT binary patch literal 74963 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 GJ@$X~{F7J! literal 0 HcmV?d00001 From 74fbdd96683cdfdc126ae358e0856ee0758a68a0 Mon Sep 17 00:00:00 2001 From: inbargazit Date: Tue, 25 Jun 2024 11:02:21 -0700 Subject: [PATCH 327/363] Pushing correct version of Maestro SDK --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index d960fc2..01b19fe 100644 --- a/Gemfile +++ b/Gemfile @@ -71,7 +71,7 @@ end gem 'docusign_admin', '~> 1.3.0' gem 'docusign_click', '~> 1.4.0' gem 'docusign_esign', '~> 4.0.0.rc1' -gem 'docusign_maestro', '~> 1.0.0.rc1' +gem 'docusign_maestro', '~> 2.0.0.rc1' gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' gem 'omniauth-oauth2', '~> 1.8.0' From f1554fc93794a3e4abc8b98603d4cc1ec7137c02 Mon Sep 17 00:00:00 2001 From: inbargazit Date: Tue, 25 Jun 2024 13:49:37 -0700 Subject: [PATCH 328/363] Fixing --- Gemfile.lock | 190 ++++++++++++++++++++++++++------------------------- 1 file changed, 96 insertions(+), 94 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5d3da65..a01a0d1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,35 +1,35 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.1.3.2) - actionpack (= 7.1.3.2) - activesupport (= 7.1.3.2) + actioncable (7.1.3.4) + actionpack (= 7.1.3.4) + activesupport (= 7.1.3.4) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.3.2) - actionpack (= 7.1.3.2) - activejob (= 7.1.3.2) - activerecord (= 7.1.3.2) - activestorage (= 7.1.3.2) - activesupport (= 7.1.3.2) + actionmailbox (7.1.3.4) + actionpack (= 7.1.3.4) + activejob (= 7.1.3.4) + activerecord (= 7.1.3.4) + activestorage (= 7.1.3.4) + activesupport (= 7.1.3.4) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.1.3.2) - actionpack (= 7.1.3.2) - actionview (= 7.1.3.2) - activejob (= 7.1.3.2) - activesupport (= 7.1.3.2) + actionmailer (7.1.3.4) + actionpack (= 7.1.3.4) + actionview (= 7.1.3.4) + activejob (= 7.1.3.4) + activesupport (= 7.1.3.4) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.2) - actionpack (7.1.3.2) - actionview (= 7.1.3.2) - activesupport (= 7.1.3.2) + actionpack (7.1.3.4) + actionview (= 7.1.3.4) + activesupport (= 7.1.3.4) nokogiri (>= 1.8.5) racc rack (>= 2.2.4) @@ -37,35 +37,35 @@ GEM rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.3.2) - actionpack (= 7.1.3.2) - activerecord (= 7.1.3.2) - activestorage (= 7.1.3.2) - activesupport (= 7.1.3.2) + actiontext (7.1.3.4) + actionpack (= 7.1.3.4) + activerecord (= 7.1.3.4) + activestorage (= 7.1.3.4) + activesupport (= 7.1.3.4) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.3.2) - activesupport (= 7.1.3.2) + actionview (7.1.3.4) + activesupport (= 7.1.3.4) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.1.3.2) - activesupport (= 7.1.3.2) + activejob (7.1.3.4) + activesupport (= 7.1.3.4) globalid (>= 0.3.6) - activemodel (7.1.3.2) - activesupport (= 7.1.3.2) - activerecord (7.1.3.2) - activemodel (= 7.1.3.2) - activesupport (= 7.1.3.2) + activemodel (7.1.3.4) + activesupport (= 7.1.3.4) + activerecord (7.1.3.4) + activemodel (= 7.1.3.4) + activesupport (= 7.1.3.4) timeout (>= 0.4.0) - activestorage (7.1.3.2) - actionpack (= 7.1.3.2) - activejob (= 7.1.3.2) - activerecord (= 7.1.3.2) - activesupport (= 7.1.3.2) + activestorage (7.1.3.4) + actionpack (= 7.1.3.4) + activejob (= 7.1.3.4) + activerecord (= 7.1.3.4) + activesupport (= 7.1.3.4) marcel (~> 1.0) - activesupport (7.1.3.2) + activesupport (7.1.3.4) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) @@ -75,8 +75,8 @@ GEM minitest (>= 5.1) mutex_m tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) archive-zip (0.12.0) io-like (~> 0.3.0) ast (2.4.2) @@ -85,7 +85,7 @@ GEM bindex (0.8.1) bootsnap (1.7.7) msgpack (~> 1.0) - builder (3.2.4) + builder (3.3.0) byebug (11.1.3) capybara (3.40.0) addressable @@ -107,7 +107,7 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.2.3) + concurrent-ruby (1.3.3) connection_pool (2.4.1) crass (1.0.6) date (3.3.4) @@ -121,12 +121,12 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (4.0.0.rc1) + docusign_esign (4.0.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_maestro (1.0.0.rc1) + docusign_maestro (2.0.0.rc1) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -142,16 +142,16 @@ GEM jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) drb (2.2.1) - erubi (1.12.0) + erubi (1.13.0) ethon (0.16.0) ffi (>= 1.15.0) execjs (2.9.1) - faraday (2.9.0) + faraday (2.9.2) faraday-net_http (>= 2.0, < 3.2) faraday-net_http (3.1.0) net-http - ffi (1.16.3) - ffi (1.16.3-x64-mingw-ucrt) + ffi (1.17.0-x64-mingw-ucrt) + ffi (1.17.0-x86_64-linux-gnu) globalid (1.2.1) activesupport (>= 6.1) hashie (5.0.0) @@ -159,14 +159,14 @@ GEM concurrent-ruby (~> 1.0) io-console (0.7.2) io-like (0.3.1) - irb (1.13.1) + irb (1.13.2) rdoc (>= 4.0.0) reline (>= 0.4.2) jbuilder (2.11.5) actionview (>= 5.0.0) activesupport (>= 5.0.0) json (2.7.2) - jwt (2.8.1) + jwt (2.8.2) base64 language_server-protocol (3.17.0.3) listen (3.9.0) @@ -184,14 +184,14 @@ GEM matrix (0.4.2) method_source (1.1.0) mini_mime (1.1.5) - minitest (5.22.3) + minitest (5.24.0) msgpack (1.7.2) multi_xml (0.7.1) bigdecimal (~> 3.1) mutex_m (0.2.0) net-http (0.4.1) uri - net-imap (0.4.11) + net-imap (0.4.14) date net-protocol net-pop (0.1.2) @@ -201,9 +201,9 @@ GEM net-smtp (0.5.0) net-protocol nio4r (2.7.3) - nokogiri (1.16.5-x64-mingw-ucrt) + nokogiri (1.16.6-x64-mingw-ucrt) racc (~> 1.4) - nokogiri (1.16.5-x86_64-linux) + nokogiri (1.16.6-x86_64-linux) racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) @@ -222,8 +222,8 @@ GEM omniauth-rails_csrf_protection (1.0.2) actionpack (>= 4.2) omniauth (~> 2.0) - parallel (1.24.0) - parser (3.3.1.0) + parallel (1.25.1) + parser (3.3.3.0) ast (~> 2.4.1) racc power_assert (2.0.3) @@ -232,39 +232,39 @@ GEM method_source (~> 1.0) pry-nav (1.0.0) pry (>= 0.9.10, < 0.15) - pry-rails (0.3.9) - pry (>= 0.10.4) + pry-rails (0.3.11) + pry (>= 0.13.0) psych (5.1.2) stringio - public_suffix (5.0.5) + public_suffix (6.0.0) puma (6.4.2) nio4r (~> 2.0) - racc (1.7.3) - rack (2.2.9) - rack-protection (3.2.0) + racc (1.8.0) + rack (3.1.4) + rack-protection (4.0.0) base64 (>= 0.1.0) - rack (~> 2.2, >= 2.2.4) - rack-session (1.0.2) - rack (< 3) + rack (>= 3.0.0, < 4) + rack-session (2.0.0) + rack (>= 3.0.0) rack-test (2.1.0) rack (>= 1.3) - rackup (1.0.0) - rack (< 3) - webrick - rails (7.1.3.2) - actioncable (= 7.1.3.2) - actionmailbox (= 7.1.3.2) - actionmailer (= 7.1.3.2) - actionpack (= 7.1.3.2) - actiontext (= 7.1.3.2) - actionview (= 7.1.3.2) - activejob (= 7.1.3.2) - activemodel (= 7.1.3.2) - activerecord (= 7.1.3.2) - activestorage (= 7.1.3.2) - activesupport (= 7.1.3.2) + rackup (2.1.0) + rack (>= 3) + webrick (~> 1.8) + rails (7.1.3.4) + actioncable (= 7.1.3.4) + actionmailbox (= 7.1.3.4) + actionmailer (= 7.1.3.4) + actionpack (= 7.1.3.4) + actiontext (= 7.1.3.4) + actionview (= 7.1.3.4) + activejob (= 7.1.3.4) + activemodel (= 7.1.3.4) + activerecord (= 7.1.3.4) + activestorage (= 7.1.3.4) + activesupport (= 7.1.3.4) bundler (>= 1.15.0) - railties (= 7.1.3.2) + railties (= 7.1.3.4) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -272,9 +272,9 @@ GEM rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) - railties (7.1.3.2) - actionpack (= 7.1.3.2) - activesupport (= 7.1.3.2) + railties (7.1.3.4) + actionpack (= 7.1.3.4) + activesupport (= 7.1.3.4) irb rackup (>= 1.0.0) rake (>= 12.2) @@ -283,15 +283,16 @@ GEM rainbow (3.1.1) rake (13.2.1) rb-fsevent (0.11.2) - rb-inotify (0.10.1) + rb-inotify (0.11.1) ffi (~> 1.0) rdoc (6.7.0) psych (>= 4.0.0) - regexp_parser (2.9.1) - reline (0.5.8) + regexp_parser (2.9.2) + reline (0.5.9) io-console (~> 0.5) - rexml (3.2.6) - rubocop (1.63.3) + rexml (3.3.1) + strscan + rubocop (1.63.5) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) @@ -331,13 +332,14 @@ GEM sprockets (4.2.1) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) - sprockets-rails (3.4.2) - actionpack (>= 5.2) - activesupport (>= 5.2) + sprockets-rails (3.5.1) + actionpack (>= 6.1) + activesupport (>= 6.1) sprockets (>= 3.0.0) sqlite3 (1.7.3-x64-mingw-ucrt) sqlite3 (1.7.3-x86_64-linux) - stringio (3.1.0) + stringio (3.1.1) + strscan (3.1.0) test-unit (3.6.2) power_assert thor (1.3.1) @@ -370,7 +372,7 @@ GEM websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.14) + zeitwerk (2.6.16) PLATFORMS x64-mingw-ucrt @@ -385,7 +387,7 @@ DEPENDENCIES docusign_admin (~> 1.3.0) docusign_click (~> 1.4.0) docusign_esign (~> 4.0.0.rc1) - docusign_maestro (~> 1.0.0.rc1) + docusign_maestro (~> 2.0.0.rc1) docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) jbuilder (~> 2.11.5) From a210a8535f36a4eee12821d7ad64b6f4a84fece2 Mon Sep 17 00:00:00 2001 From: inbargazit Date: Tue, 25 Jun 2024 13:54:35 -0700 Subject: [PATCH 329/363] Fixing again --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index a01a0d1..dac9d8f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -150,8 +150,8 @@ GEM faraday-net_http (>= 2.0, < 3.2) faraday-net_http (3.1.0) net-http - ffi (1.17.0-x64-mingw-ucrt) - ffi (1.17.0-x86_64-linux-gnu) + ffi (1.16.3) + ffi (1.16.3-x64-mingw-ucrt) globalid (1.2.1) activesupport (>= 6.1) hashie (5.0.0) From 42a32693bb783087a7d5e93e330b0f2f7052ddfd Mon Sep 17 00:00:00 2001 From: inbargazit Date: Tue, 25 Jun 2024 15:08:46 -0700 Subject: [PATCH 330/363] Updating images, SDK versions and improving the recipient auth examples --- Gemfile | 20 +- Gemfile.lock | 263 ++++++++------- .../eeg020_phone_authentication_controller.rb | 6 + .../eeg022_kba_authentication_controller.rb | 6 + .../eeg023_idv_authentication_controller.rb | 6 + .../mseg001_trigger_workflow_service.rb | 2 +- app/views/admin_api/index.html.erb | 4 +- app/views/clickwrap/index.html.erb | 4 +- app/views/ds_common/index.html.erb | 4 +- .../eeg020_phone_authentication/get.html.erb | 4 +- .../eeg022_kba_authentication/get.html.erb | 5 +- .../eeg023_idv_authentication/get.html.erb | 5 +- app/views/monitor_api/index.html.erb | 4 +- app/views/room_api/index.html.erb | 4 +- config/appsettings.example.yml | 2 +- jwt_console_project/jwt_console.rb | 2 +- public/banner-code.png | Bin 53558 -> 0 bytes public/header.png | Bin 0 -> 74963 bytes quick_acg/Gemfile | 18 +- quick_acg/Gemfile.lock | 306 ++++++++++-------- 20 files changed, 378 insertions(+), 287 deletions(-) delete mode 100644 public/banner-code.png create mode 100644 public/header.png diff --git a/Gemfile b/Gemfile index fb610f1..01b19fe 100644 --- a/Gemfile +++ b/Gemfile @@ -6,11 +6,11 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '~>3.1.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 7.0.4.3' +gem 'rails', '~> 7.1.3.2' # Use sqlite3 as the database for Active Record -gem 'sqlite3', '~> 1.6.1' +gem 'sqlite3', '~> 1.7.3' # Use Puma as the app server -gem 'puma', '~> 6.1.1' +gem 'puma', '~> 6.4.2' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets @@ -49,20 +49,20 @@ end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. - gem 'listen', '~> 3.8.0' - gem 'web-console', '~> 4.2.0' + gem 'listen', '~> 3.9.0' + gem 'web-console', '~> 4.2.1' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'pry-nav', '~> 1.0.0' gem 'pry-rails', '~> 0.3.9' - gem 'rubocop', '~> 1.48.1', require: false - gem 'spring', '~> 4.1.1' + gem 'rubocop', '~> 1.63.3', require: false + gem 'spring', '~> 4.2.1' gem 'spring-watcher-listen', '~> 2.1.0' end group :test do # Adds support for Capybara system testing and selenium driver - gem 'capybara', '~> 3.38.0' - gem 'selenium-webdriver', '~> 4.8.1' + gem 'capybara', '~> 3.40.0' + gem 'selenium-webdriver', '~> 4.19.0' # Easy installation and use of chromedriver to run system tests with Chrome gem 'chromedriver-helper', '~> 2.1.1' gem 'test-unit' @@ -71,7 +71,7 @@ end gem 'docusign_admin', '~> 1.3.0' gem 'docusign_click', '~> 1.4.0' gem 'docusign_esign', '~> 4.0.0.rc1' -gem 'docusign_maestro', '~> 1.0.0.rc1' +gem 'docusign_maestro', '~> 2.0.0.rc1' gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' gem 'omniauth-oauth2', '~> 1.8.0' diff --git a/Gemfile.lock b/Gemfile.lock index 9453977..dac9d8f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,73 +1,82 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.0.4.3) - actionpack (= 7.0.4.3) - activesupport (= 7.0.4.3) + actioncable (7.1.3.4) + actionpack (= 7.1.3.4) + activesupport (= 7.1.3.4) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.4.3) - actionpack (= 7.0.4.3) - activejob (= 7.0.4.3) - activerecord (= 7.0.4.3) - activestorage (= 7.0.4.3) - activesupport (= 7.0.4.3) + zeitwerk (~> 2.6) + actionmailbox (7.1.3.4) + actionpack (= 7.1.3.4) + activejob (= 7.1.3.4) + activerecord (= 7.1.3.4) + activestorage (= 7.1.3.4) + activesupport (= 7.1.3.4) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.0.4.3) - actionpack (= 7.0.4.3) - actionview (= 7.0.4.3) - activejob (= 7.0.4.3) - activesupport (= 7.0.4.3) + actionmailer (7.1.3.4) + actionpack (= 7.1.3.4) + actionview (= 7.1.3.4) + activejob (= 7.1.3.4) + activesupport (= 7.1.3.4) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp - rails-dom-testing (~> 2.0) - actionpack (7.0.4.3) - actionview (= 7.0.4.3) - activesupport (= 7.0.4.3) - rack (~> 2.0, >= 2.2.0) + rails-dom-testing (~> 2.2) + actionpack (7.1.3.4) + actionview (= 7.1.3.4) + activesupport (= 7.1.3.4) + nokogiri (>= 1.8.5) + racc + rack (>= 2.2.4) + rack-session (>= 1.0.1) rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.4.3) - actionpack (= 7.0.4.3) - activerecord (= 7.0.4.3) - activestorage (= 7.0.4.3) - activesupport (= 7.0.4.3) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + actiontext (7.1.3.4) + actionpack (= 7.1.3.4) + activerecord (= 7.1.3.4) + activestorage (= 7.1.3.4) + activesupport (= 7.1.3.4) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.4.3) - activesupport (= 7.0.4.3) + actionview (7.1.3.4) + activesupport (= 7.1.3.4) builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (7.0.4.3) - activesupport (= 7.0.4.3) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (7.1.3.4) + activesupport (= 7.1.3.4) globalid (>= 0.3.6) - activemodel (7.0.4.3) - activesupport (= 7.0.4.3) - activerecord (7.0.4.3) - activemodel (= 7.0.4.3) - activesupport (= 7.0.4.3) - activestorage (7.0.4.3) - actionpack (= 7.0.4.3) - activejob (= 7.0.4.3) - activerecord (= 7.0.4.3) - activesupport (= 7.0.4.3) + activemodel (7.1.3.4) + activesupport (= 7.1.3.4) + activerecord (7.1.3.4) + activemodel (= 7.1.3.4) + activesupport (= 7.1.3.4) + timeout (>= 0.4.0) + activestorage (7.1.3.4) + actionpack (= 7.1.3.4) + activejob (= 7.1.3.4) + activerecord (= 7.1.3.4) + activesupport (= 7.1.3.4) marcel (~> 1.0) - mini_mime (>= 1.1.0) - activesupport (7.0.4.3) + activesupport (7.1.3.4) + base64 + bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) minitest (>= 5.1) + mutex_m tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) archive-zip (0.12.0) io-like (~> 0.3.0) ast (2.4.2) @@ -76,13 +85,13 @@ GEM bindex (0.8.1) bootsnap (1.7.7) msgpack (~> 1.0) - builder (3.2.4) + builder (3.3.0) byebug (11.1.3) - capybara (3.38.0) + capybara (3.40.0) addressable matrix mini_mime (>= 0.1.3) - nokogiri (~> 1.8) + nokogiri (~> 1.11) rack (>= 1.6.0) rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) @@ -98,7 +107,8 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.2.3) + concurrent-ruby (1.3.3) + connection_pool (2.4.1) crass (1.0.6) date (3.3.4) docusign_admin (1.3.0) @@ -111,12 +121,12 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (4.0.0.rc1) + docusign_esign (4.0.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_maestro (1.0.0.rc1) + docusign_maestro (2.0.0.rc1) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -131,11 +141,12 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - erubi (1.12.0) + drb (2.2.1) + erubi (1.13.0) ethon (0.16.0) ffi (>= 1.15.0) execjs (2.9.1) - faraday (2.9.0) + faraday (2.9.2) faraday-net_http (>= 2.0, < 3.2) faraday-net_http (3.1.0) net-http @@ -146,14 +157,19 @@ GEM hashie (5.0.0) i18n (1.14.5) concurrent-ruby (~> 1.0) + io-console (0.7.2) io-like (0.3.1) + irb (1.13.2) + rdoc (>= 4.0.0) + reline (>= 0.4.2) jbuilder (2.11.5) actionview (>= 5.0.0) activesupport (>= 5.0.0) json (2.7.2) - jwt (2.8.1) + jwt (2.8.2) base64 - listen (3.8.0) + language_server-protocol (3.17.0.3) + listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) loofah (2.22.0) @@ -168,13 +184,14 @@ GEM matrix (0.4.2) method_source (1.1.0) mini_mime (1.1.5) - minitest (5.22.3) + minitest (5.24.0) msgpack (1.7.2) multi_xml (0.7.1) bigdecimal (~> 3.1) + mutex_m (0.2.0) net-http (0.4.1) uri - net-imap (0.4.11) + net-imap (0.4.14) date net-protocol net-pop (0.1.2) @@ -184,9 +201,9 @@ GEM net-smtp (0.5.0) net-protocol nio4r (2.7.3) - nokogiri (1.16.5-x64-mingw-ucrt) + nokogiri (1.16.6-x64-mingw-ucrt) racc (~> 1.4) - nokogiri (1.16.5-x86_64-linux) + nokogiri (1.16.6-x86_64-linux) racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) @@ -205,8 +222,8 @@ GEM omniauth-rails_csrf_protection (1.0.2) actionpack (>= 4.2) omniauth (~> 2.0) - parallel (1.24.0) - parser (3.3.1.0) + parallel (1.25.1) + parser (3.3.3.0) ast (~> 2.4.1) racc power_assert (2.0.3) @@ -215,32 +232,39 @@ GEM method_source (~> 1.0) pry-nav (1.0.0) pry (>= 0.9.10, < 0.15) - pry-rails (0.3.9) - pry (>= 0.10.4) - public_suffix (5.0.5) - puma (6.1.1) + pry-rails (0.3.11) + pry (>= 0.13.0) + psych (5.1.2) + stringio + public_suffix (6.0.0) + puma (6.4.2) nio4r (~> 2.0) - racc (1.7.3) - rack (2.2.9) - rack-protection (3.2.0) + racc (1.8.0) + rack (3.1.4) + rack-protection (4.0.0) base64 (>= 0.1.0) - rack (~> 2.2, >= 2.2.4) + rack (>= 3.0.0, < 4) + rack-session (2.0.0) + rack (>= 3.0.0) rack-test (2.1.0) rack (>= 1.3) - rails (7.0.4.3) - actioncable (= 7.0.4.3) - actionmailbox (= 7.0.4.3) - actionmailer (= 7.0.4.3) - actionpack (= 7.0.4.3) - actiontext (= 7.0.4.3) - actionview (= 7.0.4.3) - activejob (= 7.0.4.3) - activemodel (= 7.0.4.3) - activerecord (= 7.0.4.3) - activestorage (= 7.0.4.3) - activesupport (= 7.0.4.3) + rackup (2.1.0) + rack (>= 3) + webrick (~> 1.8) + rails (7.1.3.4) + actioncable (= 7.1.3.4) + actionmailbox (= 7.1.3.4) + actionmailer (= 7.1.3.4) + actionpack (= 7.1.3.4) + actiontext (= 7.1.3.4) + actionview (= 7.1.3.4) + activejob (= 7.1.3.4) + activemodel (= 7.1.3.4) + activerecord (= 7.1.3.4) + activestorage (= 7.1.3.4) + activesupport (= 7.1.3.4) bundler (>= 1.15.0) - railties (= 7.0.4.3) + railties (= 7.1.3.4) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -248,28 +272,35 @@ GEM rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) - railties (7.0.4.3) - actionpack (= 7.0.4.3) - activesupport (= 7.0.4.3) - method_source + railties (7.1.3.4) + actionpack (= 7.1.3.4) + activesupport (= 7.1.3.4) + irb + rackup (>= 1.0.0) rake (>= 12.2) - thor (~> 1.0) - zeitwerk (~> 2.5) + thor (~> 1.0, >= 1.2.2) + zeitwerk (~> 2.6) rainbow (3.1.1) rake (13.2.1) rb-fsevent (0.11.2) - rb-inotify (0.10.1) + rb-inotify (0.11.1) ffi (~> 1.0) - regexp_parser (2.9.1) - rexml (3.2.6) - rubocop (1.48.1) + rdoc (6.7.0) + psych (>= 4.0.0) + regexp_parser (2.9.2) + reline (0.5.9) + io-console (~> 0.5) + rexml (3.3.1) + strscan + rubocop (1.63.5) json (~> 2.3) + language_server-protocol (>= 3.17.0) parallel (~> 1.10) - parser (>= 3.2.0.0) + parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.26.0, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) rubocop-ast (1.31.3) @@ -286,26 +317,29 @@ GEM sprockets (> 3.0) sprockets-rails tilt - selenium-webdriver (4.8.6) + selenium-webdriver (4.19.0) + base64 (~> 0.2) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) snaky_hash (2.0.1) hashie version_gem (~> 1.1, >= 1.1.1) - spring (4.1.3) + spring (4.2.1) spring-watcher-listen (2.1.0) listen (>= 2.7, < 4.0) spring (>= 4) sprockets (4.2.1) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) - sprockets-rails (3.4.2) - actionpack (>= 5.2) - activesupport (>= 5.2) + sprockets-rails (3.5.1) + actionpack (>= 6.1) + activesupport (>= 6.1) sprockets (>= 3.0.0) - sqlite3 (1.6.9-x64-mingw-ucrt) - sqlite3 (1.6.9-x86_64-linux) + sqlite3 (1.7.3-x64-mingw-ucrt) + sqlite3 (1.7.3-x86_64-linux) + stringio (3.1.1) + strscan (3.1.0) test-unit (3.6.2) power_assert thor (1.3.1) @@ -331,13 +365,14 @@ GEM activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) + webrick (1.8.1) websocket (1.2.10) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.14) + zeitwerk (2.6.16) PLATFORMS x64-mingw-ucrt @@ -346,36 +381,36 @@ PLATFORMS DEPENDENCIES bootsnap (~> 1.7.3) byebug (~> 11.1.3) - capybara (~> 3.38.0) + capybara (~> 3.40.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) docusign_admin (~> 1.3.0) docusign_click (~> 1.4.0) docusign_esign (~> 4.0.0.rc1) - docusign_maestro (~> 1.0.0.rc1) + docusign_maestro (~> 2.0.0.rc1) docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) jbuilder (~> 2.11.5) - listen (~> 3.8.0) + listen (~> 3.9.0) matrix (~> 0.4.2) omniauth-oauth2 (~> 1.8.0) omniauth-rails_csrf_protection pry-nav (~> 1.0.0) pry-rails (~> 0.3.9) - puma (~> 6.1.1) - rails (~> 7.0.4.3) - rubocop (~> 1.48.1) + puma (~> 6.4.2) + rails (~> 7.1.3.2) + rubocop (~> 1.63.3) sass-rails (~> 6.0.0) - selenium-webdriver (~> 4.8.1) - spring (~> 4.1.1) + selenium-webdriver (~> 4.19.0) + spring (~> 4.2.1) spring-watcher-listen (~> 2.1.0) - sqlite3 (~> 1.6.1) + sqlite3 (~> 1.7.3) test-unit turbolinks (~> 5.2.1) tzinfo-data (~> 1.2022.7, >= 1.2022.7) uglifier (~> 4.2.0) wdm (>= 0.1.1) - web-console (~> 4.2.0) + web-console (~> 4.2.1) RUBY VERSION ruby 3.1.2p20 diff --git a/app/controllers/e_sign/eeg020_phone_authentication_controller.rb b/app/controllers/e_sign/eeg020_phone_authentication_controller.rb index d6ad9a5..92aa261 100644 --- a/app/controllers/e_sign/eeg020_phone_authentication_controller.rb +++ b/app/controllers/e_sign/eeg020_phone_authentication_controller.rb @@ -19,6 +19,12 @@ def create envelope_args: envelope_args } + if Rails.application.config.signer_email == envelope_args[:signer_email] + @error_code = 400 + @error_message = @manifest['SupportingTexts']['IdenticalEmailsNotAllowedErrorMessage'] + return render 'ds_common/error' + end + phone_auth_service = ESign::Eg020PhoneAuthenticationService.new(args) # Retrieve the workflow id diff --git a/app/controllers/e_sign/eeg022_kba_authentication_controller.rb b/app/controllers/e_sign/eeg022_kba_authentication_controller.rb index 25da5a1..3601b79 100644 --- a/app/controllers/e_sign/eeg022_kba_authentication_controller.rb +++ b/app/controllers/e_sign/eeg022_kba_authentication_controller.rb @@ -17,6 +17,12 @@ def create envelope_args: envelope_args } + if Rails.application.config.signer_email == envelope_args[:signer_email] + @error_code = 400 + @error_message = @manifest['SupportingTexts']['IdenticalEmailsNotAllowedErrorMessage'] + return render 'ds_common/error' + end + results = ESign::Eg022KbaAuthenticationService.new(args).worker session[:envelope_id] = results.envelope_id diff --git a/app/controllers/e_sign/eeg023_idv_authentication_controller.rb b/app/controllers/e_sign/eeg023_idv_authentication_controller.rb index 9620368..ccc50c2 100644 --- a/app/controllers/e_sign/eeg023_idv_authentication_controller.rb +++ b/app/controllers/e_sign/eeg023_idv_authentication_controller.rb @@ -17,6 +17,12 @@ def create envelope_args: envelope_args } + if Rails.application.config.signer_email == envelope_args[:signer_email] + @error_code = 400 + @error_message = @manifest['SupportingTexts']['IdenticalEmailsNotAllowedErrorMessage'] + return render 'ds_common/error' + end + results = ESign::Eg023IdvAuthenticationService.new(args).worker if results.to_s == 'idv_not_enabled' diff --git a/app/services/maestro_api/mseg001_trigger_workflow_service.rb b/app/services/maestro_api/mseg001_trigger_workflow_service.rb index bf7262d..4fcdd2e 100644 --- a/app/services/maestro_api/mseg001_trigger_workflow_service.rb +++ b/app/services/maestro_api/mseg001_trigger_workflow_service.rb @@ -65,7 +65,7 @@ def trigger_workflow(workflow) #ds-snippet-start:Maestro1Step5 workflow_trigger_api = DocuSign_Maestro::WorkflowTriggerApi.new(api_client) - workflow_trigger_api.trigger_workflow(args[:account_id], trigger_payload, trigger_options) + workflow_trigger_api.trigger_workflow(args[:account_id], args[:workflow_id], trigger_payload, trigger_options) #ds-snippet-end:Maestro1Step5 end end diff --git a/app/views/admin_api/index.html.erb b/app/views/admin_api/index.html.erb index 0747ff9..9ffac1e 100644 --- a/app/views/admin_api/index.html.erb +++ b/app/views/admin_api/index.html.erb @@ -1,5 +1,5 @@

    -
    +
    - +
    @@ -8,7 +8,7 @@

    Run and explore Docusign Admin API code examples with Authorization Code Grant or JWT Grant authentication

    diff --git a/app/views/clickwrap/index.html.erb b/app/views/clickwrap/index.html.erb index 2e8574f..5057376 100644 --- a/app/views/clickwrap/index.html.erb +++ b/app/views/clickwrap/index.html.erb @@ -1,6 +1,6 @@
    -
    +
    - +
    @@ -9,7 +9,7 @@

    Run and explore Click API code examples with Authorization Code Grant or JWT Grant authentication

    diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index cb5221e..86f2b79 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -1,6 +1,6 @@
    -
    - +
    +
    diff --git a/app/views/e_sign/eeg020_phone_authentication/get.html.erb b/app/views/e_sign/eeg020_phone_authentication/get.html.erb index 05f636b..2e930df 100644 --- a/app/views/e_sign/eeg020_phone_authentication/get.html.erb +++ b/app/views/e_sign/eeg020_phone_authentication/get.html.erb @@ -30,14 +30,14 @@ " required - value="<%= @config.signer_email %>" required> + required> <%= render('partials/email_will_not_be_shared') %>
    " name="signer_name" - value="<%= @config.signer_name %>" required> + required>
    <%= render('partials/submit_button') %> diff --git a/app/views/e_sign/eeg022_kba_authentication/get.html.erb b/app/views/e_sign/eeg022_kba_authentication/get.html.erb index 2fdf193..ac89ee5 100644 --- a/app/views/e_sign/eeg022_kba_authentication/get.html.erb +++ b/app/views/e_sign/eeg022_kba_authentication/get.html.erb @@ -13,15 +13,14 @@ " required - value="<%= @config.signer_email %>"> + placeholder="<%= @example["Forms"][form_index]["Inputs"][signer_email_index]["InputPlaceholder"] %>" required> <%= render('partials/email_will_not_be_shared') %>
    " name="signerName" - value="<%= @config.signer_name %>" required> + required>
    <%= render('partials/submit_button') %> \ No newline at end of file diff --git a/app/views/e_sign/eeg023_idv_authentication/get.html.erb b/app/views/e_sign/eeg023_idv_authentication/get.html.erb index 51ef8c1..90272df 100644 --- a/app/views/e_sign/eeg023_idv_authentication/get.html.erb +++ b/app/views/e_sign/eeg023_idv_authentication/get.html.erb @@ -13,15 +13,14 @@ " required - value="<%= @config.signer_email %>"> + placeholder="<%= @example["Forms"][form_index]["Inputs"][signer_email_index]["InputPlaceholder"] %>" required> <%= render('partials/email_will_not_be_shared') %>
    " name="signerName" - value="<%= @config.signer_name %>" required> + required>
    <%= render('partials/submit_button') %> diff --git a/app/views/monitor_api/index.html.erb b/app/views/monitor_api/index.html.erb index ce443c2..ad3cc1d 100644 --- a/app/views/monitor_api/index.html.erb +++ b/app/views/monitor_api/index.html.erb @@ -1,5 +1,5 @@
    -
    +
    @@ -8,7 +8,7 @@

    Run and explore eSignature REST API code examples with Authorization Code Grant or JWT Grant authentication

    - +
    @@ -8,7 +8,7 @@

    Run and explore Monitor API code examples with JWT Grant authentication

    diff --git a/app/views/room_api/index.html.erb b/app/views/room_api/index.html.erb index 3665763..fe0840f 100644 --- a/app/views/room_api/index.html.erb +++ b/app/views/room_api/index.html.erb @@ -1,6 +1,6 @@
    -
    +
    - +
    @@ -10,7 +10,7 @@ Code Grant).

    diff --git a/config/appsettings.example.yml b/config/appsettings.example.yml index 0b88d2b..9dac446 100644 --- a/config/appsettings.example.yml +++ b/config/appsettings.example.yml @@ -24,7 +24,7 @@ default: &default monitor_host: "https://lens-d.docusign.net" admin_host: "https://api-d.docusign.net/management" webforms_host: "https://apps-d.docusign.com/api/webforms/v1.1" - maestro_client_host: "https://demo.services.docusign.net/" + maestro_client_host: "https://apps-d.docusign.com/api/maestro" allow_silent_authentication: true # A user can be silently authenticated if they have an # Active login session on another tab of the same browser # Set if you want a specific Docusign AccountId, If false, the users default account will be used. diff --git a/jwt_console_project/jwt_console.rb b/jwt_console_project/jwt_console.rb index 820fba6..501a768 100644 --- a/jwt_console_project/jwt_console.rb +++ b/jwt_console_project/jwt_console.rb @@ -2,7 +2,7 @@ gemfile do source 'https://rubygems.org' - gem 'docusign_esign', ' ~> 3.22.0' + gem 'docusign_esign', ' ~> 3.27.0.rc1' end class ESign diff --git a/public/banner-code.png b/public/banner-code.png deleted file mode 100644 index 292d14e9eb8e14c7fdb570f769ae5d95af3829b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53558 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 LdK`IxC8YiX2lGP* diff --git a/public/header.png b/public/header.png new file mode 100644 index 0000000000000000000000000000000000000000..a7fcac18ebfa670cf77bdde4bc32105d9749596d GIT binary patch literal 74963 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 GJ@$X~{F7J! literal 0 HcmV?d00001 diff --git a/quick_acg/Gemfile b/quick_acg/Gemfile index 0d43063..9f14b3f 100644 --- a/quick_acg/Gemfile +++ b/quick_acg/Gemfile @@ -6,11 +6,11 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '~>3.1.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 7.0.4.3' +gem 'rails', '~> 7.1.3.2' # Use sqlite3 as the database for Active Record -gem 'sqlite3', '~> 1.6.1' +gem 'sqlite3', '~> 1.7.3' # Use Puma as the app server -gem 'puma', '~> 6.1.1' +gem 'puma', '~> 6.4.2' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets @@ -49,25 +49,25 @@ end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. - gem 'listen', '~> 3.8.0' - gem 'web-console', '~> 4.2.0' + gem 'listen', '~> 3.9.0' + gem 'web-console', '~> 4.2.1' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'pry-nav', '~> 1.0.0' gem 'pry-rails', '~> 0.3.9' - gem 'spring', '~> 4.1.1' + gem 'spring', '~> 4.2.1' gem 'spring-watcher-listen', '~> 2.1.0' end group :test do # Adds support for Capybara system testing and selenium driver - gem 'capybara', '~> 3.38.0' - gem 'selenium-webdriver', '~> 4.8.1' + gem 'capybara', '~> 3.40.0' + gem 'selenium-webdriver', '~> 4.19.0' # Easy installation and use of chromedriver to run system tests with Chrome gem 'chromedriver-helper', '~> 2.1.1' gem 'test-unit' end -gem 'docusign_esign', '~> 3.22.0' +gem 'docusign_esign', '~> 3.27.0.rc1' gem 'omniauth-oauth2', '~> 1.8.0' gem 'omniauth-rails_csrf_protection' diff --git a/quick_acg/Gemfile.lock b/quick_acg/Gemfile.lock index 30e4a57..80a99ff 100644 --- a/quick_acg/Gemfile.lock +++ b/quick_acg/Gemfile.lock @@ -1,85 +1,96 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.0.4.3) - actionpack (= 7.0.4.3) - activesupport (= 7.0.4.3) + actioncable (7.1.3.2) + actionpack (= 7.1.3.2) + activesupport (= 7.1.3.2) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.4.3) - actionpack (= 7.0.4.3) - activejob (= 7.0.4.3) - activerecord (= 7.0.4.3) - activestorage (= 7.0.4.3) - activesupport (= 7.0.4.3) + zeitwerk (~> 2.6) + actionmailbox (7.1.3.2) + actionpack (= 7.1.3.2) + activejob (= 7.1.3.2) + activerecord (= 7.1.3.2) + activestorage (= 7.1.3.2) + activesupport (= 7.1.3.2) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.0.4.3) - actionpack (= 7.0.4.3) - actionview (= 7.0.4.3) - activejob (= 7.0.4.3) - activesupport (= 7.0.4.3) + actionmailer (7.1.3.2) + actionpack (= 7.1.3.2) + actionview (= 7.1.3.2) + activejob (= 7.1.3.2) + activesupport (= 7.1.3.2) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp - rails-dom-testing (~> 2.0) - actionpack (7.0.4.3) - actionview (= 7.0.4.3) - activesupport (= 7.0.4.3) - rack (~> 2.0, >= 2.2.0) + rails-dom-testing (~> 2.2) + actionpack (7.1.3.2) + actionview (= 7.1.3.2) + activesupport (= 7.1.3.2) + nokogiri (>= 1.8.5) + racc + rack (>= 2.2.4) + rack-session (>= 1.0.1) rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.4.3) - actionpack (= 7.0.4.3) - activerecord (= 7.0.4.3) - activestorage (= 7.0.4.3) - activesupport (= 7.0.4.3) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + actiontext (7.1.3.2) + actionpack (= 7.1.3.2) + activerecord (= 7.1.3.2) + activestorage (= 7.1.3.2) + activesupport (= 7.1.3.2) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.4.3) - activesupport (= 7.0.4.3) + actionview (7.1.3.2) + activesupport (= 7.1.3.2) builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (7.0.4.3) - activesupport (= 7.0.4.3) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (7.1.3.2) + activesupport (= 7.1.3.2) globalid (>= 0.3.6) - activemodel (7.0.4.3) - activesupport (= 7.0.4.3) - activerecord (7.0.4.3) - activemodel (= 7.0.4.3) - activesupport (= 7.0.4.3) - activestorage (7.0.4.3) - actionpack (= 7.0.4.3) - activejob (= 7.0.4.3) - activerecord (= 7.0.4.3) - activesupport (= 7.0.4.3) + activemodel (7.1.3.2) + activesupport (= 7.1.3.2) + activerecord (7.1.3.2) + activemodel (= 7.1.3.2) + activesupport (= 7.1.3.2) + timeout (>= 0.4.0) + activestorage (7.1.3.2) + actionpack (= 7.1.3.2) + activejob (= 7.1.3.2) + activerecord (= 7.1.3.2) + activesupport (= 7.1.3.2) marcel (~> 1.0) - mini_mime (>= 1.1.0) - activesupport (7.0.4.3) + activesupport (7.1.3.2) + base64 + bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) minitest (>= 5.1) + mutex_m tzinfo (~> 2.0) - addressable (2.8.1) + addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) archive-zip (0.12.0) io-like (~> 0.3.0) + base64 (0.2.0) + bigdecimal (3.1.7) bindex (0.8.1) bootsnap (1.7.7) msgpack (~> 1.0) builder (3.2.4) byebug (11.1.3) - capybara (3.38.0) + capybara (3.40.0) addressable matrix mini_mime (>= 0.1.3) - nokogiri (~> 1.8) + nokogiri (~> 1.11) rack (>= 1.6.0) rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) @@ -95,63 +106,73 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.2.2) + concurrent-ruby (1.2.3) + connection_pool (2.4.1) crass (1.0.6) - date (3.3.3) - docusign_esign (3.22.0) + date (3.3.4) + docusign_esign (3.27.0.rc1) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) + drb (2.2.1) erubi (1.12.0) ethon (0.16.0) ffi (>= 1.15.0) - execjs (2.8.1) - faraday (2.7.4) - faraday-net_http (>= 2.0, < 3.1) - ruby2_keywords (>= 0.0.4) - faraday-net_http (3.0.2) - ffi (1.15.5-x64-mingw-ucrt) - globalid (1.1.0) - activesupport (>= 5.0) + execjs (2.9.1) + faraday (2.9.0) + faraday-net_http (>= 2.0, < 3.2) + faraday-net_http (3.1.0) + net-http + ffi (1.16.3-x64-mingw-ucrt) + globalid (1.2.1) + activesupport (>= 6.1) hashie (5.0.0) - i18n (1.12.0) + i18n (1.14.4) concurrent-ruby (~> 1.0) + io-console (0.7.2) io-like (0.3.1) + irb (1.12.0) + rdoc + reline (>= 0.4.2) jbuilder (2.11.5) actionview (>= 5.0.0) activesupport (>= 5.0.0) - json (2.6.3) - jwt (2.7.0) - listen (3.8.0) + json (2.7.2) + jwt (2.8.1) + base64 + listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.19.1) + loofah (2.22.0) crass (~> 1.0.2) - nokogiri (>= 1.5.9) + nokogiri (>= 1.12.0) mail (2.8.1) mini_mime (>= 0.1.1) net-imap net-pop net-smtp - marcel (1.0.2) + marcel (1.0.4) matrix (0.4.2) - method_source (1.0.0) - mini_mime (1.1.2) - minitest (5.18.0) - msgpack (1.6.1) + method_source (1.1.0) + mini_mime (1.1.5) + minitest (5.22.3) + msgpack (1.7.2) multi_xml (0.6.0) - net-imap (0.3.4) + mutex_m (0.2.0) + net-http (0.4.1) + uri + net-imap (0.4.10) date net-protocol net-pop (0.1.2) net-protocol - net-protocol (0.2.1) + net-protocol (0.2.2) timeout - net-smtp (0.3.3) + net-smtp (0.5.0) net-protocol - nio4r (2.5.8) - nokogiri (1.14.2-x64-mingw-ucrt) + nio4r (2.7.1) + nokogiri (1.16.4-x64-mingw-ucrt) racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) @@ -160,7 +181,7 @@ GEM rack (>= 1.2, < 4) snaky_hash (~> 2.0) version_gem (~> 1.1) - omniauth (2.1.1) + omniauth (2.1.2) hashie (>= 3.4.6) rack (>= 2.2.3) rack-protection @@ -178,48 +199,62 @@ GEM pry (>= 0.9.10, < 0.15) pry-rails (0.3.9) pry (>= 0.10.4) - public_suffix (5.0.1) - puma (6.1.1) + psych (5.1.2) + stringio + public_suffix (5.0.5) + puma (6.4.2) nio4r (~> 2.0) - racc (1.6.2) - rack (2.2.6.4) - rack-protection (3.0.5) - rack + racc (1.7.3) + rack (3.0.10) + rack-protection (4.0.0) + base64 (>= 0.1.0) + rack (>= 3.0.0, < 4) + rack-session (2.0.0) + rack (>= 3.0.0) rack-test (2.1.0) rack (>= 1.3) - rails (7.0.4.3) - actioncable (= 7.0.4.3) - actionmailbox (= 7.0.4.3) - actionmailer (= 7.0.4.3) - actionpack (= 7.0.4.3) - actiontext (= 7.0.4.3) - actionview (= 7.0.4.3) - activejob (= 7.0.4.3) - activemodel (= 7.0.4.3) - activerecord (= 7.0.4.3) - activestorage (= 7.0.4.3) - activesupport (= 7.0.4.3) + rackup (2.1.0) + rack (>= 3) + webrick (~> 1.8) + rails (7.1.3.2) + actioncable (= 7.1.3.2) + actionmailbox (= 7.1.3.2) + actionmailer (= 7.1.3.2) + actionpack (= 7.1.3.2) + actiontext (= 7.1.3.2) + actionview (= 7.1.3.2) + activejob (= 7.1.3.2) + activemodel (= 7.1.3.2) + activerecord (= 7.1.3.2) + activestorage (= 7.1.3.2) + activesupport (= 7.1.3.2) bundler (>= 1.15.0) - railties (= 7.0.4.3) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) + railties (= 7.1.3.2) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.5.0) - loofah (~> 2.19, >= 2.19.1) - railties (7.0.4.3) - actionpack (= 7.0.4.3) - activesupport (= 7.0.4.3) - method_source + rails-html-sanitizer (1.6.0) + loofah (~> 2.21) + nokogiri (~> 1.14) + railties (7.1.3.2) + actionpack (= 7.1.3.2) + activesupport (= 7.1.3.2) + irb + rackup (>= 1.0.0) rake (>= 12.2) - thor (~> 1.0) - zeitwerk (~> 2.5) - rake (13.0.6) + thor (~> 1.0, >= 1.2.2) + zeitwerk (~> 2.6) + rake (13.2.1) rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - regexp_parser (2.7.0) - rexml (3.2.5) - ruby2_keywords (0.0.5) + rdoc (6.6.3.1) + psych (>= 4.0.0) + regexp_parser (2.9.0) + reline (0.5.2) + io-console (~> 0.5) + rexml (3.2.6) rubyzip (2.3.2) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) @@ -231,34 +266,36 @@ GEM sprockets (> 3.0) sprockets-rails tilt - selenium-webdriver (4.8.1) + selenium-webdriver (4.19.0) + base64 (~> 0.2) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) snaky_hash (2.0.1) hashie version_gem (~> 1.1, >= 1.1.1) - spring (4.1.1) + spring (4.2.1) spring-watcher-listen (2.1.0) listen (>= 2.7, < 4.0) spring (>= 4) - sprockets (4.2.0) + sprockets (4.2.1) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) sprockets-rails (3.4.2) actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) - sqlite3 (1.6.1-x64-mingw-ucrt) - test-unit (3.5.7) + sqlite3 (1.7.3-x64-mingw-ucrt) + stringio (3.1.0) + test-unit (3.6.2) power_assert - thor (1.2.1) - tilt (2.1.0) - timeout (0.3.2) + thor (1.3.1) + tilt (2.3.0) + timeout (0.4.1) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) - typhoeus (1.4.0) + typhoeus (1.4.1) ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) @@ -266,19 +303,22 @@ GEM tzinfo (>= 1.0.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) - version_gem (1.1.2) - web-console (4.2.0) + uri (0.13.0) + version_gem (1.1.4) + wdm (0.1.1) + web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - websocket (1.2.9) - websocket-driver (0.7.5) + webrick (1.8.1) + websocket (1.2.10) + websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.7) + zeitwerk (2.6.13) PLATFORMS x64-mingw-ucrt @@ -286,32 +326,32 @@ PLATFORMS DEPENDENCIES bootsnap (~> 1.7.3) byebug (~> 11.1.3) - capybara (~> 3.38.0) + capybara (~> 3.40.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_esign (~> 3.22.0) + docusign_esign (~> 3.27.0.rc1) jbuilder (~> 2.11.5) - listen (~> 3.8.0) + listen (~> 3.9.0) omniauth-oauth2 (~> 1.8.0) omniauth-rails_csrf_protection pry-nav (~> 1.0.0) pry-rails (~> 0.3.9) - puma (~> 6.1.1) - rails (~> 7.0.4.3) + puma (~> 6.4.2) + rails (~> 7.1.3.2) sass-rails (~> 6.0.0) - selenium-webdriver (~> 4.8.1) - spring (~> 4.1.1) + selenium-webdriver (~> 4.19.0) + spring (~> 4.2.1) spring-watcher-listen (~> 2.1.0) - sqlite3 (~> 1.6.1) + sqlite3 (~> 1.7.3) test-unit turbolinks (~> 5.2.1) tzinfo-data (~> 1.2022.7, >= 1.2022.7) uglifier (~> 4.2.0) wdm (>= 0.1.1) - web-console (~> 4.2.0) + web-console (~> 4.2.1) RUBY VERSION ruby 3.1.2p20 BUNDLED WITH - 2.3.7 + 2.4.22 From 28ec052b21e38630086b4803036db0eb3be6b848 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 25 Jun 2024 15:32:50 -0700 Subject: [PATCH 331/363] Update README.md Signed-off-by: Inbar Gazit --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 103eb10..43a1a0f 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ # Ruby Launcher Code Examples +> +>### PLEASE! Share your feedback in a [two questions survey](https://docs.google.com/forms/d/e/1FAIpQLScPa74hwhJwi7XWDDj4-XZVOQTF9jJWgbIFEpulXokCqYWT4A/viewform?usp=pp_url&entry.680551577=Ruby). +> +> ### GitHub repo: [code-examples-ruby](./README.md) -This GitHub repo includes code examples for the Docusign Admin API, Click API, eSignature REST API, Monitor API, and Rooms API. To switch between API code examples, modify the `examples_API` setting in the appsettings.yml file. Set only one API type to `true` and set the remaining to `false`. +This GitHub repo includes code examples for the [Web Forms API](https://developers.docusign.com/docs/web-forms-api/), [Maestro API](https://developers.docusign.com/docs/maestro-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/). -If none of the API types are set to `true`, the Docusign eSignature REST API code examples will be shown. If multiple API types are set to `true`, only the first will be shown. ## Introduction This repo is a Ruby on Rails application that supports the following authentication workflows: From 64849c5709757cfbcbf3479a90c81a634cf52943 Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 25 Jun 2024 18:38:43 -0700 Subject: [PATCH 332/363] Update README.md Signed-off-by: Inbar Gazit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 43a1a0f..991049e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Ruby Launcher Code Examples > ->### PLEASE! Share your feedback in a [two questions survey](https://docs.google.com/forms/d/e/1FAIpQLScPa74hwhJwi7XWDDj4-XZVOQTF9jJWgbIFEpulXokCqYWT4A/viewform?usp=pp_url&entry.680551577=Ruby). +>### PLEASE! Share your feedback in a [two-question survey](https://docs.google.com/forms/d/e/1FAIpQLScPa74hwhJwi7XWDDj4-XZVOQTF9jJWgbIFEpulXokCqYWT4A/viewform?usp=pp_url&entry.680551577=Ruby). > > ### GitHub repo: [code-examples-ruby](./README.md) From a793b0c53fc74a540ae31b38aa9bddbd2273f5de Mon Sep 17 00:00:00 2001 From: inbargazit Date: Tue, 25 Jun 2024 18:39:41 -0700 Subject: [PATCH 333/363] Updating the README file --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 103eb10..991049e 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ # Ruby Launcher Code Examples +> +>### PLEASE! Share your feedback in a [two-question survey](https://docs.google.com/forms/d/e/1FAIpQLScPa74hwhJwi7XWDDj4-XZVOQTF9jJWgbIFEpulXokCqYWT4A/viewform?usp=pp_url&entry.680551577=Ruby). +> +> ### GitHub repo: [code-examples-ruby](./README.md) -This GitHub repo includes code examples for the Docusign Admin API, Click API, eSignature REST API, Monitor API, and Rooms API. To switch between API code examples, modify the `examples_API` setting in the appsettings.yml file. Set only one API type to `true` and set the remaining to `false`. +This GitHub repo includes code examples for the [Web Forms API](https://developers.docusign.com/docs/web-forms-api/), [Maestro API](https://developers.docusign.com/docs/maestro-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/). -If none of the API types are set to `true`, the Docusign eSignature REST API code examples will be shown. If multiple API types are set to `true`, only the first will be shown. ## Introduction This repo is a Ruby on Rails application that supports the following authentication workflows: From 4e72270a0b1abb30a3ac354a2e3b8636454a19e8 Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Thu, 22 Aug 2024 10:50:48 -0700 Subject: [PATCH 334/363] DEVDOCS-15065 removing outdated comment --- Gemfile.lock | 4 ++++ .../webforms/weg001_create_instance/web_form_embed.html.erb | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 066c615..c828bc3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -208,6 +208,8 @@ GEM nio4r (2.7.3) nokogiri (1.16.6-x64-mingw-ucrt) racc (~> 1.4) + nokogiri (1.16.6-x86_64-darwin) + racc (~> 1.4) nokogiri (1.16.6-x86_64-linux) racc (~> 1.4) oauth2 (2.0.9) @@ -342,6 +344,7 @@ GEM activesupport (>= 6.1) sprockets (>= 3.0.0) sqlite3 (1.7.3-x64-mingw-ucrt) + sqlite3 (1.7.3-x86_64-darwin) sqlite3 (1.7.3-x86_64-linux) stringio (3.1.1) strscan (3.1.0) @@ -381,6 +384,7 @@ GEM PLATFORMS x64-mingw-ucrt + x86_64-darwin-21 x86_64-linux DEPENDENCIES diff --git a/app/views/webforms/weg001_create_instance/web_form_embed.html.erb b/app/views/webforms/weg001_create_instance/web_form_embed.html.erb index ce23ef0..c42be1c 100644 --- a/app/views/webforms/weg001_create_instance/web_form_embed.html.erb +++ b/app/views/webforms/weg001_create_instance/web_form_embed.html.erb @@ -68,8 +68,6 @@ }); webFormWidget.on('sessionEnd', (event) => { - //There are 3 sessionEnd types sessionTimeout, remoteSigningInitiated, signingResult - // event = { type: 'sessionEnd', sessionEndType: 'sessionTimeout' }; // event = { // type: 'sessionEnd', From d0536b046ed7562217c85496da700b4218cf54f7 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Thu, 12 Sep 2024 13:08:18 +0300 Subject: [PATCH 335/363] add code example --- Gemfile | 2 +- Gemfile.lock | 4 +- .../aeg013_create_account_controller.rb | 38 ++ .../admin_api/eg013_create_account_service.rb | 62 ++ app/services/jwt_auth/jwt_creator.rb | 268 ++++---- .../aeg013_create_account/get.html.erb | 29 + config/initializers/omniauth.rb | 114 ++-- config/routes.rb | 577 +++++++++--------- 8 files changed, 613 insertions(+), 481 deletions(-) create mode 100644 app/controllers/admin_api/aeg013_create_account_controller.rb create mode 100644 app/services/admin_api/eg013_create_account_service.rb create mode 100644 app/views/admin_api/aeg013_create_account/get.html.erb diff --git a/Gemfile b/Gemfile index d8924a2..2f2c04f 100644 --- a/Gemfile +++ b/Gemfile @@ -68,7 +68,7 @@ group :test do gem 'test-unit' end -gem 'docusign_admin', '~> 1.3.0' +gem 'docusign_admin', '~> 2.0.0.rc1' gem 'docusign_click', '~> 1.4.0' gem 'docusign_esign', '~> 4.0.0.rc1' gem 'docusign_maestro', '~> 2.0.0.rc1' diff --git a/Gemfile.lock b/Gemfile.lock index c828bc3..e1663a5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -111,7 +111,7 @@ GEM connection_pool (2.4.1) crass (1.0.6) date (3.3.4) - docusign_admin (1.3.0) + docusign_admin (2.0.0.rc1) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -393,7 +393,7 @@ DEPENDENCIES capybara (~> 3.40.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_admin (~> 1.3.0) + docusign_admin (~> 2.0.0.rc1) docusign_click (~> 1.4.0) docusign_esign (~> 4.0.0.rc1) docusign_maestro (~> 2.0.0.rc1) diff --git a/app/controllers/admin_api/aeg013_create_account_controller.rb b/app/controllers/admin_api/aeg013_create_account_controller.rb new file mode 100644 index 0000000..c3bd95c --- /dev/null +++ b/app/controllers/admin_api/aeg013_create_account_controller.rb @@ -0,0 +1,38 @@ +class AdminApi::Aeg013CreateAccountController < EgController + before_action -> { check_auth('Admin') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 13, 'Admin') } + + def create + args = { + access_token: session['ds_access_token'], + organization_id: session['organization_id'], + subscription_id: session['subscription_id'], + plan_id: session['plan_id'], + email: param_gsub(params['email']), + first_name: param_gsub(params['first_name']), + last_name: param_gsub(params['last_name']) + } + + results = AdminApi::Eg013CreateAccountService.new(args).worker + + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) + end + + def get + super + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? + args = { + access_token: session['ds_access_token'], + organization_id: session['organization_id'] + } + plan_items = AdminApi::Eg013CreateAccountService.new(args).get_organization_plan_items + print plan_items + session['subscription_id'] = plan_items[0].subscription_id + session['plan_id'] = plan_items[0].plan_id + end +end diff --git a/app/services/admin_api/eg013_create_account_service.rb b/app/services/admin_api/eg013_create_account_service.rb new file mode 100644 index 0000000..b1ffa7c --- /dev/null +++ b/app/services/admin_api/eg013_create_account_service.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +class AdminApi::Eg013CreateAccountService + attr_reader :args + + def initialize(args) + @args = args + end + + def worker + #ds-snippet-start:Admin13Step2 + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:Admin13Step2 + + #ds-snippet-start:Admin13Step4 + source_account = DocuSign_Admin::AssetGroupAccountCloneSourceAccount.new + source_account.id = args[:source_account_id] + + target_account_admin = DocuSign_Admin::SubAccountCreateRequestSubAccountCreationTargetAccountAdmin.new + target_account_admin.first_name = args[:first_name] + target_account_admin.last_name = args[:last_name] + target_account_admin.email = args[:email] + target_account_admin.locale = 'en' + + target_account = DocuSign_Admin::SubAccountCreateRequestSubAccountCreationTargetAccountDetails.new + target_account.name = 'CreatedThroughAPI' + target_account.admin = target_account_admin + target_account.country_code = 'US' + + subscription_details = DocuSign_Admin::SubAccountCreateRequestSubAccountCreationSubscription.new + subscription_details.id = args[:subscription_id] + subscription_details.plan_id = args[:plan_id] + subscription_details.modules = [] + + account_data = DocuSign_Admin::SubAccountCreateRequest.new + account_data.subscription_details = subscription_details + account_data.target_account = target_account + #ds-snippet-end:Admin13Step4 + + #ds-snippet-start:Admin13Step5 + asset_group_api = DocuSign_Admin::ProvisionAssetGroupApi.new(api_client) + asset_group_api.create_asset_group_account(args[:organization_id], account_data) + #ds-snippet-end:Admin13Step5 + end + + def get_organization_plan_items + configuration = DocuSign_Admin::Configuration.new + configuration.host = Rails.configuration.admin_host + + api_client = DocuSign_Admin::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + + #ds-snippet-start:Admin13Step3 + asset_group_api = DocuSign_Admin::ProvisionAssetGroupApi.new(api_client) + asset_group_api.get_organization_plan_items(args[:organization_id]) + #ds-snippet-end:Admin13Step3 + end +end diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index 88598fe..f344aa1 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -1,134 +1,134 @@ -require 'yaml' - -module JwtAuth - class JwtCreator - include ApiCreator - - attr_reader :session, :api_client, :state - - # Docusign authorization URI to obtain individual consent - # https://developers.docusign.com/platform/auth/jwt/jwt-get-token - # https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/ - def self.consent_url(state, api) - # GET /oauth/auth - # This endpoint is used to obtain consent and is the first step in several authentication flows. - # https://developers.docusign.com/platform/auth/reference/obtain-consent - scope = 'signature impersonation' if %w[eSignature Monitor].include?(api) - scope = 'signature impersonation 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' if api == 'Rooms' - scope = 'signature impersonation click.manage click.send' if api == 'Click' - scope = 'signature impersonation organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read' if api == 'Admin' - scope = 'signature webforms_read webforms_instance_read webforms_instance_write' if api == 'WebForms' - scope = 'signature aow_manage' if api == 'Maestro' - - base_uri = "#{Rails.configuration.authorization_server}/oauth/auth" - response_type = 'code' - scopes = ERB::Util.url_encode(scope) # https://developers.docusign.com/platform/auth/reference/scopes/ - client_id = Rails.configuration.jwt_integration_key - redirect_uri = "#{Rails.configuration.app_url}/auth/docusign/callback" - consent_url = "#{base_uri}?response_type=#{response_type}&scope=#{scopes}&client_id=#{client_id}&state=#{state}&redirect_uri=#{redirect_uri}" - Rails.logger.info "==> Obtain Consent Grant required: #{consent_url}" - consent_url - end - - def initialize(session) - @session = session - scope = 'signature impersonation' - @client_module = DocuSign_eSign - if session[:api] == 'Rooms' - scope = "#{scope} 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" - @client_module = DocuSign_Rooms - end - if session[:api] == 'Click' - scope = 'signature click.manage click.send' - @client_module = DocuSign_Click - end - @client_module = DocuSign_Monitor if session[:api] == 'Monitor' - if session[:api] == 'Admin' - scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read' - @client_module = DocuSign_Admin - end - if session[:api] == 'WebForms' - scope = 'signature webforms_read webforms_instance_read webforms_instance_write' - @client_module = DocuSign_WebForms - end - - @scope = scope - @api_client = create_initial_api_client(host: Rails.configuration.aud, client_module: @client_module, debugging: false) - end - - # @return [Boolean] `true` if the token was successfully updated, `false` if consent still needs to be grant'ed - def check_jwt_token - rsa_pk = docusign_rsa_private_key_file - begin - # docusign_esign: POST /oauth/token - # This endpoint enables you to exchange an authorization code or JWT token for an access token. - # https://developers.docusign.com/platform/auth/reference/obtain-access-token - token = api_client.request_jwt_user_token(Rails.configuration.jwt_integration_key, Rails.configuration.impersonated_user_guid, rsa_pk, 3600, @scope) - rescue OpenSSL::PKey::RSAError => e - Rails.logger.error e.inspect - raise "Please add your private RSA key to: #{rsa_pk}" if File.read(rsa_pk).starts_with? '{RSA_PRIVATE_KEY}' - - raise - rescue @client_module::ApiError => e - Rails.logger.warn e.inspect - - return false if e.response_body.nil? - - body = JSON.parse(e.response_body) - - if body['error'] == 'consent_required' - false - else - details = <<~TXT - See: https://support.docusign.com/articles/DocuSign-Developer-Support-FAQs#Troubleshoot-JWT-invalid_grant - or https://developers.docusign.com/esign-rest-api/guides/authentication/oauth2-code-grant#troubleshooting-errors - or try enabling `configuration.debugging = true` in the initialize method above for more logging output - TXT - raise "JWT response error: `#{body}`. #{details}" - end - else - update_account_info(token) - true - end - end - - private - - def update_account_info(token) - # docusign_esign: GET /oauth/userinfo - # This endpoint returns information on the caller, including their name, email, account, and organizational information. - # The response includes the base_uri needed to interact with the Docusign APIs. - # https://developers.docusign.com/platform/auth/reference/user-info - user_info_response = api_client.get_user_info(token.access_token) - accounts = user_info_response.accounts - target_account_id = Rails.configuration.target_account_id - account = get_account(accounts, target_account_id) - store_data(token, user_info_response, account) - - api_client.config.host = account.base_uri - Rails.logger.info "==> JWT: Received token for impersonated user which will expire in: #{token.expires_in.to_i.seconds / 1.hour} hour at: #{Time.at(token.expires_in.to_i.seconds.from_now)}" - end - - def store_data(token, user_info, account) - session[:ds_access_token] = token.access_token - session[:ds_expires_at] = token.expires_in.to_i.seconds.from_now.to_i - session[:ds_user_name] = user_info.name - session[:ds_account_id] = account.account_id - session[:ds_base_path] = account.base_uri - session[:ds_account_name] = account.account_name - end - - def get_account(accounts, target_account_id) - if target_account_id.present? - return accounts.find { |acct| acct.account_id == target_account_id } - raise "The user does not have access to account #{target_account_id}" - else - accounts.find(&:is_default) - end - end - - def docusign_rsa_private_key_file - File.join(Rails.root, 'config', 'docusign_private_key.txt') - end - end -end +require 'yaml' + +module JwtAuth + class JwtCreator + include ApiCreator + + attr_reader :session, :api_client, :state + + # Docusign authorization URI to obtain individual consent + # https://developers.docusign.com/platform/auth/jwt/jwt-get-token + # https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/ + def self.consent_url(state, api) + # GET /oauth/auth + # This endpoint is used to obtain consent and is the first step in several authentication flows. + # https://developers.docusign.com/platform/auth/reference/obtain-consent + scope = 'signature impersonation' if %w[eSignature Monitor].include?(api) + scope = 'signature impersonation 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' if api == 'Rooms' + scope = 'signature impersonation click.manage click.send' if api == 'Click' + scope = 'signature impersonation organization_read group_read permission_read user_read user_write 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_write organization_sub_account_read' if api == 'Admin' + scope = 'signature webforms_read webforms_instance_read webforms_instance_write' if api == 'WebForms' + scope = 'signature aow_manage' if api == 'Maestro' + + base_uri = "#{Rails.configuration.authorization_server}/oauth/auth" + response_type = 'code' + scopes = ERB::Util.url_encode(scope) # https://developers.docusign.com/platform/auth/reference/scopes/ + client_id = Rails.configuration.jwt_integration_key + redirect_uri = "#{Rails.configuration.app_url}/auth/docusign/callback" + consent_url = "#{base_uri}?response_type=#{response_type}&scope=#{scopes}&client_id=#{client_id}&state=#{state}&redirect_uri=#{redirect_uri}" + Rails.logger.info "==> Obtain Consent Grant required: #{consent_url}" + consent_url + end + + def initialize(session) + @session = session + scope = 'signature impersonation' + @client_module = DocuSign_eSign + if session[:api] == 'Rooms' + scope = "#{scope} 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" + @client_module = DocuSign_Rooms + end + if session[:api] == 'Click' + scope = 'signature click.manage click.send' + @client_module = DocuSign_Click + end + @client_module = DocuSign_Monitor if session[:api] == 'Monitor' + if session[:api] == 'Admin' + scope = 'signature organization_read group_read permission_read user_read user_write 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_write organization_sub_account_read' + @client_module = DocuSign_Admin + end + if session[:api] == 'WebForms' + scope = 'signature webforms_read webforms_instance_read webforms_instance_write' + @client_module = DocuSign_WebForms + end + + @scope = scope + @api_client = create_initial_api_client(host: Rails.configuration.aud, client_module: @client_module, debugging: false) + end + + # @return [Boolean] `true` if the token was successfully updated, `false` if consent still needs to be grant'ed + def check_jwt_token + rsa_pk = docusign_rsa_private_key_file + begin + # docusign_esign: POST /oauth/token + # This endpoint enables you to exchange an authorization code or JWT token for an access token. + # https://developers.docusign.com/platform/auth/reference/obtain-access-token + token = api_client.request_jwt_user_token(Rails.configuration.jwt_integration_key, Rails.configuration.impersonated_user_guid, rsa_pk, 3600, @scope) + rescue OpenSSL::PKey::RSAError => e + Rails.logger.error e.inspect + raise "Please add your private RSA key to: #{rsa_pk}" if File.read(rsa_pk).starts_with? '{RSA_PRIVATE_KEY}' + + raise + rescue @client_module::ApiError => e + Rails.logger.warn e.inspect + + return false if e.response_body.nil? + + body = JSON.parse(e.response_body) + + if body['error'] == 'consent_required' + false + else + details = <<~TXT + See: https://support.docusign.com/articles/DocuSign-Developer-Support-FAQs#Troubleshoot-JWT-invalid_grant + or https://developers.docusign.com/esign-rest-api/guides/authentication/oauth2-code-grant#troubleshooting-errors + or try enabling `configuration.debugging = true` in the initialize method above for more logging output + TXT + raise "JWT response error: `#{body}`. #{details}" + end + else + update_account_info(token) + true + end + end + + private + + def update_account_info(token) + # docusign_esign: GET /oauth/userinfo + # This endpoint returns information on the caller, including their name, email, account, and organizational information. + # The response includes the base_uri needed to interact with the Docusign APIs. + # https://developers.docusign.com/platform/auth/reference/user-info + user_info_response = api_client.get_user_info(token.access_token) + accounts = user_info_response.accounts + target_account_id = Rails.configuration.target_account_id + account = get_account(accounts, target_account_id) + store_data(token, user_info_response, account) + + api_client.config.host = account.base_uri + Rails.logger.info "==> JWT: Received token for impersonated user which will expire in: #{token.expires_in.to_i.seconds / 1.hour} hour at: #{Time.at(token.expires_in.to_i.seconds.from_now)}" + end + + def store_data(token, user_info, account) + session[:ds_access_token] = token.access_token + session[:ds_expires_at] = token.expires_in.to_i.seconds.from_now.to_i + session[:ds_user_name] = user_info.name + session[:ds_account_id] = account.account_id + session[:ds_base_path] = account.base_uri + session[:ds_account_name] = account.account_name + end + + def get_account(accounts, target_account_id) + if target_account_id.present? + return accounts.find { |acct| acct.account_id == target_account_id } + raise "The user does not have access to account #{target_account_id}" + else + accounts.find(&:is_default) + end + end + + def docusign_rsa_private_key_file + File.join(Rails.root, 'config', 'docusign_private_key.txt') + end + end +end diff --git a/app/views/admin_api/aeg013_create_account/get.html.erb b/app/views/admin_api/aeg013_create_account/get.html.erb new file mode 100644 index 0000000..32c5dc0 --- /dev/null +++ b/app/views/admin_api/aeg013_create_account/get.html.erb @@ -0,0 +1,29 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% email_index = 0 %> +<% first_name_index = 1 %> +<% last_name_index = 2 %> + +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +

    + + +
    +
    + + +
    +
    + + +
    + <%= render('partials/submit_button') %> + diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 65c5b37..665d8b3 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -1,57 +1,57 @@ -# frozen_string_literal: true - -require 'docusign' - -# Defaults to STDOUT: https://github.com/omniauth/omniauth#logging -# Logs entries like: -# (docusign) Setup endpoint detected, running now. -# (docusign) Request phase initiated. -# (docusign) Callback phase initiated. -OmniAuth.config.logger = Rails.logger - -# https://github.com/omniauth/omniauth/wiki/FAQ#omniauthfailureendpoint-does-not-redirect-in-development-mode -# otherwise a callback exception like the following will not get caught: -# OmniAuth::Strategies::OAuth2::CallbackError (access_denied) -# GET "/auth/docusign/callback?error=access_denied&error_message=The%20user%20did%20not%20consent%20to%20connecting%20the%20application.&state= -# OmniAuth.config.failure_raise_out_environments = [] # defaults to: ['development'] - -OmniAuth.config.allowed_request_methods = %i[post get] - -config = Rails.application.config -config.middleware.use OmniAuth::Builder do - # OAuth2 login request configuration - # OAuth2 login response callback message configuration is in OmniAuth::Strategies::Docusign in lib/docusign.rb - provider :docusign, config.integration_key, config.integration_secret, setup: lambda { |env| - strategy = env['omniauth.strategy'] - - # params = strategy.request.params - # examples_API = params['examples_API'] - # strategy.request.params.delete('examples_API') - - strategy.options[:client_options].site = config.app_url - strategy.options[:prompt] = 'login' - strategy.options[:oauth_base_uri] = config.authorization_server - strategy.options[:target_account_id] = config.target_account_id - strategy.options[:allow_silent_authentication] = config.allow_silent_authentication - strategy.options[:client_options].authorize_url = "#{strategy.options[:oauth_base_uri]}/oauth/auth" - strategy.options[:client_options].user_info_url = "#{strategy.options[:oauth_base_uri]}/oauth/userinfo" - strategy.options[:client_options].token_url = "#{strategy.options[:oauth_base_uri]}/oauth/token" - strategy.options[:authorize_params].prompt = strategy.options.prompt unless strategy.options[:allow_silent_authentication] - session = strategy.session - - case session[:api] - when 'eSignature' - strategy.options[:authorize_params].scope = 'signature' - when 'Rooms' - strategy.options[:authorize_params].scope = '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' - when 'Click' - strategy.options[:authorize_params].scope = 'signature click.manage click.send' - when 'Admin' - strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read' - when 'WebForms' - strategy.options[:authorize_params].scope = 'signature webforms_read webforms_instance_read webforms_instance_write' - when 'Maestro' - strategy.options[:authorize_params].scope = 'signature aow_manage' - end - } -end +# frozen_string_literal: true + +require 'docusign' + +# Defaults to STDOUT: https://github.com/omniauth/omniauth#logging +# Logs entries like: +# (docusign) Setup endpoint detected, running now. +# (docusign) Request phase initiated. +# (docusign) Callback phase initiated. +OmniAuth.config.logger = Rails.logger + +# https://github.com/omniauth/omniauth/wiki/FAQ#omniauthfailureendpoint-does-not-redirect-in-development-mode +# otherwise a callback exception like the following will not get caught: +# OmniAuth::Strategies::OAuth2::CallbackError (access_denied) +# GET "/auth/docusign/callback?error=access_denied&error_message=The%20user%20did%20not%20consent%20to%20connecting%20the%20application.&state= +# OmniAuth.config.failure_raise_out_environments = [] # defaults to: ['development'] + +OmniAuth.config.allowed_request_methods = %i[post get] + +config = Rails.application.config +config.middleware.use OmniAuth::Builder do + # OAuth2 login request configuration + # OAuth2 login response callback message configuration is in OmniAuth::Strategies::Docusign in lib/docusign.rb + provider :docusign, config.integration_key, config.integration_secret, setup: lambda { |env| + strategy = env['omniauth.strategy'] + + # params = strategy.request.params + # examples_API = params['examples_API'] + # strategy.request.params.delete('examples_API') + + strategy.options[:client_options].site = config.app_url + strategy.options[:prompt] = 'login' + strategy.options[:oauth_base_uri] = config.authorization_server + strategy.options[:target_account_id] = config.target_account_id + strategy.options[:allow_silent_authentication] = config.allow_silent_authentication + strategy.options[:client_options].authorize_url = "#{strategy.options[:oauth_base_uri]}/oauth/auth" + strategy.options[:client_options].user_info_url = "#{strategy.options[:oauth_base_uri]}/oauth/userinfo" + strategy.options[:client_options].token_url = "#{strategy.options[:oauth_base_uri]}/oauth/token" + strategy.options[:authorize_params].prompt = strategy.options.prompt unless strategy.options[:allow_silent_authentication] + session = strategy.session + + case session[:api] + when 'eSignature' + strategy.options[:authorize_params].scope = 'signature' + when 'Rooms' + strategy.options[:authorize_params].scope = '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' + when 'Click' + strategy.options[:authorize_params].scope = 'signature click.manage click.send' + when 'Admin' + strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write 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_write organization_sub_account_read' + when 'WebForms' + strategy.options[:authorize_params].scope = 'signature webforms_read webforms_instance_read webforms_instance_write' + when 'Maestro' + strategy.options[:authorize_params].scope = 'signature aow_manage' + end + } +end diff --git a/config/routes.rb b/config/routes.rb index a1078c3..2894d53 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,287 +1,290 @@ -# frozen_string_literal: true - -Rails.application.routes.draw do - scope module: 'room_api' do - get 'reg001' => 'reg001_create_room_with_data#get' - post 'reg001' => 'reg001_create_room_with_data#create' - - get 'reg002' => 'reg002_create_room_with_template#get' - post 'reg002' => 'reg002_create_room_with_template#create' - - get 'reg003' => 'reg003_export_data_from_room#get' - post 'reg003' => 'reg003_export_data_from_room#create' - - get 'reg004' => 'reg004_add_forms_to_room#get' - post 'reg004' => 'reg004_add_forms_to_room#create' - - get 'reg005' => 'reg005_get_rooms_with_filters#get' - post 'reg005' => 'reg005_get_rooms_with_filters#create' - - get 'reg006' => 'reg006_create_an_external_form_fill_session#get_rooms' - get 'reg006_forms' => 'reg006_create_an_external_form_fill_session#get_forms' - post 'reg006' => 'reg006_create_an_external_form_fill_session#create' - - get 'reg007' => 'reg007_create_form_group#get' - post 'reg007' => 'reg007_create_form_group#create' - - get 'reg008' => 'reg008_grant_office_access_to_form_group#get' - post 'reg008' => 'reg008_grant_office_access_to_form_group#create' - - get 'reg009' => 'reg009_assign_form_to_form_group#get' - post 'reg009' => 'reg009_assign_form_to_form_group#create' - end - - scope module: 'clickwrap' do - get 'ceg001' => 'ceg001_create_clickwrap#get' - post 'ceg001' => 'ceg001_create_clickwrap#create' - - get 'ceg002' => 'ceg002_activate_clickwrap#get' - post 'ceg002' => 'ceg002_activate_clickwrap#create' - - get 'ceg003' => 'ceg003_create_new_clickwrap_version#get' - post 'ceg003' => 'ceg003_create_new_clickwrap_version#create' - - get 'ceg004' => 'ceg004_list_clickwraps#get' - post 'ceg004' => 'ceg004_list_clickwraps#create' - - get 'ceg005' => 'ceg005_clickwrap_responses#get' - post 'ceg005' => 'ceg005_clickwrap_responses#create' - - get 'ceg006' => 'ceg006_embed_clickwrap#get' - post 'ceg006' => 'ceg006_embed_clickwrap#create' - end - - scope module: 'monitor_api' do - get 'meg001' => 'meg001_get_monitoring_dataset#get' - post 'meg001' => 'meg001_get_monitoring_dataset#create' - end - - scope module: 'admin_api' do - get 'aeg001' => 'aeg001_create_user#get' - post 'aeg001' => 'aeg001_create_user#create' - - get 'aeg002' => 'aeg002_create_active_clm_esign_user#get' - post 'aeg002' => 'aeg002_create_active_clm_esign_user#create' - - get 'aeg003' => 'aeg003_bulk_export_user_data#get' - post 'aeg003' => 'aeg003_bulk_export_user_data#create' - - get 'aeg004' => 'aeg004_import_user#get' - post 'aeg004' => 'aeg004_import_user#create' - get 'aeg004status' => 'aeg004_import_user#check_status' - - get 'aeg005' => 'aeg005_audit_users#get' - post 'aeg005' => 'aeg005_audit_users#create' - - get 'aeg006' => 'aeg006_get_user_profile_by_email#get' - post 'aeg006' => 'aeg006_get_user_profile_by_email#create' - - get 'aeg007' => 'aeg007_get_user_profile_by_user_id#get' - post 'aeg007' => 'aeg007_get_user_profile_by_user_id#create' - - get 'aeg008' => 'aeg008_update_user_product_permission_profile#get' - post 'aeg008' => 'aeg008_update_user_product_permission_profile#create' - - get 'aeg009' => 'aeg009_delete_user_product_permission_profile#get' - post 'aeg009' => 'aeg009_delete_user_product_permission_profile#create' - - get 'aeg010' => 'aeg010_delete_user_data_from_organization#get' - post 'aeg010' => 'aeg010_delete_user_data_from_organization#create' - - get 'aeg011' => 'aeg011_delete_user_data_from_account#get' - post 'aeg011' => 'aeg011_delete_user_data_from_account#create' - - get 'aeg012' => 'aeg012_clone_account#get' - post 'aeg012' => 'aeg012_clone_account#create' - end - - get '/eeg001' => 'eeg001_embedded_signing#get' - post '/eeg001' => 'eeg001_embedded_signing#create' - - scope module: 'e_sign' do - # Example controllers... - get 'eeg002' => 'eeg002_signing_via_email#get' - post 'eeg002' => 'eeg002_signing_via_email#create' - - get 'eeg003' => 'eeg003_list_envelopes#get' - post 'eeg003' => 'eeg003_list_envelopes#create' - - get 'eeg004' => 'eeg004_envelope_info#get' - post 'eeg004' => 'eeg004_envelope_info#create' - - get 'eeg005' => 'eeg005_envelope_recipients#get' - post 'eeg005' => 'eeg005_envelope_recipients#create' - - get 'eeg006' => 'eeg006_envelope_docs#get' - post 'eeg006' => 'eeg006_envelope_docs#create' - - get 'eeg007' => 'eeg007_envelope_get_doc#get' - post 'eeg007' => 'eeg007_envelope_get_doc#create' - - get 'eeg008' => 'eeg008_create_template#get' - post 'eeg008' => 'eeg008_create_template#create' - - get 'eeg009' => 'eeg009_use_template#get' - post 'eeg009' => 'eeg009_use_template#create' - - get 'eeg010' => 'eeg010_send_binary_docs#get' - post 'eeg010' => 'eeg010_send_binary_docs#create' - - get 'eeg011' => 'eeg011_embedded_sending#get' - post 'eeg011' => 'eeg011_embedded_sending#create' - - get 'eeg012' => 'eeg012_embedded_console#get' - post 'eeg012' => 'eeg012_embedded_console#create' - - get 'eeg013' => 'eeg013_add_doc_to_template#get' - post 'eeg013' => 'eeg013_add_doc_to_template#create' - - get 'eeg014' => 'eeg014_collect_payment#get' - post 'eeg014' => 'eeg014_collect_payment#create' - - get 'eeg015' => 'eeg015_get_envelope_tab_data#get' - post 'eeg015' => 'eeg015_get_envelope_tab_data#create' - - get 'eeg016' => 'eeg016_set_envelope_tab_data#get' - post 'eeg016' => 'eeg016_set_envelope_tab_data#create' - - get 'eeg017' => 'eeg017_set_template_tab_values#get' - post 'eeg017' => 'eeg017_set_template_tab_values#create' - - get 'eeg018' => 'eeg018_get_envelope_custom_field_data#get' - post 'eeg018' => 'eeg018_get_envelope_custom_field_data#create' - - get 'eeg019' => 'eeg019_access_code_authentication#get' - post 'eeg019' => 'eeg019_access_code_authentication#create' - - get 'eeg020' => 'eeg020_phone_authentication#get' - post 'eeg020' => 'eeg020_phone_authentication#create' - - get 'eeg022' => 'eeg022_kba_authentication#get' - post 'eeg022' => 'eeg022_kba_authentication#create' - - get 'eeg023' => 'eeg023_idv_authentication#get' - post 'eeg023' => 'eeg023_idv_authentication#create' - - get 'eeg024' => 'eeg024_permission_create#get' - post 'eeg024' => 'eeg024_permission_create#create' - - get 'eeg025' => 'eeg025_permissions_set_user_group#get' - post 'eeg025' => 'eeg025_permissions_set_user_group#create' - - get 'eeg026' => 'eeg026_permissions_change_single_setting#get' - post 'eeg026' => 'eeg026_permissions_change_single_setting#create' - - get 'eeg027' => 'eeg027_permissions_delete#get' - post 'eeg027' => 'eeg027_permissions_delete#create' - - get 'eeg028' => 'eeg028_brands_creating#get' - post 'eeg028' => 'eeg028_brands_creating#create' - - get 'eeg029' => 'eeg029_brands_apply_to_envelope#get' - post 'eeg029' => 'eeg029_brands_apply_to_envelope#create' - - get 'eeg030' => 'eeg030_brands_apply_to_template#get' - post 'eeg030' => 'eeg030_brands_apply_to_template#create' - - get 'eeg031' => 'eeg031_bulk_sending_envelopes#get' - post 'eeg031' => 'eeg031_bulk_sending_envelopes#create' - - get 'eeg032' => 'eeg032_pauses_signature_workflow#get' - post 'eeg032' => 'eeg032_pauses_signature_workflow#create' - - get 'eeg033' => 'eeg033_unpauses_signature_workflow#get' - put 'eeg033' => 'eeg033_unpauses_signature_workflow#update' - - get 'eeg034' => 'eeg034_use_conditional_recipients#get' - post 'eeg034' => 'eeg034_use_conditional_recipients#create' - - get 'eeg035' => 'eeg035_scheduled_sending#get' - post 'eeg035' => 'eeg035_scheduled_sending#create' - - get 'eeg036' => 'eeg036_delayed_routing#get' - post 'eeg036' => 'eeg036_delayed_routing#create' - - get 'eeg037' => 'eeg037_sms_delivery#get' - post 'eeg037' => 'eeg037_sms_delivery#create' - - get 'eeg038' => 'eeg038_responsive_signing#get' - post 'eeg038' => 'eeg038_responsive_signing#create' - - get 'eeg039' => 'eeg039_signing_in_person#get' - post 'eeg039' => 'eeg039_signing_in_person#create' - - get 'eeg040' => 'eeg040_set_document_visibility#get' - post 'eeg040' => 'eeg040_set_document_visibility#create' - - get 'eeg041' => 'eeg041_cfr_embedded_signing#get' - post 'eeg041' => 'eeg041_cfr_embedded_signing#create' - - get 'eeg042' => 'eeg042_document_generation#get' - post 'eeg042' => 'eeg042_document_generation#create' - - post 'eeg043' => 'eeg043_shared_access#create_agent' - get 'eeg043' => 'eeg043_shared_access#get' - get 'eeg043auth' => 'eeg043_shared_access#create_authorization' - get 'eeg043reauthenticate' => 'eeg043_shared_access#reauthenticate' - get 'eeg043envelopes' => 'eeg043_shared_access#list_envelopes' - - get 'eeg044' => 'eeg044_focused_view#get' - post 'eeg044' => 'eeg044_focused_view#create' - end - - scope module: 'connect' do - get 'cneg001' => 'cneg001_validate_webhook_message#get' - post 'cneg001' => 'cneg001_validate_webhook_message#create' - end - - scope module: 'webforms' do - get 'weg001' => 'weg001_create_instance#get' - get 'weg001webForm' => 'weg001_create_instance#get_web_form_create_view' - post 'weg001' => 'weg001_create_instance#create_web_form_template' - post 'weg001webForm' => 'weg001_create_instance#create_web_form_instance' - end - - scope module: 'maestro_api' do - get 'mseg001' => 'mseg001_trigger_workflow#get' - post 'mseg001' => 'mseg001_trigger_workflow#create' - post 'mseg001publish' => 'mseg001_trigger_workflow#publish' - - get 'mseg002' => 'mseg002_cancel_workflow#get' - post 'mseg002' => 'mseg002_cancel_workflow#create' - - get 'mseg003' => 'mseg003_get_workflow_status#get' - post 'mseg003' => 'mseg003_get_workflow_status#create' - end - - root 'ds_common#index' - - # Login starts with POST'ing to: /auth/docusign - # /auth/docusign is an internal route created by OmniAuth and the docusign strategy from: /lib/docusign.rb - # Should be POST, see: https://nvd.nist.gov/vuln/detail/CVE-2015-9284 - # get '/ds/login' => redirect('/auth/docusign') - - # Handle OmniAuth OAuth2 login callback result that includes the AuthHash - get '/auth/:provider/callback', to: 'session#create' - - # Handle OmniAuth OAuth2 login exceptions in non development environments: - get '/auth/failure', to: 'session#omniauth_failure' - - # Logout - get '/ds/logout', to: 'session#destroy' - - get '/ds_common-return' => 'ds_common#ds_return' - get '/ds/mustAuthenticate' => 'ds_common#ds_must_authenticate' - post '/ds/mustAuthenticate' => 'ds_common#ds_must_authenticate' - get '/ds/mustAuthenticateJwt' => 'ds_common#ds_must_authenticate_jwt' - post '/ds/mustAuthenticateJwt' => 'ds_common#ds_must_authenticate' - - get '/ds/session' => 'session#show' - # default root - - get 'ds_common/index' - get 'example_done' => 'ds_common#example_done' - get 'error' => 'ds_common#error' - - # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html -end +# frozen_string_literal: true + +Rails.application.routes.draw do + scope module: 'room_api' do + get 'reg001' => 'reg001_create_room_with_data#get' + post 'reg001' => 'reg001_create_room_with_data#create' + + get 'reg002' => 'reg002_create_room_with_template#get' + post 'reg002' => 'reg002_create_room_with_template#create' + + get 'reg003' => 'reg003_export_data_from_room#get' + post 'reg003' => 'reg003_export_data_from_room#create' + + get 'reg004' => 'reg004_add_forms_to_room#get' + post 'reg004' => 'reg004_add_forms_to_room#create' + + get 'reg005' => 'reg005_get_rooms_with_filters#get' + post 'reg005' => 'reg005_get_rooms_with_filters#create' + + get 'reg006' => 'reg006_create_an_external_form_fill_session#get_rooms' + get 'reg006_forms' => 'reg006_create_an_external_form_fill_session#get_forms' + post 'reg006' => 'reg006_create_an_external_form_fill_session#create' + + get 'reg007' => 'reg007_create_form_group#get' + post 'reg007' => 'reg007_create_form_group#create' + + get 'reg008' => 'reg008_grant_office_access_to_form_group#get' + post 'reg008' => 'reg008_grant_office_access_to_form_group#create' + + get 'reg009' => 'reg009_assign_form_to_form_group#get' + post 'reg009' => 'reg009_assign_form_to_form_group#create' + end + + scope module: 'clickwrap' do + get 'ceg001' => 'ceg001_create_clickwrap#get' + post 'ceg001' => 'ceg001_create_clickwrap#create' + + get 'ceg002' => 'ceg002_activate_clickwrap#get' + post 'ceg002' => 'ceg002_activate_clickwrap#create' + + get 'ceg003' => 'ceg003_create_new_clickwrap_version#get' + post 'ceg003' => 'ceg003_create_new_clickwrap_version#create' + + get 'ceg004' => 'ceg004_list_clickwraps#get' + post 'ceg004' => 'ceg004_list_clickwraps#create' + + get 'ceg005' => 'ceg005_clickwrap_responses#get' + post 'ceg005' => 'ceg005_clickwrap_responses#create' + + get 'ceg006' => 'ceg006_embed_clickwrap#get' + post 'ceg006' => 'ceg006_embed_clickwrap#create' + end + + scope module: 'monitor_api' do + get 'meg001' => 'meg001_get_monitoring_dataset#get' + post 'meg001' => 'meg001_get_monitoring_dataset#create' + end + + scope module: 'admin_api' do + get 'aeg001' => 'aeg001_create_user#get' + post 'aeg001' => 'aeg001_create_user#create' + + get 'aeg002' => 'aeg002_create_active_clm_esign_user#get' + post 'aeg002' => 'aeg002_create_active_clm_esign_user#create' + + get 'aeg003' => 'aeg003_bulk_export_user_data#get' + post 'aeg003' => 'aeg003_bulk_export_user_data#create' + + get 'aeg004' => 'aeg004_import_user#get' + post 'aeg004' => 'aeg004_import_user#create' + get 'aeg004status' => 'aeg004_import_user#check_status' + + get 'aeg005' => 'aeg005_audit_users#get' + post 'aeg005' => 'aeg005_audit_users#create' + + get 'aeg006' => 'aeg006_get_user_profile_by_email#get' + post 'aeg006' => 'aeg006_get_user_profile_by_email#create' + + get 'aeg007' => 'aeg007_get_user_profile_by_user_id#get' + post 'aeg007' => 'aeg007_get_user_profile_by_user_id#create' + + get 'aeg008' => 'aeg008_update_user_product_permission_profile#get' + post 'aeg008' => 'aeg008_update_user_product_permission_profile#create' + + get 'aeg009' => 'aeg009_delete_user_product_permission_profile#get' + post 'aeg009' => 'aeg009_delete_user_product_permission_profile#create' + + get 'aeg010' => 'aeg010_delete_user_data_from_organization#get' + post 'aeg010' => 'aeg010_delete_user_data_from_organization#create' + + get 'aeg011' => 'aeg011_delete_user_data_from_account#get' + post 'aeg011' => 'aeg011_delete_user_data_from_account#create' + + get 'aeg012' => 'aeg012_clone_account#get' + post 'aeg012' => 'aeg012_clone_account#create' + + get 'aeg013' => 'aeg013_create_account#get' + post 'aeg013' => 'aeg013_create_account#create' + end + + get '/eeg001' => 'eeg001_embedded_signing#get' + post '/eeg001' => 'eeg001_embedded_signing#create' + + scope module: 'e_sign' do + # Example controllers... + get 'eeg002' => 'eeg002_signing_via_email#get' + post 'eeg002' => 'eeg002_signing_via_email#create' + + get 'eeg003' => 'eeg003_list_envelopes#get' + post 'eeg003' => 'eeg003_list_envelopes#create' + + get 'eeg004' => 'eeg004_envelope_info#get' + post 'eeg004' => 'eeg004_envelope_info#create' + + get 'eeg005' => 'eeg005_envelope_recipients#get' + post 'eeg005' => 'eeg005_envelope_recipients#create' + + get 'eeg006' => 'eeg006_envelope_docs#get' + post 'eeg006' => 'eeg006_envelope_docs#create' + + get 'eeg007' => 'eeg007_envelope_get_doc#get' + post 'eeg007' => 'eeg007_envelope_get_doc#create' + + get 'eeg008' => 'eeg008_create_template#get' + post 'eeg008' => 'eeg008_create_template#create' + + get 'eeg009' => 'eeg009_use_template#get' + post 'eeg009' => 'eeg009_use_template#create' + + get 'eeg010' => 'eeg010_send_binary_docs#get' + post 'eeg010' => 'eeg010_send_binary_docs#create' + + get 'eeg011' => 'eeg011_embedded_sending#get' + post 'eeg011' => 'eeg011_embedded_sending#create' + + get 'eeg012' => 'eeg012_embedded_console#get' + post 'eeg012' => 'eeg012_embedded_console#create' + + get 'eeg013' => 'eeg013_add_doc_to_template#get' + post 'eeg013' => 'eeg013_add_doc_to_template#create' + + get 'eeg014' => 'eeg014_collect_payment#get' + post 'eeg014' => 'eeg014_collect_payment#create' + + get 'eeg015' => 'eeg015_get_envelope_tab_data#get' + post 'eeg015' => 'eeg015_get_envelope_tab_data#create' + + get 'eeg016' => 'eeg016_set_envelope_tab_data#get' + post 'eeg016' => 'eeg016_set_envelope_tab_data#create' + + get 'eeg017' => 'eeg017_set_template_tab_values#get' + post 'eeg017' => 'eeg017_set_template_tab_values#create' + + get 'eeg018' => 'eeg018_get_envelope_custom_field_data#get' + post 'eeg018' => 'eeg018_get_envelope_custom_field_data#create' + + get 'eeg019' => 'eeg019_access_code_authentication#get' + post 'eeg019' => 'eeg019_access_code_authentication#create' + + get 'eeg020' => 'eeg020_phone_authentication#get' + post 'eeg020' => 'eeg020_phone_authentication#create' + + get 'eeg022' => 'eeg022_kba_authentication#get' + post 'eeg022' => 'eeg022_kba_authentication#create' + + get 'eeg023' => 'eeg023_idv_authentication#get' + post 'eeg023' => 'eeg023_idv_authentication#create' + + get 'eeg024' => 'eeg024_permission_create#get' + post 'eeg024' => 'eeg024_permission_create#create' + + get 'eeg025' => 'eeg025_permissions_set_user_group#get' + post 'eeg025' => 'eeg025_permissions_set_user_group#create' + + get 'eeg026' => 'eeg026_permissions_change_single_setting#get' + post 'eeg026' => 'eeg026_permissions_change_single_setting#create' + + get 'eeg027' => 'eeg027_permissions_delete#get' + post 'eeg027' => 'eeg027_permissions_delete#create' + + get 'eeg028' => 'eeg028_brands_creating#get' + post 'eeg028' => 'eeg028_brands_creating#create' + + get 'eeg029' => 'eeg029_brands_apply_to_envelope#get' + post 'eeg029' => 'eeg029_brands_apply_to_envelope#create' + + get 'eeg030' => 'eeg030_brands_apply_to_template#get' + post 'eeg030' => 'eeg030_brands_apply_to_template#create' + + get 'eeg031' => 'eeg031_bulk_sending_envelopes#get' + post 'eeg031' => 'eeg031_bulk_sending_envelopes#create' + + get 'eeg032' => 'eeg032_pauses_signature_workflow#get' + post 'eeg032' => 'eeg032_pauses_signature_workflow#create' + + get 'eeg033' => 'eeg033_unpauses_signature_workflow#get' + put 'eeg033' => 'eeg033_unpauses_signature_workflow#update' + + get 'eeg034' => 'eeg034_use_conditional_recipients#get' + post 'eeg034' => 'eeg034_use_conditional_recipients#create' + + get 'eeg035' => 'eeg035_scheduled_sending#get' + post 'eeg035' => 'eeg035_scheduled_sending#create' + + get 'eeg036' => 'eeg036_delayed_routing#get' + post 'eeg036' => 'eeg036_delayed_routing#create' + + get 'eeg037' => 'eeg037_sms_delivery#get' + post 'eeg037' => 'eeg037_sms_delivery#create' + + get 'eeg038' => 'eeg038_responsive_signing#get' + post 'eeg038' => 'eeg038_responsive_signing#create' + + get 'eeg039' => 'eeg039_signing_in_person#get' + post 'eeg039' => 'eeg039_signing_in_person#create' + + get 'eeg040' => 'eeg040_set_document_visibility#get' + post 'eeg040' => 'eeg040_set_document_visibility#create' + + get 'eeg041' => 'eeg041_cfr_embedded_signing#get' + post 'eeg041' => 'eeg041_cfr_embedded_signing#create' + + get 'eeg042' => 'eeg042_document_generation#get' + post 'eeg042' => 'eeg042_document_generation#create' + + post 'eeg043' => 'eeg043_shared_access#create_agent' + get 'eeg043' => 'eeg043_shared_access#get' + get 'eeg043auth' => 'eeg043_shared_access#create_authorization' + get 'eeg043reauthenticate' => 'eeg043_shared_access#reauthenticate' + get 'eeg043envelopes' => 'eeg043_shared_access#list_envelopes' + + get 'eeg044' => 'eeg044_focused_view#get' + post 'eeg044' => 'eeg044_focused_view#create' + end + + scope module: 'connect' do + get 'cneg001' => 'cneg001_validate_webhook_message#get' + post 'cneg001' => 'cneg001_validate_webhook_message#create' + end + + scope module: 'webforms' do + get 'weg001' => 'weg001_create_instance#get' + get 'weg001webForm' => 'weg001_create_instance#get_web_form_create_view' + post 'weg001' => 'weg001_create_instance#create_web_form_template' + post 'weg001webForm' => 'weg001_create_instance#create_web_form_instance' + end + + scope module: 'maestro_api' do + get 'mseg001' => 'mseg001_trigger_workflow#get' + post 'mseg001' => 'mseg001_trigger_workflow#create' + post 'mseg001publish' => 'mseg001_trigger_workflow#publish' + + get 'mseg002' => 'mseg002_cancel_workflow#get' + post 'mseg002' => 'mseg002_cancel_workflow#create' + + get 'mseg003' => 'mseg003_get_workflow_status#get' + post 'mseg003' => 'mseg003_get_workflow_status#create' + end + + root 'ds_common#index' + + # Login starts with POST'ing to: /auth/docusign + # /auth/docusign is an internal route created by OmniAuth and the docusign strategy from: /lib/docusign.rb + # Should be POST, see: https://nvd.nist.gov/vuln/detail/CVE-2015-9284 + # get '/ds/login' => redirect('/auth/docusign') + + # Handle OmniAuth OAuth2 login callback result that includes the AuthHash + get '/auth/:provider/callback', to: 'session#create' + + # Handle OmniAuth OAuth2 login exceptions in non development environments: + get '/auth/failure', to: 'session#omniauth_failure' + + # Logout + get '/ds/logout', to: 'session#destroy' + + get '/ds_common-return' => 'ds_common#ds_return' + get '/ds/mustAuthenticate' => 'ds_common#ds_must_authenticate' + post '/ds/mustAuthenticate' => 'ds_common#ds_must_authenticate' + get '/ds/mustAuthenticateJwt' => 'ds_common#ds_must_authenticate_jwt' + post '/ds/mustAuthenticateJwt' => 'ds_common#ds_must_authenticate' + + get '/ds/session' => 'session#show' + # default root + + get 'ds_common/index' + get 'example_done' => 'ds_common#example_done' + get 'error' => 'ds_common#error' + + # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html +end From 9504c50e78d9b5756b846e29df76ddde11a3186f Mon Sep 17 00:00:00 2001 From: Inbar Gazit Date: Tue, 15 Oct 2024 11:14:11 -0700 Subject: [PATCH 336/363] Update README.md Signed-off-by: Inbar Gazit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 991049e..bcccae5 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ For a list of code examples that use the Admin API, see the [How-to guides overv ### 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 free [Docusign developer account](https://www.docusign.com/developers/sandbox); create one if you don't already have one. 1. A Docusign app and integration key that is configured for authentication to use either [Authorization Code Grant](https://developers.docusign.com/platform/auth/authcode/) or [JWT Grant](https://developers.docusign.com/platform/auth/jwt/). This [video](https://www.youtube.com/watch?v=eiRI4fe5HgM) demonstrates how to obtain an integration key. From a8f46790945c6cafe886ad52123aa7e384909bf6 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Thu, 17 Oct 2024 19:54:17 +0000 Subject: [PATCH 337/363] update web forms example 1 (#176) * update web forms example 1 --- .../weg001_create_instance_controller.rb | 16 ++++++---- .../webforms/eg001_create_instance_service.rb | 30 +++++++++---------- data/web-form-config.json | 2 +- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/app/controllers/webforms/weg001_create_instance_controller.rb b/app/controllers/webforms/weg001_create_instance_controller.rb index 642c318..8899dab 100644 --- a/app/controllers/webforms/weg001_create_instance_controller.rb +++ b/app/controllers/webforms/weg001_create_instance_controller.rb @@ -12,11 +12,15 @@ def create_web_form_template access_token: session[:ds_access_token] } - web_form_template_id = Webforms::Eg001CreateInstanceService.new(args).create_web_form_template - Utils::FileUtils.new.replace_template_id(File.join('data', Rails.application.config.web_form_config_file), web_form_template_id) - session[:web_form_template_id] = web_form_template_id - - redirect_to '/weg001webForm' + begin + web_form_template_id = Webforms::Eg001CreateInstanceService.new(args).create_web_form_template + Utils::FileUtils.new.replace_template_id(File.join('data', Rails.application.config.web_form_config_file), web_form_template_id) + session[:web_form_template_id] = web_form_template_id + + redirect_to '/weg001webForm' + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end end def create_web_form_instance @@ -49,7 +53,7 @@ def get_web_form_create_view additional_page = @example['AdditionalPage'].find { |p| p['Name'] == 'create_web_form' } @title = @example['ExampleName'] - @description = additional_page['ResultsPageText'] + @description = format_string(additional_page['ResultsPageText'], 'data') render 'webforms/weg001_create_instance/web_form_create' end diff --git a/app/services/webforms/eg001_create_instance_service.rb b/app/services/webforms/eg001_create_instance_service.rb index 23b282b..e766e5c 100644 --- a/app/services/webforms/eg001_create_instance_service.rb +++ b/app/services/webforms/eg001_create_instance_service.rb @@ -95,38 +95,38 @@ def make_web_forms_template # Create a sign_here tab (field on the document) sign_here = DocuSign_eSign::SignHere.new( 'documentId' => '1', 'tabLabel' => 'Signature', - 'anchorString' => '/SignHere/', 'anchorUnits' => 'pixel', - 'anchorXOffset' => '20', 'anchorYOffset' => '10' + 'anchorString' => '/SignHere/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' ) check = DocuSign_eSign::Checkbox.new( 'documentId' => '1', 'tabLabel' => 'Yes', - 'anchorString' => '/SMS/', 'anchorUnits' => 'pixel', - 'anchorXOffset' => '20', 'anchorYOffset' => '10' + 'anchorString' => '/SMS/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' ) text1 = DocuSign_eSign::Text.new( 'documentId' => '1', 'tabLabel' => 'FullName', - 'anchorString' => '/FullName/', 'anchorUnits' => 'pixel', - 'anchorXOffset' => '20', 'anchorYOffset' => '10' + 'anchorString' => '/FullName/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' ) text2 = DocuSign_eSign::Text.new( 'documentId' => '1', 'tabLabel' => 'PhoneNumber', - 'anchorString' => '/PhoneNumber/', 'anchorUnits' => 'pixel', - 'anchorXOffset' => '20', 'anchorYOffset' => '10' + 'anchorString' => '/PhoneNumber/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' ) text3 = DocuSign_eSign::Text.new( 'documentId' => '1', 'tabLabel' => 'Company', - 'anchorString' => '/Company/', 'anchorUnits' => 'pixel', - 'anchorXOffset' => '20', 'anchorYOffset' => '10' + 'anchorString' => '/Company/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' ) text4 = DocuSign_eSign::Text.new( 'documentId' => '1', 'tabLabel' => 'JobTitle', - 'anchorString' => '/JobTitle/', 'anchorUnits' => 'pixel', - 'anchorXOffset' => '20', 'anchorYOffset' => '10' + 'anchorString' => '/JobTitle/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' ) date_signed = DocuSign_eSign::DateSigned.new( 'documentId' => '1', 'tabLabel' => 'DateSigned', - 'anchorString' => '/Date/', 'anchorUnits' => 'pixel', - 'anchorXOffset' => '20', 'anchorYOffset' => '10' + 'anchorString' => '/Date/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' ) # Add the tabs model to the signer @@ -139,7 +139,7 @@ def make_web_forms_template ) # Create top two objects envelope_template_definition = DocuSign_eSign::EnvelopeTemplate.new( - 'description' => 'Example template created via the API', + 'description' => 'Example template created via the eSignature API', 'shared' => 'false' ) diff --git a/data/web-form-config.json b/data/web-form-config.json index 484da32..5947cca 100644 --- a/data/web-form-config.json +++ b/data/web-form-config.json @@ -1 +1 @@ -{"id":"3d761225-xxxx-xxxx-xxxx-683bb52fff21","accountId":"0820f9c5-xxxx-xxxx-xxxx-8a0df87f44aa","isPublished":true,"isEnabled":true,"hasDraftChanges":false,"formState":"active","formProperties":{"name":"Web Form Example Template","isPrivateAccess":false},"formMetadata":{"source":"templates","createdDateTime":"2023-12-07T21:35:55.245Z","publishedSlug":"3f766ec2815665dbc257f97a9b7f97df","owner":{"userId":"8cb9aa3f-xxxx-xxxx-xxxx-f6ce2e16dad1","userName":"Test"},"lastModifiedDateTime":"2023-12-07T21:38:04.910Z","lastModifiedBy":{"userId":"8cb9aa3f-xxxx-xxxx-xxxx-f6ce2e16dad1","userName":"Test"},"publishedComponentNames":{"SignerName":"TextBox","SignerEmail":"Email","PhoneNumber":"TextBox","Yes":"CheckboxGroup","Company":"TextBox","JobTitle":"TextBox"},"admModelNamespace":"docusign.forms._0820f9c5_0d81_489a_bcc9_8a0df87f44aa._3d761225_6960_4bd0_a657_683bb52fff21","formContentModifiedBy":{"userId":"8cb9aa3f-xxxx-xxxx-xxxx-f6ce2e16dad1","userName":"Test"},"formContentModifiedDateTime":"2023-12-07T21:37:54.094Z","admModelVersion":"1.0.0","formPropertiesModifiedBy":{"userId":"8cb9aa3f-xxxx-xxxx-xxxx-f6ce2e16dad1","userName":"Test"},"formPropertiesModifiedDateTime":"2023-12-07T21:35:55.245Z","sender":{"userId":"8cb9aa3f-xxxx-xxxx-xxxx-f6ce2e16dad1","userName":"Test"},"lastSenderConsentDateTime":"2023-12-07T21:37:57.247Z","lastPublishedBy":{"userId":"8cb9aa3f-xxxx-xxxx-xxxx-f6ce2e16dad1","userName":"Test"},"lastPublishedDateTime":"2023-12-07T21:38:04.910Z","lastEnabledBy":{"userId":"8cb9aa3f-xxxx-xxxx-xxxx-f6ce2e16dad1","userName":"Test"},"lastEnabledDateTime":"2023-12-07T21:38:04.910Z"},"formContent":{"components":{"Root_Of_Journey":{"componentKey":"Root_Of_Journey","componentType":"Root","componentName":"Root_Of_Journey","componentRules":{},"text":"","children":["Welcome_kyK6x_Uj","Step_vGLuKyzy","Summary_j0FzHU8Q","ESignAction_qqwx19h7","Thankyou_RmjV_bGg"]},"Welcome_kyK6x_Uj":{"text":"Part time work application","subText":"","startButtonText":"Start","componentKey":"Welcome_kyK6x_Uj","componentType":"Welcome"},"Step_vGLuKyzy":{"componentKey":"Step_vGLuKyzy","componentType":"Step","componentName":"Step_vGLuKyzy","text":"Applicant information","children":["TextBox_lTHn2kiH","Email_wRqtKmus","TextBox_kLQ5AMLA","CheckboxGroup_cAHNBDer","TextBox_SiYcnTUz","TextBox_LsASX8b1"]},"Summary_j0FzHU8Q":{"text":"Summary","subText":"Please review the information you have entered:","componentKey":"Summary_j0FzHU8Q","componentType":"Summary"},"ESignAction_qqwx19h7":{"componentKey":"ESignAction_qqwx19h7","componentType":"ESignAction","primaryRecipientId":"1","templateInfoMap":{"eb388ad9-29de-40c9-90f3-211cf7dcefdd":{"templateId":"template-id","lastModified":"2023-12-07T21:35:55.9300000Z","name":"Web Form Copy - Web Form Example Template","owner":{"userName":"Test","userId":"8cb9aa3f-xxxx-xxxx-xxxx-f6ce2e16dad1","email":"example@example.com"}}},"recipientInfoMap":{"1":{"nameComponentKey":"TextBox_lTHn2kiH","emailComponentKey":"Email_wRqtKmus","recipientId":"1","recipientType":"signer","roleName":"signer","routingOrder":"1","nameFromTemplate":"","emailFromTemplate":""}},"tabInfoMap":{"a4f174b8-647d-4c96-9b91-ff548a0c0930":{"componentKey":"TextBox_lTHn2kiH","tabId":"a4f174b8-647d-4c96-9b91-ff548a0c0930","recipientId":"1","tabLabel":"FullName","tabType":"text"},"9bcf6cba-05cf-4088-8c85-e5a905ca1efb":{"componentKey":"TextBox_kLQ5AMLA","tabId":"9bcf6cba-05cf-4088-8c85-e5a905ca1efb","recipientId":"1","tabLabel":"PhoneNumber","tabType":"text"},"d2d23949-ce13-48de-9043-ce1b4d7d594a":{"componentKey":"TextBox_SiYcnTUz","tabId":"d2d23949-ce13-48de-9043-ce1b4d7d594a","recipientId":"1","tabLabel":"Company","tabType":"text"},"6308de2e-cea9-48aa-ab03-25d53a54cc5a":{"componentKey":"TextBox_LsASX8b1","tabId":"6308de2e-cea9-48aa-ab03-25d53a54cc5a","recipientId":"1","tabLabel":"JobTitle","tabType":"text"},"d1d70d31-d7d4-462b-b41a-cc1f55698ae2":{"componentKey":"CheckboxGroup_cAHNBDer","tabId":"d1d70d31-d7d4-462b-b41a-cc1f55698ae2","recipientId":"1","tabLabel":"Yes","tabType":"checkbox","name":"Yes","selected":"false"}},"requireRemoteSigning":false,"enableDocumentFieldEditing":true},"Thankyou_RmjV_bGg":{"text":"Thank you","subText":"We've received your form.","showConfirmationButton":false,"confirmationButtonText":"Done","confirmationButtonUrl":"","componentKey":"Thankyou_RmjV_bGg","componentType":"Thankyou"},"TextBox_lTHn2kiH":{"componentKey":"TextBox_lTHn2kiH","componentType":"TextBox","componentName":"SignerName","label":"Signer name","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"Email_wRqtKmus":{"componentKey":"Email_wRqtKmus","componentType":"Email","componentName":"SignerEmail","label":"Signer email","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"TextBox_kLQ5AMLA":{"componentKey":"TextBox_kLQ5AMLA","componentType":"TextBox","componentName":"PhoneNumber","label":"Phone Number","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"CheckboxGroup_cAHNBDer":{"componentKey":"CheckboxGroup_cAHNBDer","componentType":"CheckboxGroup","componentName":"Yes","label":"I prefer to be contacted by text","description":"","options":[{"optionKey":"fk4RHsoj","value":"Yes","label":"Yes","selected":false}]},"TextBox_SiYcnTUz":{"componentKey":"TextBox_SiYcnTUz","componentType":"TextBox","componentName":"Company","label":"Current company","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"TextBox_LsASX8b1":{"componentKey":"TextBox_LsASX8b1","componentType":"TextBox","componentName":"JobTitle","label":"Current job title","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000}},"isStandalone":false,"templates":[{"originalTemplateId":"template-id","clonedTemplateId":"template-id","importedDateTime":"2023-12-07T21:35:56.511Z","recipientIds":["1"]}]},"versionId":1,"eSignTemplates":[{"templateId":"template-id","uri":"/templates/template-id","name":"Web Form Copy - Web Form Example Template","shared":"false","passwordProtected":"false","description":"Example template created via the API","created":"2023-12-07T21:35:55.6300000Z","lastModified":"2023-12-07T21:38:04.3800000Z","lastModifiedBy":{"userName":"Test","userId":"8cb9aa3f-xxxx-xxxx-xxxx-f6ce2e16dad1","email":"example@example.com","uri":"/users/8cb9aa3f-xxxx-xxxx-xxxx-f6ce2e16dad1"},"lastUsed":"2023-12-07T21:35:55.9430000Z","owner":{"userName":"Test","userId":"8cb9aa3f-xxxx-xxxx-xxxx-f6ce2e16dad1","email":"example@example.com"},"pageCount":"1","folderId":"1e649420-aee9-4f2e-8265-0082f733e8f6","folderName":"Deleted Items","folderIds":["1e649420-aee9-4f2e-8265-0082f733e8f6"],"autoMatch":"true","autoMatchSpecifiedByUser":"false","documents":[{"documentId":"1","uri":"/envelopes/eb388ad9-29de-40c9-90f3-211cf7dcefdd/documents/1","name":"World_Wide_Web_Form","order":"1","pages":"1","documentBase64":"JVBERi0xLjQKJdPr6eEKMSAwIG9iago8PC9UaXRsZSAoV29ybGRfV2lkZV9Db3JwX1dlYl9Gb3JtKQovUHJvZHVjZXIgKFNraWEvUERGIG0xMjEgR29vZ2xlIERvY3MgUmVuZGVyZXIpPj4KZW5kb2JqCjMgMCBvYmoKPDwvY2EgMQovQk0gL05vcm1hbD4+CmVuZG9iago3IDAgb2JqCjw8L0NBIDEKL2NhIDEKL0xDIDAKL0xKIDAKL0xXIDEuMzMzMzMzMzcKL01MIDEwCi9TQSB0cnVlCi9CTSAvTm9ybWFsPj4KZW5kb2JqCjggMCBvYmoKPDwvVHlwZSAvWE9iamVjdAovU3VidHlwZSAvSW1hZ2UKL1dpZHRoIDgwCi9IZWlnaHQgNzQKL0NvbG9yU3BhY2UgL0RldmljZVJHQgovQml0c1BlckNvbXBvbmVudCA4Ci9GaWx0ZXIgL0ZsYXRlRGVjb2RlCi9MZW5ndGggOTkzMj4+IHN0cmVhbQp4nNWch1taeb7//6d7n7tzdzeJJSazO32TmcmU9DIzScaeGE1MTO/FRI0F7ICgYseOiArSQRAFAbEgvZ/Cqfj7HkiymdmZ2Tj37t3nx/P2PIfj4fB9nU/9cg5sb/9fPOjtJJVMUnSSpoDoZJJIi2aUTL7aziiZVnIb6P/HB03TFEXRNJZMwhSFUBRGkjiZJEmaxCkggqBJCohMUARMkyjYgaZxOomDs7G9/Xfm5E8f/0aiX3ukBwZ4SZKEcNLqj4s0a6zR5VscVVH99NnK8VMPRWcej+RWTV1unL3PU7SMLc0t+zYjKEIlAX8SiKbfANJvrf9beZl3p7a3GSW3GU+k8SSFUjSBU4kAlBjXbFxnS/9W1vHfP7S9d17wh9y+/8ob/o/88f/IH/3PgpH/LBj+r8Lx9wrG/5A3/F7u4B/P9macFx65O/6gWz2/6kdQkiJImsLBH8UAM8wU/e/kTb42Y0pgUDhwV5igzFuxhx0zn5W0/fk8/w+FI+9dmPhT0cTui1N7SiRAu0vmdl+a2V06vadsKqNsKrNMnFE2ufvS+J8vjb5XMvyfxSPv5Q3+8XveNzd6moe0vjBEEgnmNJIYMDpNkf+W2E5zUinObRCeNA7CEKcpizt6rWH8LwXt+y4N7i4a3n1BsusS0FTGJWlm6QxYZlyaySyT7imd+mPx8J8uiv5U2PfHvO7/zu3KujiUeXls19Xp9y7P7SqdyyqV7ioeyirs+Owi+1mXzBWAQKgDOydBgFPE/71jv+EFaXWbxhMEuQlh1ULlwVLuR6X9f7k0mF3MzyzsPvRA++G12ZzLk/sqZv56U7a/Yibrsnjv5amMkpE9F4cySgZ35XXszuPtzuWB5Z6C/qxSWUa5IuPKdM7l0f2XRveUjP2xuH9XcdcXZe1t40Y/QhAEDs5rOqLB4/8I9bUbUxRJMbmVnFrcOHan++Oyob0XBnbnd2bnc/bkN+7K5xy4N//JXc1Ht2U55cMHHso/fSD77JHis/vyT+/Lvq3Wf/lM8flDyV+u9u8rE+4vFeaUdO4tHci5Ks0pV2SXzWdeUewpl2ddnsgs7thdIMjIbTl7n29wuAmSACamaCamQanb/lcbGbgwk5mobVBWCDyKEi8HVJ+UCw/ckedc6M0qEuzOb9mVx8rIa8rIb8kq7vjw2tDpOt0X98XfPJv/tkp7rMF8uE5/uN5wptWS27l+vnP1VNviFy9kBx5P/+3e+Ec3Rz65P/vxY93793T7bihzrsuzK2Z2lY3tLuz8c3HfrqLuD/LZA9JFlCBICiRGikmU/2Je5vAgU4IzTFLueKKcJT5YLj50T33owcyx59oPykV/ym3JvNC2r4T3wZXuz26NHLwvPsNaON9i/rHder4NaOUc15LLt51qNPzIs5YMbV0c3CzsXj36UnmkSvbt87mTbNOx5pUvakzv353++JHy/duKvRXz2Vcle65I/lwyknNBmHO+6RlfBqOAF6f+9YEM4jVJ0hhOrYYSec/6P78x+fWj5SOVltM1C6demj+/P5NxQfDXit6Dd4e/eiz+tnLucLXi6Ev18XrdiXrN92zduZaFoq6VG+O+soG1kyzVj/ylinFf+eDmd2ztqXrFmUbtxf7Ngv6tc93rZzjWo2zLwWfGj+4b9t9U7bo8vffa7N7L43/OF+7Lb7vDGg0iRAJUd5C0/wWBnHwj0AgQSVcYPft04OBt8fGn+qM1+uO1ph/q7T80OT69I/349sQXT6aOvJAefyk/Ua8+ztIdYxlOANUqLwC6gdXLfbb7U/4K0fr3jYqSPscDaeThdPjm8NYPbM3JekX5qLts3HtxxFPU58nrdp9uXfum1nLgiXHfVWnmpbHssomsQkEGyA95vPKXQ1EYoUimPidf55X/LVRwBkkgpqFAvTE898XkwbviIy+0p2qtJ+uWzrAsue2r51otBx5Mf/VMdrhKebRWebxedYKlPsHWAOTv2OraWW/PItppQtsNsYphZx7X+EzsejETrVFEq2S+l7LIM0noap/j4ZTv0bT/zoTr8thm8cBGbtfmqVbnN8/1f7s7l1UylHlx8P2SXlCn/lQgyCpqvdYiRhGUxuIoU/7xbab3+V/ApbdTxYcGnS8eSVAP2qSf35z4tsp4om7xB5btfJO9kLdW3u87zTZ880IGIvF4neZ4AwN7EpiMrTnG0n7fpOUb0RFrYsIKjdqhigHLsXplUYf5wZjr4dhasybcooo0ygPNipBwieg0YU2q2I2RjYs9jrMc21HW8qHnC5/eV350Rw508K5sT17XnsKejMLOnCJOw5COwLBUC5YW/T8MZ+AlBEjINEYTCYKg2qaWD1QMHqtaPF6/8n3TSkGb41LnxrV+z02R9+jL+WO1ihP1yhPAsineNPLxBjXYWNCq4agCM2uYxBGtnfccbdAca9CcbpD/0CBrkIf5Bkig8fcthEVmpFcX58hD1RJ/aYfldL3+cI3hwBP9Z490X1SajtSufNe0evS5bu/F/v2lw5/dlWdeEk4sbJEgYadL1P8OL56kEzhB6hyBTyv6vnqmPfXScpZlLWyzl3Wu3xzyPpoMP5uJnW83nmarTtQrTjYo3uY92QDOgPIYS3e6QXlDaBxdiZxjzwA/P9WgPMZWH63TfFenvDdoHbLCInNUqAnx5gLNYk/tmPvJkOtCu/V4tf6b57qvnmpBfvixff1sm+Ncy/LRSnlGcc8n9+b3lE98dHtiPYiCiRdF/U9h07ygjWM8GaVyqya/eqI68dL8Hct6rsV2oXP1pmjzyXS4ah4u67GdZgNAYFllSq94GaV4j7KAY2t+aFZz9cFTtdKTDerTdVpQi7+uVhx5Lj1VLWlRhrt0ce58uFkaYIu9taObL4Y3n4x4rnbaf2hYOFVrKOA6C/kb+R1rPzSbc0qFewo7P7g2mX1tbtfVmfJ2BZpIpLw6RQx6BPp3gjOhCyYqJDU4Yzl4cwpY9hx75cc2e6Fg/eqQ6/G0r0oRvyf2naif/wnjTwS2K483KIDAbqdfSo6z5EcaVEdqNEUtuspxxzORqUXqLHg+zBJvtc2FWmcDzVJfo8TTMOWtm/I/HHAWthhzm03lve7SHveFrs0C3uqXD2Z25/HfLxX99Zp096WRj++MqlY2weyTZj41eDV7/B2k6b6RoBKuGPb9g8Gjz03n2Ov5rc4LHWvXBtyPpvy1ikiDLvFdk/pEoxrkqOO/jPyK9xg4JyzFCZb8MHv+qzrZN9Wygkbl7W59tyFUPWC8yp5+1G3kyoMcWYDRXKBdFmRP+2sm3Fc7lq/wrXeHvTcHPeX9ngudGwXt9g+uiP5aNnjg+lhWUef710cuNYxDYBpKJ5JJnABl83dZNhX+NEbizeLFLx/NnqxfOd+0VshZLxe6Hk0EGuajzbr4rZG1Y4ClUf/bvK/UAOqU4uvauS8qpw7eGf6wXHiicry4SVo3tdmpjnero13KSKciLJgPdc4HO+RBgPx8aLVyeOPBgPPpmPfhiOfGoPeScKuY5yxqd3xXa/ygtDcnvyWjpOfLu0PTi+sYqMVgssbUkh2ypufyzMvJMIyeeDT0da35u1Z7AXeztNt7Z9j/cjbSpovzzWh5v+0YW3uEBXjVv8gLNh4DmCxGx+rmj7yY+/yx+NNbA4fvDL4Y3bjOUzdL14SaIF/mFapCvZpIjzoMVoSqCGDvmA83TrmbZ0P1En+12Fc57rs3Grg24C8Tui92bOS22LOKO3Nym/cUCv52a7SUJY6DySIzTd7Z7Cn5mjc17yL7FebPH0hOsVZ+4NiLhK4Kkf+xJNSohviLUKcVze0wHmUZjtbpfiV41cdSvEfrGX1dNfvFg/EPrw99dEVwpXFWqA7x5d60erXhfn2kTxfu0QZ7NKFebVyojnWrGHNzZKHmmWDDdLBG7H864b814rva773U7Snu2Nx3Ubg3tyMnj/+Xsv5Dj2cWnT7QAIIw3qaInfCmewzmPCF08lLjzOGXy+cbHUVcR2nf1t3xQI082m5Aus3QgD1xY9ACWqmjDbrjrJ+H8Jv14/XKIzXyryqln90f+6Bc+MFlQY14q0cf79NFO2Qe3pwbgPfpI/2GSJ8+/Eq6WK82CiRUhwXKCEcebpkLs6WgLgcejftvDXuv9HlKhFuf3RjblyfYly/ILu768pG0SaRKpIyb3El+ppmMDlI6E//2IHzwlvg4aw3ES2nn2vVh35PpUJMW7lpCByzwhCPRaYyefDl9hKU9wdL8Iy/zFBTfavnXT6c/vT28/4owq7D1Xq+lVx8HBu3RhLmzW92q4IAh3q+PAt5XAuzg6Wv1aKIAGZSqVlmENROsEvvuj7orRO5LfZtf3J1iePP4IGt9fl9yrmoUYmKQ2FE5es2LYxTdKzN/9VB+ptVZ0mEt63ffnQq/VMS4RrTXio7aUYkD6TUErvUYD7M0Jxu1DGNKqbLLmPUoCNhq2ddPJJ/dHs4p7cwo5uw6V1s3vjqkDw3owl3KQLcqMGCIvdJC9LUiAwvhv0sfSyFHeYpI61ygQeqvlPjuTvqujXg+qRgG/gyUWSj48PrwoScTi+u+JIlSO+F9XYnwBEXe6lCffmkqaF8t7XJWDG09nQmytTHBEtRvi4864nPr0KTZw9e4T9TKjjepjzWqjrKVjEBOrlOdfKk4Uis7VCn+5Nbg/iu9mQWc/QWNt/nKHkNEqA91a4N92sCgPjhkCIkMYdFCVGSAXismAr3lQhj8C2hQF+nTxEA4C5Sxdlm4cTZQMx14PBm4PeI5cGMwu4CTncfbWyh4/6romxdK/pSJ+dhnR3OHV7xkNEGeq5r+vn4J5P/y3s3bo97q+XCbERZaEZEDmlyD5jdRiT1WNbXKuC5bdZSlADrGUhwB2bhOebxG8WWl9ONbg3+9xM8oaNt3oaVmwtmt9fcaQj36IJDIGBlJaRjQGSLDhvhrRcGW1EZwKkJD+nC/LtKrjXWpYzxFuEUWrJsJPpcEH4z5Pr85lJXftregIzufv6+s91Cl6iF3FgMpekcVmE7Nh+jkWgA5+kjyY5O1RLBWMeh6NB1s0ER5i/CgAx13QrMbqGITG1+B6uc2ynqXUuVVcZKlBCppn+bK14aMkRdDS3x1pG7CnVsr/fomv28RGjSGh4xhkSkiWowMGyOjpijQyCvw2GtF3haw/gCTwaLd2hhfFeYqQk3ycO1M+Jk48MUtUVZ+e3Y+Lzu/I+dCx5eVmuLq8RhGUKACv3uLleKl6G2dzX/0mTK/3V4mXLs5svVsLtxigDqXkJFVdMIZn12DZxzIlB3u1KzzdVsn6+RgCnCapQLLngWX3o2o7fCsFZkwA+eM9JkSh660DRjhYWMIaHQxnFJ0bDEGeMHyNzRiDA+CKDZEevTRLlDClKG2+TBLFqmSBIvbTNkFr3j3F7cfrNT+8GzcHUNJmnp33mTqEhfwCZHKebRKX8hdLe/duDfurpaH2k2QcAUZXUWl64jKjc/YIYOPVq7FjD7sIkd1im04zjacZc3ObiLzzrjUGhsHAwbmA25pgosrRQKZa3QxOGYOjy9Gxxfjb4jGzfHf0LApOmSMDi5E+wxRoTYsUIXaFSG2PFQzE7wtcu0v4WcVcjMLeFnF3ENPZMcejS17Y8wHeu/OC7oNpvOm+dKVk3XmIh7D+2jSU6cMc5eggdXE5Dom38SUroTOQ5r8pNGNWILk89Hl4/WGw3WmwhbFzGpcYgmOLPhHFmPDxvjIQnzMBIOoFBmiIEGNmeOv9M9IJ5ag8SVo2AwNmeKDRiaB9+qineoIRxlqnA/WzAUeTQU+rugFpBmFvD1F/G8fSQ4/FqvX/DSF/Q7e1onF0w3LJZ2bN4Y8TyV+liYmsCAiJybZIBQuXO/GDR7M6MF0LmQxQFYO6M/UKI++0H1fIxeZY0KNh6/0dajCXaowgOVNr9f06quEepERHVlERoHVzIw/vwvvyBI8bIZFTOzH+vUgUUc7VJFWRbhOFnoiCR24I8oobN9TwM0o6jz0WPrt85m5lS06Zd93RE59/MXwNo8Zz7Cspd1boJ+plAYbtVC3JTHiwGY3SLWLMLpxs5fhVW3AOi8hc8GX21VHHks+q+ivnVrna6KNc8EPippLG2Yml1CADCSQuS/Vjr4cXhpahIeX4XT8AiiGK0331vLV9iVodBkZWUIAMrDykCHep451qqIcZZQlCz+Vhos4ZsCbUcDLLOr+8qns23qlzO5lrjC+M2+q3wAJjm4aXTjTaC3rcd8e8T+fCTXrkB5rYmyVkG1SWhe56MGX/diCB5M7IcUmKtuIjtkTJc2qj0p5H5U0fX2r58A1IZi8NEp9PSo/KK8jJmjMjAj1gaElqGHScbSCUycygXKTRn7DOLkMv4FN845b0BQysDIkWoAGtGAmFeOpYmw5w/twMnS6Vr0rn5tVLDz0QnmsxTRn99PkDnip1EeRoA9tnjCdbF6+1Oe+NcrwtmjhHis6sU7I3JTWjRs9xKKP0Lsx+RoiX0/MOKEJKzABUj3kuNVl/LS8Oyuf//WNfq4iyFP4O9UhMAkaNIL+MDwGMvxifMAQAmig3PyMUWxB3jwF68xTCzKxDDOGBtnABDqxeLc+ztXGGpWh57Ph2yOBS11bn9yZ3He1/yzPcaxpec4WSPO+C2yal0pdmhfMWk43L5X2eW6O+ED8Nmsh0GkAXrmb0nvJRR8j5Vpc5oTnnIjEFheZwkJNmDcf4s572VLf4TvD+wtaPrrA+fJyd6PEB1Lr0EJIvBQDklhAQotPpkiBpqwoUJrubb3Znj4DTG1ajA8uQEIDxNPFmlQRwHtjyFvEW6sYDp1pNecJXcebl+YdwfRltXf3Z8a8JDGiWz/FXijp3bo14v877wYJ7KtjjEuafITcEZ1bhaQO4JDAdkGBwsub9/EUWwKlr1MVr57Y/KKi9y+FHQ2SoFAbGTIEJs3RqeX41HJs2gq/sWZ6mV5JM/6j0sijb/Gm7Xu1z3Wm3lQ+FDjTbsnt2TzcoFvyIclUfn5XXmb2S4LpkXI1eLxOc0HougGmRRJ/U4p3/BUvDmD1W6hsNTpjj01amC5IqPJ2yLd4Ci9H4+9Qervlni6lr1q8+X5Ja7Mi3AX8GRSjZXTIFHvarX45ZKzu102m7Mg0WouxtCmn0rKmwZkVMSM07dJv7MtleMNVsuilTuf3LDOw77lO5znh5olmwyaMgynDP/KmP8b7BaX6DZognX70TIOmuGvj6sDWw6lgnQrmgZyzTs5uETofvhAgZM7YtC02YWW6xG6tt0Ph5sl9HfMgYH08padD4RGAM6AKPhAay1jTbPFG/ZhteAk5fKtvb35rTj4nJ6/508udh24OfFjCy3sxPbKITlvRmaXozGJYYoUmLNCkFSg6aUUmV9BxCzy2DA0vxvuN0S5DvF0bZ6tiVfPwBd56MXf99pjn6tDaWaEvv1kTxUEskvSrOw/S5mP0G7x06rpYJEEXtaqLQPM85Lk34a+SR7kmSLSKzbpwjRcDvPJ1SGyNjJhBGxDgqzy8eSAv4OUrvXyVu1PtBepSBwTKIFvsrGie4cpd31zlZP3Izi7kZ+Vys/Lame4XTHCYqRPv8zIBV+EX24mJZWx8GU2ZFZpYiU2sIJO2xLgVGbOAFB3vN6V4dRBbHX8ug/JbbVd6PPcmvRVjW2e7tx70GhGmGabfJvpnvIB1m6LoBEk97tcV8OzXhtx3x33P58IcY3zQjko3MbUbNfhx1VYC8A4ZQ91qL1cO5OHI3IAaTFrB8JgRLkMiU3TAEO7VBoRq3/ASdPrxcFZBe2YBP6cANL2cNO/eQm5WfsfeQv7+i20Hrgk+vya802mcshFiSzx9nAlg37d5F+IcPcxSxZ/NxnJbTbdH/Y+lkZIR9/e8lU65I0EQzPVagEC/Ey9FJzE6ydwiReA9Sltum6W833V71PNUGmzRhftX4OmNBODV+zGtF5+whHu0XoHC3T7nb58DPuzt1vnHLXGxFZbYEOCQUzZkygZPWuMTlpjYgR59NLKnoCOrqHNfAW9vPicNm1PEAxYHyixqzShszSzq2FfYKpC7QWYbs4IpWOKNfUdAQ7sY61qAODq4QRkD9r0/6bs36XsyEzvXv3GiSatbD5MUxnj0T3kZp6V+WRSVBBPm1E0D1FoYOfNy/kKP+86o7+lUoEEd7gJ5ch2bd2PApbUeQrFJCDXe9llX+4yPM+sFaRkMD0S0ZAUGmrYhzNIKKk58fAV+1Kffy/RC3OzCjpwC7l6gQm6aN6cQzNl52UXtWYWcrEJeTkHb80HLkDE2YSfH7MikA5tYSYwuxUVmqM8ECQxwmxaunY8Bsz6Y9D+ZCT+cCZ3udRW3yqIkczcPcycbA/KaKM3+q7zMf0nm1i/Gpa93aPK7tm6IvE8mA9WKSDvoYx0JqYtQuHH1FiFbJ0aXYYZX6ubOerrVgUkbPm1PSFZAagW86PQKKrWg4uV407Qzp6A2M6/tjU1/TeC/+4s6PrjIPVTR+fmVtvv9hut89S2+odcI9y/CvUaUr0daNEiNnOF9MhWqU2M3xb6T3ZuN4iUkmUwwAyd+hsMQ/bpe7QAMTSVF2rU8ztKV/s0H475KWZitjwutYIpEzLnIuU1csooCZ+tfYD5869NHxgCaHZ9aQRjS15LamMpyX6jLLmCBgP1F2LSh08oGk7vCrsyCjr1gezEnq6gtG7ykALSpvOqJNaEJadfFGzUwKEbPpJGqmTB7gSjuXzvDWVK7YijwTDBqGvsZDsOS3P5FEa95md1I2h/HClvVpX3rd8Z9D2fCNcoYx4gM2fCJNWLCmRi3w+MrIIvC41YMtLgTNhQEKYhcgClJUUvs6LQjMWXDL7fKMgua30D9I286UTPK5+wrEOwtEGQVCjKLgEC8C0A225vfWCNZF5jgNj1Ur4o/n4tUScNNOrhGDf3YvV7RpY+A0E1SCeYDSurvRG94t7d/WclXp4W5hxUcgcCa5c48gfX6sPvBdPjJTKhWHuw0IQMriQEbLFqBRi2xcSaRJrrVHtBCTznQaZDD7Ym0cafAGQABaMPudhv2FbYArsy89uxC4NKcnLeo3+YFeex9BhkkcB4zkWfimslgp58Odi3GO4wQSxOtmg8/nQ03zEN8M3JzYut8p2NmJZggsESSgJLbWPInOMCCxG/wbr86MwkQvzSdoMiNGJLPWyjtcz+Y8D2Whu6Puxq1KHcR4y/GhaDzX4yDEAYlQ2xLSO34jA2fsWMzjleadmASJza1CpS4UDOYk9eWuruMm8XYuv2XQ7jwtcB5KOJl5jPG/aSUK9BHuk3xFgNUo4GeySNAbYuJruVocZ/73shyCBgmmUwpNf5/wPkt3pQYWEYgHhK9mrW8Dvv1sdCDqdCVXvvDCU/tfKQV9HWGuNAUF1mQsRUUOPM04LUTP+cFsI4EsPKQKfxBAegxOvbkC7Lyf8GrfyGui3hZBYLs3JYasUu4mOAtxFna2Atl/JksxFZHe6xY0zJe3O3QbMURipnkA95fw8FSOChFveb6BaFM5ANePJLAbnYvXOzduj0ZfTQdfySJXhtYuylaY2tinWa0dxkaskCjNgZ5irHy33mBZlfxN3ras7Avv3lPfgdoObILuGlP/s3cBTyBtz+f3b0AdxjRJj38UhV7rozVqqJdSyiYj9eA2jS3HidwlCJ/m+VdeBOgEyXICJ1EcNSwEcpvX7wqCt0VQ4+lSKUs8XA68mjK074ACczx3qUog7zC9EKSdFq2J9K8c6t4WrMObMoOHXvQnZHfnFn0qtlgqF977xtekMaZTF7Azchryyrk5tWI+01QmwGu0yJVyliVGuIsE0IL1ryAPJOseCNogiSRf8aLMpfDaJimkCT9a0KZPSkomQRHA3u2KTcL+UvXQP82Ha2cibyYj9epoUYt1L6A8M1QzxI8nOrtxaDNsCNSOzoL5EikLcvwriamnXGJE3k5YT1Qwd/zY1tWXsde0FsWAnW8lbVAk9manS/IzuvK+JHz14vNbEWAa0JY+litJl6njHDNaJcNbTdHn8+55jeCABb4IQIEWOhfZ0ktoRTIuwjsHMSJ6jFzce/mran4s5lIpSxWpYjVqeJNOoRjhASLSP8yOmxNjNmQCTsicTCOLXVg0lUcaMZJSJnEBc2sxpn5sg358KIgOx+QdqbEf5sXZG9g3OyClr/d4D8cs3GMKFsHYMP1aj9vGelapbkW6qXcM2RaD5EUShIwCQzH4PzW+FPLHfGSWHwjhl3vt5b2b92bCj2WxZ4roBoV1KBFmvUIZwHlLyaEy9igDR2xJ8bs2CToPVL5edqJT68BESBRzzni8tXorBP+4AIX8II6C3iZayIFzPQh1YCBVpN34Ibw0aS9wxprNcHNCzCoQSx1hLcU61pFuCskSxXjzG8GMBzCEyiJvzvvb/vzzwTj4PjUSgitEBiuijx3p8NP5+FqFQKQ2RqQTBItC4k2c6JzGepbAT1JYsSOjTuwSScmXsOBptYIySohtcNSJ9JrDmTltvwjb+r6COf9i53tJphjhttMUJMJZhnibG1UsEz02HGuBWZrQxyZ3QWTMYqMU4wPo2TKmX978BQFkYxgin5HRakkTNAwRlmC+J0e85XBrdvTvqfy+EsFUa9EWRqIBTo9A9YOWnoLIlzB+mzEoJ0Q2Yi+ZXTAkuhfQkVLSKfGJ1iI3hfZssD86Oe8bTlFwJnbLnGNHDPRaIDrtUi9Dm5biHYvQUIH1b5CNmj9HUr7FkLAOAnGE6OSEJVEgH3/GQhEJoFiOBUn6HdX+iUxnFyPY9Wj1itdm7cnkSfzUI0CqtPEgFg6rGUBaVsE1kF5yxjPjFVOuJ6Mrj0dW386ul456qiccFRObh57LM7O73iLlylP2YXt+y9w7g6vNS/gbH2iQQex9KCDQvvsRI8N4ywjdRpfj3HDg+JxnIjhyTi+s5G/HvwOlH4tWAG+HUJw/qzrcs/qVXHomSwCvPqlGq7XYWw92qiHmxbQGkXo5qDt9oCT0aDzzqDzrsh5b9jxYHTjwI3BrDwegE0j7y0UZBcJPrzSl9+8UN7jaDBgbAPSbooJbcioHep2kC3LRJ1sfcrqDuBkHAO8ZJRIRncy8jTvjoz7tuBEEkGIIB6XOPy3hI6rQ6v3JaFncrhKDddqkDotWq9L3BxZuyAwl3Ray4S2y0L7ld7Vsh7nlV7bRb6ZaZzyGPsCZeaCJrnzZLX2QoejkLN8gb/cYkQEK3ivk+hbRbss8Ta9v2HasuCDongS1FoYI8H4o+C078wz0yvAZFQs9dodKQL6EGDuBPMx1xqMsVTua32rt0b998GcYi72fB6uUSG1avjBlO/6iLtIYCvkrxR1ruYLnAUC61dPxNnFHVmANL9j/0XhiefK8+ylQo6jiOe41O28M7bVZ0d7V3G+DW0yRWuU3tEVnw8lohgFY+A80zEsCQYQ3eGwIYIJw3QwRgg6TCZ3pFBKr54CfJJa9KNNc67bw5v3JPEnMuS5PAb8uVoZfSyHznGXz3JWzvEc57n2PJ798wfijEJOZhH34xtD59sWf+RZirud5YNbFSO+W5Oh21N+jhVrNUVr5WvdS8GVcCKAJ0PEdpjYjqQw04oQ1M7GjNBBCCgJ5ENIL0r8fiG4PxHfRGFHgtAE4Vad5/G066ksUq2jXqjJayO+s9zl73iW7/iWc7zl71sN+6527r/ScfDeWGnPWsWwp2LUUy72lEq2Skc2rg27H0nCNTLfgDmwGsHCMOqFcA9MehHKi9A+hPYjybTA+o4GGUCTXkAKM/LCNDja7xcMhsEMxg3TWzDtQgkHTMxvRHmK9RdTrgK+9ccu248Dm7nD3vxh/8Wx4AmO+VuWprDfc1EULBnyFvevXehbv9Rjezhh7TRtqLxRd4zwI5QvDQVTb97IAwMl32hHgwxgtA8FSr7W9u8XkgyhSeYEJpKeRDKYoAIY5UmQLoxeRSlzjBA7w2z52p0h65Uey7Vey81+6+0By40+68NRZ/2cu8cSmduCrTHClaB9CQrMZEPMkvYngKi3B+lFafAWr7TDMUdwOojRISz5O5VIhhP0G4FDBXEyBESQPpz2YPQmTDnCmNmPydaiEnt4ciUitkOSVXhmHZ20RSes4elVZG4dn3ZAUkds2h6SrYYX3OhKgFiPUgDcT4CYZdiDKAneK4JuR5HtMAre9JVCab3zgJkci1GA+vcpiqXyZEpgPYoTYYLyYbQbo1ciCZMXMnpgs48w+im1h5xdg4EA1yzonFcjwwsbIsPGmMk7twrPbySUm5jChSvchHwDlq9HNS5o0Y/YI9gGTPjwZBBLRrDtWGI7jjLLGPZKUWb7DgYcf5WfyXRJ2rHAEXDwvqDJSYvciqHLPtjgRhd8uMlPAC0GCHOIWgySqo24Yi0674yo1mIqZ0xuD00ubE4YNicXtqRLfpUT0mwmVC5UvYVo3JDGAy1FaGuUtkXIlWBiM04AZFB5Y8w7Jt8SeLqDAaMEheAkEJpa36lgpqJtw+Q2RCTDKGn3I0tbsSUvuhzArSF6BShMWEPoUgAxuqEFd5zRVtzkgoH0a9FZ0+ac2TNn9s6aPPPLfrUltOCIL7pgsM+CG7KGSGeU3ognN2Lkahh3BFAPjEVJKk6+agsZETSykwHjqW+Yp0TtWASVIGmU2gZNrCuMWt0xqx+zBYnVMLkWodYj9HqUXo+Ap4jVG1v2QFYfsuJHbQHU5k8AOYKEwRnUrPg0Nj+Q2urTWn0me8i8FrW4oWV33B7E1qPkZpQAmd+NJLdgcEx4IxILYXi6+QcTIqAdjZn5/vBrEamvU+9IOHCSBOGJomBUazHKFSXccdIDMbXJB9F+IJgOgPIRB35OuKI42CG9T2o3atUPLW8GLa7QG1m3wunlRjixFWP2YcocSPupbO9PgCqP+dFEOIEijI12NlqCuSs6+UYUvQOlL7XAKB6B0DCMhxJMkgcpOsokLibQ4iCoE0kIAwLevp0KPUZgJYKlBGoWTG6FYFcIcgVTCkFbYZhRCHaHYV8Mi6b2Z16bbl/BBAH0gTgewTEIx7HU9292pOTrW7sZvb40/I4CpyvBTJFoIITcRshk4i1hRBIHIpMEtY3/VOnfoQAC4QChOFAMwRjBWHolntoClihBJ356WCBmzk5TKOOf9I4GzFwl/DnvOyj1wwGplW2S+eWIbSKZJF9/t/3vO7z5MY300d9cgaVff9s/9XUwYCKwQpAkI4L5tidYAuEEs+XN7xS8LRycqG3m9ztI+p3H/Fpv39uQfLcH/dZ31pJvHerXHu9yu8g/feFPBvAOb/prj/8HXhuHogplbmRzdHJlYW0KZW5kb2JqCjkgMCBvYmoKPDwvRmlsdGVyIC9GbGF0ZURlY29kZQovTGVuZ3RoIDEzMjU+PiBzdHJlYW0KeJzVWduOHDUQfZ+v6GekOHW3S0JI2SSb58BK8M4lEiIgwv9LlGfs7c7Murt3yC6QyV5kr11Vp07dunGC+LzA+Jadph8/Hv48pKzH1f4zFnGqn2/fTadfPn04vHzH04e/DnW/oE0IatOnnw+/HN6f3ZApIROATBmSqruXemNsIqlOibNpvfnzhVnCzd3h5a1MTNPdLwfs6saVU7LMSMI43dX7XjAkECsh8+6n6WsAfvXNdPfrgTRlPy5D29BQRzVUuo2vfPyjt3cDQUSSQorulmapUKkHujR5XaXEV1mXxKAJ631bkshmE5T7pWPc3RNcjTuWk9P8DH5MJmBhJlpyKMW6tpiTUA5DurYngBFDgIhCXgBz3NFEJYzLPPvHjxuhdmGyTDtO2HEjp7g//vOOE9RkuJLpLELxzEsPA0CACcUq8zfsHwkS3yeIOKmgb+N82+SwI2bZYak2zAiKSVn45URUhISoVm28PwL7dC4BjpPvULq7Bw194ehG61CBmQFy2fa0zloz58zlAa3HMYL8eXKqn2Nw1M9ZUOjA7MiEEfy5gOVuLieP6wGw23vTfKGBOducJPh120DVjOr3G3YKH0vqVFjmE/aqQefZrOrdN/y2bVgumM3PT1i4wAtJOee8hFFKtPT36QRqRGIEb8ERe0eQ5NAbJQJ/GxpuecJq1IO7zFq86QTOkE1oGxstu7RDokQazNNt9UB6GiMOPi9hlYfja7TestsDaI/cID1S4xqmcsGakrywspZ/4uoRyHqzHT0UQAY5NiMnsqUkq//yWeRwguwnB53w77ijNUsyS024s4k3DZQoreHEi+rBiY3Fxc83OitGykTBlyy1GxoqRT2likEm9nOH5AQEArOyPZAwtM3hkEWy9Z6FnbjW/L5Rbru2l83Xqv6WI/lGCchj/f2mpwgDc5ix+/JoX248B3i+h7TiT0Va6mhFLhfBWeFWih6A8U3fiEal4CJgR8DLPjZL9F1gkRoeT+axz8cOkXVtLz3Vcnh0AOAmPl91Nf89YEfKZFfw/xkddwnFf9QRu2IpCv1TFYB9PI+sARatJo9vshEmzXRJjkZLOtyDhZHDeFHz5W07gZAlKuxueDfD1VJY4bZmxqsmO/q+6JrOmbglwSgFsamslLct8myJKBDRwOsitBWa6OLNymPiSS3GoYXdMx4METXb9eRedowcggvnzTdpICQ7vCr7vBotcAKP/tJ3gG4U49iCa5n3yTCoDw4K7qLOyEDIwIvZMVODij0YDBcNZoQMeAx0801Xp+3oWRJE44/XpO3bQdtCp3YXKSlDgcUzoOGRPemOgZ+9ddhOUkTBFZ5b+gzNxJhwTOTiGccDPdso+IYVyMoucmpkSjP2lZ4UuuyCknVXRhhWv2GmH7aY3T6hgrgYpFrwBYbMrouovJ7n9RkIqxW5guj/M5B2xRLDk7UOvUrXB6qI22C1HLw5IXKU0ChDK9mce7+IQjEKLRw1ir1hRh0OUl9+dNRIh4QCegU1/1WLdxHNSoq2IYgWxYB5Wn4PhC4XjwTMlYCR7WtnEZq8iO7J6+bHg9FpOc+Lvx2+W1OgyJNVjVE1G4Iv/UTxkoUWbeSj55bWBF2euJqHsjKuPr4J+IIYYGkjGjLWjmJ3379WtodcvqTJKmq8VlKgvx4AzBBp7zzbBwhFuF5xfTd8vb8xEC2gV5XEZzDs8/SSOQrd6Y0m95cGEddZEml9B/r9V9Pv8WelmXdanw9F5U4xCWy9anj5Q5ne/BEC3x/+Bqo7I4gKZW5kc3RyZWFtCmVuZG9iagoyIDAgb2JqCjw8L1R5cGUgL1BhZ2UKL1Jlc291cmNlcyA8PC9Qcm9jU2V0IFsvUERGIC9UZXh0IC9JbWFnZUIgL0ltYWdlQyAvSW1hZ2VJXQovRXh0R1N0YXRlIDw8L0czIDMgMCBSCi9HNyA3IDAgUj4+Ci9YT2JqZWN0IDw8L1g4IDggMCBSPj4KL0ZvbnQgPDwvRjQgNCAwIFIKL0Y1IDUgMCBSCi9GNiA2IDAgUj4+Pj4KL01lZGlhQm94IFswIDAgNjEyIDc5Ml0KL0NvbnRlbnRzIDkgMCBSCi9TdHJ1Y3RQYXJlbnRzIDAKL1BhcmVudCAxMCAwIFI+PgplbmRvYmoKMTAgMCBvYmoKPDwvVHlwZSAvUGFnZXMKL0NvdW50IDEKL0tpZHMgWzIgMCBSXT4+CmVuZG9iagoxMSAwIG9iago8PC9UeXBlIC9DYXRhbG9nCi9QYWdlcyAxMCAwIFI+PgplbmRvYmoKMTIgMCBvYmoKPDwvTGVuZ3RoMSAxNDk0OAovRmlsdGVyIC9GbGF0ZURlY29kZQovTGVuZ3RoIDg0MTI+PiBzdHJlYW0KeJzFewt8VMX1/5n73t27m7ubze6GANllIYkGTEgIAUS5kGwSiIEQwGyQmAQICRYwvCRWVKr0D40K9vEDa221Dx+1v9Zly0+CVdD6AB/4xGdbpS0CVWLVYkuR7P2dM7uLidp/09/j87t35ztnHvfMzDlnZs5MABgAZCJIUFxdGakSlgkLAQQdcy+prp8zD7LADsCmYlqvnrdgxoqedV/HdBTTgTnzikqm3/btGqxP6UsvrayLXnnLBgnAeRuAfGTJyrYu4W2xE8tjWL5iyVXrgteqM+4DULoxr2tZV8fKma+/8y3sAKYVe0fb2i7wgw35I08wOlZcvezE5r+MAgi9iM19q3Ppyu5XHj+dAZC9GUC7pLO9bek7b5z/Y6x/GOtP7MSMjOuUTzBN7Y3uXLmuu+529WfYFwPzOldcuaTtuvarJwKIw7H8wZVt3V3ifuFpLOvCdHBV28p2X7TEg+XIj03punLtukQCrkf6VirvWtPedd64Ph+2fQIF9nMg2dn5S48IGghgALMspJNlPnzZirZ1q7As+VD+QqgDFWpB5vWLYAFK40OW/EpMVkt8Su1+yYPfqzcmJmMf/mTVW93afZzjwGchz5EB8q9//OKWjKmfQE6y8Z+37cmm+NlLzsu26vuPa/epN/Fess94g56ihdSoGORBPuJYfBn2tQhxCr4MqmEm4iX4MpgD8xAXwKWIUWhCZOIPUWoyaPLtcimyGZOMxbvgesGjCYJDEQV6pFS75566ecEgmFABV8nHEototOxAEODOARIQUz2VoBVjL8pQRLoS+3MJNMIyWA5dsBauQj0A8knmLsXcFbAG1luW9cfPv1+QYfop+J97GWOPpV9hLH9v/LJXXPCPXsmQa+SH6VVm8vdR9Tltpa3MTs9GRwjf/fpM3m8VrQClJOFcwpFvTNEMAphK0gK4UFtJWkQdF6doaUAdGYah/SZpBSmA+SjBdlgM62EJdCK1Di15HvJpx/y1KOErYRUEoQwuQH7F0Ialy7HmGsxfi2EZ1g9+CY8GxA5Mr8Av1nxJeZC38lOMSzjfiTzni5wrkFqDuidsw5xkfy7AkunIewXGDZjXgVzX4VdB3u5a3verEJdiTRw+bPoHtvB/+khPQ710AnZ8Pl+YAnvP1XF+sfwfPcpL4PyX+7AeaqVmmC58gvJMt18D9efoRbBD+QlskVow1MJ0rL+F8nG13SFelPwGy64V3wddPoZL1F7IxuCVinAOg3Ucw0kKNOvlx3ENnI/fTkL6FeQ9D+ODqTXpf/I5CIfw3QG78U0++zDvINwMd8H3UvJM5gDcjy89S+FauAFr7MA6afp78PLAfKGYTWQB9hP2GlQJATaW/RoXrtfgfXifvcSuZ/NZJouwTjYWbhHKWJM4TZaR3g2r8KvL2XPsOekNtNxV+MXL0MJOYVm38CK7VbweNgmbsIT6enfiRzgf9mJ7/+1Hg3+mj/RD+qCH9PG/8vwv6cO0z99/NzPvdmdV/aSX6fGS3B/2siwznpt75YHxoVUYVmJYgeErGK7AsBxDJ4YODMswtGNYimEJhsUY2jC0YmjBcDmGZgyLMFyGYSGGJgxRDI0YLsWwAMN8DPMwNGCYi6EewxwMszHUYbgEQy2GWRhmYqjBUI2hCkMEQyWGXlYev1LDaGJ8FUVl8ZUUTYivoKg0/hWKSuJXUDQ+vpyi4ngnRUXxDoouiC+jaFy8naKx8aUUFcaXUHR+fDFF58XbKCqIt1KUH2+hKC9+OUVj4s0UjY4voigcv4yiUfGFFIXiTRQF41GKcuONFI2MX0rRiPgCiobH51OUE59H0bB4A0XZ8bkUBeL1FPnjcyjyxWdTlBWvo8gbv4SizHgtRZ74LIrc8ZkUGfEaijLi1RS54lUUOeMRinTTqtRCyxvH50YxXIphbsP43KrK8bkRDHNmj8+twxDcWbzT3Fm/UyreyjJuZts337n5gc37N7+wWd7eeWfnA51i6/Ku5cL2y9j2hayrkW2vv7P+gfr99S/Uy9vn3jn3gbni9oY7Gx5oEKdtnLNRqL+m9Zqua8Su2axrOyve3rq9a7sI2xj+zG1d2wTYVrzN3Fa/rRUTitFldgmt61jrWtZVyaCgAM3Z49bM8oxpz/tYxo9yfyQEUOleDC4MTgw6BgcGOwYbBg2DikHBIGOQMIgYBAwMg7kREI8EtNBvvVroNZcWetWphQ7rWugVhxZ62a6FXrJpoRc1LfSCqoWeV7TQIVkLPSdpoWdFLfSMoIWeZlroIGihsCsySo+E7JGgFslVIiOlyAghMhwiw7SA5tO8mkczNJema3ZN0xRN0gQNtNpe1WqojWn1l0V3MbatKeaphdr5M/YCY9bXbyn8Lz5rZ7ARtbGcedHYjhFNtbESJGDELh/MaKoNYioc2zF3YTRWPKKpkEWWz5vBauujuzQsrViUjH1G18W7yssjy4MxmB+Nma1NlbuKoeuX5F9kdwW61vJn3bq1n3/+qx3+F551hcl1D31oetDPPa1ZuETbrX48Gzmss7gLEjpAR9TBaX2Ke7kLaRfHDDAQDXBjvhvxDHjAg3QmZCJ6wYs5WZCF6OPoBx9iAPyI2ZBt/R29vmGIOTAccTiMQByBeBpGwkjEXMhFDEIQMQQh628wCvGvEIZRSI+GMOIYGI05eZBnfYKnhzykCyAf8TzET+B8OA+xEM63TuGpohBxHIxDvIBjEVxg/YX8PMTxMB6xBEoQSxE/hglQan2EHuYEpCdCGWI5TESchPghTIZyxCmIH8GFMAVxKlxo/Rku4ngxXISl0+BipE0wEafDdOsDmMGxAmYgVnKMQIXVB1VQhVjNsQaqEWdynAU1uDPWwizrfTxbzEK6DmoRZyO+j2ehS6z30Cuag/RcmIvYAA3Wn9CDJZwP8xAXIL6HfvMCpBvhUusEnpoIm6ARcSHHy6AJ9+BFcBliM8fLYRFiC8dWaLaOoZfbgrgYWq130RtejPRSxHfRm11iHUWvuB2xA5ZhTid0IKL3i6edK6AT8SuwHHEFXIF1VsJXrD+gX0F4JaxA7IJVWLoa8Q/kU1u/R095NeI6WIO4HtYiXgXrrCOwAU9aR6Ab8R24GjYgfpXjNXA14kb4qvU27sPXIF4HGzHnesS30cu+1vodfA2uQ7yB442wCXEz4m/h63AD4v+DzYhb4OuYvxW2WL+Bb3Dsga2IN8E3rLdwdye8BXoQt8FNiNvhZutNuBW2If1NxDfhW7Ad8dtwq/UGfAe+ifhvHHfAtxF3wnes1+E2jt+FndZrcDvi6+hBfBfpO+B2xO9z/AHcgXgn4qvoaXwf8YfwA8QfIb4CP4Y7rcPwE7gL8W74IeI98GPMv5fjfXA34k/hHsT74V7rZfgZ/NR6Cf4d8WX4OdyP+AvEl+AB+HfEGPwCcRfHODxgvQi/5LgbdlkvwH9wfBDiiHvgl4i9iM+jN7jbOgQPwYNI/wp6ER+GvYiPwEPWc+g3/QpL98PDiI/CI4iPwT7rWfg1x8dhP9Z5guOT8BjmPAWPW8/AAcRn0d96AumnOT4DT1lPA+YhPsfxEDyN+DzHF+BZ6yC8CM8jvsTxZXgB8RXEA3AYXrSeglcRDwB6t4ivwyuY8wbik/AmHEZ8C/Ep+A28jvRv4Q3rCfgdvIn4NryFOe8gPgFH4DfW4/B7eBvxDxz/CO8gHuX4Lhyxfg3H4I+IxzmegKOIf0J8DN6DdxHfh2PWo3ASjiPdBycQP0DcD3+G9xA/hJNY+hH0IX4MH1j74C/wZ8RT8CHiJ4j74a/wkfUI/A3+gnia49/hFOIZjp/CX62H4SycRuznmIC/I1qIvzInzq8NzZpZU10VqayYMd2cdvFFUy+cMnlS+cSyogvGjS3IGzM6PCo34HUbGU6H3aapiiyJAoOxkXBVazCW1xqT8sI1NeMoHW7DjLYBGa2xIGZVDa4TC7byasHBNU2suexzNc1kTfNcTWYEp8LUcWODkXAwdqgyHOxlC+dGkb6lMtwUjPVxuo7TUh5PODERCuEXwUigszIYY63BSKzqqs6eSGsl8tvlsFeEK9rt48bCLrsDSQdSsYJw1y5WcDHjhFAQmbJLAM1JzcbEMZG2pbH6udFIZU4o1MTzoILziikVMZXzCi6nPsNNwV1jH+25udeAxa2F+tLw0rZF0ZjYhh/1iJGeni0xd2HsvHBl7LyvHg3gkNtjY8OVkVhhGJnVNpxrgMXkMUY42PMJYOfDfScH57SlcpQxxidAJA3xnJiwPE0D9g17iOMLhagvN/WasBgTsU1zo8l0EBbnxMEsKmyKCa1U8mi6JGsBlWxKl5z7vDUcIlVFWlO/qzoDsU2Lg+PGovT5bwz+sDwYE/NaFy/ppLitvSdcWZmUG3k8lUiYbamxRnYVF2H9tlYcxHISw9xorCjcFfOGZyQrYEaQdLB8XpR/kvos5q2IQeuS1Fexokgl9SsY6WmtTHaQeIXnRvfipn1k14Rgzi9LcQNvon7EfBWolLxIT3Tpslhua85StM9lwWhOKGY2ofiawtH2JtJS2IiddwSbC/EW+Vc4ts/VTlemkatjtGBUyBGbSFuYEaxCCM+YigUGqosnSaMzpgajLAfS1bCVVA2iBvHBhDimooaKRPq0oiYn1BRKPv+fLuWk+iSPiWkDeBmYca5PyXb+YdeStalD5wUj7ZUDOjiIqZzqYIrbl/dTIFmkGsYvNFJnTbpIHIMzF/MEZMOzSIsBdI7rg9Fwe7gpjDZk1kdpbCRrrt/aeeFa9LK5tlNzskcL187rodzwpGQWBHtmxgDNycSJM8kzIZlbhStPT09VOFjV09rT1mttWhwOGuGeXbW1PV2RVmo2iiLstR66KSdWdXNTzGjtZFOIf3jm0p7wvOjUHG6U9ecma0yomB9NdWhSykB5Aa4gM3aF2da5u0y2dd7C6F4DILh1fjQuMKGidUbTrtFYFt0bBDB5rkC5lEmJICWgluGqEBc0Xj9nrwmwiZdKPIOnl/Qy4HlaOo/Bkl4hmWek8wTMk5J5Js+jZxz39f0YFtk0eUhXJLJCKPA7/vSjDaogi/TnCBA0WZZBljDDbhsab4XzFgfxtg2qgOzSvJUkb4ddGRJvVSXEzwdUH3Shpyhp3gr2A7uuKPq/xFv8x7xVNclbtKlYF3mrslNXh8Rb01L9HlBdH1hBVWVeLjo4bwUzXEPlbfsnvDUtzRsP1cRbUzOcGgzlsaV5D6g+6NIXT+lJ3k7irRBvI2NovO32L/LOGNy4wo1IcmrYD+Jtc2fYYChPkrc8yPC+lLfssiFvVcMMzxB5Oxz/hLfdrqZ427EfqE67LdMY2rWzQ0/xHlDdGFQhxVsx7HYH9dtu87qHxlvnvJVBvN2DeDtUXq64HThGVKfDkZXpGBJvpzPFe0D1zEGNO7Qkb8OBY0SROxy+ofJ2/TPeeoq3R9c5b93h9+owlMeV5j2gundQ404bn1hqpjPJ2+kIDJU3Nwp1CLy9TpSfzQ5OPcfvGhJvgysOhz2gun9ghYwMOy/XfBnYD1RnhnNEdgYM5XF7UrwHVM8e1Ljh4OW2gGEYZLKGK5hjwFCeTC4A2yCjzhlYwePWebktx4390J3gNkLD3TCUx5vmPaD68EG8PUne9hyPx0Mm6zHGBDNhKI+PC9c+yPCCAytkeV3cQB25Xm8Wqd7rOX901pB4Zw8jxK4NqD56YAW/3+Dletjv95Pq/VkX5PthKM9wLgDnIOPIH1hhWLabl7vysrEfnkzI9qNbsIldLm6SLsfNToU80yffIX5fukNFJuW0/6l3MEwCFPX397GilmaMxhdnukPuMSF3aJMI/ZsEPKciCzyzIomOTL11XLpafhmyWIsZP57FcOFiYqPKhOsM9lUHy1KYuBVug/ugFw7iMf4ENqvqfj1fL9cl0IO6rtTqfiXi1g1DqHUrGRmIQYcD0dB1RI/Tiai7XEqtO0C1KQfRV45Hd0HYhq11Z7ANXia025hdXCheIYrnZ0zJEESHvpPdy/awA+x1dpwpwI7rjGkQgK0gUhe26DjgXutFM8PtVmrBq5sU6y6x1zqxm9pD4uPdhsGJE7szMjjx4W7qKOWYY6iz4kyvLUBlhEKtbabL5jXoI0Kh1ivCtMLCaX2FhUYfv781DtGvpbm5pbmkpdldilQzT7U0M+O19C1vH5ItzU81J0vHF/NiNS88SnB7PaUl5X4lFMT5A6ES6aKK1ucf+9OfH3n+ylW/SHyQ+H3iQTxq+v8s3/izqsTuxJkziae/9d2fsx+weayGxckx3IHb7m3y4zjNPazMHOs1Sc4BJ4tCN5ZqGVszhIxIp9qtCqTGLSorUJnqzcwUatVe6z0+fCQ+NB2kJdVOX/O0nzSl6qQjVSD5pehe65SZQTpT7ZUq87N8JjISKAkJiZO7iTUSpzhrJM6YDhIlk6gBTCd2E2ckPuBqQeIs1UBKpQYw/alZQg2wzIDRaXQbYqNzg1OABXq7vl4XF7qZmC8zIUtndr2GCTZ3jcQ0SYBp04y+klIMXPr0G6CBwsLm/sOf0VTax1XRzApDIffoUpI/c/tKSzy4jo1ijyTeZMPmsFK27OxTFUte/jAxbri81564KfHM2ROy/OleO7uQBQQNZ8xenDZfk/fidNu3F2TrUbOIy1ZmBTITKwNQAJOgBqLQCUonqoRmj6Ti9MHpVkAyQ5s9zGWGxFEuMyTeS8oMuMyAhEl6QeID00HSgyCJjqfdJDpgJDoYTmLD3CO7+RzotZ43Heg/1UK1BBojETHjr4P+/tDSvHpNXzPKgRWWukvdew/Ke89U46jQqsRTOCoZvmn6NCkgCQelN6QT0mlJArESpGoVktbDmzmZHsCp9ADOfG4ASaXzGqmen0oqHUTec0o7ee+rFbEm1dk+Zhz7rKvGMaMPuzu+mDoaytpxUNiBnf10N/bWaZ1UnsDe6qx9l0CnQ3O4ahdEWWI2yebAg5os6A67rKh2VRBcTrdnctGhQ8bv6IfN4OP2+CePL87Zpfw3PjYnVgsMakRWjb0vcNW4ul1bXQddMv2bKxwS65bYBmA1WIi+JlNVUVKqZEeV3mudNhfb7UqtJuMMKNer9Q26NEmukbtlUe8GuVvSu9l6ENdL1RJDPnCDTbpBEwTbeuSlavlaudao3YsnB61T6BYENhN7Yd8GwnZN3SYBjkHnY0j21eijl68/RTQHJmcXBSinuZmQCvtxjcIFqw/HmV1Eg6VFi08pWreaoaW5qUkOMxbGycF/0tlpiR8nHpqWKHmR5bEZVexiVviiV/z4rEs+dJaJ1llR7Edrr7X6xJPyMfSDstlI05djcsuoc2brddVO5gySBTnTKxISf01akFOjepTmUwCJo8kp4NTJfDD9h91kQUh8bC4jC3J6+ULlnb1FYZOUGkUARSNOyjDipAwjNgrfhxS+DykGVVd0+lYZNsZX5ov4xPPdU9yz3KIYFTtFwRdw4Dc+g7j4GkQ37RYuynI32GpsTHDZaSd5kO8fDhtOyj3E3abibj1tWiG+LShdvmMMXpUw0V84YFXqn2r00UwcU6bg1lA2AUpL/GjrIm4USpYRKplYLl6w5JGnz7DggXsu3bev5trvPsJax+HOPGcJC374EVswm310JkecuOJoLHHt5CDtDtOtk9JwqQLdwlHMMreM5lKP+pnYq7Ie9Xb1fvUh9Rn1LVURGmXWqXVrW7XbtPs0uUCbpNVoUe2zrF7toPaGpkNjYAMufKNISxrfI7UASVQbS2PWuCw1g2Sp5c6uHskEf6A8UB3oCGwJ7AzcG9gTOBCwBWiFItEj8TbXNxK/3U3MAkl9cuIwXzMCtCwSVyLMrxDnABs5m83eYrBJRo0RxT1CMgxiZ/A92uB6MoaTggwfsTC4QRhcw0Z4i7pTvVcVIV8ul6vlRlkS1IbztSnaLE0UG7UObYMmqppfE7Re69HdxERLdkUh4lGzjI9TH1lfzRpZB3dJZGAm3+JMvrOZfDNjcnQYG9bg5b3x0g5JhUSYfPH2cvv1dqCrM8u70CvI3EGSG3SHV6W1j2zF4M5Ds3tyEbeWPuNVMpPVSOF8XP2ZIeFE7jN+l05g8RPnyNXJvZDMioW8fh/3NlS0r/y8MqN8IlqYL8vLRqmKGpqQnyc5z57tuGz7j1fWj71szc3P3PL9H9765Ls3XJcYff2lDQ5hbs0cQX64PdryjbHB87+x02K2u7Z/beOhaWx5w+x1a+vm49o0HY3OwlmeBT/ZC34UYAZqxE9yG0eiXO9hYtYknDRRm2hzuHTVIdepdY66Gp2BLpD2dA/JSyfvgExVJ3m5STJ6kOSn+0h2mPuROYw7m15SjG5r0FwNGUJDpm7PUDJp2vGVbip6vZ/tdH0opKnGU8ZTzU+NL8Z1jBUWMj61vP7SrLAb37LSCSQR4ZkpJY2r5bfe2nfHHc/cM69Fnurd3J4z4q6zq8Xtdx16byTOq3rc9R+Tn8CDhBvefDCTqz8Th/kgn/nXiOmNDonT3LCROMMNG4m/m9xRFt0uvW6Dm4FbosXPzcfvdnGfOT1+N22u3HPutY4lFz6qoVD6tOkY4EH3Wq+ZfBa4Ndr83ZnOuQaQ4LlAYaPC+4iLnd1QyFd6rZCWpEEuEsqo/ymDL0h8HSpkJWgcaCt5ZRMmiiiekJvVjo9ExhdHKsu/zebKT0SKKTm+8sxUlMynL9EJYod1UlDRAjQ4sBfsaAE0NjvNJRoeEeb53Mm0++359nJ7tb3R3mHfYNdUxa/kK6Ii1CXdyteZBAMdyg/SDuXH5POccyglYoa5z5l+7k5y751lclfSx91I5GHmOBxI2fbIB2SB2bVhGs14SWlQHYyspW+wv56URNItKizMxDXY6yvNCu7Yt6Q+sZ0VSXs+XX7pkvtptFsAlBG4vuayXnNSyCRrD3EPXB2Op5NQZ0jID5WHGkM7QwdCMtSV57Jcg8aTq9FgcofTQHKpg34aTC5fSnMlUnMuVzOW9SXVnMuPIZhOmCNooLlaXTl68pybyk1HHUbc1HPcVM5N5dxUjbhhWd/ulBefMAPci1eIrWrUqW6/O9993C0BmRb37Nzcj+M2Zdhs3AbRa+O2ypm60w4fL+BKcdu51Wopkz1lzuPGyrcFd9A/PH94+XCRBfhCGTCpkcBY6kZ1oBH3iA0BCQIm3xlMF20LvgyvT2zI0Rt8uXbN7rbnqD7VoyRdmaQvg37YIVIX19kXrPmzzbWwuW9QgpSbXANC7gm4CKg4/yfkpYhSPy0DExF8WW655TeRbt++DYsnfy1n38Zpq+4+tij4i0X3PCjc079g4tkTwt/nXBYtO/ueVLTx1u0XNTwZ75+QtAvxDbQLPKyYgUy+66oZ/gyBbchkUOc2UuI9zBcJLnAuVi5HLlE7l+ZncnRzgQ/n0j23AHBdciK1BJwyDTJ0t1an2vy2fJsItnM6s3Gd2ciTohZsKRccKa4zW1rryQLql403byMr4KcMm0dqcLntNnRWXSokVTBQ5IMFTjtXSsahwaINut3isI6rp2/L23fD1MtfZa3ClT/7xuzJZ49KRT0/SMzvX572XOwoQQdksanmGL9JnfabtIvskRmb5Gfu2X6lXKlWOhRJkahUIXeCr3J4puTLp5J0HjiRdCcUcjG520dOCPf8yK+4int/+uwtsBPuhT1wAI6Dkj64SXSTRucavjYDv8+AID+Rcf8CuB8J3MiBexngu0Jk7TYmdrhYZyYTIq4FrnaXOCtzYeYVmaKL+wSuBlsmHbR9fO9oEFM3DsnbB0fqkiJ5N/Ef/LZC5XcP/OoBf81fPOSSP3l4gInTto/LF/mReKqF8CjIJC+yDA+4ynTmeOtYInH2yLsWHGQjvr4zcfSG7wnDTrPxid8kzib6E6+yCxgkVr7xK7btMOljS2KRNBb1kQE5rM70jeA2fXwE882utv/NLlTbd9oFO4mbOm0nKZOA7Gm529M7IhLHuNypjjmSpGV3u5lUx+r8AlMFv5AvbBGOC38TFBDoI7JdgZ8HSAcCt2IhZZNIceMVuKUK6TYEWt5KSWiCQE0JAjUjDI86O51Co9qBB7mIl83KZl6+Y6Z8tAZnNl0IUQ4Rpk652Q0qc4mKM11ChOnlJxOHyr9W+ddqWjs0KZLXQ1+8g0B3jPsgKSVhijQ0hqZF1kRSkheVlCe6fT6cI3zKsMi+fSu+ezRhwceV3/N51pWzxfftLVh3YSIkvxJdkTia+OBU4tlicWz/rTnj2a3PPjwpdXYnn98FD5gj7eg0kF8eMAqMg4Z0wPW6S3AptjqlrhN3j/T2qqa3V/Xc9qry7VWVUhdCH+xObSBn0xtI8jKNcswxXA4ZAzd0BWQ7X8ntQoOu4eFZV5Ne2aHCksELNfmufK+FlDuWFodfOHTxtPad+/Z1HiptFbsLH7qx/3ap6Gf7PeRnopdxFscYguNmYZjbopYbyBVUl98lFIRrwlvDIkzRWdkIJh50M7c8u2PEhhHCiPStExJHzIVkSiP84J+N/udO/V59j36crjEl7mOOOpHN8nMY3ZflZ7CCIBPah60fJohq9jDRK9Z4op5OT7fnoEf2ZJSz5GFgA7+fVPG8T+y97kyctQ1Bb4AIb0NG0JGh8msqMo8n0b1/spnuDlpS94JcKnQo5z4YOvFp1x2wqLC8HH33sgn5F4hl3ElVU66r35f00aZX3NkWu//GyypCj35vfXzi6jWVzeu3XrvmmV/+1Nzd+Z0rLpl68Zym0s3fmRVbaI7vKLt48rdW3Ur/mQ6utU6Kf5SKwAOfmvleLskNXmZHt1zVmF+rxvPQvZq0RdujHddETSeda+TLkoy0tP0QkZyfmo/rguTMD0romKWrfsgtR6PtJYsfp6DuhOe0R1A9fk++RwRPehv0EH9i5qFpHyZr9OjElv5shKgRZ49E3DwScfLw5YCa8WSKDS6b3eXQlJSf8PktatA94Oo1fX3Js5HbW4rna/T0wmUK93jd7MLXL78je9++4GOLYr+SivoXnF5RLXz46Uvfmbb8mYeE/SQ7HWX3jlQCCvSl7p1cksAcsiIoCp4rRQnHuoc6LkmaSncpheeujTwD7pvcgz9K1R1c1ews15hGvwI8mNOhnA7kqognsjn5fBtsVDYocoEwSagRokK3ICvXgnAtkyRYP4n1MiGflTOBScVZfqVWCjpQdr0S80v5UrnUIW2QZJBWM4eCnaAm6aIN3f8iXKEmX8RviPrRLo0+PE6OL+b3P3TzI9hKEmUvshwWOuCVqvo9wgcA/wnlv1r6CmVuZHN0cmVhbQplbmRvYmoKMTMgMCBvYmoKPDwvVHlwZSAvRm9udERlc2NyaXB0b3IKL0ZvbnROYW1lIC9BQUFBQUErVHJlYnVjaGV0TVMKL0ZsYWdzIDQKL0FzY2VudCA5MzguOTY0ODQKL0Rlc2NlbnQgLTIyMi4xNjc5NwovU3RlbVYgNjEuMDM1MTU2Ci9DYXBIZWlnaHQgMzU0Ljk4MDQ3Ci9JdGFsaWNBbmdsZSAwCi9Gb250QkJveCBbLTg1LjkzNzUgLTI2Mi4yMDcwMyAxMDgyLjAzMTI1IDk0Mi44NzEwOV0KL0ZvbnRGaWxlMiAxMiAwIFI+PgplbmRvYmoKMTQgMCBvYmoKPDwvVHlwZSAvRm9udAovRm9udERlc2NyaXB0b3IgMTMgMCBSCi9CYXNlRm9udCAvQUFBQUFBK1RyZWJ1Y2hldE1TCi9TdWJ0eXBlIC9DSURGb250VHlwZTIKL0NJRFRvR0lETWFwIC9JZGVudGl0eQovQ0lEU3lzdGVtSW5mbyA8PC9SZWdpc3RyeSAoQWRvYmUpCi9PcmRlcmluZyAoSWRlbnRpdHkpCi9TdXBwbGVtZW50IDA+PgovVyBbMzggWzU5OC4xNDQ1MyA2MTMuMjgxMjVdIDQ0IFsyNzguMzIwMzEgMCAwIDUwNi4zNDc2Nl0gNTggWzg1Mi4wNTA3OF0gNzEgWzU1Ny4xMjg5MSA1NDUuNDEwMTYgMzY5LjYyODkxIDAgMCAyODUuMTU2MjUgMCAwIDI5NC45MjE4OCA4MzAuMDc4MTMgNTQ2LjM4NjcyIDUzNi42MjEwOSA1NTcuMTI4OTEgMCAzODguNjcxODggNDA0Ljc4NTE2IDAgNTQ2LjM4NjcyIDQ4OS43NDYwOV1dCi9EVyA1MDA+PgplbmRvYmoKMTUgMCBvYmoKPDwvRmlsdGVyIC9GbGF0ZURlY29kZQovTGVuZ3RoIDI5MD4+IHN0cmVhbQp4nF1R22qEMBB9z1fM4/Zh0fWydkGExbLgQy/U9gM0Gd1AjSHGB/++MeNaaCDCmTmXOBOU1UulpIXgw4y8RgudVMLgNM6GI7TYS8VOEQjJ7Yb8lw+NZoET18tkcahUN7I8Bwg+XXeyZoHDVYwtPrHg3Qg0UvVw+C5rh+tZ6x8cUFkIWVGAwM45vTb6rRkQAi87VsL1pV2OTvPH+Fo0QuTxiV7DR4GTbjiaRvXI8tCdAvKbOwVDJf71E1K1Hb83ZmVHpWOHYXIpPLoRKj2Krx6lmUcJMc8X77s5pA+/PT46e1qUkVNM2uyR4i0SKlJYGlORMtOUiuSSRVR8piLJs3R7AWWuP7kuY58gn41xw/Mb81Nb5yUV7kvVo15V6/0FL+SViQplbmRzdHJlYW0KZW5kb2JqCjQgMCBvYmoKPDwvVHlwZSAvRm9udAovU3VidHlwZSAvVHlwZTAKL0Jhc2VGb250IC9BQUFBQUErVHJlYnVjaGV0TVMKL0VuY29kaW5nIC9JZGVudGl0eS1ICi9EZXNjZW5kYW50Rm9udHMgWzE0IDAgUl0KL1RvVW5pY29kZSAxNSAwIFI+PgplbmRvYmoKMTYgMCBvYmoKPDwvTGVuZ3RoMSAxNjE3MgovRmlsdGVyIC9GbGF0ZURlY29kZQovTGVuZ3RoIDgwNzI+PiBzdHJlYW0KeJzlmgl4VEW2gKvu7SW9pbuTdKezdnduOlsn3dlJSEiabGQhbElLAgSysCqYmBBAFIg6iBNFHHHfQMd1otJpUBtBQcVd1HFw31BxQc2Iu4Mk/U7d0x0Tlpk3M++b977v3Ztz/6pTp+pWnVNVt1oklBASSvoIT1qnNziza2+NGiSE3gDa1o4VbV2Vts/uh/wvkL+hY9VKi7Mmr4YQuYcQWcjiriUrbv+yDMo1PkIU4UvaerqIiQhg+zWIbsny8xfPe+bcSwkxvkRI2IGli9oWHn277U1orxXK85eCIlQh1UC+GPKJS1esXFP2s/R2QqSZhHB9yzs72u568vZwSF8FNmUr2tZ0aS7itoDtCRDLuW0rFpnacqYSwh+C8nldnT0r/TEE3kdjWXlX96KuZ4+tdBCSCvUNtxAKo1QQJdESud8PTzb27WQjkZLrQTiiI04CPVN30MlgyazFy29ibZ7mgvoyMkLoAbnL7/CnyyPEFsde21Hz2aKhWP3qBdriH0lUiFiw56sLX2J8bt2ueX7HSI88QvY22CqgF3jx/JvcXuhViPRGaQ68Kh7Jv0oe5UgI4bRyjpdIeE7SR4L9xKu+wWIhFpJh0QX6dhuXhH0Fw/3SUOYZsQYVxwjDJRJyBTAexs/DXMggk8kMMpu0kQ6yiCwj55Iu0k1WkgcsOvAaOaX8HNI5przb/5T/Xf9hkI/9R/xf+IfAfz/6f/J/d3jLKd4h4tt/u1rIQnjehjet/x+9Xzj9zS0M3vyMU+7P8JZ4x99S+bh7k/R52eXyMLg3jr1DksX7bnYrJv3H7nbRk3Iyh0VXooD0QvAmptH/mGaT6LpAmicTybxAWgIruCKQlpJ0yGFaBilCyiHqyyHm7RDxZTATyiD2y+ENZ8FM6CY9oOuE+WIhecRBMuG2gEUvaJmNhWSRbNCNb8My2kY95DpA1wntdJLFMKMmQumZrFlZtviOvFHdfaO6CZA6tT3WGpurXeKzDTTYXweUTIYWlgNngW4JWQplPWJuEZCNbRU8FxKHJHT89JW8TSJPuzf8H7gkZWTzP2MvdxH7yTr+ezLlH9Xjm0n1uPfKSe3fs6c/w55xprbeJOuhfL3sYrJeUkfWi+3Vj29/3LsCNuzi3hqTfub/blz+1YvrIUUQpdsIGdk6Rn0R3LeQAfIQeZQ8QV4gfyHfUyV8xzaSfeQT8iX5jvxKCZVTA42lqf9zvRm5RLqCaPj9sDOAp/3H/UdH7vMfhW936BjNVshFSpJ+0/jD/EMn60a2jvhGXpapiE6sq+NeBO0xOuQ/zpWyvD+f5blNLC3WOCa/bWTHyLZx3WHfqF6yhpxP1pILyDqYCRvIJfDd3kQuI78HX2yA9OXwndtMriRbyFXkD+RqspVcQ66FXfB6cgO5kdxEbgY/3gq75bZAGcuzb9F1YikruYPcDbvM/cA/kjvJXeQeci/k/wTev588CDrUYP4B0Gwnt4P2btAyK6bbAbeHDBIv2Ul2QcwwH8z5yH7yMHkEuBuiuYfsJY+RxyGO+yGyT4o6pgnmz2yJz6fIAfI0eYY8S54jz8PMeJG8RA6Sl8kr/1LJ06MalnuV/Jm8BnPtEHmdvEHeJG+Td8kH5ENymHwMs+7rU8rfAot3wOb9gNVHYPUpOQqWQ2CJdmjznlj6hdjCIah7mByhIeRHypFfiR9SLHrXiRG6UYwjix6Lzp2in1k8dkCeReie0dg8AD5+AOLJcix9UyAaD4LtIHgw6L/Te+3lQHTQ33vBhvmClRwM+OLZQCRYO4+P1n1RLPOK9Z4cbfU3j+IIXx/jnffG+PBT8pnoGfQelv7mPWZxBGyYl1kb4337MdRF77O6TD+2Dit7B/JHYXf4GjzN+JUYia/I56PpzwPlQ+Sv5Bvyo/g8Rr6F/eR78gPkfwLNMcidqj1Z8zPcv5C/keMQwRNkeExu+KSSYTiy+mG3opSjPBn5LfWbVhQJlVIZ7GkhVEGVVE01NJRqqQ4040tUoyX6U0rUpylTiJowGk4jYL+MpCYaTWNg34yj8dRMrTRhTFnUaIkFSgSaSG2BMqNYM2q0rhksIsfYptJMuhqeduqgTkhn0VyaRyfQQtBkQD4b8hOhLFNkGZy22+Fsclz6BfcStB8Bu8qgq2rB/JZ5c+c0N7kbG2bNnDF9Wv3Uutqa6ilVlRXlZZNdpSWTiosmFhZMyM9zOjLSU5JsiUKC2RSh12k1KqUiRC6Two8HStIrhapWiyep1SNJEqqrM1heaANF2xhFq8cCqqrxNh5Lq2hmGW/pAsvFJ1m60NI1akl1lmJSnJFuqRQsnoMVgsVH58xsgvTmCqHZ4hkS0/ViWpIkZjSQsVqhhqXStLTC4qGtlkpP1aql/ZWtFdDeoEpZLpQvUmakk0GlCpIqSHlShK5BmlJCxQSXUjlxEE69GvZaD2+rbFvomTGzqbIixmptFnWkXGzLIyv3yMW2LMtYn8nllsH0/f1X+HSkvdWuXigsbJvX5OHboFI/X9nfv8mjt3tShQpP6tojJhjyIk+6UFHpsQvQWN2s0RdQj9SmEyz9PxLovDD09XhNW0Ajs+l+JCzJhjjqJigPpgn0DXoI47NaWV8u97lIO2Q8fTObMG8h7TFe4nLamz1cKyvZHywxuFlJX7BktHqrYGWhqmwN/K1aavL0tVsy0sH74p8N/qDc4uGTWts7ljK2LeoXKirQb41NHlcFJFxtgbFWDmY6wb6tFQaxjLlhZpPHKXR5IoQyNACFhcVgWUOTWCVQzRNR7iGtHYFaHmdlBeuXpbK/tQI7yNoSZjbtJjn+w4O5lpidOSSXNLN+eIzlEJSkyv6mhYs95taYhTA/F1uaYqweVzO4r1loWtTMoiToPKmH4XVW8Y1iLRjbSdZBYzZyuS3E0sTF8M0sWqCwVMFDKCuGAh2ES8yyiJYVW5poDAmawVsCFiw1rh3I8LbyalbEs6rl1THWZitef6dLMYE+SW2ekDFt6UAx2id8zxm7htasQ6mWykUVYzo4rlFpoIOB1k7fT475IvBiqBHCwlkdLOJtsHJBx0EzoopF0WTxkBmWJmGR0CzAHHLNaGJjY74W41vXINTNnNMkRjswSxrH5bC8AHMeYoXiYIYrhzlYZY8JhlXMTxHzo9nqk4prgsWW/hChrqGfNS4EGiQWWEEwaFlSTdvlBWG5sDSrYHcTqtoEi85S1d/m8/e19w+6XP1dla1LJ7I2hJqF/UJDU3GM2NdZTeti1rJXhZE6WtdYlpEOe0/ZoEAvmznoopc1zGnaDWdZy2WNTV6OcuWtZc2DiVDWtNtCiEvUckzLlCxjYRnW0izIhIj2MbtdhPSJpRJRIeY7fJSIupCgjpIOH4c6XVDHgU6COpeoYxcEybQUXAzbbaVlIQvPhc1L+1ub2eIiRggl/FEPFUqIhxNKBiknU3uUwqIyj0ooY/pSpi9FvYzp5TAx4FsIzmF7Un+rAPsUTKgmEkNxKvKsSYvP729ssh6MGWq2wlSbBzKnyaOww94vtdWC3RQmraCe4unraGP9IO4mVlduq+lohmkbbBBMajwKaEERaAEsqsQ6bDpCpQ6IDQRQrN8HGU9fs6fZzl7atKxZnM46D6kWJkLYsU1pEnuRs7k/TMgW1yYsBaVtE4MC+kYamlATA1l4WTM6Sa6GnncIUNTRagFvS0hHA0x13EuVMahZBFuiJGmRKMqYQCFhw+JtKo3So3BAg/DH0ioHW5JSm7y5GTsv5jYFDODdOo8KepQ0xpWBCuAdKKphfYG/TdBVZvoEa2amj8wS1sDOwjottiSHYo/GVtMGmz/WV4FGKAhWDmF7hCrQxgHUytnI1eB33tbo898jnG8dc2WkC+zjwCYmidkNE5s095+s8My1Z6SHnKzViOr+/hDN6Sugv0I0owQl/PSEX6U9/LvwK5InclJI6sk00riXaOit8FNzIn1xV0VFSIb8cchyxEJfJCFwpLzVFS7hNDExpUKe7Ap+pr6mVH4F10hKhz94/xl4HAwrdB6kzveH3hjSDT+jL3QOHRrKyqR6q16UiFBOLpfJhAQHl5eclJ+Tk13C5eUmCQmhnKjLzZ9Qwudkx3N8RFBTwrE85d89MZ2vHE7kzrcWNWRJqd0WaQ4PCeHN8RpbjkVbVy/kp0RLJSEyXhoiT84vE9yraxNeVpqSY+OSTUpgXCxw+Elp6PHvpKG/zpZU/LqX+6KwqSRRdr5GxUkVIbemxBsSs2In1Wm0GmloTGR0rDxEH6pMq24bvjHaFqlURtqiY22sLdtwEXgk0n9c8pQ0giSQJPIRLONyN3xnE/1f7FJp6VTB5//CFc9SNrVGMGmIkYYak1RKIUFJLBKB6oUkm4+mueJdKqKmYbxanRyXKAjxSo2RCAkmeVjcrDC31E1MpaWlYZGFBfocPXgWzrA50fVD2TTKOb8l2nQwO2fdpgMHqOnA/BZMZmUSuz1mfDceYol/521ZmXZ7s81oxLgl81Z5KC8kJCXlT6AYrEi5wFslg2qZsSArpzBeLZk9Ej1LoonLsztyI2RqukWmE0pyiqqS9bIn6SO0sz0xzSDlFToNlQyHhqskssg0QXKh3qDieZUx/Jnhd8C7m8G7PMzMWJJK+tC7g4myPdxWoidx3BMuBdHbTKJ/fdS+UyZTs6EGxkztu1yGmWpxPDAAO4xlyE6dh4Z0bDAxD/9zFbMym9m8FQR9cE7qc/NzrNnxEmmug6nZJJbwFRc/1rdcE5+dnJQTr85KoVmOhpWrG9NHhjKr6lO7VpW682P5jSvu7Ske6VDqlDIZPCRXOJ3yyJIFG9ormtJUIzUJk9zw+bH7j8sjYF4Vkw04bpfCqVST4sxMdbaPq3cpi9WRJo1NENQJPu5aV5jLpJ4wK21WpqDiT4pjaSlMFNMhGElYYZSzsDCs0KQ7JKbDIF0IrnBpz1gVhm1jcWYRF/hAikLU88WQh+eEB4IfSMH8kEs/lBnSynIKK1PCpK9wB6RhyeUTJkJGNvKOgosqzHFOiFXyn9CvJRpzfkZmoTlU8gP3Ca+MzXWmZxl5RbkpTiuVauNMfO6JlyLjdGJasiwx1SjlVYbwE1b+rXCTRirRmCJOpPDv6SI1UqnRboPZMsV/lF/Fv0lyiIumote8ishcHzd3F0lOJhN9XKVLp+cj6feRNNKnzqUncmmuz7/fpVBr6NTcXMfkNB81uWIOJ1B+XcLmBM6VMCOhNYHXJpgTOLUkIUES5/MfdoWqYZrEmXS0Pu64o3YSW+MKyEw64lLXS4jJKU6a0iG7HVdPS8uCliG2kuwt5w21nEedQwcKnTAH0fP/y71h8Y1gSzopKS8vsCWzzTYnj83q0Q25RMKCbJAzjSHCmJOdP4FfFWFPy0jVT9h81pTVszMnnb9r9Wx98uTM0o6pOTqVXiVTxlbN7yxadm1r+s+tk87Kj5pSmtfsMIfq5HJd6JSiMlvN8uppPXWJ+WmlaRGxCbGh0UmR5sQ4IT481X3pvHfCEnOsBa78XPYvbtX+L3kr/wbJI7cGohpLkh/nVpJQYqJmYh7d6BJ91OwNr5U8SqtJFnhSpaL1WeniOk/30SqvS1EPUzu6fth+yD5UCs8hFg22G+z9t1sSPRkqG/O5khkixKyQAKl4jm0Q4kfNykvlpom1sx1Lti2fUL7mzvaU+vI8o0LKR+j0SbnV2e1Lo3Pqc3LrCpI0CrVc4okWTNpIa7TOtW7Xykuf6isJNcUbtSYhaqIT3Hb91dXn1trMSWZlTBqBNVALa+BhWAN2kkul6K2d4eHWdB9X7rXnSnxct0tp5dPD07mY9KckbLpFamg9kegk3NQZklYJt13ikXASSawTZtJOLa1ndFnAxnkkqdb0EwnVhXJ6PlRhUtN6hQkMFH9zxQadYT8EU2woMNtazpvfYh+a3wI+zn4fNhwnm/CK/+y7xW1bJljH+N8wPkqcITlfPHrI+YdTE4c/iilqmVy2sCZTq1CH8JwkRDNxzsqy1TvXFJWsuu/srm2LM3/g5y7InOKM4uhxR3phy+SE8MhweZg1ymg2akNNkfritY+uW71vY1VZ7/b5lrPPT5zU4IS4nOM/TjdLpxEDsZJKjMs+YuT2wafNwLUSJTHTCx5yRelqpFPZ7vsGrFqKxyb4kJ9ahrMt+CEKDCSczbckOD7BPkzXquMybbbMOHWQ4SWN7qJJ7sbiBKVWKZXCg1+r1KpkMpVWSTOnTiyomVpUCKttvf84v0faRXJJe7CfWdDDBKKGJ5wUuId3ZmQYlT7uEVeoixgTVNKUmtgq/VTsHHw3CgvhKyt+bpxw/Ms+wsKuOp3ZmEEkU/0pw9EHDhawjOSUGo38HlVcdkpqjjVMPvLmyaOjISER1qwkW45ZrdWO/EodapVVqVVIJeyA8cZISnDMUkGpY2PWKU98SzvUYaJWpU0IH3lrJCMiDsdP18L4DaQ08OXVagwUNgCVkmoIVUmIj2t9yKXUVeFQqFOMh7i3tsTsDKpPG6FTo5JwasewDzIFrOIZZCBw6qkK93ELdsbHZ4PjF3hnlCTvgWhkE11gv9L5aL23rjbR99v+VQ/hmVxbUpVRUJMxNWqs34OfBJhghYeG2PG8UJxm/1Zj48cr7npy/d9RBDxiCJwkAqGWKdSxmbakzDiVXsizZczLBz8lMj/pE/ITHfPygm5TRqeaLWmRytqtMyY0VWbrU+rr6pKb19ZZRv3J6TNq8+Kqyod3nFnDXxhMLZkxI9JebLOXJIcXL+mvJ4F18BrEIJtcFIhBWjhzejxRQQRIvM7nP7YTPgs65iZ1wG0ulSujNi0qsWbUR2HoocDJM+jof6bmP/DseEca+NfUsVmJtqxYdXhiYVJm+6kuu7Fh7rr6hFFH0eHJf88t4I422L+q/UclEvBGOEkm5wX3hQiuF35ixsNTSaICkyXKR6NdCm2tYAqcpmO9Linu0cFJF9jV/rs1gkfvMXu2NHA6CX5XJZLitb4LVntWFkxa+8gFazw9BSPDhuyG0oLG/BhjVmNJYWN+ND3avfey2rL1vlXdj22qnbzed1FZ5yxH6vTOKcCM1GmdMMr1I9dK2L+mp5FJ5LrAWcOar2RhNxA7txF+cBiU+XlWiTQzuDgyfbTOpUmqjanRTS8UR1Doo7VjR1AKY4DDdOCnB5sBD/+rbYxxRfJppgAuoqBz5HqjUXQOyWm/en7y5EnFltG5EJVqjk+NUibXTWtwtvfPThk5rk8tz47KysmPz2vNzapMN9Ch1fsurdaaHeaRecGdSfJBcGIsS5mUGlF/qXd14bJZWdqE/JSRd8prsmcuxnXD7RFP4V2BdZOkhR3TpSbRWqVZ6VTyGl7JPvCwApQ+2uBSuuy1SVqDpcYgzvvgnrKAnRwOBFaM8h/bj/ENjv4M/pFxe+CrrgyJiIoPM6RlwEI5aYEIJQUFsZp4i0kllXB8XaIjWikPkesTi9OHD526RDqzJydpeblCqTakwegj/V9zV0oGyUSyFUf/iF6vKUolQgbbtyM1GcGYZ8AJc6dQHacJKjTsyBlZneWjU7wueSDyEPaD4qLJGc4+kK3HQ9RukvGvNIL7iAR9Ih4U8KAf9E7gW8t+4hqDhyXuSlWYAD/Y6s6tTjgnPIIN+GxVHO4vTzIXRIQ/5SiKsETp5TKVTLo23RkOR4qk6Wtm0eedE+JSIpXPwuSRSmHyPKuMTImb4BxpqamRK+RyQyJ4q4hu4Qq4FqIlei+Rq3ZTK5EQJ5x8DmZliuc2PM5YWU8KjKaR1iijMYpuV+vVUvrzRIezsMChNKWQQQXv4/7mjY8z+7hfvPF2wM/e+HTAT4gfET9g2feY+w7xLeIY4hvEX9FyCPE1Kr9CfIk4ivgC8TniM8SniCPeeAXgE8x9jPjIGxcGOOyNiwJ86I1zAj5AvI94D/EumryDubcRbyHeRLyBeB1xCPEXxGuIPyNeRbyCeBk7cRDxEuJFxAv42ufR8jnEs4hnEE8jDiCeQjyJeAKxH7EP23wc8Rgq9yL2IB5F7Eb4EI8gHkY8hNiF2InwIga9sdkAD2KHNzYH8CDiAcT9iAHEn7yxWYD7EPdivXsQdyPuQtyJ+CPiDqx+O2I7YhviNsStiFuw6ZsRN2H1GxE3IK5HXIe4Futdg9iKuBrxB8RViC2IK7HpzVj9CsTliH7E7xGXYYVNiEsRGxG/Q1yCuNgbkwu4CNGH2IBYj1iHuBBxAWIt4nzEGsRqxCpEL2IlogfRjTgP0YXo9EbnAc5FrEAsR5yDOBuxDLEUsQSxGLEIsRDRgWhHtCFaEQsQ8xEtiHmIuYg5iGZv1ARAE2I24iyEG9GIaEDMQsxEzEBMR0xD1COmIuoQtYgaRDViCqIKUYmoQJQjyhCTES5EKaIEMQlRjChCTEQUek2FgALEBEQ+Ig+Ri8hBZCOyEJkieOo1OSDnRKUDkYFIR9gRaYhURAoiGZGEsHkjiwCJCMEbySZ0gjdyIsCKSgvCjIhHxCFiETGIaEQUwoSIRBgRBnxDBL4hHJVhCD1Ch9AiQhEahBqhQigRCmwzBCFHpQwhRUgQPIJDUAQRQf2IEcQw4gTiV8RxxN8QvyB+Fl9LfxJHRH9E5Q+I7xHfIb5FHEN8g/grYgjxNeIrxJeIo4gvEJ/j+z7zGgXAp4gjXiNMMPoJ4mOvsQDwEeKw11gO+NBrrAB8gHgf8Z7XWAl412usAryDeBvxFjb9JuINbOx1bOwQ4i+I17CxP2O9VxGvIF5GHES8hHgR672ATT+PeA47/yziGXzf015jGeAAVngKX/Qk9voJbGw/Yh/iccRjiL2IPYhHsend2LQPm34Em34Y8RBiF75oJ8KLGMTXehA7EA9i0w8g7kcMIP6EuM9rgH2X3us1TAbcg7jba6gH3OU1TAPc6TVMB/zRa5gFuMNrcAFuR5PtaLINTW5Dk1ux7Ba0vBlzN6HljYgbsML1iOu8hhmAa7H6NYitiKuxS39Ay6vQcgviSq9hJmAzWl6BuBzR741oAvzeG9EMuMwbMQ+wyRvRArjUG1EL2OiNmAv4HZZdgpYXo8lFrh3AY9pK8zeh1ebD6mnmJ0GeANkPsk91ltkLMgjiAdkB8iDIAyD3gwyA/AnkPpB7Qe4BuRvkLpA7Qf4IcgfI7SDbQbaB3KZcar4J5EaQG0CuB7kO5FqQa0C2glwN8geQqxRLzVtArgTZDHIFyGQFd4I7Ts4iZu5X4FJiphu84Ww5rveGsam1EtHj1bOp1Y04D9GF6ESci1iBWI44B3E2ohhR5NUxTEQUIgoQExD5iDxELiIHke3VsnmahchEhCH0CB1CiwhFaLwQFB9VI1QIJUKBCEHIvRoWaplrLvCvIEMgX4N8BfIlyFEI54cgH4C8D/IeyLsg74C8DWF5C+RNkMdBHgPZC7IH5FGQWyEUt4D4aB96eq1Xz6b8+eicNYjViFWIXkQ5ogz9MBnhQpQiShCTcMgGRAQinGE3z/Oc12W+83GeI7tADoDwPMG+XIBowKjPwp7NRMxATEdMQ9QjpiLqELWIGkQ1YgqiClGJqEAkIKzYeQvCjIhHxCFiETGIaEQUwoTDjEQYXTcDh0FOgPwKchzkbxDgX0B+BvkJ5EeQH0C+h6h+B/ItyOcgn4F8CnIE5BOQj0E+gugeBHkJ5EWQF0CeB3kO5FmQZ0CeBjkA8hSID+QRiPjDIA+B7ALZCXIziz43jD5eh7gQscyrh6MQXYpYgm5ZjFiEWIjoQLQj2hCtiAWI+YgWxDzEXMQcRDOiCTEbcRbCjWhEOBEOdHUGIh1hR6QhUhEpiGREEsKGsUlECAgpQoLgERyC4ookrjuAfpARkC/AsW+AvA5yCOQvIK+B/BnkVZBXQF4GR+8G2cjbzL/jHeZLqMN8cXWf+6KBPveG6nXu9QPr3Kp1Revq1vGqdTGAC9YNrHt3nezC6rXuCwbWuiVrI9ZyyvOrV7vXDKx2q1ZT9arqXndj75HeH3r5iN7G3oW9K3uv6T0ECvmdvbt6D/Ty7F+nwnoLiqr6eq/q5SKgnCO9VMvU1l5VaNXK6m53z0C3W9Kd280V/dBND3dTLrObzuhu7ebAamd3YkoVs87rNkZX6bozu13d/HnVne6ugU739M7Ozg2d2zr3dUo3dG7p5HZAinN1KjRV51avcH+4gpK9nJ/oQPZzfi+v7NzDjRBKvuFGXH56DjjgbHDEMscS99KBJe7FjoXuRQML3R2Odnebo9W9wNHinj/Q4p7nmOOeOzDH3exocs8G+7McjW73QKO7wTHTPWtgpnu6Y5p7GujrHXXuqQN17lpHtbtmoNo9o5pOcVS5K/l8M3xBSDz8dcX3xR+Ll6ha47riuK64w3HH4viu2GOx3IYYqo3eEL0lmtfCg8NHlDlqS9S2qB1RUq2Y4NVdYX1hXJe+T89l6l36V/WH9RKi367ntFu027Q7tPx07QLtN1q/VrJDS3eE7gt9JZSfHrogtDOU14ayPK9zhTqyqrQas8Y1xanhi52aUs10Db9FQ10aR3aVS5OYXFWqnq5eoOa3qalLnZRa9Y3Sr+RcSij4RuFXcH4FJTy1UEqoDsCHsBhRg7kK5uNOI5VSOFoMNjbY7XU+uX9WnSdkxlwPvcxja2BP18w5HtllHuKeM7dpkNIrm9l/2mv0RLD/+VHMb9y8mZTF1XniGpo82+Oa6zx9kHCxhB8SJG7QSMqa7fN7ent6Vtp77PAAmd8DmpW98CeCwhPYu5KVrOwhYGI/w8Usehh6RaOe3gW90AYUgLpHVLPcfNHkTG38R68zjuQ/cdH/zZf//75MC+b/F3kJSOkKZW5kc3RyZWFtCmVuZG9iagoxNyAwIG9iago8PC9UeXBlIC9Gb250RGVzY3JpcHRvcgovRm9udE5hbWUgL0JBQUFBQStDYWxpYnJpLUJvbGQKL0ZsYWdzIDQKL0FzY2VudCA3NTAKL0Rlc2NlbnQgLTI1MAovU3RlbVYgNjguODQ3NjU2Ci9DYXBIZWlnaHQgNjMxLjgzNTk0Ci9JdGFsaWNBbmdsZSAwCi9Gb250QkJveCBbLTEwMi41MzkwNjMgLTE5My44NDc2NiA4ODQuNzY1NjMgODU1Ljk1NzAzXQovRm9udEZpbGUyIDE2IDAgUj4+CmVuZG9iagoxOCAwIG9iago8PC9UeXBlIC9Gb250Ci9Gb250RGVzY3JpcHRvciAxNyAwIFIKL0Jhc2VGb250IC9CQUFBQUErQ2FsaWJyaS1Cb2xkCi9TdWJ0eXBlIC9DSURGb250VHlwZTIKL0NJRFRvR0lETWFwIC9JZGVudGl0eQovQ0lEU3lzdGVtSW5mbyA8PC9SZWdpc3RyeSAoQWRvYmUpCi9PcmRlcmluZyAoSWRlbnRpdHkpCi9TdXBwbGVtZW50IDA+PgovVyBbMCBbNTA2LjgzNTk0IDAgMCAwIDYwNS45NTcwM10gNDMgWzUzMi4yMjY1Nl0gNTUgWzkwNi4yNV0gNjAgWzQ5My42NTIzNF0gNjkgWzQxOC40NTcwMyAwIDAgMCA1MDMuNDE3OTddIDgxIFsyNDUuNjA1NDddIDg4IFs0NzkuOTgwNDcgMjQ1LjYwNTQ3IDgxMy40NzY1NiA1MzYuNjIxMDkgMCA1MzcuNTk3NjZdIDEwMCBbNTM2LjYyMTA5IDAgMCAzNTUuNDY4NzUgMCAwIDM0Ni42Nzk2OV0gMTU5IFszMDYuMTUyMzRdXQovRFcgMD4+CmVuZG9iagoxOSAwIG9iago8PC9GaWx0ZXIgL0ZsYXRlRGVjb2RlCi9MZW5ndGggMzAwPj4gc3RyZWFtCnicXZHPasMwDMbvfgodu0NJkzbJCiHQNgRy2B+W9QFSW+kMi2Mc95C3nyN1Hcxgww/ps6RP0ampGqM9RO9ulC166LVRDqfx5iTCBa/aiDgBpaW/E71y6KyIgridJ49DY/pRFAVA9BGik3czrA5qvOCTiN6cQqfNFVbnUxu4vVn7jQMaDxtRlqCwDz+9dPa1GxAikq0bFeLaz+ug+cv4nC1CQhxzN3JUONlOouvMFUWxCaeEog6nFGjUv3iYhGSXXn51jtJ3IT28cblQciRKN0TbnClnOhFlnLlLmbZMe6aUKI2Z9kwVU02Ucb2cK2RcIU+YDkw7on1NlFQ0yL3j+Lf/x7zpMzfJnWfHezbHFweWTT3slTfngrO0TrJ0MVMbfGzcjnZRLfcHBAqa9gplbmRzdHJlYW0KZW5kb2JqCjUgMCBvYmoKPDwvVHlwZSAvRm9udAovU3VidHlwZSAvVHlwZTAKL0Jhc2VGb250IC9CQUFBQUErQ2FsaWJyaS1Cb2xkCi9FbmNvZGluZyAvSWRlbnRpdHktSAovRGVzY2VuZGFudEZvbnRzIFsxOCAwIFJdCi9Ub1VuaWNvZGUgMTkgMCBSPj4KZW5kb2JqCjIwIDAgb2JqCjw8L0xlbmd0aDEgMjQ1MjAKL0ZpbHRlciAvRmxhdGVEZWNvZGUKL0xlbmd0aCAxMjU5Mj4+IHN0cmVhbQp4nNV8B3hcxdnuzDnbey9arXZXK+1KWkmrZjXL0qp3yyprS7ZlS5ZccZF7L9hgwGBKKMF0EroBr9Y2ljEBkzgBkhgcQkkCISYhoZpAQgjN0v3mzBlZNoab/z73uf/9d/Xu+045szPf+eY73zmSjTBCSId2IB71tXWG8xqWr38XIXwr1PYNLOsfkv9W/k8ofwHlQwPr1nhjt594GSH59QhJExcMLVz2+eetGoQ0jyKkTFjYv3oIJSI/9P0IYFi4dOOCGy63PoFQye8QSv1k0fz+wfcP9J+A8fqgvXARVGhPS5OgXAbllEXL1mzYdYduC4ztRYgbWrpioD9nceAlhPh3oE/psv4NQ6YD3Cno+w3Au7x/2XzL1TlToC98Py4cWrF6zZgL7QadSNqHVs0fuuQAN4qQ9XkY3oAwrFKJVMiM5GNjSI/I2u9AlyMp+iGAQwYURvMRMl6Pd0JP0lt4jTnImBd5wfEyNIrwCXn5WMlYtey0MOLE1x205m/z1z6dOW2uvuxfyKkQGo59uOXXhJ/femj2WMnoatlp2S+gqIRZ0BfPP4uvh1kppPuk+fBVSZT5U2g3hxSI00s5jpPwnITO49yrtdPrRRFYyUZxbndxAdaHPyLVEcsIK8PCGuHkIQl6CDgR1s9DKYxKUQ2qQ01oKpqGusAii9EQWoc2gs2Q0FoNrQ2oFVo7UT9agJaiVWgDtC5FUbAWnJ+xV8beGHsT+D3Bfl+JM3SIIC+b8I0pgtbCuXAgJ0pCZfDNtageNaIeNBPNQr1oEC1Ei9ASdAnMARwPamHWEiXoQbRB1HR0qjnw5iWi5lEOzJZqCdRniloKivWXCfXTYZWr0GpY6Qq0HOwzCWXDsTmgqtBaqF0K3+ZFuSgP6qphzUuhbh4csRissBgNgFoBR68AW6yBb/Re0IfU5AnjTUId8E0LYcyl0GMVeni8pQjUt8ciI62AmiHhsx9q6AyzoaUSxlgK3AF1xEZr4CivMP5qYTXr4HMQepLXvd/1xknwvvq892f4M+4m7k/szdcI708l11z4lrLX67Ly73ifOf8t360wwfthxcPKpvH3SdWT6nL1kQveX2ne0C6F91cT37obyFuv0p/SnzK0GN5kb+ONxhtNftOV/4fvU9/xhqgn0V1053/vS1IDZ4rwR+jR7+rDP0bbJN+gR2EPf6sftxd8XXzJXkePSjO+e6zx700+vw98Rz3/N9hb/4UX/yqa/b3fUYD28fNgF1LdJxzzNezTC17cSpTKn0CTSH/8GsTY73lB+z7ZINpH+grjFtPxv+v7x7/jlzAXH2oX9OPIB203fWs9d6JkgdejdP5uqv9fvbgUdOy/0p+3k0gmvwuh0RvPa5gGEW01XKN3wHVoL7oRPYPegMiyC9Q+dA96AKJIDD2LXkCv/9+c/ehG6TKk4Y9AhDSTGD52ZvQBwAhcQc7V3Agls8R7rmbMMPbxBXUfj944ZhgdkZmQSjhWy70Mtf/EZ8e+4ipIeayQlLkrQOuFIz6V3zV6YPTBC2zQLlwRZoOv9cH+mgexbRFEPnJlWIqWQUwkpeXQthA+F0BpLvQagF4LxOsH7bVCjKVrIAavg/eQEPdpibStFMpr0Xp4b0Ab0Sa0GW1BW8XP9ULNFmjZJJQ3ALah7XBmLkU7BcWY1uxCl4Hv70ZXoCvRVd9bumpc7UFXo2vgPF+LrvtOvfe80vXwvgH9APzhJnQzugXdCn5xO+Qe59f+UKi/Dd2F7gafIW03Q83dgiKtT6FfoMPocXQAPSHYcgCsRi3C7LJAsOEQ2GALrHDXhBlT+60ft9Y2WDtZ2x5xpRugfueEI9aJdiQ9d0FPOgo9D2SUrRdY4npYA9XnVkRLNwvrP1c70SrfV8vscccEy9wulIi6sPa79C3oTtiB98InsSpRPwJN1d2Cnlh/13jfe4Tyj9F96H44Fw8KijGteQD0g5CXPYweQfshrj86QU9UlB9HjwlnLoaGURwdRIfgTD6BjqARof772i5Wf1Csj4/XHEVPQix7Cj2NjkOk+Sm8Wc1PoO4ZsfaEUEfLP0U/gzLpRUu/QM9BhPol+hX6NXoJ/RxKLwqfz0PpFHoZ/Ra9jrWgfoPeh8+z6JT0HcjMKuFe4Emw8x1oDpoTqR+cO6d39qyZPd3Rrs6O9mltU1tbmpsaG+rramuqqyojFeVTyiaXlhQXFU4KZ2dlpgVSU/zJHofFaNBr1SqlQi6TQsaMUWatv67PGwv0xSQBf0NDFin7+6Gif0JFX8wLVXXn94l5+4Ru3vN7RqDnggt6RmjPyHhPbPCWobKsTG+t3xs7WeP3juCZ7d2g99b4e7yxM4JuFbQkIBS0UPD54AhvrWNRjTeG+7y1sbp1i/bU9tXAeMNqVbW/er4qKxMNq9Qg1aBiaf6hYZxWjgXBpdWWDsP9gpZ8bYxPre0fjE1r766tcfl8PUIdqhbGismqY3JhLO9iMmd0tXc48/iea0YMaF5fSDPoH+yf3R3j++GgPXztnj1XxIyhWLq/Jpa+6R0HLHl+LNNfUxsL+WGw5o7xL8AxaarB793zLwST95/56PyafrFGlmr4FyKSLHHcTNDONIK5wQxhfT4fmcvVIxE0DwqxHe3dtOxF81xxFAmHemJcH2k5zlqsUdKyg7WMH97n95FTVdsn/qxb5IjtmOfNygTrCz+p8APt3hgf6Js3sIhw//w9/poaareu7likBkSkX1xr7XBOGPr398EiFhMztHfHwv6hmMVfRTtAhZecg8Wd3cIh4mExS3UMbrbFo2Lh2hoyL2/tnr4aOkEylr+9+yjKHzs9XOB1HcxHBaiHzCNmq4aTEqjd0z24IObpcw2Cfy7wdrt8sUgPmK/H3z2/h5wlvyGWfhq+zid8o3AUrO2C3qwzWbk8VeHt5lx8DzlbUOGtgw9/VRk0GOB0CUVyRqvKvN3YhVg3+BaxB1HnjQMFPrW6gTTx5NDqBpevx0df3zMllzgnaWpMMWEsA1SMz4l+z3dOjfYmE0r31s6vmTDB8waVihMUR7v4PDliC/GL4QgFOZ0NrIlPhZ0LdRwMI1SRs+jwxtA0b7d/vr/HDz4UmdZN1kZsLZzf5k5/c/vMbuFsi17SdV6JthfTUgz5oJkVuGrwwbqQi51WoVwvlMeLDRc0N7Jm7x6Fv7lzDxncLw6IvLCDYNGyQGP/1cWmAtiadRDd/HX9fq/BW7enf2Rsx7w9w5HInqHavkWlZAx/4+Aef2d3mUuYa0f3Vtcm8lUm1Iybu6qyMiH2VA378ZXtwxF8ZefM7qMGhLxXdnXHOcxV91X1DKdAW/dRL0IRoZYjtaSSFLykQEbqgIJC6O86GkFoh9AqESqE8sAIRkKdgtVhNDDC0ToDq+OgTkLrIkIdecFJciwCE0O4rfUOktOzpWfRnr4esrmQDU4l/OAY9pejGOcvH8acTBNT+edXxdT+KlJfQeoraL2M1MvBMbANg3FITNrT54c4BQ7VjVyYuiJPhvSOjI11dftOus70+MDVZgNmdseUIYj90tQm6FdP0AfV9bEdA/1kHijaTY6VpzYO9IDbsgGhS2NMCSMoxRGgR51wDHFHOGgAzg2cQOH4HVCI7eiJ9YTIl3Yv7hHc2RBDDf5SOO10TGmAfFG4Z4/JnyfsTdgKqtQrCClhbqizm9a4oAhf1kONJNfAzAf80DTQ5wVrS9BAJ7g6jaUqF62ZDyFREpgvQOUSGxFZFp+q1qpiymwYEH6IVmeTLSlNlff00MkLpSvEDvDdhpgaZhSYYErxALAONDWSucDPFTBV0vVZMkz7COrwb4DIQiYtjCSH5pg2tbEfgj89Xg01/mJ2sILECLU4xglaKycr14Dd+dSukbEH/Rt9E15ZmX5ycSCOiVxHwbFRz54LK2KzQlmZigtrtUL1nj0K7cUPoPZSaMeZVHpr4aqBUFzJe0e4yw4pHbgJxC4mdjJxKRM7mNjOxDYmtjKxhYnNTGxiYiMTG5hYz8Q6JtYysYaJ1UysZGKIiRVMLGdiGRNLmbiEiSVMLGZiERMLmVjAxHwmBpkYYGIeE/1M9DExl4k5TPQyMZuJWUzMZKKHiW4mZjAxnYkoE11MdDLRwUQ7E9OYaGNiKhOtTLQw0cxEExONTDQwUc9EHRO1TNQwUc1EFROVTESYqGCinIkpTJQxMZmJUiZKmChmooiJQiYmMVHARD4TeUzkMpHDRJiJbCaymMhkIsREBhPpTKQxEWQiwEQqEylM+JlIZsLHhJcJDxNJTLiZSGTCxUQCE04mHEzYmbAxYWXCwoSZCRMTRiYMTOiZ0DGhZULDhJoJFRNKJhRMyJmQMSFlQsIEzwTHBGYCiQKPMTHKxFkmvmHiaya+YuJLJr5g4t9MfM7Ev5j4jIl/MvEPJj5l4hMm/s7Ex0ycYeIjJj5k4gMm3mfiPSbeZeJvTPyViXeY+AsTf2bibSZOM/EnJt5i4o9MvMnEG0z8gYnfM/E7Jl5n4jUmXmXiFSZ+y8TLTPyGiVNMvMTEi0ycZOLXTPyKiV8y8QITzzPxHBO/YOLnTJxg4mdM/JSJZ5k4zsQzTDzNxE+YeIqJY0w8ycRRJkaYOMLEE0wcZuIQEweZiDMxzESMiQNMPM7EY0w8ysR+Jh5h4mEmHmLiQSYeYOJ+Ju5j4sdM/IiJe5m4h4m7mbiLiTuZuIOJ25m4jYl9TNzKxA+ZuIWJm5m4iYkbmfgBEzcwcT0T1zFxLRN7mbiGiauZ2MPEVUxcycQVTOxm4nImWNqDWdqDWdqDWdqDWdqDWdqDWdqDWdqDWdqDWdqDWdqDWdqDWdqDWdqDWdqDWdqDWdqDWdqDVzHB8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M8h/M0h7M0h7M0h7Msh3Msh3Msh3Msh3Msh3Msh3Msh3Msh3Msh1cfZAIyJrjSeUeyJnjSVagnbR0aTypFGgHLW2ntC2epAHaSktbKG2mtInSxri7EmhD3F0NtJ7SOkpradsaWlpNaRWtXBl3VwENUVpBaTntsozSUkqXxBNrgZZQWkxpEaWFlBbEE2uA5tPSIKUBSvMo9VPqozSX0hx6XC8tzaY0i9JMSj2UuinNoDSdUpRSF6VOSh2U2ilNo9RGaSqlVkotlJopNcVdjUCNlBririagekp1cVczUG3c1QJUQ6maUhVtq6THRShV0OPKKU2hVEZ7TqZUSg8voVRMqYhSIaVJdLACSvl0lDxKuZRy6GBhStn0uCxKmZRClDIopVNKoxSkQwcopdIxUyj5KSXToX2UvPQ4D6UkSm5KiZRclBLiCVOBnJQc8YQ2IDslG620UrLQSjMlEyUjbTNQ0tNKHSUtJQ1tU1NSUVLSNgUlOSVZ3DkNSBp3tgNJKPG0kqMlTAkJhMcojQpd8Fla+obS15S+om1f0tIXlP5N6XNK/4o7uoA+izs6gf5JS/+g9CmlT2jb32npY0pnKH1E2z6k9AGtfJ/Se5TepfQ32uWvtPQOLf2Flv5M6W1Kp2nbnyi9RSv/SOlNSm9Q+gPt8nta+h2l1+P2GUCvxe3TgV6l9Aqt/C2llyn9htIp2uUlSi/SypOUfk3pV5R+Sbu8QOl5WvkcpV9Q+jmlE5R+Rnv+lJaepXSc0jO07WlKP6GVT1E6RulJSkcpjdCeR2jpCUqHKR2idDBuqwCKx22zgIYpxSgdoPQ4pccoPUppP6VH4jaI1/hhOspDlB6kbQ9Qup/SfZR+TOlHlO6ldA+lu+lgd9FR7qR0B227ndJtlPZRupUe8ENauoXSzZRuom030lF+QOkG2nY9pesoXUtpL6VraM+raWkPpasoXUnpCkq749Z+oMvj1nlAl1HaFbcuANpJ6dK4NQq0I26FYIy3x62FQNsobaWHb6HHbaa0KW4dBNpID99AaT2ldZTWUlpDaTUdehU9fCWlobh1AGgFHWw57bmM0lJKl1BaQmkxPW4RpYV0Zgvo4fMpDdKeA5TmUeqn1EdpLqU5dNG9dGazKc2ii55Jh+6hX9RNaQad7nT6RVE6ShelTkodlNrjlgjQtLiFfENb3ELce2rcsguoNW7JAmqhXZopNcUtkBfgRlpqoFRPK+vilm1AtXHLFUA1cct2oOq4ZQdQVdxUB1RJKUKpglJ53ATXdzyFlsrixh6gyZRK40biGiWUiuPGeqCiuLEbqDBunAk0ibYVUMqPGzOB8mjP3LiRLCwnbiR7M0wpmx6eRb8hk1KIDpZBKZ0OlkYpSClAKTVuJFZKoeSnYybTMX10MC8dxUMpiR7nppRIyUUpgZIzbugFcsQNc4DsccNcIBslKyULJTMlEz3ASA8w0Eo9JR0lLSUN7ammPVW0UklJQUlOSUZ7SmlPCa3kKXGUMCUUGdPP8xCM6gc8Z/WDnm9Afw34CvAl1H0Bdf8GfA74F+AzqP8n4B/Q9imUPwH8HfAx4AzUfwT4ENo+gPL7gPcA7wL+plvo+atukecdwF8Afwa8DXWngf8EeAvwRyi/CfwG4A+A3wN+p73E87o21/Ma8KvapZ5XtAHPbwEvg/6NNuQ5BXgJ8CK0n4S6X2uXeX4F+pegXwD9vHaJ5zntYs8vtIs8P9cu9JyAY38G4/0U8CwgMnYcPp8BPA34iWal5ynNKs8xzWrPk5o1nqOAEcARqH8CcBjaDkHbQaiLA4YBMcAB9UbP4+pNnsfUWzyPqrd69qu3eR4BPAx4CPAg4AHA/eosz33APwb8CI65F/ge9SWeu0HfBfpOwB2gb4exboOx9sFYt0LdDwG3AG4G3AS4EfADOO4GGO961VTPdao2z7WqhZ69qvs916ge9FzOp3ou44s9u3CxZ2d0R/TS/Tui26Nbo9v2b42qt2L1VtfW5q2bt+7f+sbWiEmm2hLdFN28f1N0Y3R9dMP+9dEnud1oAXd5pCy6bv/aqGStZe2atfxna/H+tbhmLc5Zizm01rDWu5bXrImuiq7evyqKVk1btWNVbJVkcmzV6VUcWoVVI2PHD65yJdUBR7as0hrqVkZXRIf2r4guX7AsugQmuLh4YXTR/oXRBcWD0fn7B6MDxfOi/cV90bnFvdE5+3ujs4tnRmftnxntKe6OzoD+04u7otH9XdHO4vZox/72aFvx1OhUqG8tbo627G+ONhU3RBv3N0Tri+uitbB4lGhI9CbyBjKBqYkwE+TCVTmuiOu06xOXBLliruMu3qRP8CRw6Xonrm5z4hXO7c7rnLze8ZKDizjSM+v09pfsf7L/3S4xR+zp2XXIZrB5bbyVrM3W2lUncEUN5dxJwlpbbf5And6K9VaPlav1WDEynjZ+YuStzxheMnB6Pdbrx/RcRA/d9TqPjiMfYzo+osstqtNrPVqOfIxpeVtECzVkxKBmWledXu1Rc9EKdZuai6grqusi6qycOsRjL8YIG4B4BZkFtnrqYF8ftGEphuv5cFdnKNQ8okAdzTHFtFkxfGUstZN8RtpnxmRXxlB05qzuYYyv7RnGXHVXzEJ+YyuUL9+7F1W5m2Puzu7YPe6e5tgOEBEixkAg97ANVfWE5qxeuzoUWjMHPuasXhMSfqCE15JSiFSSn9VroEzea4UyCn3vi3YDmrsaXmtY5ZrvP+r/9xf+757A//zXMCJ/ZFA5xl2GBrldgJ2ASwE7ANsB2wBbAVsAmwGbABsBGwDrAesAawFrAKsBKwFDgBWA5YBlgKWASwBLAIsBiwALAQsA8wGDgAHAPEA/oA8wFzAH0AuYDZgFmAnoAXQDZgCmA6KALkAnoAPQDpgGaANMBbQCWgDNgCZAI6ABUA+oA9QCagDVgCpAJSACqACUA6YAygCTAaWAEkAxoAhQCJgEKADkA/IAuYAcQBiQDcgCZAJCgAxAOiANEAQEAKmAFIAfkAzwAbwADyAJ4AYkAlyABIAT4ADYATaAFWABmAEmgBFgAOgBOoAWoAGoASqAEqAAyAEygBQgqRyDTx7AATAAoUEMdXgUcBbwDeBrwFeALwFfAP4N+BzwL8BngH8C/gH4FPAJ4O+AjwFnAB8BPgR8AHgf8B7gXcDfAH8FvAP4C+DPgLcBpwF/ArwF+CPgTcAbgD8Afg/4HeB1wGuAVwGvAH4LeBnwG8ApwEuAFwEnAb8G/ArwS8ALgOcBzwF+Afg54ATgZ4CfAp4FHAc8A3ga8BPAU4BjgCcBRwEjgCOAJwCHAYcABwFxwDAgBjgAeBzwGOBRwH7AI4CHAQ8BHgQ8ALgfcB/gx4AfAe4F3AO4G3AX4E7AHYDbAbcB9gFuBfwQcAvgZsBNgBsBPwDcALgecB3gWsBewDWAqwF7AFcBrgRcAdgNuBwNVu7AsP8x7H8M+x/D/sew/zHsfwz7H8P+x7D/Mex/DPsfw/7HsP8x7H8M+x/D/sew/zHsf7wKADEAQwzAEAMwxAAMMQBDDMAQAzDEAAwxAEMMwBADMMQADDEAQwzAEAMwxAAMMQBDDMAQAzDEAAwxAEMMwBADMMQADDEAQwzAEAMwxAAMMQBDDMAQAzDEAAz7H8P+x7D/Mex9DHsfw97HsPcx7H0Mex/D3sew9zHsfQx7/787Dv8Pf/X8d0/gf/jLMXcOkiI0upp/WapDPJKjEtSKpqJZTyEtuLQNleLDh601NYos+dPgrhzygsMrEMbVEb2E0x5JSKjwH5kk28sbG+Hm/VCFfC+E8oqzb519MXz2rTOmkvAZHP7j22+9bfj0RWNJOP/tV97OzcFGn1GARcfJ5RaZPzmbmxQMFObn55VzkwoC/mQdJ9QVFBaV8/l5SRxvYTXlHClj/uVvZvJtZ2XcNn/F9HxpUoLeopVJuUSHKass1dA5K7Us2y3n5TJeqpCnFVUlNy+tTf6D3Oi22twmhcLktlndRvnZN6S6r/4h1X1dLVn69U28bPLsihT+VpWCk8hkI0kOZ8ZkX+N0vdkgUZsNRptCbjJq0mpmn91tTSRjJFqtdKyzrQij/rFPJBppElhv3sFENDk0MvbeQQNuBf7koF7gjw5qBf74oEbg9w6qgZ+G67cOOXAY+VAAZ8bNnZJjOANNQjk4e1g5HUz5yhkCHH5bOF+G107k5qRadLIJ5pBZRfMQw1ktSRyxIzGTRMNJFZbI3M2N2351XWvnLb/ZXrxkZp1LIeUlCrVCl9e2sm363sGiSQPXz2pd3V6gl6tk/BGDw6SzpAddXfd9eue93xyYbfVmuHTmBJMl0awMhoO1u5/dsvkn2ysD4YDMmAQO8ShCkuvAd0zIg9ZH3BU+bHbAys0GWLbZAms2m2DBZges1nwMMhWEEqhtEkTbCKwV+HNimwTRNgnHIKdQgm00cV27awQHhqVdqOJMxbgtXqGUm9NLPMnvSw5MMhYU5vtg5fICsIbfSAwhuW76/Z88MPqxPT3djlMfeu/O9sMFKx7ZfWB4yyOrSrjbHvr6/g5PULIz6Jnx4/f2LT58WdM3xvIdz5J/8/ro2Fd8F6wsiGYPy83iGTWLszaLszaLszaLszaPcMbDWjdKcstHsOag2eyUjeC0g8ntziiqqBB3RPiEsYROPg+2gzB5I5m2lUrm7Ww1fJdEpZWPBvBxuVYlEXREYfEmOJItinQ7VyfUnjAnGhWjDXKDy2p2GZVn/yrXyqVS+JA8HvSAm4orkkyTWlAYjRyqyMV+jbgojbgojbgojbgojbgoDSwqkmhPUZMzqyZnVm2AbmoV9FGTM6se4QwRO4pYcSuKmMmHwQhXwAi0Izu5lYUGwk9Amz2jI2UEZ0b0xzX4lAZrNCZ3hykqJeapAPP0rjxTgcNwdol5RCMZxo3VmzpunIl2ov5uhTomJdMUFp8jwWtRnD0IyklspbAkO5w+i4JrFawHKkGhIUbSKLjysz9lWvIHps5+xcmYFu2Hu8F+VjTtSIW9zX7AziPRhEg0IRJNiEQTItGE6EnwZtXY8SNgCZWhQ1guLHPchVO/tRjczeattPrszomzPTdDMiv52Mf4HZhVGuo+Sv4h9X88HTdMx4hb3Tp/h/IYzkNm2GzZw1Ix6oCbjk8P09nJWAAWIvW5mb6TWLOiI7EoO1ktl3I8xBaF05/tSc7xGugSzEpc17pjZq5Sb9RojE6TDaKv3qQ3ZrdX8neR9UhgPdS+shDsuDL0aMTQVz5UzmlzcuzhsCrb4UgY+Q/DBvHVpJRcjUZFvFVFvFVFvFVFvFVFvFVFFo/GjkecxBIphe1qh10bduRmyzxp7Z4oc8YKk73EmA92eIX5oTHfMK6MJVPC+fnG/PPOnR/reKKC2H/eLiZmsuN8DJczwWKykMLicdp9ZgU3ms+rrW6LNcmi5kbrMXim0+E1yzNdi7w5KQ4lXi/Fu9UJnoBzmd5l1pxzgYVf3yRXyXkJBG24fO0br38gI0WTkOb6Zgb/QFKGU600u63izt8mNaIp6PKDQb3eIhpTYL3IWoE/Ica0iMa0CMZMUmVn5xFj5jn05AM65hk0REGXPNLFgJKKO1TZ+qDESSKdrAtR8xHjfct24XzhEgYBWrBUIBD022zWi9gribfnBwLn/EyyTWtN0BYlBP1+6+gib2Uix3EKs8fh8JgUmQkd7qDHbcSl7sK8XAfmMLQ4bV6Tot4C12u1Oy/InS7ZOrnhlqZv/jkeGh9JS1bZ0z1nny8Y6OsNt+1v456Wa5QSiRLckVzb4ArwHPhjIkpHG4ZTZKLVZKILykQXlIkuKBOtJiMmsRvdxGRu4n9ug0aLW9xeaHOTPwNAxtQRrDook2n8I1h90NqumXBxoAYznH998F94UZBMuMTxz0XWP7bhRqXZ5yRhIiMBWzNaFy9rST88eUZv5t23T11Yl8Lf2H/H8rLR7HE/gaXL7RWzN85oW1KgO/tlWv0AiSX1Y2f4AakPNaJ3j6LKsfcO6Q24pVJcp8AGkTUCC+utHOEyI6G8iNmCW/IiEFFS8lLyNC4HOdZFtp7LYCAfcIiLuIzrSS6X7L+DLiEgHT/oFNlC+Qk9uXhoso/hICpCKhyIqI3eIlwUUWtwi5E8RVURVWQsMtrK4Cp7uNIlTe+0jeB0IXidgctIyRljSQkEsFCv4YyBGPXc1cREGy4IbZLzQlvBeKi7MLmS8QPV6+/trVwxY7JdDWFLocuftrKpuLc6Ja9j8fJFHfmTF9/QFZrRWmaWSThepparwzW9pYXTChLyOpcsX9KZjy+Zde1Ans2b7Ej1QDYqT07zJxVNyy+aOjk3v7xrZVv79ulZeqfHrDY6zCbIuRL9bndOVWrh1LK8/CmdK+Ec6cErXwevTEbzjzgiYF6HkVjtEAnz/7GLkhBoHDt+GNqMMhNJUdyiF+bBZelTwTg/DxlOhMYTlHMXXpZ6CrnJ6xKlVjF6E7tWgdIqpFL44C9TaJViXvL1XeN+N09hTDSbaepM9ths8LgK/pcoH0VQLOLVV3mqwlW8Wmkv0MB8C4j7FBCnKTAQdyoYwf+OQEoW1COsQWRvoVLRG0vFGFYqLpGw4L6lI5wiYjHaf44KDAXc5OMFGBXggoLsyowR7IroTyXj5GSJ+4PspilvalolKExyTJKInDEK6cicXpZxngjN6S0J052ZV5KbMwcivwwycYhRk2TnMvL8SQXUXcQaiRC85NSBbPl5hUV8hSHRleDRTb6hvX51e1b5mocWb7HlTi2Z0t+Yq1FAAJK7qqYvKOi/sitw396awSpPz7TKFVMcGg1EDM3MirrUugWVLUNNqXUF0ya53H63wuDUO90Jfrc5M7qt64Q9qyK9rrOqBqy7D6z7qnQlyiCR/zCkHCpfoegKhaJrFIr2ImXBXoUj+IuIyxoieXvIS+5aiP1DJJqFDMLNDKeKKJFVVTjJJ5HmjGDpE4EmV52hpQTksLSV7EASzewl49H/nM16xf3GBa3fTt/o3Z5cNJ/caLMJ4e3V/IHre0ONdXVBhcllhXAuk5u9DifE9rTmhoa0eVfPSHvcWjA94i2P1AZrtlSXdxc58btrj11WZwyUpi8H15NIwPWkxQqaaijO/jW92G+Yuiu2tnbn4BRTRlXe6L7OGWUDm2F3zQSLefkX4BbsquFEISrRdOq0mEa9d4gkDUFxnwXFfRYUb+yCojGBPyAHBEc4dUQb1mGd811PRKVt8EDuyx0yN/Ef5pI9q9Q25GaOYNmwspVkXaEzwgcO91K7naCXgG/f8MloSJJNvN3jvZxU7ixr7g733zJ/UuXKfT2h9ppJDqWMM2n1wbJo6frtvkhvWcn0ipCGpA4/MjqNWmeq2xTZfHDt5c9smmxISHbozA5T0ONL8x15fMau7lBKyK8wC/u0D+xyh3QZCsA97tURT8VkrHaVkN1ZQvKqEhLhS4h3lBBnKTmGv4Q7vTC1Wlg0Vlg0VljcsWHRWGHiUCqzr05dEnRJdBnk192OJtjqkoO6VmkLCUqCO1VccOcn+NN48jVxC+bZ7ONexQcCE2+Mi/g75MZEC7mJr983a+CaGWl5826Y27YrIrd4iE8pH6jeWlMBHgQeVembEqkLOpkDrW+d3rpreN6aY5fV11ZzapZFnK0F35m3JVKzcz74UnUusVYvWGsfRLUQKkCPRzLChRWFKwp5M9lNZi+5fTT7Msn1MJNYK5OYMVOIb+ALXx6uCd0X4sijg8NktxVIROeTiD4mlNUC0wAnIfbz+TKf2yG5XsIdl+BTEiyRJIbfDDQ5PujTDek4nfKDRMHBesXYtnIVC2p5fwxRZ4Nq8WZa5vdNcCvr+c7HWYOFgkHl/L6g82w8qW6oPTLYGNbI1TKe4+XqwukrIyseXFVatvKegSU392U9wG9cP2V2eTIka0Ff84bp2dYEq1znNGnNeo3a6TCXbxrZtObopbU1q2/vNu+8KbtlfhHJRFLHvuJ2SzfAvcBg3GYgG1DYeC4xarlYtHKJ4cwlOpOL/GFfTkbqyNipiInchaaqzhTWJwTO5DR4WwwNJDE9k0ceIoRO5H9K91j+ifE0gF7mrXTdsolpF4R5Ft0FO0i43RKpQia3JqW7Ugu8uhcUaqXUpH9BAaEJEnjFdoOBhJrt/oZlTf6qFI2Cl+rNdp1UqVY68ttL58mNCeYU7zcfwt2ShDyO4a3eFHOCUd4754rp6Vq9xuwi/+/UpNEb+av451E5mormolMRqymrnuyyegUsud5rMOOW+vyKkbEviAkqxP0FfPoJ0lQhbwMZ0epNuKXNJdHn8PlyOfEeg2Cv4xEtiKx8ucslz8+SEBtHCoiRu8lXdHsNcFh3RmpEDZyqz5HzxU1/0HS+Z7X2FfPvlzVkeKt+X9w06/feNkQvmRXCFfPMazT0h/JPEuPaIdsi+ZYRKg0nQ/ATYh/E6mBjSP4FKweCMohnNrs9ibdOeOBXBJfXgkLhk+5sX54NFwTGL6flnLkgEAzqeLHEX2XWX+pPzOvdMbVowGWyVxZ+WD3UkV1wyQMrl+2bl2nw5Xpzw3mpnpSC2Ze2pNd7sMFoHB2d35tTH7bPn5XbELZ3zm1/35vuUF62rnl+uYtf4/ekzAhP3dCZ6baZspP82ZyK803pmVw+FM1NjfQU+MqL853OlswpfYHU3qrWTV1ZSoVv9NPZC73FjWk9CzxFDWfnlFZwCmdWepq1stqdU078ex9kcffAlTkPbTxUUYAzzj1AEh17wpMl8UkTXJbtSfShi/D4RXjyIoQNNWlT0ectcNdngCvKkaymlDpnixA+hXuL8ft5ejEuOf+hg3A1kV/kkUphIY2i9yhM9JrryG7MKd9SA0XhRpVdiuuvb5y5ucXnZP7M6Vvn1KR0R89ezWomXn+bG6csuKqfRMrLx77C7dIwsiIfuuZIhb/Nv8LP28RczibaQCibBRac1yZ6uk00mu0YtxLu0qzUUlbxKKvYamUmtYKZnlB5InAk+RO3Q05Do2Cf186ExGgoXlku/kTGTC67xBnBC3H5hQYwZ04uDRGMm4C/jD3bwDmlGeklAPHM43I481YUEZ4irRCeIl38MQ2bOSL/nE1lqBOmK8714k+NvjUv57ftL85CegquUNPQBxGXyaAWn9EGDOTWKuggn0MduO7bzzfpPeCE56AfjHtnUpINZFJSHn3WIjx1ER64CE6qgsh8ZBq5P5xWHhSHnZAvfXJBPiUYJHgMfwFbxIBl8eYmSJ1kEW1lU3ldVnFjVsu4c8Md3cTnwiXi8xpjCXuARXxd+EOV73P479oBVroD7DQ5tUpP0Y1gVlgya7JLVteSgG/3meW2zOrskjXj+0JmSrTb3AZ5y3WNxT01OYas9ub6lBnrGj3ndoi/5IId8u0auIlSK3leqVasj7YlhCvTcmsyzLB1WlgEgTOYh26K6OkZJB9iMLnwLH3H02qS6iepDQYWU4SHuxOe6+IvjohhhQSViCqrKcOZ0shMT2L+ueeEhvOs/R8EF+v/LriMG/GHrf+b4HKeocBAfSS2kFz+LbCQGQXRQ5HEinScZsLpRhzQ4oAGBxQ4IMcZPE7ncJKYoiaJBksSc64kMedKEg2WRFKtpLAKqyzkfshCzGUhWZ2F3C1ZiM0sT3Iq8nTjiB61DsFpcpK/0NQ3+SHvF2+OSH4vmowl+mAy9sITrn0Tb4dYAsu/Vbr6sVUr7l9eWLL60dXARY+7ype0NS6u8bkqlrQ1LKnx4r8uP7q7uWrboVXATcBbGnfOKymYu7O1aWd/ScGcneTOcPQm/lWwDbkz3EHuDH2FKtFLVKKXqFj0UYmrVwmXICu9KRRuD4VnPPT+8KJ3hY2Gtu+8K7zYTeFFfOS7bwp/MCetpjKSMsFZLFaXSZ7e0tqeNW8PuSnMF24K64I1m6rLe4oS8PvrntpVb0gu8I+Ws1goeR98hufBezZmlKdbWy47sLb20sEyc3p17uhtnd1lg1vEaMk9KDylGDg0NAkH9KKJ9KJl9MxUetGGemIqk/jLEAh5iNgMJYAFUyPKUFNAb/U2WskeEoIXDp9gz6cmmoMu+DtMIuMe5GRKhcLuTrE6cyaV+i/cNKmVpSVurS/FrZHwmJ9nSzIqlUqFJbul6Gzs29tmV2FNUM8rVCqlzkVW3D52hnsRVtyIXoxows0VzW3N25sPNEsnPAz8XHwIKOyYSnKrbL7gIaHwcBC/GfHQJ4LCs0ASXMQHgiRdJzvI9ST+XHggryIPdDQR4VdOUAzAeBWaAxpOk/3HItWHxmnGPuOQkacP/t4gT/2abO9R1xp/5Cc+8Oslv0Ga8MDv3HX9v/rAj3sxf87OqTkzanNsKgl5oBeqmF6cUZPnCkamRdsjwfSOzR0pDaXpVjnP83KVTJlc2BjOiKRb0yId0c5IEOtql8L5tjstKR5zgkHu8rpM/sLUQEGaJzlUPr1sUn9jpsZkNWj0NoPRaZDbnDazPycxOCnNm5xR1kXOhW/s79wyyWOoFM0+lI6M/izR5lniucgSz0WWGMWyRK/MIk6osWuzzvgb3Noz9oZcuKceltMgdJK4Xb54J33yBH3MILn4zc75t0Q2dmvILVMYvOnZ9rrBiHub3kSe+m1lace75DmWSf9uUb09JdGikCqlklnuZINOKUttXj2V09G7ndfY4/bX6P3QqKp3rlKllOocZN03kWcO/FNwhftBxAPXNXWQeFCQeFBQQbIGIa8IGoQEAn/5BN1pHtEqHtEqwF8Ie5MIYhYP26we0UchGfwyojRnNQbVUmcjpBnScw8eyP5kmcW4S130wcO5nFmI1IVF5x5B3CE3ua12t1HWeotwIZNb6E2iPdyQU765Vm7xwM41Kcevb+ujU8sWXjWPS2a78+xnbXOrU7uj3FpWQ+yTDBnAZrBPJvrLUeQfg9hM0jaPgnymenASFUnYJq7TKrLlXDInsElkI7RHikAUwTXSiIMGnCbFyWlQMSUZpyRjH5EVPpziw16h1otTvDiox+t82EduuJVGa4PPC7sWSu9FlOCKPvK0g5TImfCR8TVwoC+t0adOaFTTACj8vhdeKNQrXAdD9AeTqyG1O5RDIeHvRcZ/wXbuAmk324vM4h+KbMYcz42elGgT0pKS0pw6yeiLEin5VZDd7TcrJaMS/mtOZfa57ElGOX+3RKnSyL95WK1T8BKFTsXP0JiUPKTrHHwozyZoNNzflHDjzinUxNrpYO1msHYY7T6KciE8GcmzK+KH2cQDJ2djB6zvCfKs2oHtoq/ZWJUNK8nqM0hWT44pQ7jYjwvVWO0lyZeXpFzq3Jz0Rr/a6G40jidYJRVGE6aPZhAkB73EGNQeoVSbhbpekOeJWQKBwiKM4ZMmrGbBKDabTI75aoU56EnyW9WS370uUVuTE92pRqzEjtF/K7A56HX7LSrJyVMSldHjcqeaOOXol5k6s0bKy9VyPH/0diBeqjHr8BH8oM6slfAylXx0GLfJyG8g1Rb96BzijZBRbAH7pKCOo8gFa51EPMmF013YIdxaOHBAV6jjgkqcQEJ8aQJ2FhPDObGn0akyN6qaJW2oWUzpK8AVQtQJiDP4eLrUInMgEMSBAnGNON8sPBSwWeRc/gZZbl6C18jJtigN/OgzCkNKUlKyRSnFmP9CZkz2JqYYZaOHDUapxqLDJRKTip9tdeikvEKvPZvNvWZWSyHumCA3Ojb2b7yXv1nIG13DyDLCbT6iSvJD1qtvQBUnK06SwJl37qER80TjBWW8V+lM83jTHEqlI83rSXMqLyzzXm+mS612ZXqTswhnnU3z0QqfLwscMCGLeB4efZdXSZ+GO0bFsEGKwuHcHDvdB0VYTI8ekmgtbqvTZ5LIuF6J1pxkhSAskX6q1Sskcq1ZK9us1St5ucai/V8JYxNiCmVuZHN0cmVhbQplbmRvYmoKMjEgMCBvYmoKPDwvVHlwZSAvRm9udERlc2NyaXB0b3IKL0ZvbnROYW1lIC9DQUFBQUErQ2FsaWJyaQovRmxhZ3MgNAovQXNjZW50IDc1MAovRGVzY2VudCAtMjUwCi9TdGVtViA0NS44OTg0MzgKL0NhcEhlaWdodCA2MzEuODM1OTQKL0l0YWxpY0FuZ2xlIDAKL0ZvbnRCQm94IFstOTcuMTY3OTY5IC0xOTMuODQ3NjYgODU5LjM3NSA4NDYuNjc5NjldCi9Gb250RmlsZTIgMjAgMCBSPj4KZW5kb2JqCjIyIDAgb2JqCjw8L1R5cGUgL0ZvbnQKL0ZvbnREZXNjcmlwdG9yIDIxIDAgUgovQmFzZUZvbnQgL0NBQUFBQStDYWxpYnJpCi9TdWJ0eXBlIC9DSURGb250VHlwZTIKL0NJRFRvR0lETWFwIC9JZGVudGl0eQovQ0lEU3lzdGVtSW5mbyA8PC9SZWdpc3RyeSAoQWRvYmUpCi9PcmRlcmluZyAoSWRlbnRpdHkpCi9TdXBwbGVtZW50IDA+PgovVyBbMCBbNTA2LjgzNTk0XSAxMyBbNTMzLjIwMzEzIDAgNjE1LjIzNDM4XSAyMiBbNDU5LjQ3MjY2IDAgNjIzLjA0Njg4IDI1MS45NTMxM10gMzAgWzMxOC44NDc2NiAwIDAgODU0Ljk4MDQ3IDY0NS41MDc4MV0gNDMgWzUxNi42MDE1NiAwIDAgMCA0NTkuNDcyNjYgNDg3LjMwNDY5XSA2MCBbNDc5LjAwMzkxXSA2OCBbNTI1LjM5MDYzIDQyMi44NTE1NiAwIDUyNS4zOTA2MyAwIDQ5Ny41NTg1OV0gNzggWzMwNS4xNzU3OCA0NzAuNzAzMTMgNTI1LjM5MDYzXSA4MSA4OSAyMjkuNDkyMTkgOTAgWzc5OC44MjgxMyA1MjUuMzkwNjMgMCA1MjcuMzQzNzVdIDEwMCBbNTI1LjM5MDYzIDAgMCAzNDguNjMyODEgMzkxLjExMzI4IDAgMzM0Ljk2MDk0IDUyNS4zOTA2M10gMTEyIFs0NTEuNjYwMTYgMCA0MzMuMTA1NDcgNDUyLjYzNjcyXSAxNDMgWzI2Ny41NzgxM10gMTU1IFszODYuMjMwNDddXQovRFcgMD4+CmVuZG9iagoyMyAwIG9iago8PC9GaWx0ZXIgL0ZsYXRlRGVjb2RlCi9MZW5ndGggMzYyPj4gc3RyZWFtCnicXZLLboMwEEX3fIWX6SICAwYiIaSUNBKLPlTaDyB4SJGKsQxZ8Pc1vjSVigTojOdxL4xfVqdK9TPz38zY1jSzrlfS0DTeTEvsQtdeeTxksm/njdyzHRrt+ba4XqaZhkp1o5fnjPnv9nSazcJ2Rzle6MHzX40k06sr232WteX6pvU3DaRmFnhFwSR1ttNzo1+agZjvyvaVtOf9vOxtzV/Gx6KJhY451LSjpEk3LZlGXcnLA3sVLD/bq/BIyX/nPELZpWu/GuPSTzY9COKocHQGxY54AkpAT6Cjo/DRkQgcRaWjhDuKUxC6xAeQcCQwLzk7sikrpeiSBiDMy6AlwrwD5oWwtek//Lq5u+eZS+OYGWfQylEbInhCcGuPmQL+Y+iJBUSGCMK4QJcE6gQmCMhKStjZjENEivLkiCAyU3yUFFrSCK9scwUf639b9+u+FO3NGLsPbgndIqwr0Cu676ke9Vq13j9wXb7UCmVuZHN0cmVhbQplbmRvYmoKNiAwIG9iago8PC9UeXBlIC9Gb250Ci9TdWJ0eXBlIC9UeXBlMAovQmFzZUZvbnQgL0NBQUFBQStDYWxpYnJpCi9FbmNvZGluZyAvSWRlbnRpdHktSAovRGVzY2VuZGFudEZvbnRzIFsyMiAwIFJdCi9Ub1VuaWNvZGUgMjMgMCBSPj4KZW5kb2JqCnhyZWYKMCAyNAowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMTUgMDAwMDAgbiAKMDAwMDAxMTczMiAwMDAwMCBuIAowMDAwMDAwMTE1IDAwMDAwIG4gCjAwMDAwMjE2MzQgMDAwMDAgbiAKMDAwMDAzMDk5MSAwMDAwMCBuIAowMDAwMDQ1MTI2IDAwMDAwIG4gCjAwMDAwMDAxNTIgMDAwMDAgbiAKMDAwMDAwMDIzOCAwMDAwMCBuIAowMDAwMDEwMzM2IDAwMDAwIG4gCjAwMDAwMTE5OTQgMDAwMDAgbiAKMDAwMDAxMjA1MCAwMDAwMCBuIAowMDAwMDEyMDk5IDAwMDAwIG4gCjAwMDAwMjA1OTggMDAwMDAgbiAKMDAwMDAyMDg0MSAwMDAwMCBuIAowMDAwMDIxMjczIDAwMDAwIG4gCjAwMDAwMjE3NzcgMDAwMDAgbiAKMDAwMDAyOTkzNiAwMDAwMCBuIAowMDAwMDMwMTcwIDAwMDAwIG4gCjAwMDAwMzA2MjAgMDAwMDAgbiAKMDAwMDAzMTEzNSAwMDAwMCBuIAowMDAwMDQzODE1IDAwMDAwIG4gCjAwMDAwNDQwNDEgMDAwMDAgbiAKMDAwMDA0NDY5MyAwMDAwMCBuIAp0cmFpbGVyCjw8L1NpemUgMjQKL1Jvb3QgMTEgMCBSCi9JbmZvIDEgMCBSPj4Kc3RhcnR4cmVmCjQ1MjY1CiUlRU9GCg==","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","messageLock":"false","recipientsLock":"false","brandLock":"false","customFields":{"textCustomFields":[{"fieldId":"11003755255","name":"##SFSource","show":"true","required":"false","value":""},{"fieldId":"11003755256","name":"##SFDocumentWriteBack","show":"true","required":"false","value":""},{"fieldId":"11003756051","name":"ModelNamespace","show":"false","required":"false","value":"docusign.forms._0820f9c5_0d81_489a_bcc9_8a0df87f44aa._3d761225_6960_4bd0_a657_683bb52fff21"},{"fieldId":"11003756052","name":"ModelVersion","show":"false","required":"false","value":"1"},{"fieldId":"11003756053","name":"ModelAccount","show":"false","required":"false","value":"0820f9c5-0d81-489a-bcc9-8a0df87f44aa"}],"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":"779409ee-df52-4560-82f5-d036273703ae","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":"4f92b805-4bd3-41e3-94cb-343cea58c9b8","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":"a4f174b8-647d-4c96-9b91-ff548a0c0930","mergeFieldXml":"{\"adm\":{\"path\":\"ADM.Form.SignerName\"}}","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":"9bcf6cba-05cf-4088-8c85-e5a905ca1efb","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":"d2d23949-ce13-48de-9043-ce1b4d7d594a","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":"6308de2e-cea9-48aa-ab03-25d53a54cc5a","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":"d1d70d31-d7d4-462b-b41a-cc1f55698ae2","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","allowComments":"true","disableResponsiveDocument":"true","anySigner":null,"envelopeLocation":"current_site"}]} +{"id":"39410656-f165-41e3-b1a4-bfd53fbb0e32","accountId":"0ef36a2b-ab23-47f2-9b96-a406e16044a5","isPublished":true,"isEnabled":true,"hasDraftChanges":false,"formState":"active","formProperties":{"name":"Web Form Example Template","isPrivateAccess":false},"formMetadata":{"source":"templates","createdDateTime":"2024-10-09T18:38:29.598Z","publishedSlug":"cb0d0f6a9e3772eb4dcbe24de6ba331d","owner":{"userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","userName":"Inbar WebForms"},"lastModifiedDateTime":"2024-10-09T18:39:31.391Z","lastModifiedBy":{"userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","userName":"Inbar WebForms"},"publishedComponentNames":{"signer_name":"TextBox","signer_email":"Email","FullName":"TextBox","PhoneNumber":"TextBox","Yes":"CheckboxGroup","Company":"TextBox","JobTitle":"TextBox"},"admModelNamespace":"docusign.forms._0ef36a2b_ab23_47f2_9b96_a406e16044a5._39410656_f165_41e3_b1a4_bfd53fbb0e32","formContentModifiedBy":{"userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","userName":"Inbar WebForms"},"formContentModifiedDateTime":"2024-10-09T18:39:18.097Z","admModelVersion":"1.0.0","type":"hasEsignTemplate","formPropertiesModifiedBy":{"userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","userName":"Inbar WebForms"},"formPropertiesModifiedDateTime":"2024-10-09T18:39:07.573Z","sender":{"userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","userName":"Inbar WebForms"},"lastSenderConsentDateTime":"2024-10-09T18:39:23.162Z","lastPublishedBy":{"userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","userName":"Inbar WebForms"},"lastPublishedDateTime":"2024-10-09T18:39:31.391Z","lastEnabledBy":{"userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","userName":"Inbar WebForms"},"lastEnabledDateTime":"2024-10-09T18:39:31.391Z"},"formContent":{"components":{"Root_Of_Journey":{"componentKey":"Root_Of_Journey","componentType":"Root","componentName":"Root_Of_Journey","componentRules":{},"text":"","children":["Welcome_mLgvoXc_","Step_8CmDcmdk","Summary_eFmqGlfG","ESignAction_WDkwveBt","Thankyou_kyyG6Evn"]},"Welcome_mLgvoXc_":{"text":"Welcome","subText":"Part time work application","startButtonText":"Start","componentKey":"Welcome_mLgvoXc_","componentType":"Welcome"},"Step_8CmDcmdk":{"componentKey":"Step_8CmDcmdk","componentType":"Step","componentName":"Step_8CmDcmdk","text":"Untitled page","children":["TextBox_CnHrDIYv","Email_x5VWUgAp","TextBox_5ulrY7z8","TextBox_yZu4JilU","CheckboxGroup_Zg4TE6Sy","TextBox_6Qui50QM","TextBox_dikybASu"]},"Summary_eFmqGlfG":{"text":"Summary","subText":"Please review the information you have entered:","componentKey":"Summary_eFmqGlfG","componentType":"Summary"},"ESignAction_WDkwveBt":{"componentKey":"ESignAction_WDkwveBt","componentType":"ESignAction","primaryRecipientId":"1","templateInfoMap":{"3d41614e-ae79-40f6-bbf0-c2748f5800ac":{"templateId":"3d41614e-ae79-40f6-bbf0-c2748f5800ac","lastModified":"2024-10-09T18:38:30.4470000Z","name":"Web Form Copy - Web Form Example Template","owner":{"userName":"Inbar WebForms","userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","email":"inbar27@mailinator.com"}}},"documentInfoMap":{"Document_JfypoAaN":{"name":"World_Wide_Web_Form","documentId":"1","order":"1"}},"recipientInfoMap":{"1":{"nameComponentKey":"TextBox_CnHrDIYv","emailComponentKey":"Email_x5VWUgAp","recipientId":"1","recipientType":"signer","roleName":"signer","routingOrder":"1","nameFromTemplate":"","emailFromTemplate":""}},"tabInfoMap":{"81db13d8-66be-4aab-aa59-b9d974bb4627":{"componentKey":"TextBox_5ulrY7z8","tabId":"81db13d8-66be-4aab-aa59-b9d974bb4627","recipientId":"1","tabLabel":"FullName","tabType":"text","locked":"false"},"e57b222b-55fa-4fc7-a9c7-f40f2b5d6dbd":{"componentKey":"TextBox_yZu4JilU","tabId":"e57b222b-55fa-4fc7-a9c7-f40f2b5d6dbd","recipientId":"1","tabLabel":"PhoneNumber","tabType":"text","locked":"false"},"938f353b-5694-4d12-9e88-e8f9e7ccc0f1":{"componentKey":"TextBox_6Qui50QM","tabId":"938f353b-5694-4d12-9e88-e8f9e7ccc0f1","recipientId":"1","tabLabel":"Company","tabType":"text","locked":"false"},"56685845-2115-45a6-8b88-915e3c2f91ff":{"componentKey":"TextBox_dikybASu","tabId":"56685845-2115-45a6-8b88-915e3c2f91ff","recipientId":"1","tabLabel":"JobTitle","tabType":"text","locked":"false"},"256a3887-d854-46f8-9ee5-ae0b3f5866b0":{"componentKey":"CheckboxGroup_Zg4TE6Sy","tabId":"256a3887-d854-46f8-9ee5-ae0b3f5866b0","recipientId":"1","tabLabel":"Yes","tabType":"checkbox","name":"Yes","selected":"false","locked":"false"}},"requireRemoteSigning":false,"enableDocumentFieldEditing":true},"Thankyou_kyyG6Evn":{"text":"Thank you","subText":"We've received your form.","showConfirmationButton":false,"confirmationButtonText":"Done","confirmationButtonUrl":"","componentKey":"Thankyou_kyyG6Evn","componentType":"Thankyou"},"TextBox_CnHrDIYv":{"componentKey":"TextBox_CnHrDIYv","componentType":"TextBox","componentName":"signer_name","label":"signer name","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"Email_x5VWUgAp":{"componentKey":"Email_x5VWUgAp","componentType":"Email","componentName":"signer_email","label":"signer email","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"TextBox_5ulrY7z8":{"componentKey":"TextBox_5ulrY7z8","componentType":"TextBox","componentName":"FullName","label":"FullName","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"TextBox_yZu4JilU":{"componentKey":"TextBox_yZu4JilU","componentType":"TextBox","componentName":"PhoneNumber","label":"PhoneNumber","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"CheckboxGroup_Zg4TE6Sy":{"componentKey":"CheckboxGroup_Zg4TE6Sy","componentType":"CheckboxGroup","componentName":"Yes","label":"","description":"","options":[{"optionKey":"Zd9v2gRs","value":"Yes","label":"Yes","selected":false}]},"TextBox_6Qui50QM":{"componentKey":"TextBox_6Qui50QM","componentType":"TextBox","componentName":"Company","label":"Company","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"TextBox_dikybASu":{"componentKey":"TextBox_dikybASu","componentType":"TextBox","componentName":"JobTitle","label":"JobTitle","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000}},"isStandalone":false,"templates":[{"originalTemplateId":"90e1562e-9f65-486d-9a5f-2f6db09d1878","clonedTemplateId":"3d41614e-ae79-40f6-bbf0-c2748f5800ac","importedDateTime":"2024-10-09T18:38:31.275Z","recipientIds":["1"]}]},"formLocale":"en","versionId":1,"eSignTemplates":[{"templateId":"3d41614e-ae79-40f6-bbf0-c2748f5800ac","uri":"/templates/3d41614e-ae79-40f6-bbf0-c2748f5800ac","name":"Web Form Copy - Web Form Example Template","shared":"false","passwordProtected":"false","description":"Example template created via the eSignature API","created":"2024-10-09T18:38:30.0100000Z","lastModified":"2024-10-09T18:39:30.8100000Z","lastModifiedBy":{"userName":"Inbar WebForms","userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","email":"inbar27@mailinator.com","uri":"/users/06958f21-168b-44aa-b530-8abc0cb6cf18"},"lastUsed":"2024-10-09T18:38:30.4470000Z","owner":{"userName":"Inbar WebForms","userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","email":"inbar27@mailinator.com"},"pageCount":"1","folderId":"e4e93cf6-a3d9-4e0c-88f6-bd9bbfc73fc5","folderName":"Deleted Items","folderIds":["e4e93cf6-a3d9-4e0c-88f6-bd9bbfc73fc5"],"autoMatch":"true","autoMatchSpecifiedByUser":"false","documents":[{"documentId":"1","uri":"/envelopes/3d41614e-ae79-40f6-bbf0-c2748f5800ac/documents/1","name":"World_Wide_Web_Form","order":"1","pages":"1","documentBase64":"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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","messageLock":"false","recipientsLock":"false","brandLock":"false","customFields":{"textCustomFields":[{"fieldId":"11126003281","name":"ModelNamespace","show":"false","required":"false","value":"docusign.forms._0ef36a2b_ab23_47f2_9b96_a406e16044a5._39410656_f165_41e3_b1a4_bfd53fbb0e32"},{"fieldId":"11126003282","name":"ModelVersion","show":"false","required":"false","value":"1"},{"fieldId":"11126003283","name":"ModelAccount","show":"false","required":"false","value":"0ef36a2b-ab23-47f2-9b96-a406e16044a5"}],"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":"0d3171e2-42d0-4034-a929-1897b6078c25","tabType":"signhere"}],"dateSignedTabs":[{"name":"DateSigned","value":"","tabLabel":"DateSigned","localePolicy":{},"documentId":"1","recipientId":"1","pageNumber":"1","xPosition":"389","yPosition":"386","anchorString":"/Date/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"5bfda557-b893-4097-af42-b38a130638cf","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":"125","yPosition":"224","width":"0","height":"0","anchorString":"/FullName/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"81db13d8-66be-4aab-aa59-b9d974bb4627","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":"147","yPosition":"251","width":"0","height":"0","anchorString":"/PhoneNumber/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"e57b222b-55fa-4fc7-a9c7-f40f2b5d6dbd","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":"162","yPosition":"305","width":"0","height":"0","anchorString":"/Company/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"938f353b-5694-4d12-9e88-e8f9e7ccc0f1","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":"117","yPosition":"332","width":"0","height":"0","anchorString":"/Title/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"56685845-2115-45a6-8b88-915e3c2f91ff","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":"217","yPosition":"278","width":"0","height":"0","anchorString":"/SMS/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"256a3887-d854-46f8-9ee5-ae0b3f5866b0","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","allowComments":"true","disableResponsiveDocument":"true","anySigner":null,"envelopeLocation":"current_site"}]} \ No newline at end of file From 012d3d4de59bf41de5233b5d991772175d228676 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Wed, 23 Oct 2024 15:51:55 +0300 Subject: [PATCH 338/363] update packages --- Gemfile | 20 +- Gemfile.lock | 194 +++++++++--------- .../admin_api/eg013_create_account_service.rb | 3 - jwt_console_project/jwt_console.rb | 2 +- quick_acg/Gemfile | 16 +- quick_acg/Gemfile.lock | 179 ++++++++-------- 6 files changed, 203 insertions(+), 211 deletions(-) diff --git a/Gemfile b/Gemfile index 2f2c04f..76eec36 100644 --- a/Gemfile +++ b/Gemfile @@ -6,15 +6,15 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '~>3.1.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 7.1.3.2' +gem 'rails', '~> 7.2.1.1' # Use sqlite3 as the database for Active Record -gem 'sqlite3', '~> 1.7.3' +gem 'sqlite3', '~> 2.1.1' # Use Puma as the app server -gem 'puma', '~> 6.4.2' +gem 'puma', '~> 6.4.3' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets -gem 'uglifier', '~> 4.2.0' +gem 'uglifier', '~> 4.2.1' # See https://github.com/rails/execjs#readme for more supported runtimes # gem 'mini_racer', platforms: :ruby @@ -23,7 +23,7 @@ gem 'coffee-rails', '~> 5.0.0' # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks gem 'turbolinks', '~> 5.2.1' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder -gem 'jbuilder', '~> 2.11.5' +gem 'jbuilder', '~> 2.13.0' # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 4.0' # Use ActiveModel has_secure_password @@ -53,8 +53,8 @@ group :development do gem 'web-console', '~> 4.2.1' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'pry-nav', '~> 1.0.0' - gem 'pry-rails', '~> 0.3.9' - gem 'rubocop', '~> 1.63.3', require: false + gem 'pry-rails', '~> 0.3.11' + gem 'rubocop', '~> 1.67.0', require: false gem 'spring', '~> 4.2.1' gem 'spring-watcher-listen', '~> 2.1.0' end @@ -62,15 +62,15 @@ end group :test do # Adds support for Capybara system testing and selenium driver gem 'capybara', '~> 3.40.0' - gem 'selenium-webdriver', '~> 4.19.0' + gem 'selenium-webdriver', '~> 4.25.0' # Easy installation and use of chromedriver to run system tests with Chrome gem 'chromedriver-helper', '~> 2.1.1' gem 'test-unit' end -gem 'docusign_admin', '~> 2.0.0.rc1' +gem 'docusign_admin', '~> 2.0.0.rc2' gem 'docusign_click', '~> 1.4.0' -gem 'docusign_esign', '~> 4.0.0.rc1' +gem 'docusign_esign', '~> 5.0.0' gem 'docusign_maestro', '~> 2.0.0.rc1' gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' diff --git a/Gemfile.lock b/Gemfile.lock index e1663a5..d5aa9f7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,80 +1,76 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.1.3.4) - actionpack (= 7.1.3.4) - activesupport (= 7.1.3.4) + actioncable (7.2.1.1) + actionpack (= 7.2.1.1) + activesupport (= 7.2.1.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.3.4) - actionpack (= 7.1.3.4) - activejob (= 7.1.3.4) - activerecord (= 7.1.3.4) - activestorage (= 7.1.3.4) - activesupport (= 7.1.3.4) - mail (>= 2.7.1) - net-imap - net-pop - net-smtp - actionmailer (7.1.3.4) - actionpack (= 7.1.3.4) - actionview (= 7.1.3.4) - activejob (= 7.1.3.4) - activesupport (= 7.1.3.4) - mail (~> 2.5, >= 2.5.4) - net-imap - net-pop - net-smtp + actionmailbox (7.2.1.1) + actionpack (= 7.2.1.1) + activejob (= 7.2.1.1) + activerecord (= 7.2.1.1) + activestorage (= 7.2.1.1) + activesupport (= 7.2.1.1) + mail (>= 2.8.0) + actionmailer (7.2.1.1) + actionpack (= 7.2.1.1) + actionview (= 7.2.1.1) + activejob (= 7.2.1.1) + activesupport (= 7.2.1.1) + mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.1.3.4) - actionview (= 7.1.3.4) - activesupport (= 7.1.3.4) + actionpack (7.2.1.1) + actionview (= 7.2.1.1) + activesupport (= 7.2.1.1) nokogiri (>= 1.8.5) racc - rack (>= 2.2.4) + rack (>= 2.2.4, < 3.2) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.3.4) - actionpack (= 7.1.3.4) - activerecord (= 7.1.3.4) - activestorage (= 7.1.3.4) - activesupport (= 7.1.3.4) + useragent (~> 0.16) + actiontext (7.2.1.1) + actionpack (= 7.2.1.1) + activerecord (= 7.2.1.1) + activestorage (= 7.2.1.1) + activesupport (= 7.2.1.1) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.3.4) - activesupport (= 7.1.3.4) + actionview (7.2.1.1) + activesupport (= 7.2.1.1) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.1.3.4) - activesupport (= 7.1.3.4) + activejob (7.2.1.1) + activesupport (= 7.2.1.1) globalid (>= 0.3.6) - activemodel (7.1.3.4) - activesupport (= 7.1.3.4) - activerecord (7.1.3.4) - activemodel (= 7.1.3.4) - activesupport (= 7.1.3.4) + activemodel (7.2.1.1) + activesupport (= 7.2.1.1) + activerecord (7.2.1.1) + activemodel (= 7.2.1.1) + activesupport (= 7.2.1.1) timeout (>= 0.4.0) - activestorage (7.1.3.4) - actionpack (= 7.1.3.4) - activejob (= 7.1.3.4) - activerecord (= 7.1.3.4) - activesupport (= 7.1.3.4) + activestorage (7.2.1.1) + actionpack (= 7.2.1.1) + activejob (= 7.2.1.1) + activerecord (= 7.2.1.1) + activesupport (= 7.2.1.1) marcel (~> 1.0) - activesupport (7.1.3.4) + activesupport (7.2.1.1) base64 bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) + concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) - mutex_m - tzinfo (~> 2.0) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) archive-zip (0.12.0) @@ -111,7 +107,7 @@ GEM connection_pool (2.4.1) crass (1.0.6) date (3.3.4) - docusign_admin (2.0.0.rc1) + docusign_admin (2.0.0.rc2) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -121,7 +117,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (4.0.0) + docusign_esign (5.0.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -167,7 +163,7 @@ GEM irb (1.13.2) rdoc (>= 4.0.0) reline (>= 0.4.2) - jbuilder (2.11.5) + jbuilder (2.13.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) json (2.7.2) @@ -177,6 +173,7 @@ GEM listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) + logger (1.6.1) loofah (2.22.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) @@ -193,10 +190,9 @@ GEM msgpack (1.7.2) multi_xml (0.7.1) bigdecimal (~> 3.1) - mutex_m (0.2.0) net-http (0.4.1) uri - net-imap (0.4.14) + net-imap (0.5.0) date net-protocol net-pop (0.1.2) @@ -229,8 +225,8 @@ GEM omniauth-rails_csrf_protection (1.0.2) actionpack (>= 4.2) omniauth (~> 2.0) - parallel (1.25.1) - parser (3.3.3.0) + parallel (1.26.3) + parser (3.3.5.0) ast (~> 2.4.1) racc power_assert (2.0.3) @@ -244,7 +240,7 @@ GEM psych (5.1.2) stringio public_suffix (6.0.0) - puma (6.4.2) + puma (6.4.3) nio4r (~> 2.0) racc (1.8.0) rack (3.1.4) @@ -258,20 +254,20 @@ GEM rackup (2.1.0) rack (>= 3) webrick (~> 1.8) - rails (7.1.3.4) - actioncable (= 7.1.3.4) - actionmailbox (= 7.1.3.4) - actionmailer (= 7.1.3.4) - actionpack (= 7.1.3.4) - actiontext (= 7.1.3.4) - actionview (= 7.1.3.4) - activejob (= 7.1.3.4) - activemodel (= 7.1.3.4) - activerecord (= 7.1.3.4) - activestorage (= 7.1.3.4) - activesupport (= 7.1.3.4) + rails (7.2.1.1) + actioncable (= 7.2.1.1) + actionmailbox (= 7.2.1.1) + actionmailer (= 7.2.1.1) + actionpack (= 7.2.1.1) + actiontext (= 7.2.1.1) + actionview (= 7.2.1.1) + activejob (= 7.2.1.1) + activemodel (= 7.2.1.1) + activerecord (= 7.2.1.1) + activestorage (= 7.2.1.1) + activesupport (= 7.2.1.1) bundler (>= 1.15.0) - railties (= 7.1.3.4) + railties (= 7.2.1.1) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -279,10 +275,10 @@ GEM rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) - railties (7.1.3.4) - actionpack (= 7.1.3.4) - activesupport (= 7.1.3.4) - irb + railties (7.2.1.1) + actionpack (= 7.2.1.1) + activesupport (= 7.2.1.1) + irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) @@ -297,20 +293,18 @@ GEM regexp_parser (2.9.2) reline (0.5.9) io-console (~> 0.5) - rexml (3.3.1) - strscan - rubocop (1.63.5) + rexml (3.3.8) + rubocop (1.67.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.31.1, < 2.0) + regexp_parser (>= 2.4, < 3.0) + rubocop-ast (>= 1.32.2, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.31.3) + rubocop-ast (1.32.3) parser (>= 3.3.1.0) ruby-progressbar (1.13.0) rubyzip (2.3.2) @@ -324,8 +318,10 @@ GEM sprockets (> 3.0) sprockets-rails tilt - selenium-webdriver (4.19.0) + securerandom (0.3.1) + selenium-webdriver (4.25.0) base64 (~> 0.2) + logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) @@ -343,11 +339,10 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) - sqlite3 (1.7.3-x64-mingw-ucrt) - sqlite3 (1.7.3-x86_64-darwin) - sqlite3 (1.7.3-x86_64-linux) + sqlite3 (2.1.1-x64-mingw-ucrt) + sqlite3 (2.1.1-x86_64-darwin) + sqlite3 (2.1.1-x86_64-linux-gnu) stringio (3.1.1) - strscan (3.1.0) test-unit (3.6.2) power_assert thor (1.3.1) @@ -362,10 +357,11 @@ GEM concurrent-ruby (~> 1.0) tzinfo-data (1.2022.7) tzinfo (>= 1.0.0) - uglifier (4.2.0) + uglifier (4.2.1) execjs (>= 0.3.0, < 3) - unicode-display_width (2.5.0) + unicode-display_width (2.6.0) uri (0.13.0) + useragent (0.16.10) version_gem (1.1.4) wdm (0.1.1) web-console (4.2.1) @@ -374,7 +370,7 @@ GEM bindex (>= 0.4.0) railties (>= 6.0.0) webrick (1.8.1) - websocket (1.2.10) + websocket (1.2.11) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) @@ -393,32 +389,32 @@ DEPENDENCIES capybara (~> 3.40.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_admin (~> 2.0.0.rc1) + docusign_admin (~> 2.0.0.rc2) docusign_click (~> 1.4.0) - docusign_esign (~> 4.0.0.rc1) + docusign_esign (~> 5.0.0) docusign_maestro (~> 2.0.0.rc1) docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) docusign_webforms (~> 1.0.0) - jbuilder (~> 2.11.5) + jbuilder (~> 2.13.0) listen (~> 3.9.0) matrix (~> 0.4.2) omniauth-oauth2 (~> 1.8.0) omniauth-rails_csrf_protection pry-nav (~> 1.0.0) - pry-rails (~> 0.3.9) - puma (~> 6.4.2) - rails (~> 7.1.3.2) - rubocop (~> 1.63.3) + pry-rails (~> 0.3.11) + puma (~> 6.4.3) + rails (~> 7.2.1.1) + rubocop (~> 1.67.0) sass-rails (~> 6.0.0) - selenium-webdriver (~> 4.19.0) + selenium-webdriver (~> 4.25.0) spring (~> 4.2.1) spring-watcher-listen (~> 2.1.0) - sqlite3 (~> 1.7.3) + sqlite3 (~> 2.1.1) test-unit turbolinks (~> 5.2.1) tzinfo-data (~> 1.2022.7, >= 1.2022.7) - uglifier (~> 4.2.0) + uglifier (~> 4.2.1) wdm (>= 0.1.1) web-console (~> 4.2.1) diff --git a/app/services/admin_api/eg013_create_account_service.rb b/app/services/admin_api/eg013_create_account_service.rb index b1ffa7c..848b0d5 100644 --- a/app/services/admin_api/eg013_create_account_service.rb +++ b/app/services/admin_api/eg013_create_account_service.rb @@ -17,9 +17,6 @@ def worker #ds-snippet-end:Admin13Step2 #ds-snippet-start:Admin13Step4 - source_account = DocuSign_Admin::AssetGroupAccountCloneSourceAccount.new - source_account.id = args[:source_account_id] - target_account_admin = DocuSign_Admin::SubAccountCreateRequestSubAccountCreationTargetAccountAdmin.new target_account_admin.first_name = args[:first_name] target_account_admin.last_name = args[:last_name] diff --git a/jwt_console_project/jwt_console.rb b/jwt_console_project/jwt_console.rb index 501a768..1d61d1e 100644 --- a/jwt_console_project/jwt_console.rb +++ b/jwt_console_project/jwt_console.rb @@ -2,7 +2,7 @@ gemfile do source 'https://rubygems.org' - gem 'docusign_esign', ' ~> 3.27.0.rc1' + gem 'docusign_esign', ' ~> 5.0.0' end class ESign diff --git a/quick_acg/Gemfile b/quick_acg/Gemfile index 9f14b3f..cb0ebbc 100644 --- a/quick_acg/Gemfile +++ b/quick_acg/Gemfile @@ -6,15 +6,15 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '~>3.1.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 7.1.3.2' +gem 'rails', '~> 7.2.1.1' # Use sqlite3 as the database for Active Record -gem 'sqlite3', '~> 1.7.3' +gem 'sqlite3', '~> 2.1.1' # Use Puma as the app server -gem 'puma', '~> 6.4.2' +gem 'puma', '~> 6.4.3' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets -gem 'uglifier', '~> 4.2.0' +gem 'uglifier', '~> 4.2.1' # See https://github.com/rails/execjs#readme for more supported runtimes # gem 'mini_racer', platforms: :ruby @@ -23,7 +23,7 @@ gem 'coffee-rails', '~> 5.0.0' # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks gem 'turbolinks', '~> 5.2.1' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder -gem 'jbuilder', '~> 2.11.5' +gem 'jbuilder', '~> 2.13.0' # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 4.0' # Use ActiveModel has_secure_password @@ -53,7 +53,7 @@ group :development do gem 'web-console', '~> 4.2.1' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'pry-nav', '~> 1.0.0' - gem 'pry-rails', '~> 0.3.9' + gem 'pry-rails', '~> 0.3.11' gem 'spring', '~> 4.2.1' gem 'spring-watcher-listen', '~> 2.1.0' end @@ -61,13 +61,13 @@ end group :test do # Adds support for Capybara system testing and selenium driver gem 'capybara', '~> 3.40.0' - gem 'selenium-webdriver', '~> 4.19.0' + gem 'selenium-webdriver', '~> 4.25.0' # Easy installation and use of chromedriver to run system tests with Chrome gem 'chromedriver-helper', '~> 2.1.1' gem 'test-unit' end -gem 'docusign_esign', '~> 3.27.0.rc1' +gem 'docusign_esign', '~> 5.0.0' gem 'omniauth-oauth2', '~> 1.8.0' gem 'omniauth-rails_csrf_protection' diff --git a/quick_acg/Gemfile.lock b/quick_acg/Gemfile.lock index 80a99ff..4b67c06 100644 --- a/quick_acg/Gemfile.lock +++ b/quick_acg/Gemfile.lock @@ -1,80 +1,76 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.1.3.2) - actionpack (= 7.1.3.2) - activesupport (= 7.1.3.2) + actioncable (7.2.1.1) + actionpack (= 7.2.1.1) + activesupport (= 7.2.1.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.3.2) - actionpack (= 7.1.3.2) - activejob (= 7.1.3.2) - activerecord (= 7.1.3.2) - activestorage (= 7.1.3.2) - activesupport (= 7.1.3.2) - mail (>= 2.7.1) - net-imap - net-pop - net-smtp - actionmailer (7.1.3.2) - actionpack (= 7.1.3.2) - actionview (= 7.1.3.2) - activejob (= 7.1.3.2) - activesupport (= 7.1.3.2) - mail (~> 2.5, >= 2.5.4) - net-imap - net-pop - net-smtp + actionmailbox (7.2.1.1) + actionpack (= 7.2.1.1) + activejob (= 7.2.1.1) + activerecord (= 7.2.1.1) + activestorage (= 7.2.1.1) + activesupport (= 7.2.1.1) + mail (>= 2.8.0) + actionmailer (7.2.1.1) + actionpack (= 7.2.1.1) + actionview (= 7.2.1.1) + activejob (= 7.2.1.1) + activesupport (= 7.2.1.1) + mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.1.3.2) - actionview (= 7.1.3.2) - activesupport (= 7.1.3.2) + actionpack (7.2.1.1) + actionview (= 7.2.1.1) + activesupport (= 7.2.1.1) nokogiri (>= 1.8.5) racc - rack (>= 2.2.4) + rack (>= 2.2.4, < 3.2) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.3.2) - actionpack (= 7.1.3.2) - activerecord (= 7.1.3.2) - activestorage (= 7.1.3.2) - activesupport (= 7.1.3.2) + useragent (~> 0.16) + actiontext (7.2.1.1) + actionpack (= 7.2.1.1) + activerecord (= 7.2.1.1) + activestorage (= 7.2.1.1) + activesupport (= 7.2.1.1) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.3.2) - activesupport (= 7.1.3.2) + actionview (7.2.1.1) + activesupport (= 7.2.1.1) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.1.3.2) - activesupport (= 7.1.3.2) + activejob (7.2.1.1) + activesupport (= 7.2.1.1) globalid (>= 0.3.6) - activemodel (7.1.3.2) - activesupport (= 7.1.3.2) - activerecord (7.1.3.2) - activemodel (= 7.1.3.2) - activesupport (= 7.1.3.2) + activemodel (7.2.1.1) + activesupport (= 7.2.1.1) + activerecord (7.2.1.1) + activemodel (= 7.2.1.1) + activesupport (= 7.2.1.1) timeout (>= 0.4.0) - activestorage (7.1.3.2) - actionpack (= 7.1.3.2) - activejob (= 7.1.3.2) - activerecord (= 7.1.3.2) - activesupport (= 7.1.3.2) + activestorage (7.2.1.1) + actionpack (= 7.2.1.1) + activejob (= 7.2.1.1) + activerecord (= 7.2.1.1) + activesupport (= 7.2.1.1) marcel (~> 1.0) - activesupport (7.1.3.2) + activesupport (7.2.1.1) base64 bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) + concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) - mutex_m - tzinfo (~> 2.0) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) archive-zip (0.12.0) @@ -106,11 +102,11 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.2.3) + concurrent-ruby (1.3.4) connection_pool (2.4.1) crass (1.0.6) date (3.3.4) - docusign_esign (3.27.0.rc1) + docusign_esign (5.0.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -132,10 +128,10 @@ GEM concurrent-ruby (~> 1.0) io-console (0.7.2) io-like (0.3.1) - irb (1.12.0) - rdoc + irb (1.14.1) + rdoc (>= 4.0.0) reline (>= 0.4.2) - jbuilder (2.11.5) + jbuilder (2.13.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) json (2.7.2) @@ -144,6 +140,7 @@ GEM listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) + logger (1.6.1) loofah (2.22.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) @@ -159,10 +156,9 @@ GEM minitest (5.22.3) msgpack (1.7.2) multi_xml (0.6.0) - mutex_m (0.2.0) net-http (0.4.1) uri - net-imap (0.4.10) + net-imap (0.5.0) date net-protocol net-pop (0.1.2) @@ -171,7 +167,7 @@ GEM timeout net-smtp (0.5.0) net-protocol - nio4r (2.7.1) + nio4r (2.7.3) nokogiri (1.16.4-x64-mingw-ucrt) racc (~> 1.4) oauth2 (2.0.9) @@ -197,12 +193,12 @@ GEM method_source (~> 1.0) pry-nav (1.0.0) pry (>= 0.9.10, < 0.15) - pry-rails (0.3.9) - pry (>= 0.10.4) + pry-rails (0.3.11) + pry (>= 0.13.0) psych (5.1.2) stringio public_suffix (5.0.5) - puma (6.4.2) + puma (6.4.3) nio4r (~> 2.0) racc (1.7.3) rack (3.0.10) @@ -216,20 +212,20 @@ GEM rackup (2.1.0) rack (>= 3) webrick (~> 1.8) - rails (7.1.3.2) - actioncable (= 7.1.3.2) - actionmailbox (= 7.1.3.2) - actionmailer (= 7.1.3.2) - actionpack (= 7.1.3.2) - actiontext (= 7.1.3.2) - actionview (= 7.1.3.2) - activejob (= 7.1.3.2) - activemodel (= 7.1.3.2) - activerecord (= 7.1.3.2) - activestorage (= 7.1.3.2) - activesupport (= 7.1.3.2) + rails (7.2.1.1) + actioncable (= 7.2.1.1) + actionmailbox (= 7.2.1.1) + actionmailer (= 7.2.1.1) + actionpack (= 7.2.1.1) + actiontext (= 7.2.1.1) + actionview (= 7.2.1.1) + activejob (= 7.2.1.1) + activemodel (= 7.2.1.1) + activerecord (= 7.2.1.1) + activestorage (= 7.2.1.1) + activesupport (= 7.2.1.1) bundler (>= 1.15.0) - railties (= 7.1.3.2) + railties (= 7.2.1.1) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -237,10 +233,10 @@ GEM rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) - railties (7.1.3.2) - actionpack (= 7.1.3.2) - activesupport (= 7.1.3.2) - irb + railties (7.2.1.1) + actionpack (= 7.2.1.1) + activesupport (= 7.2.1.1) + irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) @@ -254,7 +250,7 @@ GEM regexp_parser (2.9.0) reline (0.5.2) io-console (~> 0.5) - rexml (3.2.6) + rexml (3.3.8) rubyzip (2.3.2) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) @@ -266,8 +262,10 @@ GEM sprockets (> 3.0) sprockets-rails tilt - selenium-webdriver (4.19.0) + securerandom (0.3.1) + selenium-webdriver (4.25.0) base64 (~> 0.2) + logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) @@ -285,7 +283,7 @@ GEM actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) - sqlite3 (1.7.3-x64-mingw-ucrt) + sqlite3 (2.1.1-x64-mingw-ucrt) stringio (3.1.0) test-unit (3.6.2) power_assert @@ -301,9 +299,10 @@ GEM concurrent-ruby (~> 1.0) tzinfo-data (1.2022.7) tzinfo (>= 1.0.0) - uglifier (4.2.0) + uglifier (4.2.1) execjs (>= 0.3.0, < 3) uri (0.13.0) + useragent (0.16.10) version_gem (1.1.4) wdm (0.1.1) web-console (4.2.1) @@ -312,7 +311,7 @@ GEM bindex (>= 0.4.0) railties (>= 6.0.0) webrick (1.8.1) - websocket (1.2.10) + websocket (1.2.11) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) @@ -329,24 +328,24 @@ DEPENDENCIES capybara (~> 3.40.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_esign (~> 3.27.0.rc1) - jbuilder (~> 2.11.5) + docusign_esign (~> 5.0.0) + jbuilder (~> 2.13.0) listen (~> 3.9.0) omniauth-oauth2 (~> 1.8.0) omniauth-rails_csrf_protection pry-nav (~> 1.0.0) - pry-rails (~> 0.3.9) - puma (~> 6.4.2) - rails (~> 7.1.3.2) + pry-rails (~> 0.3.11) + puma (~> 6.4.3) + rails (~> 7.2.1.1) sass-rails (~> 6.0.0) - selenium-webdriver (~> 4.19.0) + selenium-webdriver (~> 4.25.0) spring (~> 4.2.1) spring-watcher-listen (~> 2.1.0) - sqlite3 (~> 1.7.3) + sqlite3 (~> 2.1.1) test-unit turbolinks (~> 5.2.1) tzinfo-data (~> 1.2022.7, >= 1.2022.7) - uglifier (~> 4.2.0) + uglifier (~> 4.2.1) wdm (>= 0.1.1) web-console (~> 4.2.1) From aaa5975e7c793085289a15f728674fbd5835a713 Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Fri, 25 Oct 2024 10:25:53 -0700 Subject: [PATCH 339/363] removing template IDs --- data/web-form-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/web-form-config.json b/data/web-form-config.json index 5947cca..10910b2 100644 --- a/data/web-form-config.json +++ b/data/web-form-config.json @@ -1 +1 @@ -{"id":"39410656-f165-41e3-b1a4-bfd53fbb0e32","accountId":"0ef36a2b-ab23-47f2-9b96-a406e16044a5","isPublished":true,"isEnabled":true,"hasDraftChanges":false,"formState":"active","formProperties":{"name":"Web Form Example Template","isPrivateAccess":false},"formMetadata":{"source":"templates","createdDateTime":"2024-10-09T18:38:29.598Z","publishedSlug":"cb0d0f6a9e3772eb4dcbe24de6ba331d","owner":{"userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","userName":"Inbar WebForms"},"lastModifiedDateTime":"2024-10-09T18:39:31.391Z","lastModifiedBy":{"userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","userName":"Inbar WebForms"},"publishedComponentNames":{"signer_name":"TextBox","signer_email":"Email","FullName":"TextBox","PhoneNumber":"TextBox","Yes":"CheckboxGroup","Company":"TextBox","JobTitle":"TextBox"},"admModelNamespace":"docusign.forms._0ef36a2b_ab23_47f2_9b96_a406e16044a5._39410656_f165_41e3_b1a4_bfd53fbb0e32","formContentModifiedBy":{"userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","userName":"Inbar WebForms"},"formContentModifiedDateTime":"2024-10-09T18:39:18.097Z","admModelVersion":"1.0.0","type":"hasEsignTemplate","formPropertiesModifiedBy":{"userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","userName":"Inbar WebForms"},"formPropertiesModifiedDateTime":"2024-10-09T18:39:07.573Z","sender":{"userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","userName":"Inbar WebForms"},"lastSenderConsentDateTime":"2024-10-09T18:39:23.162Z","lastPublishedBy":{"userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","userName":"Inbar WebForms"},"lastPublishedDateTime":"2024-10-09T18:39:31.391Z","lastEnabledBy":{"userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","userName":"Inbar WebForms"},"lastEnabledDateTime":"2024-10-09T18:39:31.391Z"},"formContent":{"components":{"Root_Of_Journey":{"componentKey":"Root_Of_Journey","componentType":"Root","componentName":"Root_Of_Journey","componentRules":{},"text":"","children":["Welcome_mLgvoXc_","Step_8CmDcmdk","Summary_eFmqGlfG","ESignAction_WDkwveBt","Thankyou_kyyG6Evn"]},"Welcome_mLgvoXc_":{"text":"Welcome","subText":"Part time work application","startButtonText":"Start","componentKey":"Welcome_mLgvoXc_","componentType":"Welcome"},"Step_8CmDcmdk":{"componentKey":"Step_8CmDcmdk","componentType":"Step","componentName":"Step_8CmDcmdk","text":"Untitled page","children":["TextBox_CnHrDIYv","Email_x5VWUgAp","TextBox_5ulrY7z8","TextBox_yZu4JilU","CheckboxGroup_Zg4TE6Sy","TextBox_6Qui50QM","TextBox_dikybASu"]},"Summary_eFmqGlfG":{"text":"Summary","subText":"Please review the information you have entered:","componentKey":"Summary_eFmqGlfG","componentType":"Summary"},"ESignAction_WDkwveBt":{"componentKey":"ESignAction_WDkwveBt","componentType":"ESignAction","primaryRecipientId":"1","templateInfoMap":{"3d41614e-ae79-40f6-bbf0-c2748f5800ac":{"templateId":"3d41614e-ae79-40f6-bbf0-c2748f5800ac","lastModified":"2024-10-09T18:38:30.4470000Z","name":"Web Form Copy - Web Form Example Template","owner":{"userName":"Inbar WebForms","userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","email":"inbar27@mailinator.com"}}},"documentInfoMap":{"Document_JfypoAaN":{"name":"World_Wide_Web_Form","documentId":"1","order":"1"}},"recipientInfoMap":{"1":{"nameComponentKey":"TextBox_CnHrDIYv","emailComponentKey":"Email_x5VWUgAp","recipientId":"1","recipientType":"signer","roleName":"signer","routingOrder":"1","nameFromTemplate":"","emailFromTemplate":""}},"tabInfoMap":{"81db13d8-66be-4aab-aa59-b9d974bb4627":{"componentKey":"TextBox_5ulrY7z8","tabId":"81db13d8-66be-4aab-aa59-b9d974bb4627","recipientId":"1","tabLabel":"FullName","tabType":"text","locked":"false"},"e57b222b-55fa-4fc7-a9c7-f40f2b5d6dbd":{"componentKey":"TextBox_yZu4JilU","tabId":"e57b222b-55fa-4fc7-a9c7-f40f2b5d6dbd","recipientId":"1","tabLabel":"PhoneNumber","tabType":"text","locked":"false"},"938f353b-5694-4d12-9e88-e8f9e7ccc0f1":{"componentKey":"TextBox_6Qui50QM","tabId":"938f353b-5694-4d12-9e88-e8f9e7ccc0f1","recipientId":"1","tabLabel":"Company","tabType":"text","locked":"false"},"56685845-2115-45a6-8b88-915e3c2f91ff":{"componentKey":"TextBox_dikybASu","tabId":"56685845-2115-45a6-8b88-915e3c2f91ff","recipientId":"1","tabLabel":"JobTitle","tabType":"text","locked":"false"},"256a3887-d854-46f8-9ee5-ae0b3f5866b0":{"componentKey":"CheckboxGroup_Zg4TE6Sy","tabId":"256a3887-d854-46f8-9ee5-ae0b3f5866b0","recipientId":"1","tabLabel":"Yes","tabType":"checkbox","name":"Yes","selected":"false","locked":"false"}},"requireRemoteSigning":false,"enableDocumentFieldEditing":true},"Thankyou_kyyG6Evn":{"text":"Thank you","subText":"We've received your form.","showConfirmationButton":false,"confirmationButtonText":"Done","confirmationButtonUrl":"","componentKey":"Thankyou_kyyG6Evn","componentType":"Thankyou"},"TextBox_CnHrDIYv":{"componentKey":"TextBox_CnHrDIYv","componentType":"TextBox","componentName":"signer_name","label":"signer name","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"Email_x5VWUgAp":{"componentKey":"Email_x5VWUgAp","componentType":"Email","componentName":"signer_email","label":"signer email","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"TextBox_5ulrY7z8":{"componentKey":"TextBox_5ulrY7z8","componentType":"TextBox","componentName":"FullName","label":"FullName","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"TextBox_yZu4JilU":{"componentKey":"TextBox_yZu4JilU","componentType":"TextBox","componentName":"PhoneNumber","label":"PhoneNumber","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"CheckboxGroup_Zg4TE6Sy":{"componentKey":"CheckboxGroup_Zg4TE6Sy","componentType":"CheckboxGroup","componentName":"Yes","label":"","description":"","options":[{"optionKey":"Zd9v2gRs","value":"Yes","label":"Yes","selected":false}]},"TextBox_6Qui50QM":{"componentKey":"TextBox_6Qui50QM","componentType":"TextBox","componentName":"Company","label":"Company","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"TextBox_dikybASu":{"componentKey":"TextBox_dikybASu","componentType":"TextBox","componentName":"JobTitle","label":"JobTitle","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000}},"isStandalone":false,"templates":[{"originalTemplateId":"90e1562e-9f65-486d-9a5f-2f6db09d1878","clonedTemplateId":"3d41614e-ae79-40f6-bbf0-c2748f5800ac","importedDateTime":"2024-10-09T18:38:31.275Z","recipientIds":["1"]}]},"formLocale":"en","versionId":1,"eSignTemplates":[{"templateId":"3d41614e-ae79-40f6-bbf0-c2748f5800ac","uri":"/templates/3d41614e-ae79-40f6-bbf0-c2748f5800ac","name":"Web Form Copy - Web Form Example Template","shared":"false","passwordProtected":"false","description":"Example template created via the eSignature API","created":"2024-10-09T18:38:30.0100000Z","lastModified":"2024-10-09T18:39:30.8100000Z","lastModifiedBy":{"userName":"Inbar WebForms","userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","email":"inbar27@mailinator.com","uri":"/users/06958f21-168b-44aa-b530-8abc0cb6cf18"},"lastUsed":"2024-10-09T18:38:30.4470000Z","owner":{"userName":"Inbar WebForms","userId":"06958f21-168b-44aa-b530-8abc0cb6cf18","email":"inbar27@mailinator.com"},"pageCount":"1","folderId":"e4e93cf6-a3d9-4e0c-88f6-bd9bbfc73fc5","folderName":"Deleted Items","folderIds":["e4e93cf6-a3d9-4e0c-88f6-bd9bbfc73fc5"],"autoMatch":"true","autoMatchSpecifiedByUser":"false","documents":[{"documentId":"1","uri":"/envelopes/3d41614e-ae79-40f6-bbf0-c2748f5800ac/documents/1","name":"World_Wide_Web_Form","order":"1","pages":"1","documentBase64":"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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","messageLock":"false","recipientsLock":"false","brandLock":"false","customFields":{"textCustomFields":[{"fieldId":"11126003281","name":"ModelNamespace","show":"false","required":"false","value":"docusign.forms._0ef36a2b_ab23_47f2_9b96_a406e16044a5._39410656_f165_41e3_b1a4_bfd53fbb0e32"},{"fieldId":"11126003282","name":"ModelVersion","show":"false","required":"false","value":"1"},{"fieldId":"11126003283","name":"ModelAccount","show":"false","required":"false","value":"0ef36a2b-ab23-47f2-9b96-a406e16044a5"}],"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":"0d3171e2-42d0-4034-a929-1897b6078c25","tabType":"signhere"}],"dateSignedTabs":[{"name":"DateSigned","value":"","tabLabel":"DateSigned","localePolicy":{},"documentId":"1","recipientId":"1","pageNumber":"1","xPosition":"389","yPosition":"386","anchorString":"/Date/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"5bfda557-b893-4097-af42-b38a130638cf","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":"125","yPosition":"224","width":"0","height":"0","anchorString":"/FullName/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"81db13d8-66be-4aab-aa59-b9d974bb4627","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":"147","yPosition":"251","width":"0","height":"0","anchorString":"/PhoneNumber/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"e57b222b-55fa-4fc7-a9c7-f40f2b5d6dbd","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":"162","yPosition":"305","width":"0","height":"0","anchorString":"/Company/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"938f353b-5694-4d12-9e88-e8f9e7ccc0f1","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":"117","yPosition":"332","width":"0","height":"0","anchorString":"/Title/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"56685845-2115-45a6-8b88-915e3c2f91ff","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":"217","yPosition":"278","width":"0","height":"0","anchorString":"/SMS/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"256a3887-d854-46f8-9ee5-ae0b3f5866b0","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","allowComments":"true","disableResponsiveDocument":"true","anySigner":null,"envelopeLocation":"current_site"}]} \ No newline at end of file +{"id":"39410656-f165-41e3-b1a4-bfd53fbb0e32","accountId":"0ef36a2b-xxxx-xxxx-xxxx-a406e16044a5","isPublished":true,"isEnabled":true,"hasDraftChanges":false,"formState":"active","formProperties":{"name":"Web Form Example Template","isPrivateAccess":false},"formMetadata":{"source":"templates","createdDateTime":"2024-10-09T18:38:29.598Z","publishedSlug":"cb0d0f6a9e3772eb4dcbe24de6ba331d","owner":{"userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","userName":"Inbar WebForms"},"lastModifiedDateTime":"2024-10-09T18:39:31.391Z","lastModifiedBy":{"userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","userName":"Inbar WebForms"},"publishedComponentNames":{"signer_name":"TextBox","signer_email":"Email","FullName":"TextBox","PhoneNumber":"TextBox","Yes":"CheckboxGroup","Company":"TextBox","JobTitle":"TextBox"},"admModelNamespace":"docusign.forms._0ef36a2b_ab23_47f2_9b96_a406e16044a5._39410656_f165_41e3_b1a4_bfd53fbb0e32","formContentModifiedBy":{"userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","userName":"Inbar WebForms"},"formContentModifiedDateTime":"2024-10-09T18:39:18.097Z","admModelVersion":"1.0.0","type":"hasEsignTemplate","formPropertiesModifiedBy":{"userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","userName":"Inbar WebForms"},"formPropertiesModifiedDateTime":"2024-10-09T18:39:07.573Z","sender":{"userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","userName":"Inbar WebForms"},"lastSenderConsentDateTime":"2024-10-09T18:39:23.162Z","lastPublishedBy":{"userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","userName":"Inbar WebForms"},"lastPublishedDateTime":"2024-10-09T18:39:31.391Z","lastEnabledBy":{"userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","userName":"Inbar WebForms"},"lastEnabledDateTime":"2024-10-09T18:39:31.391Z"},"formContent":{"components":{"Root_Of_Journey":{"componentKey":"Root_Of_Journey","componentType":"Root","componentName":"Root_Of_Journey","componentRules":{},"text":"","children":["Welcome_mLgvoXc_","Step_8CmDcmdk","Summary_eFmqGlfG","ESignAction_WDkwveBt","Thankyou_kyyG6Evn"]},"Welcome_mLgvoXc_":{"text":"Welcome","subText":"Part time work application","startButtonText":"Start","componentKey":"Welcome_mLgvoXc_","componentType":"Welcome"},"Step_8CmDcmdk":{"componentKey":"Step_8CmDcmdk","componentType":"Step","componentName":"Step_8CmDcmdk","text":"Untitled page","children":["TextBox_CnHrDIYv","Email_x5VWUgAp","TextBox_5ulrY7z8","TextBox_yZu4JilU","CheckboxGroup_Zg4TE6Sy","TextBox_6Qui50QM","TextBox_dikybASu"]},"Summary_eFmqGlfG":{"text":"Summary","subText":"Please review the information you have entered:","componentKey":"Summary_eFmqGlfG","componentType":"Summary"},"ESignAction_WDkwveBt":{"componentKey":"ESignAction_WDkwveBt","componentType":"ESignAction","primaryRecipientId":"1","templateInfoMap":{"3d41614e-ae79-40f6-bbf0-c2748f5800ac":{"templateId":"template-id","lastModified":"2024-10-09T18:38:30.4470000Z","name":"Web Form Copy - Web Form Example Template","owner":{"userName":"Inbar WebForms","userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","email":"example@example.com"}}},"documentInfoMap":{"Document_JfypoAaN":{"name":"World_Wide_Web_Form","documentId":"1","order":"1"}},"recipientInfoMap":{"1":{"nameComponentKey":"TextBox_CnHrDIYv","emailComponentKey":"Email_x5VWUgAp","recipientId":"1","recipientType":"signer","roleName":"signer","routingOrder":"1","nameFromTemplate":"","emailFromTemplate":""}},"tabInfoMap":{"81db13d8-66be-4aab-aa59-b9d974bb4627":{"componentKey":"TextBox_5ulrY7z8","tabId":"81db13d8-66be-4aab-aa59-b9d974bb4627","recipientId":"1","tabLabel":"FullName","tabType":"text","locked":"false"},"e57b222b-55fa-4fc7-a9c7-f40f2b5d6dbd":{"componentKey":"TextBox_yZu4JilU","tabId":"e57b222b-55fa-4fc7-a9c7-f40f2b5d6dbd","recipientId":"1","tabLabel":"PhoneNumber","tabType":"text","locked":"false"},"938f353b-5694-4d12-9e88-e8f9e7ccc0f1":{"componentKey":"TextBox_6Qui50QM","tabId":"938f353b-5694-4d12-9e88-e8f9e7ccc0f1","recipientId":"1","tabLabel":"Company","tabType":"text","locked":"false"},"56685845-2115-45a6-8b88-915e3c2f91ff":{"componentKey":"TextBox_dikybASu","tabId":"56685845-2115-45a6-8b88-915e3c2f91ff","recipientId":"1","tabLabel":"JobTitle","tabType":"text","locked":"false"},"256a3887-d854-46f8-9ee5-ae0b3f5866b0":{"componentKey":"CheckboxGroup_Zg4TE6Sy","tabId":"256a3887-d854-46f8-9ee5-ae0b3f5866b0","recipientId":"1","tabLabel":"Yes","tabType":"checkbox","name":"Yes","selected":"false","locked":"false"}},"requireRemoteSigning":false,"enableDocumentFieldEditing":true},"Thankyou_kyyG6Evn":{"text":"Thank you","subText":"We've received your form.","showConfirmationButton":false,"confirmationButtonText":"Done","confirmationButtonUrl":"","componentKey":"Thankyou_kyyG6Evn","componentType":"Thankyou"},"TextBox_CnHrDIYv":{"componentKey":"TextBox_CnHrDIYv","componentType":"TextBox","componentName":"signer_name","label":"signer name","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"Email_x5VWUgAp":{"componentKey":"Email_x5VWUgAp","componentType":"Email","componentName":"signer_email","label":"signer email","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"TextBox_5ulrY7z8":{"componentKey":"TextBox_5ulrY7z8","componentType":"TextBox","componentName":"FullName","label":"FullName","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"TextBox_yZu4JilU":{"componentKey":"TextBox_yZu4JilU","componentType":"TextBox","componentName":"PhoneNumber","label":"PhoneNumber","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"CheckboxGroup_Zg4TE6Sy":{"componentKey":"CheckboxGroup_Zg4TE6Sy","componentType":"CheckboxGroup","componentName":"Yes","label":"","description":"","options":[{"optionKey":"Zd9v2gRs","value":"Yes","label":"Yes","selected":false}]},"TextBox_6Qui50QM":{"componentKey":"TextBox_6Qui50QM","componentType":"TextBox","componentName":"Company","label":"Company","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"TextBox_dikybASu":{"componentKey":"TextBox_dikybASu","componentType":"TextBox","componentName":"JobTitle","label":"JobTitle","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000}},"isStandalone":false,"templates":[{"originalTemplateId":"template-id","clonedTemplateId":"3d41614e-ae79-40f6-bbf0-c2748f5800ac","importedDateTime":"2024-10-09T18:38:31.275Z","recipientIds":["1"]}]},"formLocale":"en","versionId":1,"eSignTemplates":[{"templateId":"template-id","uri":"/templates/template-id","name":"Web Form Copy - Web Form Example Template","shared":"false","passwordProtected":"false","description":"Example template created via the eSignature API","created":"2024-10-09T18:38:30.0100000Z","lastModified":"2024-10-09T18:39:30.8100000Z","lastModifiedBy":{"userName":"Inbar WebForms","userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","email":"example@example.com","uri":"/users/06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18"},"lastUsed":"2024-10-09T18:38:30.4470000Z","owner":{"userName":"Inbar WebForms","userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","email":"example@example.com"},"pageCount":"1","folderId":"e4e93cf6-a3d9-4e0c-88f6-bd9bbfc73fc5","folderName":"Deleted Items","folderIds":["e4e93cf6-a3d9-4e0c-88f6-bd9bbfc73fc5"],"autoMatch":"true","autoMatchSpecifiedByUser":"false","documents":[{"documentId":"1","uri":"/envelopes/3d41614e-ae79-40f6-bbf0-c2748f5800ac/documents/1","name":"World_Wide_Web_Form","order":"1","pages":"1","documentBase64":"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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","messageLock":"false","recipientsLock":"false","brandLock":"false","customFields":{"textCustomFields":[{"fieldId":"11126003281","name":"ModelNamespace","show":"false","required":"false","value":"docusign.forms._0ef36a2b_ab23_47f2_9b96_a406e16044a5._39410656_f165_41e3_b1a4_bfd53fbb0e32"},{"fieldId":"11126003282","name":"ModelVersion","show":"false","required":"false","value":"1"},{"fieldId":"11126003283","name":"ModelAccount","show":"false","required":"false","value":"0ef36a2b-ab23-47f2-9b96-a406e16044a5"}],"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":"0d3171e2-42d0-4034-a929-1897b6078c25","tabType":"signhere"}],"dateSignedTabs":[{"name":"DateSigned","value":"","tabLabel":"DateSigned","localePolicy":{},"documentId":"1","recipientId":"1","pageNumber":"1","xPosition":"389","yPosition":"386","anchorString":"/Date/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"5bfda557-b893-4097-af42-b38a130638cf","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":"125","yPosition":"224","width":"0","height":"0","anchorString":"/FullName/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"81db13d8-66be-4aab-aa59-b9d974bb4627","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":"147","yPosition":"251","width":"0","height":"0","anchorString":"/PhoneNumber/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"e57b222b-55fa-4fc7-a9c7-f40f2b5d6dbd","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":"162","yPosition":"305","width":"0","height":"0","anchorString":"/Company/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"938f353b-5694-4d12-9e88-e8f9e7ccc0f1","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":"117","yPosition":"332","width":"0","height":"0","anchorString":"/Title/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"56685845-2115-45a6-8b88-915e3c2f91ff","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":"217","yPosition":"278","width":"0","height":"0","anchorString":"/SMS/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"256a3887-d854-46f8-9ee5-ae0b3f5866b0","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","allowComments":"true","disableResponsiveDocument":"true","anySigner":null,"envelopeLocation":"current_site"}]} \ No newline at end of file From 9b51fbf0d9f300643ed4634bf285a7cd219b6153 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Tue, 26 Nov 2024 00:55:52 +0200 Subject: [PATCH 340/363] Add PKCE authorization (#179) * add pkce auth * fixes for tests * add rubygems update to github action * move bundle install to a separate step --- .github/workflows/rubyonrails.yml | 88 ++++----- .../aeg001_create_user_controller.rb | 134 +++++++------- .../ceg001_create_clickwrap_controller.rb | 48 ++--- .../ceg005_clickwrap_responses_controller.rb | 42 ++--- ...32_pauses_signature_workflow_controller.rb | 78 ++++---- ...4_use_conditional_recipients_controller.rb | 100 +++++----- app/controllers/session_controller.rb | 172 +++++++++--------- config/initializers/omniauth.rb | 118 ++++++------ .../app/controllers/ds_common_controller.rb | 2 + quick_acg/config/initializers/omniauth.rb | 106 +++++------ quick_acg/config/routes.rb | 83 +++++---- 11 files changed, 498 insertions(+), 473 deletions(-) diff --git a/.github/workflows/rubyonrails.yml b/.github/workflows/rubyonrails.yml index 6a933ce..6dcb601 100644 --- a/.github/workflows/rubyonrails.yml +++ b/.github/workflows/rubyonrails.yml @@ -1,41 +1,47 @@ -# This workflow uses actions that are not certified by GitHub. They are -# provided by a third-party and are governed by separate terms of service, -# privacy policy, and support documentation. -# -# This workflow will install a prebuilt Ruby version, install dependencies, and -# run tests and linters. -name: "Ruby on Rails CI" -on: - push: - branches: [ "master" ] - pull_request: - branches: [ "master" ] -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Install Ruby and gems - uses: ruby/setup-ruby@v1 - with: - bundler-cache: true - ruby-version: 3.1.2 - - - name: Run linter - run: bundle exec rubocop --parallel - - - name: Run tests - run: | - gem install docusign_esign - gem install docusign_click - ruby test/run_tests.rb - env: - CLIENT_ID: ${{ secrets.CLIENT_ID }} - USER_ID: ${{ secrets.USER_ID }} - SIGNER_EMAIL: ${{ secrets.SIGNER_EMAIL }} - SIGNER_NAME: ${{ secrets.SIGNER_NAME }} - PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} - +# This workflow uses actions that are not certified by GitHub. They are +# provided by a third-party and are governed by separate terms of service, +# privacy policy, and support documentation. +# +# This workflow will install a prebuilt Ruby version, install dependencies, and +# run tests and linters. +name: "Ruby on Rails CI" +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install Ruby + uses: ruby/setup-ruby@v1 + with: + bundler-cache: false + ruby-version: 3.1.2 + + - name: Update rubygems + run: gem update --system + + - name: Install dependencies + run: bundle install + + - name: Run linter + run: bundle exec rubocop --parallel + + - name: Run tests + run: | + gem install docusign_esign + gem install docusign_click + ruby test/run_tests.rb + env: + CLIENT_ID: ${{ secrets.CLIENT_ID }} + USER_ID: ${{ secrets.USER_ID }} + SIGNER_EMAIL: ${{ secrets.SIGNER_EMAIL }} + SIGNER_NAME: ${{ secrets.SIGNER_NAME }} + PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} + diff --git a/app/controllers/admin_api/aeg001_create_user_controller.rb b/app/controllers/admin_api/aeg001_create_user_controller.rb index 9f8ceb0..76eaf0f 100644 --- a/app/controllers/admin_api/aeg001_create_user_controller.rb +++ b/app/controllers/admin_api/aeg001_create_user_controller.rb @@ -1,67 +1,67 @@ -class AdminApi::Aeg001CreateUserController < EgController - include ApiCreator - before_action -> { check_auth('Admin') } - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1, 'Admin') } - - def create - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'], - organization_id: session['organization_id'] - } - #ds-snippet-start:Admin1Step5 - user_data = { - user_name: param_gsub(params['user_name']), - first_name: param_gsub(params['first_name']), - last_name: param_gsub(params['last_name']), - email: param_gsub(params['email']), - auto_activate_memberships: true, - accounts: [ - { - id: args[:account_id], - permission_profile: { - id: request['permission_profile_id'] - }, - groups: [ - { - id: request['group_id'] - } - ] - } - ] - } - #ds-snippet-end:Admin1Step5 - - begin - results = AdminApi::Eg001CreateUserService.new(args, user_data).worker - - @title = @example['ExampleName'] - @message = @example['ResultsPageText'] - @json = results.to_json.to_json - render 'ds_common/example_done' - rescue DocuSign_Admin::ApiError => e - handle_error(e) - end - end - - def get - super - session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? - args = { - account_id: session['ds_account_id'], - base_path: session['ds_base_path'], - access_token: session['ds_access_token'] - } - - #ds-snippet-start:Admin1Step3 - accounts_api = create_account_api(args) - @permission_profiles = accounts_api.list_permissions(args[:account_id]).permission_profiles - #ds-snippet-end:Admin1Step3 - - #ds-snippet-start:Admin1Step4 - groups_api = create_group_api(args) - @groups = groups_api.list_groups(args[:account_id]).groups - #ds-snippet-end:Admin1Step4 - end -end +class AdminApi::Aeg001CreateUserController < EgController + include ApiCreator + before_action -> { check_auth('Admin') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1, 'Admin') } + + def create + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + organization_id: session['organization_id'] + } + #ds-snippet-start:Admin1Step5 + user_data = { + user_name: param_gsub(params['user_name']), + first_name: param_gsub(params['first_name']), + last_name: param_gsub(params['last_name']), + email: param_gsub(params['email']), + auto_activate_memberships: true, + accounts: [ + { + id: args[:account_id], + permission_profile: { + id: param_gsub(params['permission_profile_id']) + }, + groups: [ + { + id: param_gsub(params['group_id']) + } + ] + } + ] + } + #ds-snippet-end:Admin1Step5 + + begin + results = AdminApi::Eg001CreateUserService.new(args, user_data).worker + + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json + render 'ds_common/example_done' + rescue DocuSign_Admin::ApiError => e + handle_error(e) + end + end + + def get + super + session[:organization_id] = AdminApi::GetDataService.new(session).get_organization_id if session[:organization_id].nil? + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'] + } + + #ds-snippet-start:Admin1Step3 + accounts_api = create_account_api(args) + @permission_profiles = accounts_api.list_permissions(args[:account_id]).permission_profiles + #ds-snippet-end:Admin1Step3 + + #ds-snippet-start:Admin1Step4 + groups_api = create_group_api(args) + @groups = groups_api.list_groups(args[:account_id]).groups + #ds-snippet-end:Admin1Step4 + end +end diff --git a/app/controllers/clickwrap/ceg001_create_clickwrap_controller.rb b/app/controllers/clickwrap/ceg001_create_clickwrap_controller.rb index cc3ea4d..83b3ce9 100644 --- a/app/controllers/clickwrap/ceg001_create_clickwrap_controller.rb +++ b/app/controllers/clickwrap/ceg001_create_clickwrap_controller.rb @@ -1,24 +1,24 @@ -class Clickwrap::Ceg001CreateClickwrapController < EgController - before_action -> { check_auth('Click') } - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1, 'Click') } - - def create - args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - doc_pdf: File.join('data', Rails.configuration.doc_terms_pdf), - clickwrap_name: request[:clickwrapName] - } - - results = Clickwrap::Eg001CreateClickwrapService.new(args).worker - - session[:clickwrap_id] = results.clickwrap_id - session[:clickwrap_name] = results.clickwrap_name - - @title = @example['ExampleName'] - @message = format_string(@example['ResultsPageText'], results.clickwrap_name) - @json = results.to_json.to_json - render 'ds_common/example_done' - end -end +class Clickwrap::Ceg001CreateClickwrapController < EgController + before_action -> { check_auth('Click') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1, 'Click') } + + def create + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + doc_pdf: File.join('data', Rails.configuration.doc_terms_pdf), + clickwrap_name: param_gsub(params[:clickwrapName]) + } + + results = Clickwrap::Eg001CreateClickwrapService.new(args).worker + + session[:clickwrap_id] = results.clickwrap_id + session[:clickwrap_name] = results.clickwrap_name + + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results.clickwrap_name) + @json = results.to_json.to_json + render 'ds_common/example_done' + end +end diff --git a/app/controllers/clickwrap/ceg005_clickwrap_responses_controller.rb b/app/controllers/clickwrap/ceg005_clickwrap_responses_controller.rb index 6de4326..cf2f3a9 100644 --- a/app/controllers/clickwrap/ceg005_clickwrap_responses_controller.rb +++ b/app/controllers/clickwrap/ceg005_clickwrap_responses_controller.rb @@ -1,21 +1,21 @@ -class Clickwrap::Ceg005ClickwrapResponsesController < EgController - before_action -> { check_auth('Click') } - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 5, 'Click') } - - def create - args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - clickwrap_id: session[:clickwrap_id], - client_user_id: request[:client_user_id] - } - - results = Clickwrap::Eg005ClickwrapResponsesService.new(args).worker - - @title = @example['ExampleName'] - @message = @example['ResultsPageText'] - @json = results.to_json.to_json - render 'ds_common/example_done' - end -end +class Clickwrap::Ceg005ClickwrapResponsesController < EgController + before_action -> { check_auth('Click') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 5, 'Click') } + + def create + args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + clickwrap_id: session[:clickwrap_id], + client_user_id: param_gsub(params[:client_user_id]) + } + + results = Clickwrap::Eg005ClickwrapResponsesService.new(args).worker + + @title = @example['ExampleName'] + @message = @example['ResultsPageText'] + @json = results.to_json.to_json + render 'ds_common/example_done' + end +end diff --git a/app/controllers/e_sign/eeg032_pauses_signature_workflow_controller.rb b/app/controllers/e_sign/eeg032_pauses_signature_workflow_controller.rb index d2d229b..cf7e25c 100644 --- a/app/controllers/e_sign/eeg032_pauses_signature_workflow_controller.rb +++ b/app/controllers/e_sign/eeg032_pauses_signature_workflow_controller.rb @@ -1,39 +1,39 @@ -# frozen_string_literal: true - -class ESign::Eeg032PausesSignatureWorkflowController < EgController - before_action -> { check_auth('eSignature') } - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 32, 'eSignature') } - - def create - signers = { - signerEmail1: request['signerEmail1'], - signerName1: request['signerName1'], - signerEmail2: request['signerEmail2'], - signerName2: request['signerName2'] - } - args = { - accountId: session['ds_account_id'], - basePath: session['ds_base_path'], - accessToken: session['ds_access_token'], - status: 'sent' - } - - results = ESign::Eg032PausesSignatureWorkflowService.new(args, signers).worker - - @envelop_id = results.to_hash[:envelopeId].to_s - session[:envelope_id] = @envelop_id - - render 'e_sign/eeg032_pauses_signature_workflow/return' - end - - def get - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) - if enableCFR == 'enabled' - session[:status_cfr] = 'enabled' - @title = 'Not CFR Part 11 compatible' - @error_information = @manifest['SupportingTexts']['CFRError'] - render 'ds_common/error' - end - super - end -end +# frozen_string_literal: true + +class ESign::Eeg032PausesSignatureWorkflowController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 32, 'eSignature') } + + def create + signers = { + signerEmail1: param_gsub(params['signerEmail1']), + signerName1: param_gsub(params['signerName1']), + signerEmail2: param_gsub(params['signerEmail2']), + signerName2: param_gsub(params['signerName2']) + } + args = { + accountId: session['ds_account_id'], + basePath: session['ds_base_path'], + accessToken: session['ds_access_token'], + status: 'sent' + } + + results = ESign::Eg032PausesSignatureWorkflowService.new(args, signers).worker + + @envelop_id = results.to_hash[:envelopeId].to_s + session[:envelope_id] = @envelop_id + + render 'e_sign/eeg032_pauses_signature_workflow/return' + end + + def get + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR == 'enabled' + session[:status_cfr] = 'enabled' + @title = 'Not CFR Part 11 compatible' + @error_information = @manifest['SupportingTexts']['CFRError'] + render 'ds_common/error' + end + super + end +end diff --git a/app/controllers/e_sign/eeg034_use_conditional_recipients_controller.rb b/app/controllers/e_sign/eeg034_use_conditional_recipients_controller.rb index 0ab2001..ab7e5a2 100644 --- a/app/controllers/e_sign/eeg034_use_conditional_recipients_controller.rb +++ b/app/controllers/e_sign/eeg034_use_conditional_recipients_controller.rb @@ -1,50 +1,50 @@ -# frozen_string_literal: true - -class ESign::Eeg034UseConditionalRecipientsController < EgController - before_action -> { check_auth('eSignature') } - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 34, 'eSignature') } - - def create - signers = { - signerEmail1: request['signerEmail1'], - signerName1: request['signerName1'], - - signerEmailNotChecked: request['signerEmailNotChecked'], - signerNameNotChecked: request['signerNameNotChecked'], - - signerEmailChecked: request['signerEmailChecked'], - signerNameChecked: request['signerNameChecked'] - } - - args = { - accountId: session['ds_account_id'], - basePath: session['ds_base_path'], - accessToken: session['ds_access_token'] - } - - results = ESign::Eg034UseConditionalRecipientsService.new(args, signers).worker - @envelop_id = results.to_hash[:envelopeId].to_s - render 'e_sign/eeg034_use_conditional_recipients/return' - rescue DocuSign_eSign::ApiError => e - error = JSON.parse e.response_body - @error_code = error['errorCode'] - if error['errorCode']['WORKFLOW_UPDATE_RECIPIENTROUTING_NOT_ALLOWED'] - @error_message = @example['CustomErrorTexts'][0]['ErrorMessage'] - @error_information = @example['CustomErrorTexts'][0]['ErrorMessage'] - else - @error_message = error['message'] - end - render 'ds_common/error' - end - - def get - enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) - if enableCFR == 'enabled' - session[:status_cfr] = 'enabled' - @title = 'Not CFR Part 11 compatible' - @error_information = @manifest['SupportingTexts']['CFRError'] - render 'ds_common/error' - end - super - end -end +# frozen_string_literal: true + +class ESign::Eeg034UseConditionalRecipientsController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 34, 'eSignature') } + + def create + signers = { + signerEmail1: param_gsub(params['signerEmail1']), + signerName1: param_gsub(params['signerName1']), + + signerEmailNotChecked: param_gsub(params['signerEmailNotChecked']), + signerNameNotChecked: param_gsub(params['signerNameNotChecked']), + + signerEmailChecked: param_gsub(params['signerEmailChecked']), + signerNameChecked: param_gsub(params['signerNameChecked']) + } + + args = { + accountId: session['ds_account_id'], + basePath: session['ds_base_path'], + accessToken: session['ds_access_token'] + } + + results = ESign::Eg034UseConditionalRecipientsService.new(args, signers).worker + @envelop_id = results.to_hash[:envelopeId].to_s + render 'e_sign/eeg034_use_conditional_recipients/return' + rescue DocuSign_eSign::ApiError => e + error = JSON.parse e.response_body + @error_code = error['errorCode'] + if error['errorCode']['WORKFLOW_UPDATE_RECIPIENTROUTING_NOT_ALLOWED'] + @error_message = @example['CustomErrorTexts'][0]['ErrorMessage'] + @error_information = @example['CustomErrorTexts'][0]['ErrorMessage'] + else + @error_message = error['message'] + end + render 'ds_common/error' + end + + def get + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR == 'enabled' + session[:status_cfr] = 'enabled' + @title = 'Not CFR Part 11 compatible' + @error_information = @manifest['SupportingTexts']['CFRError'] + render 'ds_common/error' + end + super + end +end diff --git a/app/controllers/session_controller.rb b/app/controllers/session_controller.rb index e9791cd..39d51bc 100644 --- a/app/controllers/session_controller.rb +++ b/app/controllers/session_controller.rb @@ -1,83 +1,89 @@ -# frozen_string_literal: true - -class SessionController < ApplicationController - # GET /auth/:provider/callback - def create - redirect_url = if session[:eg] - "/#{session[:eg]}" - else - root_path - end - - # reset the session - internal_destroy - - Rails.logger.debug "\n==> Docusign callback Authentication response:\n#{auth_hash.to_yaml}\n" - Rails.logger.info "==> Login: New token for admin user which will expire at: #{Time.at(auth_hash.credentials['expires_at'])}" - store_auth_hash_from_docusign_callback - redirect_to redirect_url - end - - # GET /ds/logout - def destroy - internal_destroy - redirect_to root_path - end - - # def switch_api - # internal_destroy - # end - - # GET /auth/failure - def omniauth_failure - error_msg = "OmniAuth authentication failure message: #{params[:message]} for strategy: #{params[:strategy]} and HTTP_REFERER: #{params[:origin]}" - Rails.logger.warn "\n==> #{error_msg}" - flash[:notice] = error_msg - redirect_to root_path - end - - def show - Rails.logger.debug "==> Session:\n#{session.to_h.to_yaml}" - render json: session.to_json - end - - protected - - def internal_destroy - session.delete :ds_expires_at - session.delete :ds_user_name - session.delete :ds_access_token - session.delete :ds_account_id - session.delete :ds_account_name - session.delete :ds_base_path - session.delete 'omniauth.state' - session.delete 'omniauth.params' - session.delete 'omniauth.origin' - session.delete :envelope_id - session.delete :envelope_documents - session.delete :template_id - session.delete :eg - session.delete :manifest - session.delete :status_cfr - session.delete :is_workflow_published - end - - def store_auth_hash_from_docusign_callback - session[:ds_expires_at] = auth_hash.credentials['expires_at'] - session[:ds_user_name] = auth_hash.info.name - session[:ds_access_token] = auth_hash.credentials.token - session[:ds_account_id] = auth_hash.extra.account_id - session[:ds_account_name] = auth_hash.extra.account_name - session[:ds_base_path] = auth_hash.extra.base_uri - end - - # returns hash with key structure of: - # - provider - # - uid - # - info: [name, email, first_name, last_name] - # - credentials: [token, refresh_token, expires_at, expires] - # - extra: [sub, account_id, account_name, base_uri] - def auth_hash - @auth_hash ||= request.env['omniauth.auth'] - end -end +# frozen_string_literal: true + +class SessionController < ApplicationController + # GET /auth/:provider/callback + def create + redirect_url = if session[:eg] + "/#{session[:eg]}" + else + root_path + end + + # reset the session + internal_destroy + + Rails.logger.debug "\n==> Docusign callback Authentication response:\n#{auth_hash.to_yaml}\n" + Rails.logger.info "==> Login: New token for admin user which will expire at: #{Time.at(auth_hash.credentials['expires_at'])}" + store_auth_hash_from_docusign_callback + redirect_to redirect_url + end + + # GET /ds/logout + def destroy + internal_destroy + redirect_to root_path + end + + # def switch_api + # internal_destroy + # end + + # GET /auth/failure + def omniauth_failure + unless session[:pkce_failed] + Rails.logger.warn "PKCE Auth failed \n" + session[:pkce_failed] = true + return redirect_to '/auth/docusign' + end + + error_msg = "OmniAuth authentication failure message: #{params[:message]} for strategy: #{params[:strategy]} and HTTP_REFERER: #{params[:origin]}" + Rails.logger.warn "\n==> #{error_msg}" + flash[:notice] = error_msg + redirect_to root_path + end + + def show + Rails.logger.debug "==> Session:\n#{session.to_h.to_yaml}" + render json: session.to_json + end + + protected + + def internal_destroy + session.delete :ds_expires_at + session.delete :ds_user_name + session.delete :ds_access_token + session.delete :ds_account_id + session.delete :ds_account_name + session.delete :ds_base_path + session.delete 'omniauth.state' + session.delete 'omniauth.params' + session.delete 'omniauth.origin' + session.delete :envelope_id + session.delete :envelope_documents + session.delete :template_id + session.delete :eg + session.delete :manifest + session.delete :status_cfr + session.delete :is_workflow_published + end + + def store_auth_hash_from_docusign_callback + session[:ds_expires_at] = auth_hash.credentials['expires_at'] + session[:ds_user_name] = auth_hash.info.name + session[:ds_access_token] = auth_hash.credentials.token + session[:ds_account_id] = auth_hash.extra.account_id + session[:ds_account_name] = auth_hash.extra.account_name + session[:ds_base_path] = auth_hash.extra.base_uri + end + + # returns hash with key structure of: + # - provider + # - uid + # - info: [name, email, first_name, last_name] + # - credentials: [token, refresh_token, expires_at, expires] + # - extra: [sub, account_id, account_name, base_uri] + def auth_hash + @auth_hash ||= request.env['omniauth.auth'] + end +end diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 665d8b3..7b75d1d 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -1,57 +1,61 @@ -# frozen_string_literal: true - -require 'docusign' - -# Defaults to STDOUT: https://github.com/omniauth/omniauth#logging -# Logs entries like: -# (docusign) Setup endpoint detected, running now. -# (docusign) Request phase initiated. -# (docusign) Callback phase initiated. -OmniAuth.config.logger = Rails.logger - -# https://github.com/omniauth/omniauth/wiki/FAQ#omniauthfailureendpoint-does-not-redirect-in-development-mode -# otherwise a callback exception like the following will not get caught: -# OmniAuth::Strategies::OAuth2::CallbackError (access_denied) -# GET "/auth/docusign/callback?error=access_denied&error_message=The%20user%20did%20not%20consent%20to%20connecting%20the%20application.&state= -# OmniAuth.config.failure_raise_out_environments = [] # defaults to: ['development'] - -OmniAuth.config.allowed_request_methods = %i[post get] - -config = Rails.application.config -config.middleware.use OmniAuth::Builder do - # OAuth2 login request configuration - # OAuth2 login response callback message configuration is in OmniAuth::Strategies::Docusign in lib/docusign.rb - provider :docusign, config.integration_key, config.integration_secret, setup: lambda { |env| - strategy = env['omniauth.strategy'] - - # params = strategy.request.params - # examples_API = params['examples_API'] - # strategy.request.params.delete('examples_API') - - strategy.options[:client_options].site = config.app_url - strategy.options[:prompt] = 'login' - strategy.options[:oauth_base_uri] = config.authorization_server - strategy.options[:target_account_id] = config.target_account_id - strategy.options[:allow_silent_authentication] = config.allow_silent_authentication - strategy.options[:client_options].authorize_url = "#{strategy.options[:oauth_base_uri]}/oauth/auth" - strategy.options[:client_options].user_info_url = "#{strategy.options[:oauth_base_uri]}/oauth/userinfo" - strategy.options[:client_options].token_url = "#{strategy.options[:oauth_base_uri]}/oauth/token" - strategy.options[:authorize_params].prompt = strategy.options.prompt unless strategy.options[:allow_silent_authentication] - session = strategy.session - - case session[:api] - when 'eSignature' - strategy.options[:authorize_params].scope = 'signature' - when 'Rooms' - strategy.options[:authorize_params].scope = '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' - when 'Click' - strategy.options[:authorize_params].scope = 'signature click.manage click.send' - when 'Admin' - strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write 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_write organization_sub_account_read' - when 'WebForms' - strategy.options[:authorize_params].scope = 'signature webforms_read webforms_instance_read webforms_instance_write' - when 'Maestro' - strategy.options[:authorize_params].scope = 'signature aow_manage' - end - } -end +# frozen_string_literal: true + +require 'docusign' + +# Defaults to STDOUT: https://github.com/omniauth/omniauth#logging +# Logs entries like: +# (docusign) Setup endpoint detected, running now. +# (docusign) Request phase initiated. +# (docusign) Callback phase initiated. +OmniAuth.config.logger = Rails.logger + +# https://github.com/omniauth/omniauth/wiki/FAQ#omniauthfailureendpoint-does-not-redirect-in-development-mode +# otherwise a callback exception like the following will not get caught: +# OmniAuth::Strategies::OAuth2::CallbackError (access_denied) +# GET "/auth/docusign/callback?error=access_denied&error_message=The%20user%20did%20not%20consent%20to%20connecting%20the%20application.&state= +# OmniAuth.config.failure_raise_out_environments = [] # defaults to: ['development'] + +OmniAuth.config.allowed_request_methods = %i[post get] + +config = Rails.application.config +config.middleware.use OmniAuth::Builder do + # OAuth2 login request configuration + # OAuth2 login response callback message configuration is in OmniAuth::Strategies::Docusign in lib/docusign.rb + provider :docusign, config.integration_key, config.integration_secret, setup: lambda { |env| + strategy = env['omniauth.strategy'] + + # params = strategy.request.params + # examples_API = params['examples_API'] + # strategy.request.params.delete('examples_API') + + strategy.options[:client_options].site = config.app_url + strategy.options[:prompt] = 'login' + strategy.options[:oauth_base_uri] = config.authorization_server + strategy.options[:target_account_id] = config.target_account_id + strategy.options[:allow_silent_authentication] = config.allow_silent_authentication + strategy.options[:client_options].authorize_url = "#{strategy.options[:oauth_base_uri]}/oauth/auth" + strategy.options[:client_options].user_info_url = "#{strategy.options[:oauth_base_uri]}/oauth/userinfo" + strategy.options[:client_options].token_url = "#{strategy.options[:oauth_base_uri]}/oauth/token" + strategy.options[:authorize_params].prompt = strategy.options.prompt unless strategy.options[:allow_silent_authentication] + session = strategy.session + + unless session[:pkce_failed] + strategy.options[:pkce] = true + end + + case session[:api] + when 'eSignature' + strategy.options[:authorize_params].scope = 'signature' + when 'Rooms' + strategy.options[:authorize_params].scope = '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' + when 'Click' + strategy.options[:authorize_params].scope = 'signature click.manage click.send' + when 'Admin' + strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write 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_write organization_sub_account_read' + when 'WebForms' + strategy.options[:authorize_params].scope = 'signature webforms_read webforms_instance_read webforms_instance_write' + when 'Maestro' + strategy.options[:authorize_params].scope = 'signature aow_manage' + end + } +end diff --git a/quick_acg/app/controllers/ds_common_controller.rb b/quick_acg/app/controllers/ds_common_controller.rb index d5f40da..16e63b1 100644 --- a/quick_acg/app/controllers/ds_common_controller.rb +++ b/quick_acg/app/controllers/ds_common_controller.rb @@ -12,6 +12,8 @@ def handle_redirects session[:quickstarted] = true redirect_to '/auth/docusign' else + return redirect_to '/auth/docusign' if session[:ds_access_token].nil? || session[:ds_base_path].nil? + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) if enableCFR == 'enabled' session[:status_cfr] = 'enabled' diff --git a/quick_acg/config/initializers/omniauth.rb b/quick_acg/config/initializers/omniauth.rb index ad1e5dd..3e72d08 100644 --- a/quick_acg/config/initializers/omniauth.rb +++ b/quick_acg/config/initializers/omniauth.rb @@ -1,51 +1,55 @@ -# frozen_string_literal: true - -require 'docusign' - -# Defaults to STDOUT: https://github.com/omniauth/omniauth#logging -# Logs entries like: -# (docusign) Setup endpoint detected, running now. -# (docusign) Request phase initiated. -# (docusign) Callback phase initiated. -OmniAuth.config.logger = Rails.logger - -# https://github.com/omniauth/omniauth/wiki/FAQ#omniauthfailureendpoint-does-not-redirect-in-development-mode -# otherwise a callback exception like the following will not get caught: -# OmniAuth::Strategies::OAuth2::CallbackError (access_denied) -# GET "/auth/docusign/callback?error=access_denied&error_message=The%20user%20did%20not%20consent%20to%20connecting%20the%20application.&state= -# OmniAuth.config.failure_raise_out_environments = [] # defaults to: ['development'] - -OmniAuth.config.allowed_request_methods = %i[post get] - -config = Rails.application.config -config.middleware.use OmniAuth::Builder do - # OAuth2 login request configuration - # OAuth2 login response callback message configuration is in OmniAuth::Strategies::Docusign in lib/docusign.rb - provider :docusign, config.integration_key, config.integration_secret, setup: lambda { |env| - strategy = env['omniauth.strategy'] - - # params = strategy.request.params - # examples_API = params['examples_API'] - # strategy.request.params.delete('examples_API') - - strategy.options[:client_options].site = config.app_url - strategy.options[:prompt] = 'login' - strategy.options[:oauth_base_uri] = config.authorization_server - strategy.options[:target_account_id] = config.target_account_id - strategy.options[:allow_silent_authentication] = config.allow_silent_authentication - strategy.options[:client_options].authorize_url = "#{strategy.options[:oauth_base_uri]}/oauth/auth" - strategy.options[:client_options].user_info_url = "#{strategy.options[:oauth_base_uri]}/oauth/userinfo" - strategy.options[:client_options].token_url = "#{strategy.options[:oauth_base_uri]}/oauth/token" - strategy.options[:authorize_params].prompt = strategy.options.prompt unless strategy.options[:allow_silent_authentication] - session = strategy.session - - case session[:api] - when 'Rooms' - strategy.options[:authorize_params].scope = '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' - when 'Click' - strategy.options[:authorize_params].scope = 'signature click.manage click.send' - when 'Admin' - strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read' - end - } -end +# frozen_string_literal: true + +require 'docusign' + +# Defaults to STDOUT: https://github.com/omniauth/omniauth#logging +# Logs entries like: +# (docusign) Setup endpoint detected, running now. +# (docusign) Request phase initiated. +# (docusign) Callback phase initiated. +OmniAuth.config.logger = Rails.logger + +# https://github.com/omniauth/omniauth/wiki/FAQ#omniauthfailureendpoint-does-not-redirect-in-development-mode +# otherwise a callback exception like the following will not get caught: +# OmniAuth::Strategies::OAuth2::CallbackError (access_denied) +# GET "/auth/docusign/callback?error=access_denied&error_message=The%20user%20did%20not%20consent%20to%20connecting%20the%20application.&state= +OmniAuth.config.failure_raise_out_environments = [] # defaults to: ['development'] + +OmniAuth.config.allowed_request_methods = %i[post get] + +config = Rails.application.config +config.middleware.use OmniAuth::Builder do + # OAuth2 login request configuration + # OAuth2 login response callback message configuration is in OmniAuth::Strategies::Docusign in lib/docusign.rb + provider :docusign, config.integration_key, config.integration_secret, setup: lambda { |env| + strategy = env['omniauth.strategy'] + + # params = strategy.request.params + # examples_API = params['examples_API'] + # strategy.request.params.delete('examples_API') + + strategy.options[:client_options].site = config.app_url + strategy.options[:prompt] = 'login' + strategy.options[:oauth_base_uri] = config.authorization_server + strategy.options[:target_account_id] = config.target_account_id + strategy.options[:allow_silent_authentication] = config.allow_silent_authentication + strategy.options[:client_options].authorize_url = "#{strategy.options[:oauth_base_uri]}/oauth/auth" + strategy.options[:client_options].user_info_url = "#{strategy.options[:oauth_base_uri]}/oauth/userinfo" + strategy.options[:client_options].token_url = "#{strategy.options[:oauth_base_uri]}/oauth/token" + strategy.options[:authorize_params].prompt = strategy.options.prompt unless strategy.options[:allow_silent_authentication] + session = strategy.session + + unless session[:pkce_failed] + strategy.options[:pkce] = true + end + + case session[:api] + when 'Rooms' + strategy.options[:authorize_params].scope = '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' + when 'Click' + strategy.options[:authorize_params].scope = 'signature click.manage click.send' + when 'Admin' + strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read' + end + } +end diff --git a/quick_acg/config/routes.rb b/quick_acg/config/routes.rb index 2c44db4..99c540a 100644 --- a/quick_acg/config/routes.rb +++ b/quick_acg/config/routes.rb @@ -1,40 +1,43 @@ -require_relative '../../app/controllers/application_controller' -require_relative '../../app/controllers/eg_controller' -require_relative '../../app/controllers/session_controller' -require_relative '../../app/services/api_creator' -require_relative '../../app/controllers/eeg001_embedded_signing_controller' -require_relative '../../app/services/eg001_embedded_signing_service' -require_relative '../../app/services/utils' - -class ESign -end - -require_relative '../../app/controllers/e_sign/eeg041_cfr_embedded_signing_controller' -require_relative '../../app/services/e_sign/eg041_cfr_embedded_signing_service' -require_relative '../../app/services/e_sign/get_data_service' - -Rails.application.routes.draw do - root 'ds_common#index' - - get '/eeg001' => 'eeg001_embedded_signing#get' - post '/eeg001' => 'eeg001_embedded_signing#create' - - scope module: 'e_sign' do - get 'eeg041' => 'eeg041_cfr_embedded_signing#get' - post 'eeg041' => 'eeg041_cfr_embedded_signing#create' - end - # Login starts with POST'ing to: /auth/docusign - # /auth/docusign is an internal route created by OmniAuth and the docusign strategy from: /lib/docusign.rb - # Should be POST, see: https://nvd.nist.gov/vuln/detail/CVE-2015-9284 - # get '/ds/login' => redirect('/auth/docusign') - - # Handle OmniAuth OAuth2 login callback result that includes the AuthHash - get '/auth/:provider/callback', to: 'session#create' - - get '/ds_common-return' => 'ds_common#index' - - get '/ds/mustAuthenticate' => 'ds_common#ds_must_authenticate' - post '/ds/mustAuthenticate' => 'ds_common#ds_must_authenticate' - - # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html -end +require_relative '../../app/controllers/application_controller' +require_relative '../../app/controllers/eg_controller' +require_relative '../../app/controllers/session_controller' +require_relative '../../app/services/api_creator' +require_relative '../../app/controllers/eeg001_embedded_signing_controller' +require_relative '../../app/services/eg001_embedded_signing_service' +require_relative '../../app/services/utils' + +class ESign +end + +require_relative '../../app/controllers/e_sign/eeg041_cfr_embedded_signing_controller' +require_relative '../../app/services/e_sign/eg041_cfr_embedded_signing_service' +require_relative '../../app/services/e_sign/get_data_service' + +Rails.application.routes.draw do + root 'ds_common#index' + + get '/eeg001' => 'eeg001_embedded_signing#get' + post '/eeg001' => 'eeg001_embedded_signing#create' + + scope module: 'e_sign' do + get 'eeg041' => 'eeg041_cfr_embedded_signing#get' + post 'eeg041' => 'eeg041_cfr_embedded_signing#create' + end + # Login starts with POST'ing to: /auth/docusign + # /auth/docusign is an internal route created by OmniAuth and the docusign strategy from: /lib/docusign.rb + # Should be POST, see: https://nvd.nist.gov/vuln/detail/CVE-2015-9284 + # get '/ds/login' => redirect('/auth/docusign') + + # Handle OmniAuth OAuth2 login callback result that includes the AuthHash + get '/auth/:provider/callback', to: 'session#create' + + # Handle OmniAuth OAuth2 login exceptions + get '/auth/failure', to: 'session#omniauth_failure' + + get '/ds_common-return' => 'ds_common#index' + + get '/ds/mustAuthenticate' => 'ds_common#ds_must_authenticate' + post '/ds/mustAuthenticate' => 'ds_common#ds_must_authenticate' + + # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html +end From 89e89b8f5fbc52fdd319a5f3afe3d81de6b34860 Mon Sep 17 00:00:00 2001 From: nianiB9 Date: Wed, 18 Dec 2024 10:16:07 -0600 Subject: [PATCH 341/363] adjust cursor_value and limit --- .../monitor_api/eg001_get_monitoring_dataset_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb index 7c3f1f7..8e3df88 100644 --- a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb +++ b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb @@ -19,8 +19,8 @@ def worker #ds-snippet-start:Monitor1Step3 monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) begin - cursor_value = '' - limit = 100 + cursor_value = '2024-01-01T00:00:00Z' + limit = 2000 function_results = [] options = DocuSign_Monitor::GetStreamOptions.new options.limit = limit From 93e282735b2245fa62268cf035288f53ea35f240 Mon Sep 17 00:00:00 2001 From: nianiB9 Date: Mon, 30 Dec 2024 14:08:30 -0600 Subject: [PATCH 342/363] revert cursor value --- .../monitor_api/eg001_get_monitoring_dataset_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb index 8e3df88..636a538 100644 --- a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb +++ b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb @@ -19,7 +19,7 @@ def worker #ds-snippet-start:Monitor1Step3 monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) begin - cursor_value = '2024-01-01T00:00:00Z' + cursor_value = '' limit = 2000 function_results = [] options = DocuSign_Monitor::GetStreamOptions.new From 67ce0c8581334ff6fc1dc0f7b05c10f556174de3 Mon Sep 17 00:00:00 2001 From: nianiB9 Date: Tue, 31 Dec 2024 12:45:52 -0600 Subject: [PATCH 343/363] Update cursorDate to calculate date from 1 year ago --- .../monitor_api/eg001_get_monitoring_dataset_service.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb index 636a538..ba7a12d 100644 --- a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb +++ b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb @@ -19,7 +19,8 @@ def worker #ds-snippet-start:Monitor1Step3 monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) begin - cursor_value = '' + cursor_date = Date.today.prev_year + cursor_value = cursor_date.strftime('%Y-%m-%dT00:00:00Z') limit = 2000 function_results = [] options = DocuSign_Monitor::GetStreamOptions.new From 4ef6b53399d5acfb636b75ca2ff3a5edbb558cef Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Tue, 14 Jan 2025 16:20:53 -0800 Subject: [PATCH 344/363] removing Maestro codeDepot --- .../maestro_api/mseg001_trigger_workflow_service.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/services/maestro_api/mseg001_trigger_workflow_service.rb b/app/services/maestro_api/mseg001_trigger_workflow_service.rb index 4fcdd2e..7f0a3df 100644 --- a/app/services/maestro_api/mseg001_trigger_workflow_service.rb +++ b/app/services/maestro_api/mseg001_trigger_workflow_service.rb @@ -9,13 +9,11 @@ def initialize(args) end def get_workflow_definitions - #ds-snippet-start:Maestro1Step2 configuration = DocuSign_Maestro::Configuration.new configuration.host = args[:base_path] api_client = DocuSign_Maestro::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - #ds-snippet-end:Maestro1Step2 workflow_management_api = DocuSign_Maestro::WorkflowManagementApi.new(api_client) @@ -31,10 +29,8 @@ def get_workflow_definition api_client = DocuSign_Maestro::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - #ds-snippet-start:Maestro1Step3 workflow_management_api = DocuSign_Maestro::WorkflowManagementApi.new(api_client) workflow_management_api.get_workflow_definition(args[:account_id], args[:workflow_id]) - #ds-snippet-end:Maestro1Step3 end def trigger_workflow(workflow) @@ -44,7 +40,6 @@ def trigger_workflow(workflow) api_client = DocuSign_Maestro::ApiClient.new(configuration) api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - #ds-snippet-start:Maestro1Step4 trigger_payload = DocuSign_Maestro::TriggerPayload.new trigger_payload.instance_name = args[:instance_name] trigger_payload.participants = {} @@ -61,11 +56,8 @@ def trigger_workflow(workflow) trigger_options = DocuSign_Maestro::TriggerWorkflowOptions.new trigger_options.mtid = mtid trigger_options.mtsec = mtsec - #ds-snippet-end:Maestro1Step4 - #ds-snippet-start:Maestro1Step5 workflow_trigger_api = DocuSign_Maestro::WorkflowTriggerApi.new(api_client) workflow_trigger_api.trigger_workflow(args[:account_id], args[:workflow_id], trigger_payload, trigger_options) - #ds-snippet-end:Maestro1Step5 end end From ff3b682db6fee0538e7e2dd3a2cd99109cb3d944 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Tue, 21 Jan 2025 14:36:24 -0800 Subject: [PATCH 345/363] Devdocs 16120 (#183) * remove maestro --- Gemfile | 1 - Gemfile.lock | 12 +- README.md | 2 +- app/assets/javascripts/search.js | 3 - .../mseg001_trigger_workflow_controller.rb | 112 ---- .../mseg002_cancel_workflow_controller.rb | 52 -- .../mseg003_get_workflow_status_controller.rb | 34 - app/services/jwt_auth/jwt_creator.rb | 1 - .../mseg001_trigger_workflow_service.rb | 63 -- .../mseg002_cancel_workflow_service.rb | 41 -- .../mseg003_get_workflow_status_service.rb | 29 - app/services/maestro_api/utils.rb | 621 ------------------ app/views/ds_common/index.html.erb | 2 - .../mseg001_trigger_workflow/get.html.erb | 54 -- .../publish_workflow.html.erb | 7 - .../mseg002_cancel_workflow/get.html.erb | 33 - .../mseg003_get_workflow_status/get.html.erb | 33 - config/appsettings.example.yml | 1 - config/initializers/omniauth.rb | 2 - config/routes.rb | 12 - 20 files changed, 6 insertions(+), 1109 deletions(-) delete mode 100644 app/controllers/maestro_api/mseg001_trigger_workflow_controller.rb delete mode 100644 app/controllers/maestro_api/mseg002_cancel_workflow_controller.rb delete mode 100644 app/controllers/maestro_api/mseg003_get_workflow_status_controller.rb delete mode 100644 app/services/maestro_api/mseg001_trigger_workflow_service.rb delete mode 100644 app/services/maestro_api/mseg002_cancel_workflow_service.rb delete mode 100644 app/services/maestro_api/mseg003_get_workflow_status_service.rb delete mode 100644 app/services/maestro_api/utils.rb delete mode 100644 app/views/maestro_api/mseg001_trigger_workflow/get.html.erb delete mode 100644 app/views/maestro_api/mseg001_trigger_workflow/publish_workflow.html.erb delete mode 100644 app/views/maestro_api/mseg002_cancel_workflow/get.html.erb delete mode 100644 app/views/maestro_api/mseg003_get_workflow_status/get.html.erb diff --git a/Gemfile b/Gemfile index 76eec36..188bc26 100644 --- a/Gemfile +++ b/Gemfile @@ -71,7 +71,6 @@ end gem 'docusign_admin', '~> 2.0.0.rc2' gem 'docusign_click', '~> 1.4.0' gem 'docusign_esign', '~> 5.0.0' -gem 'docusign_maestro', '~> 2.0.0.rc1' gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' gem 'docusign_webforms', '~> 1.0.0' diff --git a/Gemfile.lock b/Gemfile.lock index d5aa9f7..52d202c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -122,11 +122,6 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_maestro (2.0.0.rc1) - addressable (~> 2.7, >= 2.7.0) - json (~> 2.1, >= 2.1.0) - jwt (~> 2.2, >= 2.2.1) - typhoeus (~> 1.0, >= 1.0.1) docusign_monitor (1.2.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) @@ -202,6 +197,8 @@ GEM net-smtp (0.5.0) net-protocol nio4r (2.7.3) + nokogiri (1.16.6-arm64-darwin) + racc (~> 1.4) nokogiri (1.16.6-x64-mingw-ucrt) racc (~> 1.4) nokogiri (1.16.6-x86_64-darwin) @@ -339,9 +336,10 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) + sqlite3 (2.1.1-arm64-darwin) sqlite3 (2.1.1-x64-mingw-ucrt) sqlite3 (2.1.1-x86_64-darwin) - sqlite3 (2.1.1-x86_64-linux-gnu) + sqlite3 (2.1.1-x86_64-linux) stringio (3.1.1) test-unit (3.6.2) power_assert @@ -379,6 +377,7 @@ GEM zeitwerk (2.6.16) PLATFORMS + arm64-darwin-24 x64-mingw-ucrt x86_64-darwin-21 x86_64-linux @@ -392,7 +391,6 @@ DEPENDENCIES docusign_admin (~> 2.0.0.rc2) docusign_click (~> 1.4.0) docusign_esign (~> 5.0.0) - docusign_maestro (~> 2.0.0.rc1) docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) docusign_webforms (~> 1.0.0) diff --git a/README.md b/README.md index bcccae5..5cc4fd5 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ > ### GitHub repo: [code-examples-ruby](./README.md) -This GitHub repo includes code examples for the [Web Forms API](https://developers.docusign.com/docs/web-forms-api/), [Maestro API](https://developers.docusign.com/docs/maestro-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/). +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 diff --git a/app/assets/javascripts/search.js b/app/assets/javascripts/search.js index 612e088..9668b39 100644 --- a/app/assets/javascripts/search.js +++ b/app/assets/javascripts/search.js @@ -7,7 +7,6 @@ const DS_SEARCH = (function () { ADMIN: "admin", CONNECT: "connect", WEBFORMS: "webforms", - MAESTRO: "maestro", } const processJSONData = function () { @@ -146,8 +145,6 @@ const DS_SEARCH = (function () { return "cneg"; case API_TYPES.WEBFORMS: return "weg"; - case API_TYPES.MAESTRO: - return "mseg"; } } diff --git a/app/controllers/maestro_api/mseg001_trigger_workflow_controller.rb b/app/controllers/maestro_api/mseg001_trigger_workflow_controller.rb deleted file mode 100644 index db30552..0000000 --- a/app/controllers/maestro_api/mseg001_trigger_workflow_controller.rb +++ /dev/null @@ -1,112 +0,0 @@ -class MaestroApi::Mseg001TriggerWorkflowController < EgController - before_action -> { check_auth('Maestro') } - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1, 'Maestro') } - - def create - args = { - instance_name: params[:instance_name], - signer_email: params[:signer_email], - signer_name: params[:signer_name], - cc_email: params[:cc_email], - cc_name: params[:cc_name], - workflow_id: session[:workflow_id], - account_id: session[:ds_account_id], - access_token: session[:ds_access_token], - base_path: Rails.application.config.maestro_client_host - } - - trigger_workflow_service = MaestroApi::Mseg001TriggerWorkflowService.new args - workflow = trigger_workflow_service.get_workflow_definition - results = trigger_workflow_service.trigger_workflow workflow - - session[:instance_id] = results.instance_id - - @title = @example['ExampleName'] - @message = format_string(@example['ResultsPageText'], results.instance_id) - @json = results.to_json.to_json - - render 'ds_common/example_done' - rescue DocuSign_Maestro::ApiError => e - @error_code = e.code || error['errorCode'] - if e.to_s == '403' - @error_message = format_string(@manifest['SupportingTexts']['ContactSupportToEnableFeature'], 'Maestro') - return render 'ds_common/error' - end - handle_error(e) - end - - def get - args = { - template_id: session[:workflow_template_id], - account_id: session[:ds_account_id], - access_token: session[:ds_access_token], - base_path: Rails.application.config.maestro_client_host - } - - trigger_workflow_service = MaestroApi::Mseg001TriggerWorkflowService.new args - workflows = trigger_workflow_service.get_workflow_definitions - - if workflows.count.positive? - sorted_workflows = workflows.value.sort_by(&:last_updated_date).reverse - - session[:workflow_id] = sorted_workflows[0].id if sorted_workflows - session[:is_workflow_published] = true - end - - unless session[:workflow_id] - unless session[:workflow_template_id] - @show_template_not_ok = true - return render 'maestro_api/mseg001_trigger_workflow/get' - end - - session[:workflow_id] = MaestroApi::Utils.new.create_workflow args - end - unless session[:is_workflow_published] - consent_url = MaestroApi::Utils.new.publish_workflow args, session[:workflow_id] - if consent_url - additional_page_data = @example['AdditionalPage'].find { |p| p['Name'] == 'publish_workflow' } - @title = @example['ExampleName'] - @message = additional_page_data['ResultsPageText'] - @consent_url = consent_url - - render 'maestro_api/mseg001_trigger_workflow/publish_workflow' - end - end - rescue DocuSign_Maestro::ApiError => e - @error_code = e.code || error['errorCode'] - if e.to_s == '403' - @error_message = format_string(@manifest['SupportingTexts']['ContactSupportToEnableFeature'], 'Maestro') - return render 'ds_common/error' - end - handle_error(e) - end - - def publish - args = { - account_id: session[:ds_account_id], - access_token: session[:ds_access_token], - base_path: Rails.application.config.maestro_client_host - } - - consent_url = MaestroApi::Utils.new.publish_workflow args, session[:workflow_id] - - if consent_url - additional_page_data = @example['AdditionalPage'].find { |p| p['Name'] == 'publish_workflow' } - @title = @example['ExampleName'] - @message = additional_page_data['ResultsPageText'] - @consent_url = consent_url - - return render 'maestro_api/mseg001_trigger_workflow/publish_workflow' - end - - session[:is_workflow_published] = true - render 'maestro_api/mseg001_trigger_workflow/get' - rescue DocuSign_Maestro::ApiError => e - @error_code = e.code || error['errorCode'] - if e.to_s == '403' - @error_message = format_string(@manifest['SupportingTexts']['ContactSupportToEnableFeature'], 'Maestro') - return render 'ds_common/error' - end - handle_error(e) - end -end diff --git a/app/controllers/maestro_api/mseg002_cancel_workflow_controller.rb b/app/controllers/maestro_api/mseg002_cancel_workflow_controller.rb deleted file mode 100644 index 673ab8c..0000000 --- a/app/controllers/maestro_api/mseg002_cancel_workflow_controller.rb +++ /dev/null @@ -1,52 +0,0 @@ -class MaestroApi::Mseg002CancelWorkflowController < EgController - before_action -> { check_auth('Maestro') } - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2, 'Maestro') } - - def create - args = { - workflow_id: session[:workflow_id], - instance_id: session[:instance_id], - account_id: session[:ds_account_id], - access_token: session[:ds_access_token], - base_path: Rails.application.config.maestro_client_host - } - - results = MaestroApi::Mseg002CancelWorkflowService.new(args).cancel_workflow_instance - - @title = @example['ExampleName'] - @message = format_string(@example['ResultsPageText'], session[:instance_id]) - @json = results.to_json.to_json - - render 'ds_common/example_done' - rescue DocuSign_Maestro::ApiError => e - @error_code = e.code || error['errorCode'] - if e.to_s == '403' - @error_message = format_string(@manifest['SupportingTexts']['ContactSupportToEnableFeature'], 'Maestro') - return render 'ds_common/error' - end - handle_error(e) - end - - def get - args = { - workflow_id: session[:workflow_id], - instance_id: session[:instance_id], - account_id: session[:ds_account_id], - access_token: session[:ds_access_token], - base_path: Rails.application.config.maestro_client_host - } - - state = MaestroApi::Mseg002CancelWorkflowService.new(args).get_instance_state - @instance_ok = state.downcase == 'in progress' - - @workflow_id = session[:workflow_id] - @instance_id = session[:instance_id] - rescue DocuSign_Maestro::ApiError => e - @error_code = e.code || error['errorCode'] - if e.to_s == '403' - @error_message = format_string(@manifest['SupportingTexts']['ContactSupportToEnableFeature'], 'Maestro') - return render 'ds_common/error' - end - handle_error(e) - end -end diff --git a/app/controllers/maestro_api/mseg003_get_workflow_status_controller.rb b/app/controllers/maestro_api/mseg003_get_workflow_status_controller.rb deleted file mode 100644 index 43bcd2e..0000000 --- a/app/controllers/maestro_api/mseg003_get_workflow_status_controller.rb +++ /dev/null @@ -1,34 +0,0 @@ -class MaestroApi::Mseg003GetWorkflowStatusController < EgController - before_action -> { check_auth('Maestro') } - before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 3, 'Maestro') } - - def create - args = { - workflow_id: session[:workflow_id], - instance_id: session[:instance_id], - account_id: session[:ds_account_id], - access_token: session[:ds_access_token], - base_path: Rails.application.config.maestro_client_host - } - - results = MaestroApi::Mseg003GetWorkflowStatusService.new(args).get_instance_state - - @title = @example['ExampleName'] - @message = format_string(@example['ResultsPageText'], results.instance_state) - @json = results.to_json.to_json - - render 'ds_common/example_done' - rescue DocuSign_Maestro::ApiError => e - @error_code = e.code || error['errorCode'] - if e.to_s == '403' - @error_message = format_string(@manifest['SupportingTexts']['ContactSupportToEnableFeature'], 'Maestro') - return render 'ds_common/error' - end - handle_error(e) - end - - def get - @workflow_id = session[:workflow_id] - @instance_id = session[:instance_id] - end -end diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index f344aa1..7d09806 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -18,7 +18,6 @@ def self.consent_url(state, api) scope = 'signature impersonation click.manage click.send' if api == 'Click' scope = 'signature impersonation organization_read group_read permission_read user_read user_write 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_write organization_sub_account_read' if api == 'Admin' scope = 'signature webforms_read webforms_instance_read webforms_instance_write' if api == 'WebForms' - scope = 'signature aow_manage' if api == 'Maestro' base_uri = "#{Rails.configuration.authorization_server}/oauth/auth" response_type = 'code' diff --git a/app/services/maestro_api/mseg001_trigger_workflow_service.rb b/app/services/maestro_api/mseg001_trigger_workflow_service.rb deleted file mode 100644 index 7f0a3df..0000000 --- a/app/services/maestro_api/mseg001_trigger_workflow_service.rb +++ /dev/null @@ -1,63 +0,0 @@ -# frozen_string_literal: true - -class MaestroApi::Mseg001TriggerWorkflowService - include Utils - attr_reader :args - - def initialize(args) - @args = args - end - - def get_workflow_definitions - configuration = DocuSign_Maestro::Configuration.new - configuration.host = args[:base_path] - - api_client = DocuSign_Maestro::ApiClient.new(configuration) - api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - - workflow_management_api = DocuSign_Maestro::WorkflowManagementApi.new(api_client) - - options = DocuSign_Maestro::GetWorkflowDefinitionsOptions.new - options.status = 'active' - workflow_management_api.get_workflow_definitions(args[:account_id], options) - end - - def get_workflow_definition - configuration = DocuSign_Maestro::Configuration.new - configuration.host = args[:base_path] - - api_client = DocuSign_Maestro::ApiClient.new(configuration) - api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - - workflow_management_api = DocuSign_Maestro::WorkflowManagementApi.new(api_client) - workflow_management_api.get_workflow_definition(args[:account_id], args[:workflow_id]) - end - - def trigger_workflow(workflow) - configuration = DocuSign_Maestro::Configuration.new - configuration.host = args[:base_path] - - api_client = DocuSign_Maestro::ApiClient.new(configuration) - api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - - trigger_payload = DocuSign_Maestro::TriggerPayload.new - trigger_payload.instance_name = args[:instance_name] - trigger_payload.participants = {} - trigger_payload.payload = { - signerEmail: args[:signer_email], - signerName: args[:signer_name], - ccEmail: args[:cc_email], - ccName: args[:cc_name] - } - trigger_payload.metadata = {} - - mtid = URLUtils.new.get_parameter_value_from_url(workflow.trigger_url, 'mtid') - mtsec = URLUtils.new.get_parameter_value_from_url(workflow.trigger_url, 'mtsec') - trigger_options = DocuSign_Maestro::TriggerWorkflowOptions.new - trigger_options.mtid = mtid - trigger_options.mtsec = mtsec - - workflow_trigger_api = DocuSign_Maestro::WorkflowTriggerApi.new(api_client) - workflow_trigger_api.trigger_workflow(args[:account_id], args[:workflow_id], trigger_payload, trigger_options) - end -end diff --git a/app/services/maestro_api/mseg002_cancel_workflow_service.rb b/app/services/maestro_api/mseg002_cancel_workflow_service.rb deleted file mode 100644 index 1717e49..0000000 --- a/app/services/maestro_api/mseg002_cancel_workflow_service.rb +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -class MaestroApi::Mseg002CancelWorkflowService - attr_reader :args - - def initialize(args) - @args = args - end - - def get_instance_state - configuration = DocuSign_Maestro::Configuration.new - configuration.host = args[:base_path] - - api_client = DocuSign_Maestro::ApiClient.new(configuration) - api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - - workflow_instance_management_api = DocuSign_Maestro::WorkflowInstanceManagementApi.new(api_client) - - workflow_instance_management_api.get_workflow_instance( - args[:account_id], - args[:workflow_id], - args[:instance_id] - ).instance_state - end - - def cancel_workflow_instance - #ds-snippet-start:Maestro2Step2 - configuration = DocuSign_Maestro::Configuration.new - configuration.host = args[:base_path] - - api_client = DocuSign_Maestro::ApiClient.new(configuration) - api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - #ds-snippet-end:Maestro2Step2 - - #ds-snippet-start:Maestro2Step3 - workflow_instance_management_api = DocuSign_Maestro::WorkflowInstanceManagementApi.new(api_client) - - workflow_instance_management_api.cancel_workflow_instance(args[:account_id], args[:instance_id]) - #ds-snippet-end:Maestro2Step3 - end -end diff --git a/app/services/maestro_api/mseg003_get_workflow_status_service.rb b/app/services/maestro_api/mseg003_get_workflow_status_service.rb deleted file mode 100644 index 47e1c06..0000000 --- a/app/services/maestro_api/mseg003_get_workflow_status_service.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -class MaestroApi::Mseg003GetWorkflowStatusService - attr_reader :args - - def initialize(args) - @args = args - end - - def get_instance_state - #ds-snippet-start:Maestro3Step2 - configuration = DocuSign_Maestro::Configuration.new - configuration.host = args[:base_path] - - api_client = DocuSign_Maestro::ApiClient.new(configuration) - api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - #ds-snippet-end:Maestro3Step2 - - #ds-snippet-start:Maestro3Step3 - workflow_instance_management_api = DocuSign_Maestro::WorkflowInstanceManagementApi.new(api_client) - - workflow_instance_management_api.get_workflow_instance( - args[:account_id], - args[:workflow_id], - args[:instance_id] - ) - #ds-snippet-end:Maestro3Step3 - end -end diff --git a/app/services/maestro_api/utils.rb b/app/services/maestro_api/utils.rb deleted file mode 100644 index 58a9f02..0000000 --- a/app/services/maestro_api/utils.rb +++ /dev/null @@ -1,621 +0,0 @@ -# frozen_string_literal: true - -require 'securerandom' - -class MaestroApi::Utils - def create_workflow(args) - signer_id = SecureRandom.uuid - cc_id = SecureRandom.uuid - trigger_id = 'wfTrigger' - - participants = { - signer_id => { - 'participantRole' => 'Signer' - }, - cc_id => { - 'participantRole' => 'CC' - } - } - - dac_id_field = "dacId_#{trigger_id}" - id_field = "id_#{trigger_id}" - signer_name_field = "signerName_#{trigger_id}" - signer_email_field = "signerEmail_#{trigger_id}" - cc_name_field = "ccName_#{trigger_id}" - cc_email_field = "ccEmail_#{trigger_id}" - - trigger = DocuSign_Maestro::DSWorkflowTrigger.new({ - name: 'Get_URL', - type: 'Http', - httpType: 'Get', - id: trigger_id, - input: { - metadata: { - customAttributes: {} - }, - payload: { - "#{dac_id_field}": { - source: 'step', - propertyName: 'dacId', - stepId: trigger_id - }, - "#{id_field}": { - source: 'step', - propertyName: 'id', - stepId: trigger_id - }, - "#{signer_name_field}": { - source: 'step', - propertyName: 'signerName', - stepId: trigger_id - }, - "#{signer_email_field}": { - source: 'step', - propertyName: 'signerEmail', - stepId: trigger_id - }, - "#{cc_name_field}": { - source: 'step', - propertyName: 'ccName', - stepId: trigger_id - }, - "#{cc_email_field}": { - source: 'step', - propertyName: 'ccEmail', - stepId: trigger_id - } - }, - participants: {} - }, - output: { - "#{dac_id_field}": { - source: 'step', - propertyName: 'dacId', - stepId: trigger_id - } - } - }) - - variables = { - "#{dac_id_field}": DocuSign_Maestro::DSWorkflowVariableFromVariable.new({ - source: 'step', - propertyName: 'dacId', - stepId: trigger_id - }), - "#{id_field}": DocuSign_Maestro::DSWorkflowVariableFromVariable.new({ - source: 'step', - propertyName: 'id', - stepId: trigger_id - }), - "#{signer_name_field}": DocuSign_Maestro::DSWorkflowVariableFromVariable.new({ - source: 'step', - propertyName: 'signerName', - stepId: trigger_id - }), - "#{signer_email_field}": DocuSign_Maestro::DSWorkflowVariableFromVariable.new({ - source: 'step', - propertyName: 'signerEmail', - stepId: trigger_id - }), - "#{cc_name_field}": DocuSign_Maestro::DSWorkflowVariableFromVariable.new({ - source: 'step', - propertyName: 'ccName', - stepId: trigger_id - }), - "#{cc_email_field}": DocuSign_Maestro::DSWorkflowVariableFromVariable.new({ - 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' - } - } - - step1 = { - 'id': 'step1', - 'name': 'Set Up Invite', - 'moduleName': 'Notification-SendEmail', - 'configurationProgress': 'Completed', - 'type': 'DS-EmailNotification', - 'config': { - 'templateType': 'WorkflowParticipantNotification', - 'templateVersion': 1, - 'language': 'en', - 'sender_name': 'DocuSign Orchestration', - 'sender_alias': 'Orchestration', - 'participantId': signer_id - }, - 'input': { - 'recipients': [ - { - 'name': { - 'source': 'step', - 'propertyName': 'signerName', - 'stepId': trigger_id - }, - 'email': { - 'source': 'step', - 'propertyName': 'signerEmail', - 'stepId': trigger_id - } - } - ], - 'mergeValues': { - 'CustomMessage': 'Follow this link to access and complete the workflow.', - 'ParticipantFullName': { - 'source': 'step', - 'propertyName': 'signerName', - 'stepId': trigger_id - } - } - }, - 'output': {} - } - - step2 = { - "id": 'step2', - "name": 'Get Signatures', - "moduleName": 'ESign', - "configurationProgress": 'Completed', - "type": 'DS-Sign', - "config": { - "participantId": signer_id - }, - "input": { - "isEmbeddedSign": true, - "documents": [ - { - "type": 'FromDSTemplate', - "eSignTemplateId": args[: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' - } - } - } - - step3 = { - "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": {} - } - - workflow_definition = DocuSign_Maestro::WorkflowDefinition.new({ - workflowName: 'Example workflow - send invite to signer', - workflowDescription: '', - documentVersion: '1.0.0', - schemaVersion: '1.0.0', - accountId: args[:account_id], - participants: participants, - trigger: trigger, - variables: variables, - steps: [step1, step2, step3] - }) - - configuration = DocuSign_Maestro::Configuration.new - configuration.host = args[:base_path] - - api_client = DocuSign_Maestro::ApiClient.new(configuration) - api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - - workflow_management_api = DocuSign_Maestro::WorkflowManagementApi.new(api_client) - workflow_management_api.create_workflow_definition( - args[:account_id], - { "workflowDefinition": workflow_definition } - ).workflow_definition_id - end - - def publish_workflow(args, workflow_id) - configuration = DocuSign_Maestro::Configuration.new - configuration.host = args[:base_path] - - api_client = DocuSign_Maestro::ApiClient.new(configuration) - api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - - workflow_management_api = DocuSign_Maestro::WorkflowManagementApi.new(api_client) - - deploy_request = DocuSign_Maestro::DeployRequest.new({ - deploymentStatus: DocuSign_Maestro::DeployStatus::PUBLISH - }) - begin - workflow_management_api.publish_or_un_publish_workflow_definition( - args[:account_id], - workflow_id, - deploy_request - ) - - # return false if workflow does not require a consent to be published - false - rescue Exception => e - return raise e unless e.respond_to?(:response_body) - - response_body = JSON.parse(e.response_body) - return raise e unless response_body.key?('responseType') - - is_consent_required = response_body['responseType'] == 'NeedConsent' - return response_body['consentUrl'] if is_consent_required - - raise e - end - end -end diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index 86f2b79..1be4c5b 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -55,8 +55,6 @@ "cn" elsif api["Name"] == "WebForms" "w" - elsif api["Name"] == "Maestro" - "ms" else "e" end %> diff --git a/app/views/maestro_api/mseg001_trigger_workflow/get.html.erb b/app/views/maestro_api/mseg001_trigger_workflow/get.html.erb deleted file mode 100644 index 0a76846..0000000 --- a/app/views/maestro_api/mseg001_trigger_workflow/get.html.erb +++ /dev/null @@ -1,54 +0,0 @@ -<%= render('partials/example_info') %> - -<% form_index = 0 %> -<% instance_name_index = 0 %> -<% signer_email_index = 1 %> -<% signer_name_index = 2 %> -<% cc_email_index = 3 %> -<% cc_name_index = 4 %> -<% redirect_to8_index = 0 %> - -<% unless @show_template_not_ok %> -
    - <% if @example["Forms"][form_index]["FormName"] %> - <%= sanitize @example["Forms"][form_index]["FormName"] %> - <% end %> - -
    - - -
    -
    - - - <%= render('partials/email_will_not_be_shared') %> -
    -
    - - -
    -
    - - - The email for the cc recipient must be different from the signer's email. -
    -
    - - -
    - - <%= render('partials/submit_button') %> - -<% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to8_index]["RedirectText"], 'href="eeg008"') %> - -
    - <%= render('partials/continue_button') %> - -<% end %> diff --git a/app/views/maestro_api/mseg001_trigger_workflow/publish_workflow.html.erb b/app/views/maestro_api/mseg001_trigger_workflow/publish_workflow.html.erb deleted file mode 100644 index 0ea0ec4..0000000 --- a/app/views/maestro_api/mseg001_trigger_workflow/publish_workflow.html.erb +++ /dev/null @@ -1,7 +0,0 @@ -

    <%= @title %>

    -<%= format_string(@message, @consent_url).html_safe %> - -
    - - <%= render('partials/submit_button') %> - diff --git a/app/views/maestro_api/mseg002_cancel_workflow/get.html.erb b/app/views/maestro_api/mseg002_cancel_workflow/get.html.erb deleted file mode 100644 index 5ad3a90..0000000 --- a/app/views/maestro_api/mseg002_cancel_workflow/get.html.erb +++ /dev/null @@ -1,33 +0,0 @@ -<%= render('partials/example_info') %> - -<% form_index = 0 %> -<% workflow_id_index = 0 %> -<% instance_id_index = 1 %> -<% redirect_to1_index = 0 %> - -<% if @instance_ok %> -
    - <% if @example["Forms"][form_index]["FormName"] %> - <%= sanitize @example["Forms"][form_index]["FormName"] %> - <% end %> - -
    - - -
    -
    - - -
    - - <%= render('partials/submit_button') %> - -<% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="mseg001"') %> - -
    - <%= render('partials/continue_button') %> - -<% end %> diff --git a/app/views/maestro_api/mseg003_get_workflow_status/get.html.erb b/app/views/maestro_api/mseg003_get_workflow_status/get.html.erb deleted file mode 100644 index 9e536b8..0000000 --- a/app/views/maestro_api/mseg003_get_workflow_status/get.html.erb +++ /dev/null @@ -1,33 +0,0 @@ -<%= render('partials/example_info') %> - -<% form_index = 0 %> -<% workflow_id_index = 0 %> -<% instance_id_index = 1 %> -<% redirect_to1_index = 0 %> - -<% if @workflow_id && @instance_id %> -
    - <% if @example["Forms"][form_index]["FormName"] %> - <%= sanitize @example["Forms"][form_index]["FormName"] %> - <% end %> - -
    - - -
    -
    - - -
    - - <%= render('partials/submit_button') %> - -<% else %> - <%= sanitize format_string(@example["RedirectsToOtherCodeExamples"][redirect_to1_index]["RedirectText"], 'href="mseg001"') %> - -
    - <%= render('partials/continue_button') %> - -<% end %> diff --git a/config/appsettings.example.yml b/config/appsettings.example.yml index 9dac446..6eb5779 100644 --- a/config/appsettings.example.yml +++ b/config/appsettings.example.yml @@ -24,7 +24,6 @@ default: &default monitor_host: "https://lens-d.docusign.net" admin_host: "https://api-d.docusign.net/management" webforms_host: "https://apps-d.docusign.com/api/webforms/v1.1" - maestro_client_host: "https://apps-d.docusign.com/api/maestro" allow_silent_authentication: true # A user can be silently authenticated if they have an # Active login session on another tab of the same browser # Set if you want a specific Docusign AccountId, If false, the users default account will be used. diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 7b75d1d..8dd1993 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -54,8 +54,6 @@ strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write 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_write organization_sub_account_read' when 'WebForms' strategy.options[:authorize_params].scope = 'signature webforms_read webforms_instance_read webforms_instance_write' - when 'Maestro' - strategy.options[:authorize_params].scope = 'signature aow_manage' end } end diff --git a/config/routes.rb b/config/routes.rb index 2894d53..e586969 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -245,18 +245,6 @@ post 'weg001webForm' => 'weg001_create_instance#create_web_form_instance' end - scope module: 'maestro_api' do - get 'mseg001' => 'mseg001_trigger_workflow#get' - post 'mseg001' => 'mseg001_trigger_workflow#create' - post 'mseg001publish' => 'mseg001_trigger_workflow#publish' - - get 'mseg002' => 'mseg002_cancel_workflow#get' - post 'mseg002' => 'mseg002_cancel_workflow#create' - - get 'mseg003' => 'mseg003_get_workflow_status#get' - post 'mseg003' => 'mseg003_get_workflow_status#create' - end - root 'ds_common#index' # Login starts with POST'ing to: /auth/docusign From 0305ff0163ded81df44dd6ba83e8cc8ad695d102 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Wed, 29 Jan 2025 17:17:17 +0200 Subject: [PATCH 346/363] add notary example --- app/assets/javascripts/search.js | 3 + ...send_with_third_party_notary_controller.rb | 28 ++++ app/services/jwt_auth/jwt_creator.rb | 5 + ...04_send_with_third_party_notary_service.rb | 140 ++++++++++++++++++ app/views/ds_common/index.html.erb | 2 + .../get.html.erb | 27 ++++ config/initializers/omniauth.rb | 2 + config/routes.rb | 5 + 8 files changed, 212 insertions(+) create mode 100644 app/controllers/notary/neg004_send_with_third_party_notary_controller.rb create mode 100644 app/services/notary/eg004_send_with_third_party_notary_service.rb create mode 100644 app/views/notary/neg004_send_with_third_party_notary/get.html.erb diff --git a/app/assets/javascripts/search.js b/app/assets/javascripts/search.js index 9668b39..8014fa7 100644 --- a/app/assets/javascripts/search.js +++ b/app/assets/javascripts/search.js @@ -7,6 +7,7 @@ const DS_SEARCH = (function () { ADMIN: "admin", CONNECT: "connect", WEBFORMS: "webforms", + NOTARY: "notary" } const processJSONData = function () { @@ -145,6 +146,8 @@ const DS_SEARCH = (function () { return "cneg"; case API_TYPES.WEBFORMS: return "weg"; + case API_TYPES.NOTARY: + return "neg"; } } diff --git a/app/controllers/notary/neg004_send_with_third_party_notary_controller.rb b/app/controllers/notary/neg004_send_with_third_party_notary_controller.rb new file mode 100644 index 0000000..f18df0f --- /dev/null +++ b/app/controllers/notary/neg004_send_with_third_party_notary_controller.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require_relative '../../services/utils' + +class Notary::Neg004SendWithThirdPartyNotaryController < EgController + before_action -> { check_auth('Notary') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 4, 'Notary') } + + def create + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + doc_pdf: File.join('data', Rails.application.config.doc_pdf) + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + results = Notary::Eg004SendWithThirdPartyNotaryService.new(args).worker + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results['envelope_id']) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end +end diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index 7d09806..911f221 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -18,6 +18,7 @@ def self.consent_url(state, api) scope = 'signature impersonation click.manage click.send' if api == 'Click' scope = 'signature impersonation organization_read group_read permission_read user_read user_write 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_write organization_sub_account_read' if api == 'Admin' scope = 'signature webforms_read webforms_instance_read webforms_instance_write' if api == 'WebForms' + scope = 'signature organization_read notary_read notary_write' if api == 'Notary' base_uri = "#{Rails.configuration.authorization_server}/oauth/auth" response_type = 'code' @@ -50,6 +51,10 @@ def initialize(session) scope = 'signature webforms_read webforms_instance_read webforms_instance_write' @client_module = DocuSign_WebForms end + if session[:api] == 'Notary' + scope = 'signature organization_read notary_read notary_write' + @client_module = DocuSign_eSign + end @scope = scope @api_client = create_initial_api_client(host: Rails.configuration.aud, client_module: @client_module, debugging: false) diff --git a/app/services/notary/eg004_send_with_third_party_notary_service.rb b/app/services/notary/eg004_send_with_third_party_notary_service.rb new file mode 100644 index 0000000..8f27d0d --- /dev/null +++ b/app/services/notary/eg004_send_with_third_party_notary_service.rb @@ -0,0 +1,140 @@ +# frozen_string_literal: true + +class Notary::Eg004SendWithThirdPartyNotaryService + attr_reader :args + + include ApiCreator + + def initialize(args) + @args = args + end + + #ds-snippet-start:Notary4Step3 + def worker + # Create the envelope request object + envelope_definition = make_envelope args[:envelope_args] + # Call Envelopes::create API method + # Exceptions will be caught by the calling function + envelope_api = create_envelope_api(args) + + results = envelope_api.create_envelope args[:account_id], envelope_definition + envelope_id = results.envelope_id + { 'envelope_id' => envelope_id } + end + #ds-snippet-end:Notary4Step3 + + private + + #ds-snippet-start:Notary4Step2 + def make_envelope(envelope_args) + # 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 + + # Create the envelope definition + envelope_definition = DocuSign_eSign::EnvelopeDefinition.new + + envelope_definition.email_subject = 'Please sign this document set' + + # Add the document + doc_b64 = Base64.encode64(File.binread(envelope_args[:doc_pdf])) + + # Create the document model + document = DocuSign_eSign::Document.new( + # Create the Docusign document object + documentBase64: doc_b64, + name: 'Order acknowledgement', # Can be different from actual file name + fileExtension: 'html', # Many different document types are accepted + documentId: '1' # A label used to reference the doc + ) + + # The order in the docs array determines the order in the envelope + envelope_definition.documents = [document] + + # Create the signer recipient model + signer = DocuSign_eSign::Signer.new + signer.email = envelope_args[:signer_email] + signer.name = envelope_args[:signer_name] + signer.recipient_id = '1' + signer.routing_order = '1' + ## 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 + + # Create signHere fields (also known as tabs) on the documents + # We're using anchor (autoPlace) positioning + # + # The Docusign platform searches throughout your envelope's documents for matching + # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 + # since they use the same anchor string for their "signer 1" tabs. + sign_here = DocuSign_eSign::SignHere.new( + anchorString: '/sn1/', + anchorYOffset: '10', + anchorUnits: 'pixels', + anchorXOffset: '20' + ) + + # Add the tabs model (including the sign_here tabs) to the signer + # The Tabs object takes arrays of the different field/tab types + signer_tab = DocuSign_eSign::Tabs.new({ + signHereTabs: [sign_here] + }) + + signer.tabs = signer_tab + + notary_seal = DocuSign_eSign::NotarySeal.new( + xPosition: '300', + yPosition: '235', + documentId: '1', + pageNumber: '1', + ) + + notary_sign_here = DocuSign_eSign::SignHere.new( + xPosition: '300', + yPosition: '150', + documentId: '1', + pageNumber: '1', + ) + + notary_tabs = DocuSign_eSign::Tabs.new( + signHereTabs: [notary_sign_here], + notarySealTabs: [notary_seal] + ) + + notary_recipient = DocuSign_eSign::NotaryRecipient.new( + email: '', + name: 'Notary', + recipientId: '1', + routingOrder: '1', + tabs: notary_tabs, + notaryType: 'remote', + notarySourceType: 'thirdparty', + notaryThirdPartyPartner: 'onenotary', + recipientSignatureProviders: [ + { + sealDocumentsWithTabsOnly: 'false', + signatureProviderName: 'ds_authority_idv', + signatureProviderOptions: {} + } + ] + ) + + # Add the recipients to the envelope object + recipients = DocuSign_eSign::Recipients.new( + signers: [signer], + notary: [notary_recipient] + ) + # Request that the envelope be sent by setting status to "sent". + # To request that the envelope be created as a draft, set status to "created" + envelope_definition.recipients = recipients + envelope_definition.status = 'sent' + envelope_definition + end + #ds-snippet-end:Notary4Step2 +end diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index 1be4c5b..da7e2ca 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -55,6 +55,8 @@ "cn" elsif api["Name"] == "WebForms" "w" + elsif api["Name"] == "Notary" + "n" else "e" end %> diff --git a/app/views/notary/neg004_send_with_third_party_notary/get.html.erb b/app/views/notary/neg004_send_with_third_party_notary/get.html.erb new file mode 100644 index 0000000..043c707 --- /dev/null +++ b/app/views/notary/neg004_send_with_third_party_notary/get.html.erb @@ -0,0 +1,27 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %> + +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + " required + value="<%= @config.signer_email %>"> + <%= render('partials/email_will_not_be_shared') %> +
    +
    + + " name="signerName" + value="<%= @config.signer_name %>" required> +
    + <%= render('partials/submit_button') %> + \ No newline at end of file diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 8dd1993..0731c69 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -54,6 +54,8 @@ strategy.options[:authorize_params].scope = 'signature organization_read group_read permission_read user_read user_write 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_write organization_sub_account_read' when 'WebForms' strategy.options[:authorize_params].scope = 'signature webforms_read webforms_instance_read webforms_instance_write' + when 'Notary' + strategy.options[:authorize_params].scope = 'signature organization_read notary_read notary_write' end } end diff --git a/config/routes.rb b/config/routes.rb index e586969..11dff34 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -245,6 +245,11 @@ post 'weg001webForm' => 'weg001_create_instance#create_web_form_instance' end + scope module: 'notary' do + get 'neg004' => 'neg004_send_with_third_party_notary#get' + post 'neg004' => 'neg004_send_with_third_party_notary#create' + end + root 'ds_common#index' # Login starts with POST'ing to: /auth/docusign From bff5cfb04b92714230932a077111cbbf74d27065 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Fri, 31 Jan 2025 13:47:30 +0200 Subject: [PATCH 347/363] update packages & fix example --- Gemfile | 6 +- Gemfile.lock | 264 +++++++++--------- ...send_with_third_party_notary_controller.rb | 2 +- ...04_send_with_third_party_notary_service.rb | 62 ++-- 4 files changed, 167 insertions(+), 167 deletions(-) diff --git a/Gemfile b/Gemfile index 188bc26..215f112 100644 --- a/Gemfile +++ b/Gemfile @@ -6,11 +6,11 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '~>3.1.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 7.2.1.1' +gem 'rails', '~> 7.2.2.1' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 2.1.1' # Use Puma as the app server -gem 'puma', '~> 6.4.3' +gem 'puma', '~> 6.6.0' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets @@ -54,7 +54,7 @@ group :development do # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'pry-nav', '~> 1.0.0' gem 'pry-rails', '~> 0.3.11' - gem 'rubocop', '~> 1.67.0', require: false + gem 'rubocop', '~> 1.71.0', require: false gem 'spring', '~> 4.2.1' gem 'spring-watcher-listen', '~> 2.1.0' end diff --git a/Gemfile.lock b/Gemfile.lock index 52d202c..1b25084 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,29 +1,29 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.2.1.1) - actionpack (= 7.2.1.1) - activesupport (= 7.2.1.1) + actioncable (7.2.2.1) + actionpack (= 7.2.2.1) + activesupport (= 7.2.2.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.2.1.1) - actionpack (= 7.2.1.1) - activejob (= 7.2.1.1) - activerecord (= 7.2.1.1) - activestorage (= 7.2.1.1) - activesupport (= 7.2.1.1) + actionmailbox (7.2.2.1) + actionpack (= 7.2.2.1) + activejob (= 7.2.2.1) + activerecord (= 7.2.2.1) + activestorage (= 7.2.2.1) + activesupport (= 7.2.2.1) mail (>= 2.8.0) - actionmailer (7.2.1.1) - actionpack (= 7.2.1.1) - actionview (= 7.2.1.1) - activejob (= 7.2.1.1) - activesupport (= 7.2.1.1) + actionmailer (7.2.2.1) + actionpack (= 7.2.2.1) + actionview (= 7.2.2.1) + activejob (= 7.2.2.1) + activesupport (= 7.2.2.1) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.2.1.1) - actionview (= 7.2.1.1) - activesupport (= 7.2.1.1) + actionpack (7.2.2.1) + actionview (= 7.2.2.1) + activesupport (= 7.2.2.1) nokogiri (>= 1.8.5) racc rack (>= 2.2.4, < 3.2) @@ -32,36 +32,37 @@ GEM rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (7.2.1.1) - actionpack (= 7.2.1.1) - activerecord (= 7.2.1.1) - activestorage (= 7.2.1.1) - activesupport (= 7.2.1.1) + actiontext (7.2.2.1) + actionpack (= 7.2.2.1) + activerecord (= 7.2.2.1) + activestorage (= 7.2.2.1) + activesupport (= 7.2.2.1) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.2.1.1) - activesupport (= 7.2.1.1) + actionview (7.2.2.1) + activesupport (= 7.2.2.1) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.2.1.1) - activesupport (= 7.2.1.1) + activejob (7.2.2.1) + activesupport (= 7.2.2.1) globalid (>= 0.3.6) - activemodel (7.2.1.1) - activesupport (= 7.2.1.1) - activerecord (7.2.1.1) - activemodel (= 7.2.1.1) - activesupport (= 7.2.1.1) + activemodel (7.2.2.1) + activesupport (= 7.2.2.1) + activerecord (7.2.2.1) + activemodel (= 7.2.2.1) + activesupport (= 7.2.2.1) timeout (>= 0.4.0) - activestorage (7.2.1.1) - actionpack (= 7.2.1.1) - activejob (= 7.2.1.1) - activerecord (= 7.2.1.1) - activesupport (= 7.2.1.1) + activestorage (7.2.2.1) + actionpack (= 7.2.2.1) + activejob (= 7.2.2.1) + activerecord (= 7.2.2.1) + activesupport (= 7.2.2.1) marcel (~> 1.0) - activesupport (7.2.1.1) + activesupport (7.2.2.1) base64 + benchmark (>= 0.3) bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) @@ -77,7 +78,8 @@ GEM io-like (~> 0.3.0) ast (2.4.2) base64 (0.2.0) - bigdecimal (3.1.8) + benchmark (0.4.0) + bigdecimal (3.1.9) bindex (0.8.1) bootsnap (1.7.7) msgpack (~> 1.0) @@ -103,11 +105,11 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.3.3) - connection_pool (2.4.1) + concurrent-ruby (1.3.5) + connection_pool (2.5.0) crass (1.0.6) - date (3.3.4) - docusign_admin (2.0.0.rc2) + date (3.4.1) + docusign_admin (2.0.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -138,38 +140,41 @@ GEM jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) drb (2.2.1) - erubi (1.13.0) + erubi (1.13.1) ethon (0.16.0) ffi (>= 1.15.0) - execjs (2.9.1) - faraday (2.9.2) - faraday-net_http (>= 2.0, < 3.2) - faraday-net_http (3.1.0) - net-http + execjs (2.10.0) + faraday (2.12.2) + faraday-net_http (>= 2.0, < 3.5) + json + logger + faraday-net_http (3.4.0) + net-http (>= 0.5.0) ffi (1.16.3) ffi (1.16.3-x64-mingw-ucrt) globalid (1.2.1) activesupport (>= 6.1) hashie (5.0.0) - i18n (1.14.5) + i18n (1.14.7) concurrent-ruby (~> 1.0) - io-console (0.7.2) + io-console (0.8.0) io-like (0.3.1) - irb (1.13.2) + irb (1.15.1) + pp (>= 0.6.0) rdoc (>= 4.0.0) reline (>= 0.4.2) jbuilder (2.13.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) - json (2.7.2) - jwt (2.8.2) + json (2.9.1) + jwt (2.10.1) base64 - language_server-protocol (3.17.0.3) + language_server-protocol (3.17.0.4) listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - logger (1.6.1) - loofah (2.22.0) + logger (1.6.5) + loofah (2.24.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) mail (2.8.1) @@ -181,13 +186,13 @@ GEM matrix (0.4.2) method_source (1.1.0) mini_mime (1.1.5) - minitest (5.24.0) - msgpack (1.7.2) + minitest (5.25.4) + msgpack (1.7.5) multi_xml (0.7.1) bigdecimal (~> 3.1) - net-http (0.4.1) + net-http (0.6.0) uri - net-imap (0.5.0) + net-imap (0.5.5) date net-protocol net-pop (0.1.2) @@ -196,14 +201,10 @@ GEM timeout net-smtp (0.5.0) net-protocol - nio4r (2.7.3) - nokogiri (1.16.6-arm64-darwin) + nio4r (2.7.4) + nokogiri (1.18.2-x64-mingw-ucrt) racc (~> 1.4) - nokogiri (1.16.6-x64-mingw-ucrt) - racc (~> 1.4) - nokogiri (1.16.6-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.16.6-x86_64-linux) + nokogiri (1.18.2-x86_64-linux-gnu) racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) @@ -223,10 +224,13 @@ GEM actionpack (>= 4.2) omniauth (~> 2.0) parallel (1.26.3) - parser (3.3.5.0) + parser (3.3.7.0) ast (~> 2.4.1) racc - power_assert (2.0.3) + power_assert (2.0.5) + pp (0.6.2) + prettyprint + prettyprint (0.2.0) pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) @@ -234,47 +238,49 @@ GEM pry (>= 0.9.10, < 0.15) pry-rails (0.3.11) pry (>= 0.13.0) - psych (5.1.2) + psych (5.2.3) + date stringio - public_suffix (6.0.0) - puma (6.4.3) + public_suffix (6.0.1) + puma (6.6.0) nio4r (~> 2.0) - racc (1.8.0) - rack (3.1.4) - rack-protection (4.0.0) + racc (1.8.1) + rack (3.1.9) + rack-protection (4.1.1) base64 (>= 0.1.0) + logger (>= 1.6.0) rack (>= 3.0.0, < 4) - rack-session (2.0.0) + rack-session (2.1.0) + base64 (>= 0.1.0) rack (>= 3.0.0) - rack-test (2.1.0) + rack-test (2.2.0) rack (>= 1.3) - rackup (2.1.0) + rackup (2.2.1) rack (>= 3) - webrick (~> 1.8) - rails (7.2.1.1) - actioncable (= 7.2.1.1) - actionmailbox (= 7.2.1.1) - actionmailer (= 7.2.1.1) - actionpack (= 7.2.1.1) - actiontext (= 7.2.1.1) - actionview (= 7.2.1.1) - activejob (= 7.2.1.1) - activemodel (= 7.2.1.1) - activerecord (= 7.2.1.1) - activestorage (= 7.2.1.1) - activesupport (= 7.2.1.1) + rails (7.2.2.1) + actioncable (= 7.2.2.1) + actionmailbox (= 7.2.2.1) + actionmailer (= 7.2.2.1) + actionpack (= 7.2.2.1) + actiontext (= 7.2.2.1) + actionview (= 7.2.2.1) + activejob (= 7.2.2.1) + activemodel (= 7.2.2.1) + activerecord (= 7.2.2.1) + activestorage (= 7.2.2.1) + activesupport (= 7.2.2.1) bundler (>= 1.15.0) - railties (= 7.2.1.1) + railties (= 7.2.2.1) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.6.0) + rails-html-sanitizer (1.6.2) loofah (~> 2.21) - nokogiri (~> 1.14) - railties (7.2.1.1) - actionpack (= 7.2.1.1) - activesupport (= 7.2.1.1) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + railties (7.2.2.1) + actionpack (= 7.2.2.1) + activesupport (= 7.2.2.1) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) @@ -285,26 +291,26 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) - rdoc (6.7.0) + rdoc (6.11.0) psych (>= 4.0.0) - regexp_parser (2.9.2) - reline (0.5.9) + regexp_parser (2.10.0) + reline (0.6.0) io-console (~> 0.5) - rexml (3.3.8) - rubocop (1.67.0) + rexml (3.4.0) + rubocop (1.71.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 2.4, < 3.0) - rubocop-ast (>= 1.32.2, < 2.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.36.2, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.32.3) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.38.0) parser (>= 3.3.1.0) ruby-progressbar (1.13.0) - rubyzip (2.3.2) + rubyzip (2.4.1) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) sassc (2.4.0) @@ -315,7 +321,7 @@ GEM sprockets (> 3.0) sprockets-rails tilt - securerandom (0.3.1) + securerandom (0.4.1) selenium-webdriver (4.25.0) base64 (~> 0.2) logger (~> 1.4) @@ -332,20 +338,18 @@ GEM sprockets (4.2.1) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) - sprockets-rails (3.5.1) + sprockets-rails (3.5.2) actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) - sqlite3 (2.1.1-arm64-darwin) sqlite3 (2.1.1-x64-mingw-ucrt) - sqlite3 (2.1.1-x86_64-darwin) - sqlite3 (2.1.1-x86_64-linux) - stringio (3.1.1) - test-unit (3.6.2) + sqlite3 (2.1.1-x86_64-linux-gnu) + stringio (3.1.2) + test-unit (3.6.7) power_assert - thor (1.3.1) - tilt (2.3.0) - timeout (0.4.1) + thor (1.3.2) + tilt (2.6.0) + timeout (0.4.3) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) @@ -357,29 +361,29 @@ GEM tzinfo (>= 1.0.0) uglifier (4.2.1) execjs (>= 0.3.0, < 3) - unicode-display_width (2.6.0) - uri (0.13.0) - useragent (0.16.10) + unicode-display_width (3.1.4) + unicode-emoji (~> 4.0, >= 4.0.4) + unicode-emoji (4.0.4) + uri (1.0.2) + useragent (0.16.11) version_gem (1.1.4) - wdm (0.1.1) + wdm (0.2.0) web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - webrick (1.8.1) websocket (1.2.11) - websocket-driver (0.7.6) + websocket-driver (0.7.7) + base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.16) + zeitwerk (2.6.18) PLATFORMS - arm64-darwin-24 x64-mingw-ucrt - x86_64-darwin-21 x86_64-linux DEPENDENCIES @@ -401,9 +405,9 @@ DEPENDENCIES omniauth-rails_csrf_protection pry-nav (~> 1.0.0) pry-rails (~> 0.3.11) - puma (~> 6.4.3) - rails (~> 7.2.1.1) - rubocop (~> 1.67.0) + puma (~> 6.6.0) + rails (~> 7.2.2.1) + rubocop (~> 1.71.0) sass-rails (~> 6.0.0) selenium-webdriver (~> 4.25.0) spring (~> 4.2.1) @@ -420,4 +424,4 @@ RUBY VERSION ruby 3.1.2p20 BUNDLED WITH - 2.4.22 + 2.5.22 diff --git a/app/controllers/notary/neg004_send_with_third_party_notary_controller.rb b/app/controllers/notary/neg004_send_with_third_party_notary_controller.rb index f18df0f..e49259a 100644 --- a/app/controllers/notary/neg004_send_with_third_party_notary_controller.rb +++ b/app/controllers/notary/neg004_send_with_third_party_notary_controller.rb @@ -10,7 +10,7 @@ def create envelope_args = { signer_email: param_gsub(params['signerEmail']), signer_name: param_gsub(params['signerName']), - doc_pdf: File.join('data', Rails.application.config.doc_pdf) + doc_path: File.join('data', Rails.application.config.doc_docx) } args = { account_id: session['ds_account_id'], diff --git a/app/services/notary/eg004_send_with_third_party_notary_service.rb b/app/services/notary/eg004_send_with_third_party_notary_service.rb index 8f27d0d..af4cc0b 100644 --- a/app/services/notary/eg004_send_with_third_party_notary_service.rb +++ b/app/services/notary/eg004_send_with_third_party_notary_service.rb @@ -27,13 +27,9 @@ def worker #ds-snippet-start:Notary4Step2 def make_envelope(envelope_args) - # 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 + # recipient 1 - notary + # recipient 2 - signer # The envelope will be sent first to the signer. # After it is signed, a copy is sent to the cc person @@ -43,7 +39,7 @@ def make_envelope(envelope_args) envelope_definition.email_subject = 'Please sign this document set' # Add the document - doc_b64 = Base64.encode64(File.binread(envelope_args[:doc_pdf])) + doc_b64 = Base64.encode64(File.binread(envelope_args[:doc_path])) # Create the document model document = DocuSign_eSign::Document.new( @@ -57,36 +53,36 @@ def make_envelope(envelope_args) # The order in the docs array determines the order in the envelope envelope_definition.documents = [document] - # Create the signer recipient model - signer = DocuSign_eSign::Signer.new - signer.email = envelope_args[:signer_email] - signer.name = envelope_args[:signer_name] - signer.recipient_id = '1' - signer.routing_order = '1' - ## 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 - - # Create signHere fields (also known as tabs) on the documents - # We're using anchor (autoPlace) positioning - # - # The Docusign platform searches throughout your envelope's documents for matching - # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 - # since they use the same anchor string for their "signer 1" tabs. - sign_here = DocuSign_eSign::SignHere.new( - anchorString: '/sn1/', - anchorYOffset: '10', - anchorUnits: 'pixels', - anchorXOffset: '20' + sign_here_1 = DocuSign_eSign::SignHere.new( + documentId: '1', + xPosition: '200', + yPosition: '235', + pageNumber: '1' + ) + sign_here_2 = DocuSign_eSign::SignHere.new( + stampType: 'stamp', + documentId: '1', + xPosition: '200', + yPosition: '150', + pageNumber: '1' ) # Add the tabs model (including the sign_here tabs) to the signer # The Tabs object takes arrays of the different field/tab types - signer_tab = DocuSign_eSign::Tabs.new({ - signHereTabs: [sign_here] - }) + signer_tab = DocuSign_eSign::Tabs.new( + signHereTabs: [sign_here_1, sign_here_2] + ) - signer.tabs = signer_tab + # Create the signer recipient model + signer = DocuSign_eSign::Signer.new( + clientUserId: '1000', + email: envelope_args[:signer_email], + name: envelope_args[:signer_name], + recipientId: '2', + routingOrder: '1', + notaryId: '1', + tabs: signer_tab + ) notary_seal = DocuSign_eSign::NotarySeal.new( xPosition: '300', @@ -128,7 +124,7 @@ def make_envelope(envelope_args) # Add the recipients to the envelope object recipients = DocuSign_eSign::Recipients.new( signers: [signer], - notary: [notary_recipient] + notaries: [notary_recipient] ) # Request that the envelope be sent by setting status to "sent". # To request that the envelope be created as a draft, set status to "created" From f993536696198b6ef0fb9ee108025de01abdaeda Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Fri, 31 Jan 2025 13:52:06 +0200 Subject: [PATCH 348/363] fix linter issues --- .../notary/eg004_send_with_third_party_notary_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/notary/eg004_send_with_third_party_notary_service.rb b/app/services/notary/eg004_send_with_third_party_notary_service.rb index af4cc0b..c9d36b5 100644 --- a/app/services/notary/eg004_send_with_third_party_notary_service.rb +++ b/app/services/notary/eg004_send_with_third_party_notary_service.rb @@ -88,14 +88,14 @@ def make_envelope(envelope_args) xPosition: '300', yPosition: '235', documentId: '1', - pageNumber: '1', + pageNumber: '1' ) notary_sign_here = DocuSign_eSign::SignHere.new( xPosition: '300', yPosition: '150', documentId: '1', - pageNumber: '1', + pageNumber: '1' ) notary_tabs = DocuSign_eSign::Tabs.new( From 123bc4884899c71955602666c847a1d6f1d5bbbd Mon Sep 17 00:00:00 2001 From: nianiB9 Date: Wed, 26 Feb 2025 13:53:48 -0600 Subject: [PATCH 349/363] notary example update --- .../eg004_send_with_third_party_notary_service.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/services/notary/eg004_send_with_third_party_notary_service.rb b/app/services/notary/eg004_send_with_third_party_notary_service.rb index c9d36b5..c939d12 100644 --- a/app/services/notary/eg004_send_with_third_party_notary_service.rb +++ b/app/services/notary/eg004_send_with_third_party_notary_service.rb @@ -9,9 +9,9 @@ def initialize(args) @args = args end - #ds-snippet-start:Notary4Step3 def worker # Create the envelope request object + #ds-snippet-start:Notary4Step4 envelope_definition = make_envelope args[:envelope_args] # Call Envelopes::create API method # Exceptions will be caught by the calling function @@ -20,12 +20,12 @@ def worker results = envelope_api.create_envelope args[:account_id], envelope_definition envelope_id = results.envelope_id { 'envelope_id' => envelope_id } + #ds-snippet-end:Notary4Step4 end - #ds-snippet-end:Notary4Step3 private - #ds-snippet-start:Notary4Step2 + #ds-snippet-start:Notary4Step3 def make_envelope(envelope_args) # The envelope has two recipients: # recipient 1 - notary @@ -104,7 +104,6 @@ def make_envelope(envelope_args) ) notary_recipient = DocuSign_eSign::NotaryRecipient.new( - email: '', name: 'Notary', recipientId: '1', routingOrder: '1', @@ -132,5 +131,5 @@ def make_envelope(envelope_args) envelope_definition.status = 'sent' envelope_definition end - #ds-snippet-end:Notary4Step2 -end + #ds-snippet-end:Notary4Step3 +end \ No newline at end of file From bf75c1e5c7e44f6aeb8c6ebc69b853ee77133d7e Mon Sep 17 00:00:00 2001 From: nianiB9 Date: Wed, 26 Feb 2025 13:58:23 -0600 Subject: [PATCH 350/363] linter fix --- .../notary/eg004_send_with_third_party_notary_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/notary/eg004_send_with_third_party_notary_service.rb b/app/services/notary/eg004_send_with_third_party_notary_service.rb index c939d12..074b8cc 100644 --- a/app/services/notary/eg004_send_with_third_party_notary_service.rb +++ b/app/services/notary/eg004_send_with_third_party_notary_service.rb @@ -132,4 +132,4 @@ def make_envelope(envelope_args) envelope_definition end #ds-snippet-end:Notary4Step3 -end \ No newline at end of file +end From 47cbb9d75c3946d279018062cdcdc81ffe71ae48 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Tue, 1 Apr 2025 21:12:23 +0300 Subject: [PATCH 351/363] Add Connected fields code example (#186) * add code example * code style fixes --- Gemfile | 4 +- Gemfile.lock | 6 +- app/assets/javascripts/search.js | 5 +- .../feg001_set_connected_fields_controller.rb | 56 ++++++ .../eg001_set_connected_fields_service.rb | 174 ++++++++++++++++++ app/services/jwt_auth/jwt_creator.rb | 5 + .../feg001_set_connected_fields/get.html.erb | 36 ++++ app/views/ds_common/index.html.erb | 2 + config/initializers/omniauth.rb | 2 + config/routes.rb | 5 + 10 files changed, 289 insertions(+), 6 deletions(-) create mode 100644 app/controllers/connected_fields/feg001_set_connected_fields_controller.rb create mode 100644 app/services/connected_fields/eg001_set_connected_fields_service.rb create mode 100644 app/views/connected_fields/feg001_set_connected_fields/get.html.erb diff --git a/Gemfile b/Gemfile index 215f112..d5fe708 100644 --- a/Gemfile +++ b/Gemfile @@ -68,12 +68,12 @@ group :test do gem 'test-unit' end -gem 'docusign_admin', '~> 2.0.0.rc2' +gem 'docusign_admin', '~> 2.0.0' gem 'docusign_click', '~> 1.4.0' gem 'docusign_esign', '~> 5.0.0' gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' -gem 'docusign_webforms', '~> 1.0.0' +gem 'docusign_webforms', '~> 2.0.0' gem 'omniauth-oauth2', '~> 1.8.0' gem 'omniauth-rails_csrf_protection' diff --git a/Gemfile.lock b/Gemfile.lock index 1b25084..4fa0735 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -134,7 +134,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_webforms (1.0.0) + docusign_webforms (2.0.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -392,12 +392,12 @@ DEPENDENCIES capybara (~> 3.40.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_admin (~> 2.0.0.rc2) + docusign_admin (~> 2.0.0) docusign_click (~> 1.4.0) docusign_esign (~> 5.0.0) docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) - docusign_webforms (~> 1.0.0) + docusign_webforms (~> 2.0.0) jbuilder (~> 2.13.0) listen (~> 3.9.0) matrix (~> 0.4.2) diff --git a/app/assets/javascripts/search.js b/app/assets/javascripts/search.js index 8014fa7..c539995 100644 --- a/app/assets/javascripts/search.js +++ b/app/assets/javascripts/search.js @@ -7,7 +7,8 @@ const DS_SEARCH = (function () { ADMIN: "admin", CONNECT: "connect", WEBFORMS: "webforms", - NOTARY: "notary" + NOTARY: "notary", + CONNECTED_FIELDS: "connectedfields" } const processJSONData = function () { @@ -148,6 +149,8 @@ const DS_SEARCH = (function () { return "weg"; case API_TYPES.NOTARY: return "neg"; + case API_TYPES.CONNECTED_FIELDS: + return "feg"; } } diff --git a/app/controllers/connected_fields/feg001_set_connected_fields_controller.rb b/app/controllers/connected_fields/feg001_set_connected_fields_controller.rb new file mode 100644 index 0000000..954dec8 --- /dev/null +++ b/app/controllers/connected_fields/feg001_set_connected_fields_controller.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require_relative '../../services/utils' + +class ConnectedFields::Feg001SetConnectedFieldsController < EgController + before_action -> { check_auth('ConnectedFields') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 1, 'ConnectedFields') } + + def get + super + args = { + account_id: session['ds_account_id'], + access_token: session['ds_access_token'], + extensions_base_path: 'https://api-d.docusign.com' + } + + example_service = ConnectedFields::Eg001SetConnectedFieldsService.new(args) + @apps = example_service.get_tab_groups + + return unless @apps.nil? || @apps.empty? + + additional_page_data = example['AdditionalPage'].find { |p| p['Name'] == 'no_verification_app' } + + @title = @example['ExampleName'] + @message = additional_page_data['ResultsPageText'] + render 'ds_common/example_done' + end + + def create + envelope_args = { + signer_email: param_gsub(params['signerEmail']), + signer_name: param_gsub(params['signerName']), + doc_pdf: File.join('data', Rails.application.config.doc_pdf) + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + extensions_base_path: 'https://api-d.docusign.com', + access_token: session['ds_access_token'], + selected_app_id: param_gsub(params['appId']), + envelope_args: envelope_args + } + + example_service = ConnectedFields::Eg001SetConnectedFieldsService.new(args) + apps = example_service.get_tab_groups + selected_app = apps.find { |app| app['appId'] == args[:selected_app_id] } + + results = example_service.send_envelope selected_app + session[:envelope_id] = results['envelope_id'] + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results['envelope_id']) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end +end diff --git a/app/services/connected_fields/eg001_set_connected_fields_service.rb b/app/services/connected_fields/eg001_set_connected_fields_service.rb new file mode 100644 index 0000000..bc22b9a --- /dev/null +++ b/app/services/connected_fields/eg001_set_connected_fields_service.rb @@ -0,0 +1,174 @@ +# frozen_string_literal: true + +class ConnectedFields::Eg001SetConnectedFieldsService + attr_reader :args + + include ApiCreator + + def initialize(args) + @args = args + end + + def get_tab_groups + #ds-snippet-start:ConnectedFields1Step2 + headers = { + 'Authorization' => "Bearer #{args[:access_token]}", + 'Accept' => 'application/json', + 'Content-Type' => 'application/json' + } + #ds-snippet-end:ConnectedFields1Step2 + + #ds-snippet-start:ConnectedFields1Step3 + url = URI("#{args[:extensions_base_path]}/v1/accounts/#{args[:account_id]}/connected-fields/tab-groups") + response = Net::HTTP.get_response(url, headers) + response_data = JSON.parse(response.body) + + filtered_apps = response_data.select do |app| + app['tabs']&.any? do |tab| + (tab['extensionData']&.dig('actionContract')&.include? 'Verify') || + (tab['tabLabel']&.include? 'connecteddata') + end + end + + # return unique apps + filtered_apps.uniq { |app| app['appId'] } + #ds-snippet-end:ConnectedFields1Step3 + end + + #ds-snippet-start:ConnectedFields1Step4 + def extract_verification_data(selected_app_id, tab) + extension_data = tab['extensionData'] + + { + app_id: selected_app_id, + extension_group_id: extension_data['extensionGroupId'], + publisher_name: extension_data['publisherName'], + application_name: extension_data['applicationName'], + action_name: extension_data['actionName'], + action_input_key: extension_data['actionInputKey'], + action_contract: extension_data['actionContract'], + extension_name: extension_data['extensionName'], + extension_contract: extension_data['extensionContract'], + required_for_extension: extension_data['requiredForExtension'], + tab_label: tab['tabLabel'], + connection_key: extension_data['connectionInstances']&.dig(0, 'connectionKey') || '', + connection_value: extension_data['connectionInstances']&.dig(0, 'connectionValue') || '' + } + end + #ds-snippet-end:ConnectedFields1Step4 + + def send_envelope(app) + # Create the envelope definition + #ds-snippet-start:ConnectedFields1Step6 + envelope = make_envelope args[:envelope_args], app + + # Call Docusign to create the envelope + envelope_api = create_envelope_api(args) + + results = envelope_api.create_envelope args[:account_id], envelope + + { 'envelope_id' => results.envelope_id } + #ds-snippet-end:ConnectedFields1Step6 + end + + private + + #ds-snippet-start:ConnectedFields1Step5 + def make_envelope(envelope_args, app) + doc = DocuSign_eSign::Document.new + doc.document_base64 = Base64.encode64(File.binread(envelope_args[:doc_pdf])) + doc.name = 'Lorem Ipsum' + doc.file_extension = 'pdf' + doc.document_id = '1' + + # The order in the docs array determines the order in the envelope + # Create a signer recipient to sign the document, identified by name and email + # We're setting the parameters via the object creation + signer = DocuSign_eSign::Signer.new + signer.email = envelope_args[:signer_email] + signer.name = envelope_args[:signer_name] + signer.recipient_id = 1 + + # The Docusign platform searches throughout your envelope's documents for matching + # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 + # since they use the same anchor string for their "signer 1" tabs. + sign_here = DocuSign_eSign::SignHere.new + sign_here.anchor_string = '/sn1/' + sign_here.anchor_units = 'pixels' + sign_here.anchor_x_offset = '20' + sign_here.anchor_y_offset = '10' + + text_tabs = [] + app['tabs'].each do |tab| + next if tab['tabLabel'].include?('SuggestionInput') + + verification_data = extract_verification_data(app['appId'], tab) + text_tabs.push(text_tab(verification_data, text_tabs.length)) + end + + tabs = DocuSign_eSign::Tabs.new + tabs.sign_here_tabs = [sign_here] + tabs.text_tabs = text_tabs + signer.tabs = tabs + + recipients = DocuSign_eSign::Recipients.new + recipients.signers = [signer] + + envelope_definition = DocuSign_eSign::EnvelopeDefinition.new + envelope_definition.email_subject = 'Please sign this document' + envelope_definition.documents = [doc] + envelope_definition.recipients = recipients + envelope_definition.status = 'sent' + envelope_definition + end + + def extension_data(verification_data) + { + extensionGroupId: verification_data[:extension_group_id], + publisherName: verification_data[:publisher_name], + applicationId: verification_data[:app_id], + applicationName: verification_data[:application_name], + actionName: verification_data[:action_name], + actionContract: verification_data[:action_contract], + extensionName: verification_data[:extension_name], + extensionContract: verification_data[:extension_contract], + requiredForExtension: verification_data[:required_for_extension], + actionInputKey: verification_data[:action_input_key], + extensionPolicy: 'MustVerifyToSign', + connectionInstances: [ + { + connectionKey: verification_data[:connection_key], + connectionValue: verification_data[:connection_value] + } + ] + } + end + + def text_tab(verification_data, text_tabs_count) + { + requireInitialOnSharedChange: false, + requireAll: false, + name: verification_data[:application_name], + required: true, + locked: false, + disableAutoSize: false, + maxLength: 4000, + tabLabel: verification_data[:tab_label], + font: 'lucidaconsole', + fontColor: 'black', + fontSize: 'size9', + documentId: '1', + recipientId: '1', + pageNumber: '1', + xPosition: (70 + 100 * (text_tabs_count / 10)).to_s, + yPosition: (560 + 20 * (text_tabs_count % 10)).to_s, + width: '84', + height: '22', + templateRequired: false, + tabType: 'text', + tooltip: verification_data[:action_input_key], + extensionData: extension_data(verification_data) + } + end + #ds-snippet-end:ConnectedFields1Step5 +end diff --git a/app/services/jwt_auth/jwt_creator.rb b/app/services/jwt_auth/jwt_creator.rb index 911f221..a0853d9 100644 --- a/app/services/jwt_auth/jwt_creator.rb +++ b/app/services/jwt_auth/jwt_creator.rb @@ -19,6 +19,7 @@ def self.consent_url(state, api) scope = 'signature impersonation organization_read group_read permission_read user_read user_write 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_write organization_sub_account_read' if api == 'Admin' scope = 'signature webforms_read webforms_instance_read webforms_instance_write' if api == 'WebForms' scope = 'signature organization_read notary_read notary_write' if api == 'Notary' + scope = 'signature adm_store_unified_repo_read' if api == 'ConnectedFields' base_uri = "#{Rails.configuration.authorization_server}/oauth/auth" response_type = 'code' @@ -55,6 +56,10 @@ def initialize(session) scope = 'signature organization_read notary_read notary_write' @client_module = DocuSign_eSign end + if session[:api] == 'ConnectedFields' + scope = 'signature adm_store_unified_repo_read' + @client_module = DocuSign_eSign + end @scope = scope @api_client = create_initial_api_client(host: Rails.configuration.aud, client_module: @client_module, debugging: false) diff --git a/app/views/connected_fields/feg001_set_connected_fields/get.html.erb b/app/views/connected_fields/feg001_set_connected_fields/get.html.erb new file mode 100644 index 0000000..cd55915 --- /dev/null +++ b/app/views/connected_fields/feg001_set_connected_fields/get.html.erb @@ -0,0 +1,36 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% signer_email_index = 0 %> +<% signer_name_index = 1 %> +<% app_index = 2 %> + +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + " required + value="<%= @config.signer_email %>"> + <%= render('partials/email_will_not_be_shared') %> +
    +
    + + " name="signerName" + value="<%= @config.signer_name %>" required> +
    +
    + + +
    + <%= render('partials/submit_button') %> + \ No newline at end of file diff --git a/app/views/ds_common/index.html.erb b/app/views/ds_common/index.html.erb index da7e2ca..6e094c1 100644 --- a/app/views/ds_common/index.html.erb +++ b/app/views/ds_common/index.html.erb @@ -57,6 +57,8 @@ "w" elsif api["Name"] == "Notary" "n" + elsif api["Name"] == "ConnectedFields" + "f" else "e" end %> diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 0731c69..31c74ef 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -56,6 +56,8 @@ strategy.options[:authorize_params].scope = 'signature webforms_read webforms_instance_read webforms_instance_write' when 'Notary' strategy.options[:authorize_params].scope = 'signature organization_read notary_read notary_write' + when 'ConnectedFields' + strategy.options[:authorize_params].scope = 'signature adm_store_unified_repo_read' end } end diff --git a/config/routes.rb b/config/routes.rb index 11dff34..54d12f5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -250,6 +250,11 @@ post 'neg004' => 'neg004_send_with_third_party_notary#create' end + scope module: 'connected_fields' do + get 'feg001' => 'feg001_set_connected_fields#get' + post 'feg001' => 'feg001_set_connected_fields#create' + end + root 'ds_common#index' # Login starts with POST'ing to: /auth/docusign From 607fe3a17b15a0851f1b1f298dd6e39ceab6784d Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware <77355790+RomanBachaloSigmaSoftware@users.noreply.github.com> Date: Fri, 9 May 2025 01:00:29 +0300 Subject: [PATCH 352/363] Fix rooms and monitor examples (#187) * fix examples --- .../eg001_get_monitoring_dataset_service.rb | 2 +- app/services/room_api/get_data_service.rb | 186 +++++++++--------- 2 files changed, 94 insertions(+), 94 deletions(-) diff --git a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb index ba7a12d..26907e0 100644 --- a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb +++ b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb @@ -19,7 +19,7 @@ def worker #ds-snippet-start:Monitor1Step3 monitor_api = DocuSign_Monitor::DataSetApi.new(api_client) begin - cursor_date = Date.today.prev_year + cursor_date = Date.today.prev_day cursor_value = cursor_date.strftime('%Y-%m-%dT00:00:00Z') limit = 2000 function_results = [] diff --git a/app/services/room_api/get_data_service.rb b/app/services/room_api/get_data_service.rb index 473be8c..2854333 100644 --- a/app/services/room_api/get_data_service.rb +++ b/app/services/room_api/get_data_service.rb @@ -1,93 +1,93 @@ -# frozen_string_literal: true - -class RoomApi::GetDataService - attr_reader :args - - def initialize(session, options = {}) - @args = { - account_id: session[:ds_account_id], - base_path: session[:ds_base_path], - access_token: session[:ds_access_token], - room_id: options - } - end - - def get_offices - worker - - #ds-snippet-start:Rooms8Step3 - offices_api = DocuSign_Rooms::OfficesApi.new(@api_client) - offices = offices_api.get_offices(args[:account_id]) - offices.as_json['officeSummaries'] - #ds-snippet-end:Rooms8Step3 - end - - def get_default_admin_role_id - worker - - roles_api = DocuSign_Rooms::RolesApi.new(@api_client) - roles = roles_api.get_roles(args[:account_id]).as_json['roles'] - default_admin_role = roles.find { |role| role['name'] == 'Default Admin' } - default_admin_role['roleId'] - end - - def get_rooms - worker - - rooms_api = DocuSign_Rooms::RoomsApi.new(@api_client) - rooms = rooms_api.get_rooms(args[:account_id]) - rooms.as_json['rooms'] - end - - def get_templates - worker - - templates_api = DocuSign_Rooms::RoomTemplatesApi.new(@api_client) - templates = templates_api.get_room_templates(args[:account_id]) - templates.as_json['roomTemplates'] - end - - def get_form_libraries - worker - - form_libraries_api = DocuSign_Rooms::FormLibrariesApi.new(@api_client) - begin - form_libraries = form_libraries_api.get_form_libraries(args[:account_id]) - rescue Exception - return - end - - form_libraries_id = form_libraries.as_json['formsLibrarySummaries'].first['formsLibraryId'] - - forms_api = DocuSign_Rooms::FormLibrariesApi.new(@api_client) - forms = forms_api.get_form_library_forms(form_libraries_id, args[:account_id]) - forms.as_json['forms'] - end - - def get_forms_from_room - worker - - room_forms_api = DocuSign_Rooms::RoomsApi.new(@api_client) - forms = room_forms_api.get_documents(args[:room_id], args[:account_id]) - forms.as_json['documents'] - end - - def get_form_groups - worker - - #ds-snippet-start:Rooms8Step4 - form_groups_api = DocuSign_Rooms::FormGroupsApi.new(@api_client) - form_groups = form_groups_api.get_form_groups(args[:account_id]) - form_groups.as_json['formGroups'] - #ds-snippet-end:Rooms8Step4 - end - - private - - def worker - configuration = DocuSign_Rooms::Configuration.new - configuration.host = 'https://demo.rooms.docusign.com/restapi' - @api_client = DocuSign_Rooms::ApiClient.new(configuration) - @api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - end -end +# frozen_string_literal: true + +class RoomApi::GetDataService + attr_reader :args + + def initialize(session, options = {}) + @args = { + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token], + room_id: options + } + end + + def get_offices + worker + + #ds-snippet-start:Rooms8Step3 + offices_api = DocuSign_Rooms::OfficesApi.new(@api_client) + offices = offices_api.get_offices(args[:account_id]) + offices.as_json['officeSummaries'] + #ds-snippet-end:Rooms8Step3 + end + + def get_default_admin_role_id + worker + + roles_api = DocuSign_Rooms::RolesApi.new(@api_client) + roles = roles_api.get_roles(args[:account_id]).as_json['roles'] + default_admin_role = roles.find { |role| role['name'] == 'Default Admin' } + default_admin_role['roleId'] + end + + def get_rooms + worker + + rooms_api = DocuSign_Rooms::RoomsApi.new(@api_client) + rooms = rooms_api.get_rooms(args[:account_id]) + rooms.as_json['rooms'] + end + + def get_templates + worker + + templates_api = DocuSign_Rooms::RoomTemplatesApi.new(@api_client) + templates = templates_api.get_room_templates(args[:account_id]) + templates.as_json['roomTemplates'] + end + + def get_form_libraries + worker + + form_libraries_api = DocuSign_Rooms::FormLibrariesApi.new(@api_client) + begin + form_libraries = form_libraries_api.get_form_libraries(args[:account_id]) + rescue Exception + return + end + + form_libraries_id = form_libraries.as_json['formsLibrarySummaries'].find { |lib| lib['formCount'].positive? }['formsLibraryId'] + + forms_api = DocuSign_Rooms::FormLibrariesApi.new(@api_client) + forms = forms_api.get_form_library_forms(form_libraries_id, args[:account_id]) + forms.as_json['forms'] + end + + def get_forms_from_room + worker + + room_forms_api = DocuSign_Rooms::RoomsApi.new(@api_client) + forms = room_forms_api.get_documents(args[:room_id], args[:account_id]) + forms.as_json['documents'] + end + + def get_form_groups + worker + + #ds-snippet-start:Rooms8Step4 + form_groups_api = DocuSign_Rooms::FormGroupsApi.new(@api_client) + form_groups = form_groups_api.get_form_groups(args[:account_id]) + form_groups.as_json['formGroups'] + #ds-snippet-end:Rooms8Step4 + end + + private + + def worker + configuration = DocuSign_Rooms::Configuration.new + configuration.host = 'https://demo.rooms.docusign.com/restapi' + @api_client = DocuSign_Rooms::ApiClient.new(configuration) + @api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + end +end From 502cd58b20ce76d37e862e1f9129457fd83b813e Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Tue, 20 May 2025 17:17:49 -0700 Subject: [PATCH 353/363] Update README.md Signed-off-by: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 5cc4fd5..ca83b49 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,14 @@ > ### GitHub repo: [code-examples-ruby](./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](#installation-steps)**–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/). @@ -132,6 +140,22 @@ Also, in order to select JSON Web Token authentication in the launcher, in confi ## JWT grant remote signing and Authorization Code Grant embedded signing projects 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 and the Authorization Code Grant embedded signing project. +### Authorization Code Grant embedded signing example: +Run in Git Bash: +``` +$ cd /quick_acg +$ bundler install +$ rails s +``` + +Open a browser to http://localhost:3000 + +### JWT grant remote signing example: +Run in Windows Command Prompt (CMD): +``` +$ cd jwt_console_project +$ ruby jwt_console.rb +``` ### Troubleshooting Windows SSL issue When using the Ruby launcher on a Windows machine you may get the following error: From db450779279717a20c5395bedfaa6c9b69be0dcd Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Tue, 10 Jun 2025 13:59:39 +0300 Subject: [PATCH 354/363] updated packages --- Gemfile | 12 +-- Gemfile.lock | 42 +++++---- jwt_console_project/jwt_console.rb | 2 +- quick_acg/Gemfile | 12 +-- quick_acg/Gemfile.lock | 145 +++++++++++++++-------------- 5 files changed, 110 insertions(+), 103 deletions(-) diff --git a/Gemfile b/Gemfile index d5fe708..086d6d7 100644 --- a/Gemfile +++ b/Gemfile @@ -44,7 +44,7 @@ end group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console - gem 'byebug', '~> 11.1.3', platforms: %i[mri mingw x64_mingw] + gem 'byebug', '~> 12.0.0', platforms: %i[mri mingw x64_mingw] end group :development do @@ -54,8 +54,8 @@ group :development do # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'pry-nav', '~> 1.0.0' gem 'pry-rails', '~> 0.3.11' - gem 'rubocop', '~> 1.71.0', require: false - gem 'spring', '~> 4.2.1' + gem 'rubocop', '~> 1.75.8', require: false + gem 'spring', '~> 4.3.0' gem 'spring-watcher-listen', '~> 2.1.0' end @@ -70,7 +70,7 @@ end gem 'docusign_admin', '~> 2.0.0' gem 'docusign_click', '~> 1.4.0' -gem 'docusign_esign', '~> 5.0.0' +gem 'docusign_esign', '~> 5.1.0' gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' gem 'docusign_webforms', '~> 2.0.0' @@ -79,5 +79,5 @@ gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'matrix', '~> 0.4.2' -gem 'tzinfo-data', '~> 1.2022.7', '>= 1.2022.7' -gem 'wdm', '>= 0.1.1', platforms: %i[mingw mswin x64_mingw] +gem 'tzinfo-data', '~> 1.2025.2' +gem 'wdm', '>= 0.2.0', platforms: %i[mingw mswin x64_mingw] diff --git a/Gemfile.lock b/Gemfile.lock index 4fa0735..86d9605 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -76,7 +76,7 @@ GEM public_suffix (>= 2.0.2, < 7.0) archive-zip (0.12.0) io-like (~> 0.3.0) - ast (2.4.2) + ast (2.4.3) base64 (0.2.0) benchmark (0.4.0) bigdecimal (3.1.9) @@ -84,7 +84,7 @@ GEM bootsnap (1.7.7) msgpack (~> 1.0) builder (3.3.0) - byebug (11.1.3) + byebug (12.0.0) capybara (3.40.0) addressable matrix @@ -119,7 +119,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_esign (5.0.0) + docusign_esign (5.1.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -169,7 +169,8 @@ GEM json (2.9.1) jwt (2.10.1) base64 - language_server-protocol (3.17.0.4) + language_server-protocol (3.17.0.5) + lint_roller (1.1.0) listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) @@ -223,14 +224,15 @@ GEM omniauth-rails_csrf_protection (1.0.2) actionpack (>= 4.2) omniauth (~> 2.0) - parallel (1.26.3) - parser (3.3.7.0) + parallel (1.27.0) + parser (3.3.8.0) ast (~> 2.4.1) racc power_assert (2.0.5) pp (0.6.2) prettyprint prettyprint (0.2.0) + prism (1.4.0) pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) @@ -297,18 +299,20 @@ GEM reline (0.6.0) io-console (~> 0.5) rexml (3.4.0) - rubocop (1.71.0) + rubocop (1.75.8) json (~> 2.3) - language_server-protocol (>= 3.17.0) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 2.9.3, < 3.0) - rubocop-ast (>= 1.36.2, < 2.0) + rubocop-ast (>= 1.44.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.38.0) - parser (>= 3.3.1.0) + rubocop-ast (1.44.1) + parser (>= 3.3.7.2) + prism (~> 1.4) ruby-progressbar (1.13.0) rubyzip (2.4.1) sass-rails (6.0.0) @@ -331,7 +335,7 @@ GEM snaky_hash (2.0.1) hashie version_gem (~> 1.1, >= 1.1.1) - spring (4.2.1) + spring (4.3.0) spring-watcher-listen (2.1.0) listen (>= 2.7, < 4.0) spring (>= 4) @@ -357,7 +361,7 @@ GEM ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - tzinfo-data (1.2022.7) + tzinfo-data (1.2025.2) tzinfo (>= 1.0.0) uglifier (4.2.1) execjs (>= 0.3.0, < 3) @@ -388,13 +392,13 @@ PLATFORMS DEPENDENCIES bootsnap (~> 1.7.3) - byebug (~> 11.1.3) + byebug (~> 12.0.0) capybara (~> 3.40.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) docusign_admin (~> 2.0.0) docusign_click (~> 1.4.0) - docusign_esign (~> 5.0.0) + docusign_esign (~> 5.1.0) docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) docusign_webforms (~> 2.0.0) @@ -407,17 +411,17 @@ DEPENDENCIES pry-rails (~> 0.3.11) puma (~> 6.6.0) rails (~> 7.2.2.1) - rubocop (~> 1.71.0) + rubocop (~> 1.75.8) sass-rails (~> 6.0.0) selenium-webdriver (~> 4.25.0) - spring (~> 4.2.1) + spring (~> 4.3.0) spring-watcher-listen (~> 2.1.0) sqlite3 (~> 2.1.1) test-unit turbolinks (~> 5.2.1) - tzinfo-data (~> 1.2022.7, >= 1.2022.7) + tzinfo-data (~> 1.2025.2) uglifier (~> 4.2.1) - wdm (>= 0.1.1) + wdm (>= 0.2.0) web-console (~> 4.2.1) RUBY VERSION diff --git a/jwt_console_project/jwt_console.rb b/jwt_console_project/jwt_console.rb index 1d61d1e..19326da 100644 --- a/jwt_console_project/jwt_console.rb +++ b/jwt_console_project/jwt_console.rb @@ -2,7 +2,7 @@ gemfile do source 'https://rubygems.org' - gem 'docusign_esign', ' ~> 5.0.0' + gem 'docusign_esign', ' ~> 5.1.0' end class ESign diff --git a/quick_acg/Gemfile b/quick_acg/Gemfile index cb0ebbc..96c931e 100644 --- a/quick_acg/Gemfile +++ b/quick_acg/Gemfile @@ -6,11 +6,11 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '~>3.1.2' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 7.2.1.1' +gem 'rails', '~> 7.2.2.1' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 2.1.1' # Use Puma as the app server -gem 'puma', '~> 6.4.3' +gem 'puma', '~> 6.6.0' # Use SCSS for stylesheets gem 'sass-rails', '~> 6.0.0' # Use Uglifier as compressor for JavaScript assets @@ -54,7 +54,7 @@ group :development do # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'pry-nav', '~> 1.0.0' gem 'pry-rails', '~> 0.3.11' - gem 'spring', '~> 4.2.1' + gem 'spring', '~> 4.3.0' gem 'spring-watcher-listen', '~> 2.1.0' end @@ -67,10 +67,10 @@ group :test do gem 'test-unit' end -gem 'docusign_esign', '~> 5.0.0' +gem 'docusign_esign', '~> 5.1.0' gem 'omniauth-oauth2', '~> 1.8.0' gem 'omniauth-rails_csrf_protection' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem 'tzinfo-data', '~> 1.2022.7', '>= 1.2022.7' -gem 'wdm', '>= 0.1.1', platforms: %i[mingw mswin x64_mingw] +gem 'tzinfo-data', '~> 1.2025.2' +gem 'wdm', '>= 0.2.0', platforms: %i[mingw mswin x64_mingw] diff --git a/quick_acg/Gemfile.lock b/quick_acg/Gemfile.lock index 4b67c06..433bbbf 100644 --- a/quick_acg/Gemfile.lock +++ b/quick_acg/Gemfile.lock @@ -1,29 +1,29 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.2.1.1) - actionpack (= 7.2.1.1) - activesupport (= 7.2.1.1) + actioncable (7.2.2.1) + actionpack (= 7.2.2.1) + activesupport (= 7.2.2.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.2.1.1) - actionpack (= 7.2.1.1) - activejob (= 7.2.1.1) - activerecord (= 7.2.1.1) - activestorage (= 7.2.1.1) - activesupport (= 7.2.1.1) + actionmailbox (7.2.2.1) + actionpack (= 7.2.2.1) + activejob (= 7.2.2.1) + activerecord (= 7.2.2.1) + activestorage (= 7.2.2.1) + activesupport (= 7.2.2.1) mail (>= 2.8.0) - actionmailer (7.2.1.1) - actionpack (= 7.2.1.1) - actionview (= 7.2.1.1) - activejob (= 7.2.1.1) - activesupport (= 7.2.1.1) + actionmailer (7.2.2.1) + actionpack (= 7.2.2.1) + actionview (= 7.2.2.1) + activejob (= 7.2.2.1) + activesupport (= 7.2.2.1) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.2.1.1) - actionview (= 7.2.1.1) - activesupport (= 7.2.1.1) + actionpack (7.2.2.1) + actionview (= 7.2.2.1) + activesupport (= 7.2.2.1) nokogiri (>= 1.8.5) racc rack (>= 2.2.4, < 3.2) @@ -32,36 +32,37 @@ GEM rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (7.2.1.1) - actionpack (= 7.2.1.1) - activerecord (= 7.2.1.1) - activestorage (= 7.2.1.1) - activesupport (= 7.2.1.1) + actiontext (7.2.2.1) + actionpack (= 7.2.2.1) + activerecord (= 7.2.2.1) + activestorage (= 7.2.2.1) + activesupport (= 7.2.2.1) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.2.1.1) - activesupport (= 7.2.1.1) + actionview (7.2.2.1) + activesupport (= 7.2.2.1) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.2.1.1) - activesupport (= 7.2.1.1) + activejob (7.2.2.1) + activesupport (= 7.2.2.1) globalid (>= 0.3.6) - activemodel (7.2.1.1) - activesupport (= 7.2.1.1) - activerecord (7.2.1.1) - activemodel (= 7.2.1.1) - activesupport (= 7.2.1.1) + activemodel (7.2.2.1) + activesupport (= 7.2.2.1) + activerecord (7.2.2.1) + activemodel (= 7.2.2.1) + activesupport (= 7.2.2.1) timeout (>= 0.4.0) - activestorage (7.2.1.1) - actionpack (= 7.2.1.1) - activejob (= 7.2.1.1) - activerecord (= 7.2.1.1) - activesupport (= 7.2.1.1) + activestorage (7.2.2.1) + actionpack (= 7.2.2.1) + activejob (= 7.2.2.1) + activerecord (= 7.2.2.1) + activesupport (= 7.2.2.1) marcel (~> 1.0) - activesupport (7.2.1.1) + activesupport (7.2.2.1) base64 + benchmark (>= 0.3) bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) @@ -76,6 +77,7 @@ GEM archive-zip (0.12.0) io-like (~> 0.3.0) base64 (0.2.0) + benchmark (0.4.1) bigdecimal (3.1.7) bindex (0.8.1) bootsnap (1.7.7) @@ -105,8 +107,8 @@ GEM concurrent-ruby (1.3.4) connection_pool (2.4.1) crass (1.0.6) - date (3.3.4) - docusign_esign (5.0.0) + date (3.4.1) + docusign_esign (5.1.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -134,7 +136,7 @@ GEM jbuilder (2.13.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) - json (2.7.2) + json (2.12.2) jwt (2.8.1) base64 listen (3.9.0) @@ -158,16 +160,16 @@ GEM multi_xml (0.6.0) net-http (0.4.1) uri - net-imap (0.5.0) + net-imap (0.5.8) date net-protocol net-pop (0.1.2) net-protocol net-protocol (0.2.2) timeout - net-smtp (0.5.0) + net-smtp (0.5.1) net-protocol - nio4r (2.7.3) + nio4r (2.7.4) nokogiri (1.16.4-x64-mingw-ucrt) racc (~> 1.4) oauth2 (2.0.9) @@ -198,7 +200,7 @@ GEM psych (5.1.2) stringio public_suffix (5.0.5) - puma (6.4.3) + puma (6.6.0) nio4r (~> 2.0) racc (1.7.3) rack (3.0.10) @@ -212,20 +214,20 @@ GEM rackup (2.1.0) rack (>= 3) webrick (~> 1.8) - rails (7.2.1.1) - actioncable (= 7.2.1.1) - actionmailbox (= 7.2.1.1) - actionmailer (= 7.2.1.1) - actionpack (= 7.2.1.1) - actiontext (= 7.2.1.1) - actionview (= 7.2.1.1) - activejob (= 7.2.1.1) - activemodel (= 7.2.1.1) - activerecord (= 7.2.1.1) - activestorage (= 7.2.1.1) - activesupport (= 7.2.1.1) + rails (7.2.2.1) + actioncable (= 7.2.2.1) + actionmailbox (= 7.2.2.1) + actionmailer (= 7.2.2.1) + actionpack (= 7.2.2.1) + actiontext (= 7.2.2.1) + actionview (= 7.2.2.1) + activejob (= 7.2.2.1) + activemodel (= 7.2.2.1) + activerecord (= 7.2.2.1) + activestorage (= 7.2.2.1) + activesupport (= 7.2.2.1) bundler (>= 1.15.0) - railties (= 7.2.1.1) + railties (= 7.2.2.1) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -233,9 +235,9 @@ GEM rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) - railties (7.2.1.1) - actionpack (= 7.2.1.1) - activesupport (= 7.2.1.1) + railties (7.2.2.1) + actionpack (= 7.2.2.1) + activesupport (= 7.2.2.1) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) @@ -272,7 +274,7 @@ GEM snaky_hash (2.0.1) hashie version_gem (~> 1.1, >= 1.1.1) - spring (4.2.1) + spring (4.3.0) spring-watcher-listen (2.1.0) listen (>= 2.7, < 4.0) spring (>= 4) @@ -289,7 +291,7 @@ GEM power_assert thor (1.3.1) tilt (2.3.0) - timeout (0.4.1) + timeout (0.4.3) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) @@ -297,14 +299,14 @@ GEM ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - tzinfo-data (1.2022.7) + tzinfo-data (1.2025.2) tzinfo (>= 1.0.0) uglifier (4.2.1) execjs (>= 0.3.0, < 3) uri (0.13.0) useragent (0.16.10) version_gem (1.1.4) - wdm (0.1.1) + wdm (0.2.0) web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -312,7 +314,8 @@ GEM railties (>= 6.0.0) webrick (1.8.1) websocket (1.2.11) - websocket-driver (0.7.6) + websocket-driver (0.8.0) + base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) @@ -328,25 +331,25 @@ DEPENDENCIES capybara (~> 3.40.0) chromedriver-helper (~> 2.1.1) coffee-rails (~> 5.0.0) - docusign_esign (~> 5.0.0) + docusign_esign (~> 5.1.0) jbuilder (~> 2.13.0) listen (~> 3.9.0) omniauth-oauth2 (~> 1.8.0) omniauth-rails_csrf_protection pry-nav (~> 1.0.0) pry-rails (~> 0.3.11) - puma (~> 6.4.3) - rails (~> 7.2.1.1) + puma (~> 6.6.0) + rails (~> 7.2.2.1) sass-rails (~> 6.0.0) selenium-webdriver (~> 4.25.0) - spring (~> 4.2.1) + spring (~> 4.3.0) spring-watcher-listen (~> 2.1.0) sqlite3 (~> 2.1.1) test-unit turbolinks (~> 5.2.1) - tzinfo-data (~> 1.2022.7, >= 1.2022.7) + tzinfo-data (~> 1.2025.2) uglifier (~> 4.2.1) - wdm (>= 0.1.1) + wdm (>= 0.2.0) web-console (~> 4.2.1) RUBY VERSION From 3aafd4447d6dc65327624a6767dc9948bf20ea7f Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Tue, 10 Jun 2025 15:43:57 +0300 Subject: [PATCH 355/363] fix linter error --- app/helpers/application_helper.rb | 34 +++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 765de0d..0813273 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,17 +1,17 @@ -# frozen_string_literal: true - -module ApplicationHelper - require 'json/ext' - - def format_string(string, *args) - string.gsub(/\{(\d+)\}/) { |s| args[s.to_i] } - end - - def to_json(hash) - hash.to_json - end - - def example_available?(example) - !(example['SkipForLanguages']) or !example['SkipForLanguages'].include? 'ruby' - end -end +# frozen_string_literal: true + +module ApplicationHelper + require 'json/ext' + + def format_string(string, *args) + string.gsub(/\{(\d+)\}/) { |s| args[s.to_i] } + end + + def to_json(hash) + hash.to_json + end + + def example_available?(example) + !example['SkipForLanguages'] or !example['SkipForLanguages'].include? 'ruby' + end +end From 073ed07d8f1e8ea711f5a27c24cef5e1d2984b0a Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Fri, 12 Sep 2025 17:52:07 +0300 Subject: [PATCH 356/363] add second example --- Gemfile | 2 +- Gemfile.lock | 4 +- app/controllers/eg_controller.rb | 2 +- ...eg002_create_remote_instance_controller.rb | 59 +++++++ .../eg002_create_remote_instance_service.rb | 163 ++++++++++++++++++ .../get.html.erb | 5 + .../web_form_create.html.erb | 6 + config/appsettings.example.yml | 2 +- config/routes.rb | 5 + data/web-form-config.json | 2 +- 10 files changed, 244 insertions(+), 6 deletions(-) create mode 100644 app/controllers/webforms/weg002_create_remote_instance_controller.rb create mode 100644 app/services/webforms/eg002_create_remote_instance_service.rb create mode 100644 app/views/webforms/weg002_create_remote_instance/get.html.erb create mode 100644 app/views/webforms/weg002_create_remote_instance/web_form_create.html.erb diff --git a/Gemfile b/Gemfile index d5fe708..3d263d9 100644 --- a/Gemfile +++ b/Gemfile @@ -73,7 +73,7 @@ gem 'docusign_click', '~> 1.4.0' gem 'docusign_esign', '~> 5.0.0' gem 'docusign_monitor', '~> 1.2.0' gem 'docusign_rooms', '~> 1.3.0' -gem 'docusign_webforms', '~> 2.0.0' +gem 'docusign_webforms', '~> 2.1.0' gem 'omniauth-oauth2', '~> 1.8.0' gem 'omniauth-rails_csrf_protection' diff --git a/Gemfile.lock b/Gemfile.lock index 4fa0735..fdafa07 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -134,7 +134,7 @@ GEM json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) typhoeus (~> 1.0, >= 1.0.1) - docusign_webforms (2.0.0) + docusign_webforms (2.1.0) addressable (~> 2.7, >= 2.7.0) json (~> 2.1, >= 2.1.0) jwt (~> 2.2, >= 2.2.1) @@ -397,7 +397,7 @@ DEPENDENCIES docusign_esign (~> 5.0.0) docusign_monitor (~> 1.2.0) docusign_rooms (~> 1.3.0) - docusign_webforms (~> 2.0.0) + docusign_webforms (~> 2.1.0) jbuilder (~> 2.13.0) listen (~> 3.9.0) matrix (~> 0.4.2) diff --git a/app/controllers/eg_controller.rb b/app/controllers/eg_controller.rb index cfaeef0..d043c78 100644 --- a/app/controllers/eg_controller.rb +++ b/app/controllers/eg_controller.rb @@ -105,6 +105,6 @@ def ensure_manifest end def format_string(string, *args) - string.gsub(/\{(\d+)\}/) { |s| args[s.to_i] } + string.gsub(/\{(\d+)\}/) { args[$1.to_i] } end end diff --git a/app/controllers/webforms/weg002_create_remote_instance_controller.rb b/app/controllers/webforms/weg002_create_remote_instance_controller.rb new file mode 100644 index 0000000..92c57b3 --- /dev/null +++ b/app/controllers/webforms/weg002_create_remote_instance_controller.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +class Webforms::Weg002CreateRemoteInstanceController < EgController + before_action -> { check_auth('WebForms') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 2, 'WebForms') } + + def create_web_form_template + args = { + template_name: 'Web Form Example Template', + account_id: session[:ds_account_id], + base_path: session[:ds_base_path], + access_token: session[:ds_access_token] + } + + begin + web_form_template_id = Webforms::Eg002CreateRemoteInstanceService.new(args).create_web_form_template + Utils::FileUtils.new.replace_template_id(File.join('data', Rails.application.config.web_form_config_file), web_form_template_id) + session[:web_form_template_id] = web_form_template_id + + redirect_to '/weg002webForm' + rescue DocuSign_eSign::ApiError => e + handle_error(e) + end + end + + def create_web_form_instance + args = { + form_name: 'Web Form Example Template', + account_id: session[:ds_account_id], + base_path: Rails.application.config.webforms_host, + signer_name: Rails.application.config.signer_name, + signer_email: Rails.application.config.signer_email, + access_token: session[:ds_access_token] + } + create_remote_instance_service = Webforms::Eg002CreateRemoteInstanceService.new(args) + web_forms = create_remote_instance_service.list_web_forms + + if web_forms.items.nil? || web_forms.items.empty? + @error_code = '404' + @error_message = @example['CustomErrorTexts'][0]['ErrorMessage'] + return render 'ds_common/error' + end + results = create_remote_instance_service.create_web_form_instance web_forms.items.first.id + + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results.envelopes[0].id, results.id) + render 'ds_common/example_done' + end + + def get_web_form_create_view + redirect_to '/weg002' if session[:web_form_template_id].nil? + + additional_page = @example['AdditionalPage'].find { |p| p['Name'] == 'create_web_form' } + @title = @example['ExampleName'] + @description = format_string(additional_page['ResultsPageText'], 'data') + + render 'webforms/weg002_create_remote_instance/web_form_create' + end +end diff --git a/app/services/webforms/eg002_create_remote_instance_service.rb b/app/services/webforms/eg002_create_remote_instance_service.rb new file mode 100644 index 0000000..c188a6d --- /dev/null +++ b/app/services/webforms/eg002_create_remote_instance_service.rb @@ -0,0 +1,163 @@ +# frozen_string_literal: true + +class Webforms::Eg002CreateRemoteInstanceService + attr_reader :args + + include ApiCreator + + def initialize(args) + @args = args + end + + def create_web_form_template + templates_api = create_template_api args + + options = DocuSign_eSign::ListTemplatesOptions.new + options.search_text = args[:template_name] + web_forms_templates = templates_api.list_templates(args[:account_id], options) + + if web_forms_templates.result_set_size.to_i.positive? + template_id = web_forms_templates.envelope_templates[0].template_id + else + template_req_object = make_web_forms_template + template = templates_api.create_template(args[:account_id], template_req_object) + template_id = template.template_id + end + + template_id + end + + def list_web_forms + #ds-snippet-start:WebForms1Step2 + configuration = DocuSign_WebForms::Configuration.new + api_client = DocuSign_WebForms::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:WebForms1Step2 + + #ds-snippet-start:WebForms1Step3 + webforms_api = DocuSign_WebForms::FormManagementApi.new(api_client) + + options = DocuSign_WebForms::ListFormsOptions.new + options.search = args[:form_name] + + webforms_api.list_forms(args[:account_id], options) + #ds-snippet-end:WebForms1Step3 + end + + def create_web_form_instance(form_id) + configuration = DocuSign_WebForms::Configuration.new + + api_client = DocuSign_WebForms::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + + #ds-snippet-start:WebForms1Step4 + web_form_values = { + 'PhoneNumber' => '555-555-5555', + 'Yes' => ['Yes'], + 'Company' => 'Tally', + 'JobTitle' => 'Programmer Writer' + } + recipient = DocuSign_WebForms::CreateInstanceRequestBodyRecipients.new({ + 'roleName' => 'signer', + 'name' => args[:signer_name], + 'email' => args[:signer_email] + }) + web_form_req_object = DocuSign_WebForms::CreateInstanceRequestBody.new({ + 'formValues' => web_form_values, + 'recipients' => [recipient], + 'sendOption' => 'now' + }) + #ds-snippet-end:WebForms1Step4 + + #ds-snippet-start:WebForms1Step5 + webforms_api = DocuSign_WebForms::FormInstanceManagementApi.new(api_client) + webforms_api.create_instance(args[:account_id], form_id, web_form_req_object) + #ds-snippet-end:WebForms1Step5 + end + + private + + def make_web_forms_template + template_name = args[:template_name] + doc_file = 'World_Wide_Corp_Web_Form.pdf' + base64_file_content = Base64.encode64(File.binread(File.join('data', doc_file))) + + # Create the document model + document = DocuSign_eSign::Document.new({ + # Create the Docusign document object + 'documentBase64' => base64_file_content, + 'name' => 'World_Wide_Web_Form', # Can be different from actual file name + 'fileExtension' => 'pdf', # Many different document types are accepted + 'documentId' => '1' # A label used to reference the doc + }) + + # Create the signer recipient model + # Since these are role definitions, no name/email: + signer = DocuSign_eSign::Signer.new({ + 'roleName' => 'signer', 'recipientId' => '1', 'routingOrder' => '1' + }) + # Create fields using absolute positioning + # Create a sign_here tab (field on the document) + sign_here = DocuSign_eSign::SignHere.new( + 'documentId' => '1', 'tabLabel' => 'Signature', + 'anchorString' => '/SignHere/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' + ) + check = DocuSign_eSign::Checkbox.new( + 'documentId' => '1', 'tabLabel' => 'Yes', + 'anchorString' => '/SMS/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' + ) + text1 = DocuSign_eSign::Text.new( + 'documentId' => '1', 'tabLabel' => 'FullName', + 'anchorString' => '/FullName/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' + ) + text2 = DocuSign_eSign::Text.new( + 'documentId' => '1', 'tabLabel' => 'PhoneNumber', + 'anchorString' => '/PhoneNumber/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' + ) + text3 = DocuSign_eSign::Text.new( + 'documentId' => '1', 'tabLabel' => 'Company', + 'anchorString' => '/Company/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' + ) + text4 = DocuSign_eSign::Text.new( + 'documentId' => '1', 'tabLabel' => 'JobTitle', + 'anchorString' => '/JobTitle/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' + ) + date_signed = DocuSign_eSign::DateSigned.new( + 'documentId' => '1', 'tabLabel' => 'DateSigned', + 'anchorString' => '/Date/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' + ) + + # Add the tabs model to the signer + # The Tabs object takes arrays of the different field/tab types + signer.tabs = DocuSign_eSign::Tabs.new( + 'signHereTabs' => [sign_here], + 'checkboxTabs' => [check], + 'textTabs' => [text1, text2, text3, text4], + 'dateSignedTabs' => [date_signed] + ) + # Create top two objects + envelope_template_definition = DocuSign_eSign::EnvelopeTemplate.new( + 'description' => 'Example template created via the eSignature API', + 'shared' => 'false' + ) + + # Top object: + DocuSign_eSign::EnvelopeTemplate.new( + 'documents' => [document], + 'name' => template_name, + 'emailSubject' => 'Please sign this document', + 'envelopeTemplateDefinition' => envelope_template_definition, + 'recipients' => DocuSign_eSign::Recipients.new( + 'signers' => [signer] + ), + 'status' => 'created' + ) + end +end diff --git a/app/views/webforms/weg002_create_remote_instance/get.html.erb b/app/views/webforms/weg002_create_remote_instance/get.html.erb new file mode 100644 index 0000000..fce42c5 --- /dev/null +++ b/app/views/webforms/weg002_create_remote_instance/get.html.erb @@ -0,0 +1,5 @@ +<%= render('partials/example_info') %> + +
    + <%= render('partials/submit_button') %> + \ No newline at end of file diff --git a/app/views/webforms/weg002_create_remote_instance/web_form_create.html.erb b/app/views/webforms/weg002_create_remote_instance/web_form_create.html.erb new file mode 100644 index 0000000..7aa71ca --- /dev/null +++ b/app/views/webforms/weg002_create_remote_instance/web_form_create.html.erb @@ -0,0 +1,6 @@ +

    <%= @title %>

    +

    <%= sanitize @description %>

    + +
    + <%= render('partials/submit_button') %> + \ No newline at end of file diff --git a/config/appsettings.example.yml b/config/appsettings.example.yml index 6eb5779..f2a6d9b 100644 --- a/config/appsettings.example.yml +++ b/config/appsettings.example.yml @@ -23,7 +23,7 @@ default: &default rooms_host: "https://demo.rooms.docusign.com/restapi" monitor_host: "https://lens-d.docusign.net" admin_host: "https://api-d.docusign.net/management" - webforms_host: "https://apps-d.docusign.com/api/webforms/v1.1" + webforms_host: "https://apps-d.docusign.com/api/webforms" allow_silent_authentication: true # A user can be silently authenticated if they have an # Active login session on another tab of the same browser # Set if you want a specific Docusign AccountId, If false, the users default account will be used. diff --git a/config/routes.rb b/config/routes.rb index 54d12f5..0fc70e1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -243,6 +243,11 @@ get 'weg001webForm' => 'weg001_create_instance#get_web_form_create_view' post 'weg001' => 'weg001_create_instance#create_web_form_template' post 'weg001webForm' => 'weg001_create_instance#create_web_form_instance' + + get 'weg002' => 'weg002_create_remote_instance#get' + get 'weg002webForm' => 'weg002_create_remote_instance#get_web_form_create_view' + post 'weg002' => 'weg002_create_remote_instance#create_web_form_template' + post 'weg002webForm' => 'weg002_create_remote_instance#create_web_form_instance' end scope module: 'notary' do diff --git a/data/web-form-config.json b/data/web-form-config.json index 10910b2..921bc76 100644 --- a/data/web-form-config.json +++ b/data/web-form-config.json @@ -1 +1 @@ -{"id":"39410656-f165-41e3-b1a4-bfd53fbb0e32","accountId":"0ef36a2b-xxxx-xxxx-xxxx-a406e16044a5","isPublished":true,"isEnabled":true,"hasDraftChanges":false,"formState":"active","formProperties":{"name":"Web Form Example Template","isPrivateAccess":false},"formMetadata":{"source":"templates","createdDateTime":"2024-10-09T18:38:29.598Z","publishedSlug":"cb0d0f6a9e3772eb4dcbe24de6ba331d","owner":{"userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","userName":"Inbar WebForms"},"lastModifiedDateTime":"2024-10-09T18:39:31.391Z","lastModifiedBy":{"userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","userName":"Inbar WebForms"},"publishedComponentNames":{"signer_name":"TextBox","signer_email":"Email","FullName":"TextBox","PhoneNumber":"TextBox","Yes":"CheckboxGroup","Company":"TextBox","JobTitle":"TextBox"},"admModelNamespace":"docusign.forms._0ef36a2b_ab23_47f2_9b96_a406e16044a5._39410656_f165_41e3_b1a4_bfd53fbb0e32","formContentModifiedBy":{"userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","userName":"Inbar WebForms"},"formContentModifiedDateTime":"2024-10-09T18:39:18.097Z","admModelVersion":"1.0.0","type":"hasEsignTemplate","formPropertiesModifiedBy":{"userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","userName":"Inbar WebForms"},"formPropertiesModifiedDateTime":"2024-10-09T18:39:07.573Z","sender":{"userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","userName":"Inbar WebForms"},"lastSenderConsentDateTime":"2024-10-09T18:39:23.162Z","lastPublishedBy":{"userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","userName":"Inbar WebForms"},"lastPublishedDateTime":"2024-10-09T18:39:31.391Z","lastEnabledBy":{"userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","userName":"Inbar WebForms"},"lastEnabledDateTime":"2024-10-09T18:39:31.391Z"},"formContent":{"components":{"Root_Of_Journey":{"componentKey":"Root_Of_Journey","componentType":"Root","componentName":"Root_Of_Journey","componentRules":{},"text":"","children":["Welcome_mLgvoXc_","Step_8CmDcmdk","Summary_eFmqGlfG","ESignAction_WDkwveBt","Thankyou_kyyG6Evn"]},"Welcome_mLgvoXc_":{"text":"Welcome","subText":"Part time work application","startButtonText":"Start","componentKey":"Welcome_mLgvoXc_","componentType":"Welcome"},"Step_8CmDcmdk":{"componentKey":"Step_8CmDcmdk","componentType":"Step","componentName":"Step_8CmDcmdk","text":"Untitled page","children":["TextBox_CnHrDIYv","Email_x5VWUgAp","TextBox_5ulrY7z8","TextBox_yZu4JilU","CheckboxGroup_Zg4TE6Sy","TextBox_6Qui50QM","TextBox_dikybASu"]},"Summary_eFmqGlfG":{"text":"Summary","subText":"Please review the information you have entered:","componentKey":"Summary_eFmqGlfG","componentType":"Summary"},"ESignAction_WDkwveBt":{"componentKey":"ESignAction_WDkwveBt","componentType":"ESignAction","primaryRecipientId":"1","templateInfoMap":{"3d41614e-ae79-40f6-bbf0-c2748f5800ac":{"templateId":"template-id","lastModified":"2024-10-09T18:38:30.4470000Z","name":"Web Form Copy - Web Form Example Template","owner":{"userName":"Inbar WebForms","userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","email":"example@example.com"}}},"documentInfoMap":{"Document_JfypoAaN":{"name":"World_Wide_Web_Form","documentId":"1","order":"1"}},"recipientInfoMap":{"1":{"nameComponentKey":"TextBox_CnHrDIYv","emailComponentKey":"Email_x5VWUgAp","recipientId":"1","recipientType":"signer","roleName":"signer","routingOrder":"1","nameFromTemplate":"","emailFromTemplate":""}},"tabInfoMap":{"81db13d8-66be-4aab-aa59-b9d974bb4627":{"componentKey":"TextBox_5ulrY7z8","tabId":"81db13d8-66be-4aab-aa59-b9d974bb4627","recipientId":"1","tabLabel":"FullName","tabType":"text","locked":"false"},"e57b222b-55fa-4fc7-a9c7-f40f2b5d6dbd":{"componentKey":"TextBox_yZu4JilU","tabId":"e57b222b-55fa-4fc7-a9c7-f40f2b5d6dbd","recipientId":"1","tabLabel":"PhoneNumber","tabType":"text","locked":"false"},"938f353b-5694-4d12-9e88-e8f9e7ccc0f1":{"componentKey":"TextBox_6Qui50QM","tabId":"938f353b-5694-4d12-9e88-e8f9e7ccc0f1","recipientId":"1","tabLabel":"Company","tabType":"text","locked":"false"},"56685845-2115-45a6-8b88-915e3c2f91ff":{"componentKey":"TextBox_dikybASu","tabId":"56685845-2115-45a6-8b88-915e3c2f91ff","recipientId":"1","tabLabel":"JobTitle","tabType":"text","locked":"false"},"256a3887-d854-46f8-9ee5-ae0b3f5866b0":{"componentKey":"CheckboxGroup_Zg4TE6Sy","tabId":"256a3887-d854-46f8-9ee5-ae0b3f5866b0","recipientId":"1","tabLabel":"Yes","tabType":"checkbox","name":"Yes","selected":"false","locked":"false"}},"requireRemoteSigning":false,"enableDocumentFieldEditing":true},"Thankyou_kyyG6Evn":{"text":"Thank you","subText":"We've received your form.","showConfirmationButton":false,"confirmationButtonText":"Done","confirmationButtonUrl":"","componentKey":"Thankyou_kyyG6Evn","componentType":"Thankyou"},"TextBox_CnHrDIYv":{"componentKey":"TextBox_CnHrDIYv","componentType":"TextBox","componentName":"signer_name","label":"signer name","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"Email_x5VWUgAp":{"componentKey":"Email_x5VWUgAp","componentType":"Email","componentName":"signer_email","label":"signer email","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"TextBox_5ulrY7z8":{"componentKey":"TextBox_5ulrY7z8","componentType":"TextBox","componentName":"FullName","label":"FullName","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"TextBox_yZu4JilU":{"componentKey":"TextBox_yZu4JilU","componentType":"TextBox","componentName":"PhoneNumber","label":"PhoneNumber","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"CheckboxGroup_Zg4TE6Sy":{"componentKey":"CheckboxGroup_Zg4TE6Sy","componentType":"CheckboxGroup","componentName":"Yes","label":"","description":"","options":[{"optionKey":"Zd9v2gRs","value":"Yes","label":"Yes","selected":false}]},"TextBox_6Qui50QM":{"componentKey":"TextBox_6Qui50QM","componentType":"TextBox","componentName":"Company","label":"Company","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000},"TextBox_dikybASu":{"componentKey":"TextBox_dikybASu","componentType":"TextBox","componentName":"JobTitle","label":"JobTitle","description":"","multiLine":false,"placeholder":"","required":true,"maxLength":4000}},"isStandalone":false,"templates":[{"originalTemplateId":"template-id","clonedTemplateId":"3d41614e-ae79-40f6-bbf0-c2748f5800ac","importedDateTime":"2024-10-09T18:38:31.275Z","recipientIds":["1"]}]},"formLocale":"en","versionId":1,"eSignTemplates":[{"templateId":"template-id","uri":"/templates/template-id","name":"Web Form Copy - Web Form Example Template","shared":"false","passwordProtected":"false","description":"Example template created via the eSignature API","created":"2024-10-09T18:38:30.0100000Z","lastModified":"2024-10-09T18:39:30.8100000Z","lastModifiedBy":{"userName":"Inbar WebForms","userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","email":"example@example.com","uri":"/users/06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18"},"lastUsed":"2024-10-09T18:38:30.4470000Z","owner":{"userName":"Inbar WebForms","userId":"06958f21-xxxx-xxxx-xxxx-8abc0cb6cf18","email":"example@example.com"},"pageCount":"1","folderId":"e4e93cf6-a3d9-4e0c-88f6-bd9bbfc73fc5","folderName":"Deleted Items","folderIds":["e4e93cf6-a3d9-4e0c-88f6-bd9bbfc73fc5"],"autoMatch":"true","autoMatchSpecifiedByUser":"false","documents":[{"documentId":"1","uri":"/envelopes/3d41614e-ae79-40f6-bbf0-c2748f5800ac/documents/1","name":"World_Wide_Web_Form","order":"1","pages":"1","documentBase64":"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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","messageLock":"false","recipientsLock":"false","brandLock":"false","customFields":{"textCustomFields":[{"fieldId":"11126003281","name":"ModelNamespace","show":"false","required":"false","value":"docusign.forms._0ef36a2b_ab23_47f2_9b96_a406e16044a5._39410656_f165_41e3_b1a4_bfd53fbb0e32"},{"fieldId":"11126003282","name":"ModelVersion","show":"false","required":"false","value":"1"},{"fieldId":"11126003283","name":"ModelAccount","show":"false","required":"false","value":"0ef36a2b-ab23-47f2-9b96-a406e16044a5"}],"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":"0d3171e2-42d0-4034-a929-1897b6078c25","tabType":"signhere"}],"dateSignedTabs":[{"name":"DateSigned","value":"","tabLabel":"DateSigned","localePolicy":{},"documentId":"1","recipientId":"1","pageNumber":"1","xPosition":"389","yPosition":"386","anchorString":"/Date/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"5bfda557-b893-4097-af42-b38a130638cf","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":"125","yPosition":"224","width":"0","height":"0","anchorString":"/FullName/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"81db13d8-66be-4aab-aa59-b9d974bb4627","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":"147","yPosition":"251","width":"0","height":"0","anchorString":"/PhoneNumber/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"e57b222b-55fa-4fc7-a9c7-f40f2b5d6dbd","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":"162","yPosition":"305","width":"0","height":"0","anchorString":"/Company/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"938f353b-5694-4d12-9e88-e8f9e7ccc0f1","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":"117","yPosition":"332","width":"0","height":"0","anchorString":"/Title/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"56685845-2115-45a6-8b88-915e3c2f91ff","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":"217","yPosition":"278","width":"0","height":"0","anchorString":"/SMS/","anchorXOffset":"0","anchorYOffset":"0","anchorUnits":"pixels","anchorCaseSensitive":"false","anchorMatchWholeWord":"true","anchorHorizontalAlignment":"left","anchorTabProcessorVersion":"v1_3","tabId":"256a3887-d854-46f8-9ee5-ae0b3f5866b0","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","allowComments":"true","disableResponsiveDocument":"true","anySigner":null,"envelopeLocation":"current_site"}]} \ No newline at end of file +{ "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": "template-id" } } }, "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": "template-id", "clonedTemplateId": "template-id", "importedDateTime": "2025-08-19T21:15:05.277Z", "recipientIds": [ "1" ] } ] }, "formLocale": "en", "versionId": 1, "eSignTemplates": [ { "templateId": "template-id", "uri": "/templates/template-id", "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 From 67c8e0362d24c19fe28bcee290cc737aba8d8d62 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Fri, 12 Sep 2025 18:01:12 +0300 Subject: [PATCH 357/363] linter fixes --- .../eg002_create_remote_instance_service.rb | 326 +++++++++--------- 1 file changed, 163 insertions(+), 163 deletions(-) diff --git a/app/services/webforms/eg002_create_remote_instance_service.rb b/app/services/webforms/eg002_create_remote_instance_service.rb index c188a6d..b2794f7 100644 --- a/app/services/webforms/eg002_create_remote_instance_service.rb +++ b/app/services/webforms/eg002_create_remote_instance_service.rb @@ -1,163 +1,163 @@ -# frozen_string_literal: true - -class Webforms::Eg002CreateRemoteInstanceService - attr_reader :args - - include ApiCreator - - def initialize(args) - @args = args - end - - def create_web_form_template - templates_api = create_template_api args - - options = DocuSign_eSign::ListTemplatesOptions.new - options.search_text = args[:template_name] - web_forms_templates = templates_api.list_templates(args[:account_id], options) - - if web_forms_templates.result_set_size.to_i.positive? - template_id = web_forms_templates.envelope_templates[0].template_id - else - template_req_object = make_web_forms_template - template = templates_api.create_template(args[:account_id], template_req_object) - template_id = template.template_id - end - - template_id - end - - def list_web_forms - #ds-snippet-start:WebForms1Step2 - configuration = DocuSign_WebForms::Configuration.new - api_client = DocuSign_WebForms::ApiClient.new(configuration) - api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - #ds-snippet-end:WebForms1Step2 - - #ds-snippet-start:WebForms1Step3 - webforms_api = DocuSign_WebForms::FormManagementApi.new(api_client) - - options = DocuSign_WebForms::ListFormsOptions.new - options.search = args[:form_name] - - webforms_api.list_forms(args[:account_id], options) - #ds-snippet-end:WebForms1Step3 - end - - def create_web_form_instance(form_id) - configuration = DocuSign_WebForms::Configuration.new - - api_client = DocuSign_WebForms::ApiClient.new(configuration) - api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") - - #ds-snippet-start:WebForms1Step4 - web_form_values = { - 'PhoneNumber' => '555-555-5555', - 'Yes' => ['Yes'], - 'Company' => 'Tally', - 'JobTitle' => 'Programmer Writer' - } - recipient = DocuSign_WebForms::CreateInstanceRequestBodyRecipients.new({ - 'roleName' => 'signer', - 'name' => args[:signer_name], - 'email' => args[:signer_email] - }) - web_form_req_object = DocuSign_WebForms::CreateInstanceRequestBody.new({ - 'formValues' => web_form_values, - 'recipients' => [recipient], - 'sendOption' => 'now' - }) - #ds-snippet-end:WebForms1Step4 - - #ds-snippet-start:WebForms1Step5 - webforms_api = DocuSign_WebForms::FormInstanceManagementApi.new(api_client) - webforms_api.create_instance(args[:account_id], form_id, web_form_req_object) - #ds-snippet-end:WebForms1Step5 - end - - private - - def make_web_forms_template - template_name = args[:template_name] - doc_file = 'World_Wide_Corp_Web_Form.pdf' - base64_file_content = Base64.encode64(File.binread(File.join('data', doc_file))) - - # Create the document model - document = DocuSign_eSign::Document.new({ - # Create the Docusign document object - 'documentBase64' => base64_file_content, - 'name' => 'World_Wide_Web_Form', # Can be different from actual file name - 'fileExtension' => 'pdf', # Many different document types are accepted - 'documentId' => '1' # A label used to reference the doc - }) - - # Create the signer recipient model - # Since these are role definitions, no name/email: - signer = DocuSign_eSign::Signer.new({ - 'roleName' => 'signer', 'recipientId' => '1', 'routingOrder' => '1' - }) - # Create fields using absolute positioning - # Create a sign_here tab (field on the document) - sign_here = DocuSign_eSign::SignHere.new( - 'documentId' => '1', 'tabLabel' => 'Signature', - 'anchorString' => '/SignHere/', 'anchorUnits' => 'pixels', - 'anchorXOffset' => '0', 'anchorYOffset' => '0' - ) - check = DocuSign_eSign::Checkbox.new( - 'documentId' => '1', 'tabLabel' => 'Yes', - 'anchorString' => '/SMS/', 'anchorUnits' => 'pixels', - 'anchorXOffset' => '0', 'anchorYOffset' => '0' - ) - text1 = DocuSign_eSign::Text.new( - 'documentId' => '1', 'tabLabel' => 'FullName', - 'anchorString' => '/FullName/', 'anchorUnits' => 'pixels', - 'anchorXOffset' => '0', 'anchorYOffset' => '0' - ) - text2 = DocuSign_eSign::Text.new( - 'documentId' => '1', 'tabLabel' => 'PhoneNumber', - 'anchorString' => '/PhoneNumber/', 'anchorUnits' => 'pixels', - 'anchorXOffset' => '0', 'anchorYOffset' => '0' - ) - text3 = DocuSign_eSign::Text.new( - 'documentId' => '1', 'tabLabel' => 'Company', - 'anchorString' => '/Company/', 'anchorUnits' => 'pixels', - 'anchorXOffset' => '0', 'anchorYOffset' => '0' - ) - text4 = DocuSign_eSign::Text.new( - 'documentId' => '1', 'tabLabel' => 'JobTitle', - 'anchorString' => '/JobTitle/', 'anchorUnits' => 'pixels', - 'anchorXOffset' => '0', 'anchorYOffset' => '0' - ) - date_signed = DocuSign_eSign::DateSigned.new( - 'documentId' => '1', 'tabLabel' => 'DateSigned', - 'anchorString' => '/Date/', 'anchorUnits' => 'pixels', - 'anchorXOffset' => '0', 'anchorYOffset' => '0' - ) - - # Add the tabs model to the signer - # The Tabs object takes arrays of the different field/tab types - signer.tabs = DocuSign_eSign::Tabs.new( - 'signHereTabs' => [sign_here], - 'checkboxTabs' => [check], - 'textTabs' => [text1, text2, text3, text4], - 'dateSignedTabs' => [date_signed] - ) - # Create top two objects - envelope_template_definition = DocuSign_eSign::EnvelopeTemplate.new( - 'description' => 'Example template created via the eSignature API', - 'shared' => 'false' - ) - - # Top object: - DocuSign_eSign::EnvelopeTemplate.new( - 'documents' => [document], - 'name' => template_name, - 'emailSubject' => 'Please sign this document', - 'envelopeTemplateDefinition' => envelope_template_definition, - 'recipients' => DocuSign_eSign::Recipients.new( - 'signers' => [signer] - ), - 'status' => 'created' - ) - end -end +# frozen_string_literal: true + +class Webforms::Eg002CreateRemoteInstanceService + attr_reader :args + + include ApiCreator + + def initialize(args) + @args = args + end + + def create_web_form_template + templates_api = create_template_api args + + options = DocuSign_eSign::ListTemplatesOptions.new + options.search_text = args[:template_name] + web_forms_templates = templates_api.list_templates(args[:account_id], options) + + if web_forms_templates.result_set_size.to_i.positive? + template_id = web_forms_templates.envelope_templates[0].template_id + else + template_req_object = make_web_forms_template + template = templates_api.create_template(args[:account_id], template_req_object) + template_id = template.template_id + end + + template_id + end + + def list_web_forms + #ds-snippet-start:WebForms2Step2 + configuration = DocuSign_WebForms::Configuration.new + api_client = DocuSign_WebForms::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + #ds-snippet-end:WebForms2Step2 + + #ds-snippet-start:WebForms2Step3 + webforms_api = DocuSign_WebForms::FormManagementApi.new(api_client) + + options = DocuSign_WebForms::ListFormsOptions.new + options.search = args[:form_name] + + webforms_api.list_forms(args[:account_id], options) + #ds-snippet-end:WebForms2Step3 + end + + def create_web_form_instance(form_id) + configuration = DocuSign_WebForms::Configuration.new + + api_client = DocuSign_WebForms::ApiClient.new(configuration) + api_client.set_default_header('Authorization', "Bearer #{args[:access_token]}") + + #ds-snippet-start:WebForms2Step4 + web_form_values = { + 'PhoneNumber' => '555-555-5555', + 'Yes' => ['Yes'], + 'Company' => 'Tally', + 'JobTitle' => 'Programmer Writer' + } + recipient = DocuSign_WebForms::CreateInstanceRequestBodyRecipients.new({ + 'roleName' => 'signer', + 'name' => args[:signer_name], + 'email' => args[:signer_email] + }) + web_form_req_object = DocuSign_WebForms::CreateInstanceRequestBody.new({ + 'formValues' => web_form_values, + 'recipients' => [recipient], + 'sendOption' => 'now' + }) + #ds-snippet-end:WebForms2Step4 + + #ds-snippet-start:WebForms2Step5 + webforms_api = DocuSign_WebForms::FormInstanceManagementApi.new(api_client) + webforms_api.create_instance(args[:account_id], form_id, web_form_req_object) + #ds-snippet-end:WebForms2Step5 + end + + private + + def make_web_forms_template + template_name = args[:template_name] + doc_file = 'World_Wide_Corp_Web_Form.pdf' + base64_file_content = Base64.encode64(File.binread(File.join('data', doc_file))) + + # Create the document model + document = DocuSign_eSign::Document.new({ + # Create the Docusign document object + 'documentBase64' => base64_file_content, + 'name' => 'World_Wide_Web_Form', # Can be different from actual file name + 'fileExtension' => 'pdf', # Many different document types are accepted + 'documentId' => '1' # A label used to reference the doc + }) + + # Create the signer recipient model + # Since these are role definitions, no name/email: + signer = DocuSign_eSign::Signer.new({ + 'roleName' => 'signer', 'recipientId' => '1', 'routingOrder' => '1' + }) + # Create fields using absolute positioning + # Create a sign_here tab (field on the document) + sign_here = DocuSign_eSign::SignHere.new( + 'documentId' => '1', 'tabLabel' => 'Signature', + 'anchorString' => '/SignHere/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' + ) + check = DocuSign_eSign::Checkbox.new( + 'documentId' => '1', 'tabLabel' => 'Yes', + 'anchorString' => '/SMS/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' + ) + text1 = DocuSign_eSign::Text.new( + 'documentId' => '1', 'tabLabel' => 'FullName', + 'anchorString' => '/FullName/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' + ) + text2 = DocuSign_eSign::Text.new( + 'documentId' => '1', 'tabLabel' => 'PhoneNumber', + 'anchorString' => '/PhoneNumber/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' + ) + text3 = DocuSign_eSign::Text.new( + 'documentId' => '1', 'tabLabel' => 'Company', + 'anchorString' => '/Company/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' + ) + text4 = DocuSign_eSign::Text.new( + 'documentId' => '1', 'tabLabel' => 'JobTitle', + 'anchorString' => '/JobTitle/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' + ) + date_signed = DocuSign_eSign::DateSigned.new( + 'documentId' => '1', 'tabLabel' => 'DateSigned', + 'anchorString' => '/Date/', 'anchorUnits' => 'pixels', + 'anchorXOffset' => '0', 'anchorYOffset' => '0' + ) + + # Add the tabs model to the signer + # The Tabs object takes arrays of the different field/tab types + signer.tabs = DocuSign_eSign::Tabs.new( + 'signHereTabs' => [sign_here], + 'checkboxTabs' => [check], + 'textTabs' => [text1, text2, text3, text4], + 'dateSignedTabs' => [date_signed] + ) + # Create top two objects + envelope_template_definition = DocuSign_eSign::EnvelopeTemplate.new( + 'description' => 'Example template created via the eSignature API', + 'shared' => 'false' + ) + + # Top object: + DocuSign_eSign::EnvelopeTemplate.new( + 'documents' => [document], + 'name' => template_name, + 'emailSubject' => 'Please sign this document', + 'envelopeTemplateDefinition' => envelope_template_definition, + 'recipients' => DocuSign_eSign::Recipients.new( + 'signers' => [signer] + ), + 'status' => 'created' + ) + end +end From cf95677026d1e84fcc2b099ffeb16a470a04f0c3 Mon Sep 17 00:00:00 2001 From: RomanBachaloSigmaSoftware Date: Fri, 12 Sep 2025 18:09:41 +0300 Subject: [PATCH 358/363] linter fixes for format_string --- app/controllers/eg_controller.rb | 220 +++++++++++++++--------------- app/helpers/application_helper.rb | 2 +- 2 files changed, 111 insertions(+), 111 deletions(-) diff --git a/app/controllers/eg_controller.rb b/app/controllers/eg_controller.rb index d043c78..d53d4ae 100644 --- a/app/controllers/eg_controller.rb +++ b/app/controllers/eg_controller.rb @@ -1,110 +1,110 @@ -# frozen_string_literal: true - -class EgController < ApplicationController - skip_before_action :verify_authenticity_token - before_action :eg_name, :set_eg, :set_meta, :ensure_manifest - - def file_name - "#{controller_path}_service.rb" - end - - def eg_name - controller_name.to(4) - end - - def set_eg - session[:eg] = controller_name.split('_', 2).first - end - - def get - @messages = '' - - # to have the user authenticate or re-authenticate. - @token_ok = check_token - @config = Rails.application.config - if @token_ok || controller_name.include?('cneg') - # addSpecialAttributes(model) - @envelope_ok = session[:envelope_id].present? - @documents_ok = session[:envelope_documents].present? - @document_options = session.fetch(:envelope_documents, {})['documents'] - @gateway_ok = @config.gateway_account_id.try(:length) > 25 - @template_ok = session[:template_id].present? - @documentation = "#{@config.documentation}#{eg_name}" #= Config.documentation + EgName - @show_doc = @config.documentation - else - redirect_to '/ds/mustAuthenticate' - end - end - - def set_meta - @source_file = file_name.to_s - #remove extra character that doesn't exist in service file - index = @source_file.index('/') - @source_file = index.nil? ? @source_file.sub(/^.*?eg/, 'eg') : @source_file.sub(%r{/.+?eg}, '/eg') - @source_url = "#{Rails.application.config.github_example_url}#{@source_file}" - end - - def check_token(buffer_in_min = 10) - buffer = buffer_in_min * 60 - expires_at = session[:ds_expires_at] - remaining_duration = expires_at.nil? ? 0 : expires_at - buffer.seconds.from_now.to_i - if expires_at.nil? - Rails.logger.info '==> Token expiration is not available: fetching token' - elsif remaining_duration.negative? - Rails.logger.debug "==> Token is about to expire in #{time_in_words(remaining_duration)} at: #{Time.at(expires_at)}: fetching token" - else - Rails.logger.debug "==> Token is OK for #{time_in_words(remaining_duration)} at: #{Time.at(expires_at)}" - end - remaining_duration.positive? - end - - private - - def time_in_words(duration) - "#{Object.new.extend(ActionView::Helpers::DateHelper).distance_of_time_in_words(duration)}#{duration.negative? ? ' ago' : ''}" - end - - def param_gsub(parameter) - parameter.gsub(/([^\w \-@.,])+/, '') - end - - def check_auth(api) - # if not authorized for same API type example or - # if it is an attempt to authorize from home page - # then user will be redirected to login page - unless (session[:api] == api) || ((api == 'eSignature') && !session[:api]) - session[:api] = api - params[:auth] = 'jwt-auth' if api == 'Monitor' - - return redirect_to '/ds/mustAuthenticate' - end - - minimum_buffer_min = 10 - token_ok = check_token(minimum_buffer_min) - return if token_ok - - flash[:messages] = 'Sorry, you need to re-authenticate.' - # We could store the parameters of the requested operation so it could be restarted automatically - # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication - redirect_to '/ds/mustAuthenticate' - end - - def handle_error(e) - error = JSON.parse e.response_body - @error_code = e.code || error['errorCode'] - @error_message = error['error_description'] || error['message'] || error['error'] - render 'ds_common/error' - end - - def create_source_path - # code here - end - - def ensure_manifest - @manifest = Utils::ManifestUtils.new.get_manifest(Rails.configuration.example_manifest_url) - end - - def format_string(string, *args) - string.gsub(/\{(\d+)\}/) { args[$1.to_i] } - end -end +# frozen_string_literal: true + +class EgController < ApplicationController + skip_before_action :verify_authenticity_token + before_action :eg_name, :set_eg, :set_meta, :ensure_manifest + + def file_name + "#{controller_path}_service.rb" + end + + def eg_name + controller_name.to(4) + end + + def set_eg + session[:eg] = controller_name.split('_', 2).first + end + + def get + @messages = '' + + # to have the user authenticate or re-authenticate. + @token_ok = check_token + @config = Rails.application.config + if @token_ok || controller_name.include?('cneg') + # addSpecialAttributes(model) + @envelope_ok = session[:envelope_id].present? + @documents_ok = session[:envelope_documents].present? + @document_options = session.fetch(:envelope_documents, {})['documents'] + @gateway_ok = @config.gateway_account_id.try(:length) > 25 + @template_ok = session[:template_id].present? + @documentation = "#{@config.documentation}#{eg_name}" #= Config.documentation + EgName + @show_doc = @config.documentation + else + redirect_to '/ds/mustAuthenticate' + end + end + + def set_meta + @source_file = file_name.to_s + #remove extra character that doesn't exist in service file + index = @source_file.index('/') + @source_file = index.nil? ? @source_file.sub(/^.*?eg/, 'eg') : @source_file.sub(%r{/.+?eg}, '/eg') + @source_url = "#{Rails.application.config.github_example_url}#{@source_file}" + end + + def check_token(buffer_in_min = 10) + buffer = buffer_in_min * 60 + expires_at = session[:ds_expires_at] + remaining_duration = expires_at.nil? ? 0 : expires_at - buffer.seconds.from_now.to_i + if expires_at.nil? + Rails.logger.info '==> Token expiration is not available: fetching token' + elsif remaining_duration.negative? + Rails.logger.debug "==> Token is about to expire in #{time_in_words(remaining_duration)} at: #{Time.at(expires_at)}: fetching token" + else + Rails.logger.debug "==> Token is OK for #{time_in_words(remaining_duration)} at: #{Time.at(expires_at)}" + end + remaining_duration.positive? + end + + private + + def time_in_words(duration) + "#{Object.new.extend(ActionView::Helpers::DateHelper).distance_of_time_in_words(duration)}#{duration.negative? ? ' ago' : ''}" + end + + def param_gsub(parameter) + parameter.gsub(/([^\w \-@.,])+/, '') + end + + def check_auth(api) + # if not authorized for same API type example or + # if it is an attempt to authorize from home page + # then user will be redirected to login page + unless (session[:api] == api) || ((api == 'eSignature') && !session[:api]) + session[:api] = api + params[:auth] = 'jwt-auth' if api == 'Monitor' + + return redirect_to '/ds/mustAuthenticate' + end + + minimum_buffer_min = 10 + token_ok = check_token(minimum_buffer_min) + return if token_ok + + flash[:messages] = 'Sorry, you need to re-authenticate.' + # We could store the parameters of the requested operation so it could be restarted automatically + # But since it should be rare to have a token issue here, we'll make the user re-enter the form data after authentication + redirect_to '/ds/mustAuthenticate' + end + + def handle_error(e) + error = JSON.parse e.response_body + @error_code = e.code || error['errorCode'] + @error_message = error['error_description'] || error['message'] || error['error'] + render 'ds_common/error' + end + + def create_source_path + # code here + end + + def ensure_manifest + @manifest = Utils::ManifestUtils.new.get_manifest(Rails.configuration.example_manifest_url) + end + + def format_string(string, *args) + string.gsub(/\{(\d+)\}/) { args[::Regexp.last_match(1).to_i] } + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 765de0d..e510487 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -4,7 +4,7 @@ module ApplicationHelper require 'json/ext' def format_string(string, *args) - string.gsub(/\{(\d+)\}/) { |s| args[s.to_i] } + string.gsub(/\{(\d+)\}/) { args[::Regexp.last_match(1).to_i] } end def to_json(hash) From 9fad80758335fc532a9a974ef70485d400bb8d2a Mon Sep 17 00:00:00 2001 From: Paige Rossi Date: Fri, 12 Sep 2025 10:23:53 -0700 Subject: [PATCH 359/363] fixing indentation --- .../eg002_create_remote_instance_service.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/services/webforms/eg002_create_remote_instance_service.rb b/app/services/webforms/eg002_create_remote_instance_service.rb index b2794f7..44947b7 100644 --- a/app/services/webforms/eg002_create_remote_instance_service.rb +++ b/app/services/webforms/eg002_create_remote_instance_service.rb @@ -58,15 +58,15 @@ def create_web_form_instance(form_id) 'JobTitle' => 'Programmer Writer' } recipient = DocuSign_WebForms::CreateInstanceRequestBodyRecipients.new({ - 'roleName' => 'signer', - 'name' => args[:signer_name], - 'email' => args[:signer_email] - }) + 'roleName' => 'signer', + 'name' => args[:signer_name], + 'email' => args[:signer_email] + }) web_form_req_object = DocuSign_WebForms::CreateInstanceRequestBody.new({ - 'formValues' => web_form_values, - 'recipients' => [recipient], - 'sendOption' => 'now' - }) + 'formValues' => web_form_values, + 'recipients' => [recipient], + 'sendOption' => 'now' + }) #ds-snippet-end:WebForms2Step4 #ds-snippet-start:WebForms2Step5 From e34b3589ccfb0cfd25fd44d6e6ef0b4cfa80073c Mon Sep 17 00:00:00 2001 From: inbargazit Date: Fri, 26 Sep 2025 09:09:34 -0700 Subject: [PATCH 360/363] Updating Web Forms timeout to 24 hours --- app/services/webforms/eg001_create_instance_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/webforms/eg001_create_instance_service.rb b/app/services/webforms/eg001_create_instance_service.rb index e766e5c..83a8573 100644 --- a/app/services/webforms/eg001_create_instance_service.rb +++ b/app/services/webforms/eg001_create_instance_service.rb @@ -60,7 +60,7 @@ def create_web_form_instance(form_id) web_form_req_object = DocuSign_WebForms::CreateInstanceRequestBody.new({ 'clientUserId' => args[:client_user_id], 'formValues' => web_form_values, - 'expirationOffset' => '3600' + 'expirationOffset' => '24' }) #ds-snippet-end:WebForms1Step4 From 1093eaecca810a9f1a013ef8de281942202ce4e3 Mon Sep 17 00:00:00 2001 From: Balaji Jayaraman Date: Sun, 19 Oct 2025 12:07:37 +0530 Subject: [PATCH 361/363] added delete and restore envelope how to code snippet --- ...g045_delete_restore_envelope_controller.rb | 82 +++++++++++++++++++ app/services/api_creator.rb | 8 ++ .../eg045_delete_restore_envelope_service.rb | 40 +++++++++ app/services/utils.rb | 13 +++ .../eg002_create_remote_instance_service.rb | 24 +++--- .../delete.html.erb | 21 +++++ .../restore.html.erb | 21 +++++ app/views/partials/_example_info.erb | 4 +- app/views/partials/_submit_button.erb | 2 +- config/routes.rb | 5 ++ 10 files changed, 207 insertions(+), 13 deletions(-) create mode 100644 app/controllers/e_sign/eeg045_delete_restore_envelope_controller.rb create mode 100644 app/services/e_sign/eg045_delete_restore_envelope_service.rb create mode 100644 app/views/e_sign/eeg045_delete_restore_envelope/delete.html.erb create mode 100644 app/views/e_sign/eeg045_delete_restore_envelope/restore.html.erb diff --git a/app/controllers/e_sign/eeg045_delete_restore_envelope_controller.rb b/app/controllers/e_sign/eeg045_delete_restore_envelope_controller.rb new file mode 100644 index 0000000..dfb3dd7 --- /dev/null +++ b/app/controllers/e_sign/eeg045_delete_restore_envelope_controller.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +require_relative '../../services/utils' + +class ESign::Eeg045DeleteRestoreEnvelopeController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 45, 'eSignature') } + + DELETE_FOLDER_ID = 'recyclebin' + + def delete_envelope + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_id: param_gsub(params['envelope_id']), + delete_folder_id: DELETE_FOLDER_ID + } + + delete_restore_envelope_service = ESign::Eg045DeleteRestoreEnvelopeService.new + + delete_restore_envelope_service.delete_envelope args + + session[:envelope_id] = args[:envelope_id] + additional_page_data = @example['AdditionalPage'].find { |p| p['Name'] == 'envelope_is_deleted' } + @title = @example['ExampleName'] + @message = format_string(additional_page_data['ResultsPageText'], args[:envelope_id]) + @redirect_url = "/#{session[:eg]}restore" + + render 'ds_common/example_done' + end + + def restore_envelope + folder_name = param_gsub(params['folder_name']) + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_id: param_gsub(session[:envelope_id]), + from_folder_id: DELETE_FOLDER_ID + } + + delete_restore_envelope_service = ESign::Eg045DeleteRestoreEnvelopeService.new + + folders = delete_restore_envelope_service.get_folders args + args[:folder_id] = Utils::DocuSignUtils.new.get_folder_id_by_name(folders.folders, folder_name) + + if args[:folder_id].nil? || args[:folder_id].empty? + additional_page_data = @example['AdditionalPage'].find { |p| p['Name'] == 'folder_does_not_exist' } + @title = @example['ExampleName'] + @message = format_string(additional_page_data['ResultsPageText'], folder_name) + @redirect_url = "/#{session[:eg]}restore" + + return render 'ds_common/example_done' + end + + delete_restore_envelope_service.move_envelope_to_folder args + + session[:envelope_id] = args[:envelope_id] + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], session[:envelope_id], args[:folder_id], folder_name) + render 'ds_common/example_done' + end + + def get_delete_envelope + get + @envelope_id = session[:envelope_id] + @submit_button_text = @manifest['SupportingTexts']['HelpingTexts']['SubmitButtonDeleteText'] + + render 'e_sign/eeg045_delete_restore_envelope/delete' + end + + def get_restore_envelope + return redirect_to "/#{session[:eg]}" if session[:envelope_id].nil? + + get + @envelope_id = session[:envelope_id] + @submit_button_text = @manifest['SupportingTexts']['HelpingTexts']['SubmitButtonRestoreText'] + + render 'e_sign/eeg045_delete_restore_envelope/restore' + end +end diff --git a/app/services/api_creator.rb b/app/services/api_creator.rb index 7feb1f3..16850e2 100644 --- a/app/services/api_creator.rb +++ b/app/services/api_creator.rb @@ -49,4 +49,12 @@ def create_group_api(args) api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" DocuSign_eSign::GroupsApi.new api_client end + + def create_folders_api(args) + configuration = DocuSign_eSign::Configuration.new + configuration.host = args[:base_path] + api_client = DocuSign_eSign::ApiClient.new configuration + api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}" + DocuSign_eSign::FoldersApi.new api_client + end end diff --git a/app/services/e_sign/eg045_delete_restore_envelope_service.rb b/app/services/e_sign/eg045_delete_restore_envelope_service.rb new file mode 100644 index 0000000..a41a2e3 --- /dev/null +++ b/app/services/e_sign/eg045_delete_restore_envelope_service.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +class ESign::Eg045DeleteRestoreEnvelopeService + include ApiCreator + + def delete_envelope(args) + #ds-snippet-start:eSign45Step2 + folders_api = create_folders_api(args) + #ds-snippet-end:eSign45Step2 + + #ds-snippet-start:eSign45Step3 + folders_request = DocuSign_eSign::FoldersRequest.new + folders_request.envelope_ids = [args[:envelope_id]] + #ds-snippet-end:eSign45Step3 + + #ds-snippet-start:eSign45Step4 + folders_api.move_envelopes(args[:account_id], args[:delete_folder_id], folders_request) + #ds-snippet-end:eSign45Step4 + end + + def move_envelope_to_folder(args) + folders_api = create_folders_api(args) + + #ds-snippet-start:eSign45Step6 + folders_request = DocuSign_eSign::FoldersRequest.new + folders_request.envelope_ids = [args[:envelope_id]] + folders_request.from_folder_id = args[:from_folder_id] + + folders_api.move_envelopes(args[:account_id], args[:folder_id], folders_request) + #ds-snippet-end:eSign45Step6 + end + + def get_folders(args) + folders_api = create_folders_api(args) + + #ds-snippet-start:eSign45Step5 + folders_api.list(args[:account_id]) + #ds-snippet-end:eSign45Step5 + end +end diff --git a/app/services/utils.rb b/app/services/utils.rb index 43af62a..c4fb4cf 100644 --- a/app/services/utils.rb +++ b/app/services/utils.rb @@ -29,6 +29,19 @@ def get_user_id(args) user_info = api_client.get_user_info(args[:access_token]) user_info.sub end + + def get_folder_id_by_name(folders, folder_name) + folders.each do |folder| + return folder.folder_id if folder.name.downcase == folder_name.downcase + + if folder.folders&.any? + folder_id = get_folder_id_by_name(folder.folders, folder_name) + return folder_id if folder_id + end + end + + nil + end end class FileUtils diff --git a/app/services/webforms/eg002_create_remote_instance_service.rb b/app/services/webforms/eg002_create_remote_instance_service.rb index 44947b7..94acc4c 100644 --- a/app/services/webforms/eg002_create_remote_instance_service.rb +++ b/app/services/webforms/eg002_create_remote_instance_service.rb @@ -57,16 +57,20 @@ def create_web_form_instance(form_id) 'Company' => 'Tally', 'JobTitle' => 'Programmer Writer' } - recipient = DocuSign_WebForms::CreateInstanceRequestBodyRecipients.new({ - 'roleName' => 'signer', - 'name' => args[:signer_name], - 'email' => args[:signer_email] - }) - web_form_req_object = DocuSign_WebForms::CreateInstanceRequestBody.new({ - 'formValues' => web_form_values, - 'recipients' => [recipient], - 'sendOption' => 'now' - }) + recipient = DocuSign_WebForms::CreateInstanceRequestBodyRecipients.new( + { + 'roleName' => 'signer', + 'name' => args[:signer_name], + 'email' => args[:signer_email] + } + ) + web_form_req_object = DocuSign_WebForms::CreateInstanceRequestBody.new( + { + 'formValues' => web_form_values, + 'recipients' => [recipient], + 'sendOption' => 'now' + } + ) #ds-snippet-end:WebForms2Step4 #ds-snippet-start:WebForms2Step5 diff --git a/app/views/e_sign/eeg045_delete_restore_envelope/delete.html.erb b/app/views/e_sign/eeg045_delete_restore_envelope/delete.html.erb new file mode 100644 index 0000000..d946c0e --- /dev/null +++ b/app/views/e_sign/eeg045_delete_restore_envelope/delete.html.erb @@ -0,0 +1,21 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% envelope_id_index = 0 %> + +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + "> + <%= @manifest["SupportingTexts"]["HelpingTexts"]["DefaultEnvelopeId"] %> +
    + + <%= render('partials/submit_button') %> + + diff --git a/app/views/e_sign/eeg045_delete_restore_envelope/restore.html.erb b/app/views/e_sign/eeg045_delete_restore_envelope/restore.html.erb new file mode 100644 index 0000000..0e6d375 --- /dev/null +++ b/app/views/e_sign/eeg045_delete_restore_envelope/restore.html.erb @@ -0,0 +1,21 @@ +

    <%= @example["ExampleName"] %>

    +

    <%= sanitize @example["ExampleDescription"] %>

    +<%= sanitize format_string(@manifest["SupportingTexts"]["HelpingTexts"]["EnvelopeWillBeRestored"], @envelope_id) %> + +<% form_index = 0 %> +<% folder_name_index = 1 %> + +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    + + "> +
    + + <%= render('partials/submit_button') %> + + diff --git a/app/views/partials/_example_info.erb b/app/views/partials/_example_info.erb index 8e18fdd..71adef9 100644 --- a/app/views/partials/_example_info.erb +++ b/app/views/partials/_example_info.erb @@ -5,8 +5,8 @@

    Documentation about this example.

    <% end %> -<% if @example["Note"] %> - <%= sanitize @example["Note"] %> +<% if @example["Notes"] %> + <%= sanitize @example["Notes"] %> <% end %> <% if @example["LinksToAPIMethod"] %> diff --git a/app/views/partials/_submit_button.erb b/app/views/partials/_submit_button.erb index 2aceab4..6f54a77 100644 --- a/app/views/partials/_submit_button.erb +++ b/app/views/partials/_submit_button.erb @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 0fc70e1..49f49d1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -231,6 +231,11 @@ get 'eeg044' => 'eeg044_focused_view#get' post 'eeg044' => 'eeg044_focused_view#create' + + get 'eeg045' => 'eeg045_delete_restore_envelope#get_delete_envelope' + post 'eeg045' => 'eeg045_delete_restore_envelope#delete_envelope' + get 'eeg045restore' => 'eeg045_delete_restore_envelope#get_restore_envelope' + post 'eeg045restore' => 'eeg045_delete_restore_envelope#restore_envelope' end scope module: 'connect' do From c87acf33cad7c9e6ff40cde74ed6ef697f49086a Mon Sep 17 00:00:00 2001 From: Balaji Jayaraman Date: Tue, 20 Jan 2026 16:16:03 +0530 Subject: [PATCH 362/363] added httpinfo updates --- .../admin_api/eg001_create_user_service.rb | 13 ++- ...02_create_active_clm_esign_user_service.rb | 13 ++- .../eg003_bulk_export_user_data_service.rb | 34 ++++++- .../admin_api/eg004_import_user_service.rb | 13 ++- .../admin_api/eg005_audit_users_service.rb | 25 ++++- ...eg006_get_user_profile_by_email_service.rb | 13 ++- ...007_get_user_profile_by_user_id_service.rb | 13 ++- ...user_product_permission_profile_service.rb | 13 ++- ...user_product_permission_profile_service.rb | 25 ++++- ...ete_user_data_from_organization_service.rb | 25 ++++- ...1_delete_user_data_from_account_service.rb | 13 ++- .../admin_api/eg012_clone_account_service.rb | 26 ++++- .../admin_api/eg013_create_account_service.rb | 26 ++++- .../eg001_create_clickwrap_service.rb | 13 ++- .../eg002_activate_clickwrap_service.rb | 28 +++++- ...03_create_new_clickwrap_version_service.rb | 13 ++- .../eg004_list_clickwraps_service.rb | 13 ++- .../eg005_clickwrap_responses_service.rb | 13 ++- .../eg006_embed_clickwrap_service.rb | 35 ++++++- .../e_sign/eg002_signing_via_email_service.rb | 12 ++- .../e_sign/eg003_list_envelopes_service.rb | 13 ++- .../e_sign/eg004_envelope_info_service.rb | 13 ++- .../eg005_envelope_recipients_service.rb | 13 ++- .../e_sign/eg006_envelope_docs_service.rb | 13 ++- .../e_sign/eg007_envelope_get_doc_service.rb | 11 ++- .../e_sign/eg008_create_template_service.rb | 23 ++++- .../e_sign/eg009_use_template_service.rb | 12 ++- .../e_sign/eg011_embedded_sending_service.rb | 24 ++++- .../e_sign/eg012_embedded_console_service.rb | 12 ++- .../eg013_add_doc_to_template_service.rb | 26 ++++- .../e_sign/eg014_collect_payment_service.rb | 12 ++- .../eg015_get_envelope_tab_data_service.rb | 13 ++- .../eg016_set_envelope_tab_data_service.rb | 23 ++++- .../eg017_set_template_tab_values_service.rb | 23 ++++- ..._get_envelope_custom_field_data_service.rb | 13 ++- ...g019_access_code_authentication_service.rb | 13 ++- .../eg020_phone_authentication_service.rb | 24 ++++- .../eg022_kba_authentication_service.rb | 13 ++- .../eg023_idv_authentication_service.rb | 25 ++++- .../e_sign/eg024_permission_create_service.rb | 17 +++- ...g025_permissions_set_user_group_service.rb | 13 ++- ...rmissions_change_single_setting_service.rb | 15 ++- .../eg027_permissions_delete_service.rb | 13 ++- .../e_sign/eg028_brands_creating_service.rb | 13 ++- .../eg029_brands_apply_to_envelope_service.rb | 13 ++- .../eg030_brands_apply_to_template_service.rb | 13 ++- .../eg031_bulk_sending_envelopes_service.rb | 60 +++++++++++- ...eg032_pauses_signature_workflow_service.rb | 13 ++- ...033_unpauses_signature_workflow_service.rb | 13 ++- ...g034_use_conditional_recipients_service.rb | 13 ++- .../e_sign/eg035_scheduled_sending_service.rb | 11 ++- .../e_sign/eg036_delayed_routing_service.rb | 11 ++- .../e_sign/eg037_sms_delivery_service.rb | 11 ++- .../eg038_responsive_signing_service.rb | 23 ++++- .../e_sign/eg039_signing_in_person_service.rb | 22 ++++- .../eg040_set_document_visibility_service.rb | 12 ++- .../eg041_cfr_embedded_signing_service.rb | 33 ++++++- .../eg042_document_generation_service.rb | 80 +++++++++++++-- .../e_sign/eg043_shared_access_service.rb | 60 +++++++++++- .../e_sign/eg044_focused_view_service.rb | 23 ++++- .../eg045_delete_restore_envelope_service.rb | 39 +++++++- .../eg001_embedded_signing_service.rb | 23 ++++- .../eg001_get_monitoring_dataset_service.rb | 12 ++- ...04_send_with_third_party_notary_service.rb | 12 ++- .../eg001_create_room_with_data_service.rb | 13 ++- ...eg002_create_room_with_template_service.rb | 13 ++- .../eg003_export_data_from_room_service.rb | 13 ++- .../eg004_add_forms_to_room_service.rb | 13 ++- .../eg005_get_rooms_with_filters_service.rb | 13 ++- ...e_an_external_form_fill_session_service.rb | 13 ++- .../eg007_create_form_group_service.rb | 13 ++- ...ant_office_access_to_form_group_service.rb | 11 ++- ...eg009_assign_form_to_form_group_service.rb | 11 ++- app/services/room_api/get_data_service.rb | 97 +++++++++++++++++-- 74 files changed, 1349 insertions(+), 127 deletions(-) diff --git a/app/services/admin_api/eg001_create_user_service.rb b/app/services/admin_api/eg001_create_user_service.rb index 878120c..7201cc8 100644 --- a/app/services/admin_api/eg001_create_user_service.rb +++ b/app/services/admin_api/eg001_create_user_service.rb @@ -19,7 +19,18 @@ def worker #ds-snippet-start:Admin1Step6 users_api = DocuSign_Admin::UsersApi.new(api_client) - users_api.create_user(args[:organization_id], user_data) + results, _status, headers = users_api.create_user_with_http_info(args[:organization_id], user_data) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Admin1Step6 + + results end end diff --git a/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb b/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb index 9b6d9e4..499e238 100644 --- a/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb +++ b/app/services/admin_api/eg002_create_active_clm_esign_user_service.rb @@ -16,8 +16,19 @@ def worker #ds-snippet-start:Admin2Step6 users_api = DocuSign_Admin::UsersApi.new(api_client) - users_api.add_or_update_user(args[:organization_id], args[:account_id], body(args)) + results, _status, headers = users_api.add_or_update_user_with_http_info(args[:organization_id], args[:account_id], body(args)) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Admin2Step6 + + results end private diff --git a/app/services/admin_api/eg003_bulk_export_user_data_service.rb b/app/services/admin_api/eg003_bulk_export_user_data_service.rb index e4e240c..679e049 100644 --- a/app/services/admin_api/eg003_bulk_export_user_data_service.rb +++ b/app/services/admin_api/eg003_bulk_export_user_data_service.rb @@ -16,7 +16,16 @@ def worker #ds-snippet-start:Admin3Step3 @bulk_exports_api = DocuSign_Admin::BulkExportsApi.new(api_client) - response = bulk_exports_api.create_user_list_export(args[:organization_id], args[:request_body]) + response, _status, headers = bulk_exports_api.create_user_list_export_with_http_info(args[:organization_id], args[:request_body]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Admin3Step3 #ds-snippet-start:Admin3Step4 @@ -28,7 +37,16 @@ def worker else retry_count -= 1 sleep(5) - response = bulk_exports_api.get_user_list_export(args[:organization_id], response.id) + response, _status, headers = bulk_exports_api.get_user_list_export_with_http_info(args[:organization_id], response.id) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end end end #ds-snippet-end:Admin3Step4 @@ -40,7 +58,17 @@ def worker #ds-snippet-start:Admin3Step5 def get_exported_user_data(args, export_id) - bulk_export_response = bulk_exports_api.get_user_list_export(args[:organization_id], export_id) + bulk_export_response, _status, headers = bulk_exports_api.get_user_list_export_with_http_info(args[:organization_id], export_id) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + data_url = bulk_export_response.results[0].url uri = URI(data_url) diff --git a/app/services/admin_api/eg004_import_user_service.rb b/app/services/admin_api/eg004_import_user_service.rb index 6a7a719..d9f0c7e 100644 --- a/app/services/admin_api/eg004_import_user_service.rb +++ b/app/services/admin_api/eg004_import_user_service.rb @@ -19,7 +19,18 @@ def worker csv_file_data = csv_file_data.gsub('{account_id}', args[:account_id]) @bulk_imports_api = DocuSign_Admin::BulkImportsApi.new(api_client) - @bulk_imports_api.create_bulk_import_add_users_request(args[:organization_id], csv_file_data) + results, _status, headers = @bulk_imports_api.create_bulk_import_add_users_request_with_http_info(args[:organization_id], csv_file_data) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Admin4Step3 + + results end end diff --git a/app/services/admin_api/eg005_audit_users_service.rb b/app/services/admin_api/eg005_audit_users_service.rb index c2a612e..7afab0c 100644 --- a/app/services/admin_api/eg005_audit_users_service.rb +++ b/app/services/admin_api/eg005_audit_users_service.rb @@ -22,19 +22,38 @@ def worker options.last_modified_since = (Date.today - 10).strftime('%Y/%m/%d') users_api = DocuSign_Admin::UsersApi.new(api_client) - modified_users = users_api.get_users(args[:organization_id], options).as_json['users'] + modified_users, _status, headers = users_api.get_users_with_http_info(args[:organization_id], options) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Admin5Step3 #ds-snippet-start:Admin5Step5 results = [] - modified_users.each do |user| + modified_users.as_json['users'].each do |user| #ds-snippet-end:Admin5Step5 #ds-snippet-start:Admin5Step4 userProfilesOptions = DocuSign_Admin::GetUserProfilesOptions.new userProfilesOptions.email = user['email'] #ds-snippet-end:Admin5Step4 #ds-snippet-start:Admin5Step5 - result = users_api.get_user_profiles(args[:organization_id], userProfilesOptions) + result, _status, headers = users_api.get_user_profiles_with_http_info(args[:organization_id], userProfilesOptions) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + results.push(result) end #ds-snippet-end:Admin5Step5 diff --git a/app/services/admin_api/eg006_get_user_profile_by_email_service.rb b/app/services/admin_api/eg006_get_user_profile_by_email_service.rb index ee00978..8fdd40c 100644 --- a/app/services/admin_api/eg006_get_user_profile_by_email_service.rb +++ b/app/services/admin_api/eg006_get_user_profile_by_email_service.rb @@ -21,7 +21,18 @@ def worker options = DocuSign_Admin::GetUserDSProfilesByEmailOptions.new options.email = args[:email] - users_api.get_user_ds_profiles_by_email(args[:organization_id], options) + results, _status, headers = users_api.get_user_ds_profiles_by_email_with_http_info(args[:organization_id], options) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Admin6Step3 + + results end end diff --git a/app/services/admin_api/eg007_get_user_profile_by_user_id_service.rb b/app/services/admin_api/eg007_get_user_profile_by_user_id_service.rb index 8f20ca4..cb4f237 100644 --- a/app/services/admin_api/eg007_get_user_profile_by_user_id_service.rb +++ b/app/services/admin_api/eg007_get_user_profile_by_user_id_service.rb @@ -18,7 +18,18 @@ def worker #ds-snippet-start:Admin7Step3 users_api = DocuSign_Admin::UsersApi.new(api_client) - users_api.get_user_ds_profile(args[:organization_id], args[:user_id]) + results, _status, headers = users_api.get_user_ds_profile_with_http_info(args[:organization_id], args[:user_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Admin7Step3 + + results end end diff --git a/app/services/admin_api/eg008_update_user_product_permission_profile_service.rb b/app/services/admin_api/eg008_update_user_product_permission_profile_service.rb index fe58f2b..60d726a 100644 --- a/app/services/admin_api/eg008_update_user_product_permission_profile_service.rb +++ b/app/services/admin_api/eg008_update_user_product_permission_profile_service.rb @@ -23,7 +23,18 @@ def worker #ds-snippet-start:Admin8Step4 product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(api_client) - product_permission_profiles_api.add_user_product_permission_profiles_by_email(args[:organization_id], args[:account_id], user_product_permission_profile_request) + results, _status, headers = product_permission_profiles_api.add_user_product_permission_profiles_by_email_with_http_info(args[:organization_id], args[:account_id], user_product_permission_profile_request) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Admin8Step4 + + results end end diff --git a/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb b/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb index baf16fd..75a9b75 100644 --- a/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb +++ b/app/services/admin_api/eg009_delete_user_product_permission_profile_service.rb @@ -22,8 +22,19 @@ def worker #ds-snippet-start:Admin9Step5 product_permission_profiles_api = DocuSign_Admin::ProductPermissionProfilesApi.new(api_client) - product_permission_profiles_api.remove_user_product_permission(args[:organization_id], args[:account_id], user_product_profile_delete_request) + results, _status, headers = product_permission_profiles_api.remove_user_product_permission_with_http_info(args[:organization_id], args[:account_id], user_product_profile_delete_request) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Admin9Step5 + + results end def get_permission_profiles_by_email @@ -39,7 +50,17 @@ def get_permission_profiles_by_email options = DocuSign_Admin::GetUserProductPermissionProfilesByEmailOptions.new options.email = args[:email] - product_permission_profiles = product_permission_profiles_api.get_user_product_permission_profiles_by_email(args[:organization_id], args[:account_id], options) + product_permission_profiles, _status, headers = product_permission_profiles_api.get_user_product_permission_profiles_by_email_with_http_info(args[:organization_id], args[:account_id], options) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + product_permission_profiles.as_json['product_permission_profiles'] #ds-snippet-end:Admin9Step3 end diff --git a/app/services/admin_api/eg010_delete_user_data_from_organization_service.rb b/app/services/admin_api/eg010_delete_user_data_from_organization_service.rb index 2ce8c20..52c0515 100644 --- a/app/services/admin_api/eg010_delete_user_data_from_organization_service.rb +++ b/app/services/admin_api/eg010_delete_user_data_from_organization_service.rb @@ -21,7 +21,17 @@ def worker options = DocuSign_Admin::GetUserDSProfilesByEmailOptions.new options.email = args[:email] - result = users_api.get_user_ds_profiles_by_email(args[:organization_id], options) + result, _status, headers = users_api.get_user_ds_profiles_by_email_with_http_info(args[:organization_id], options) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + user = result.users[0] #ds-snippet-start:Admin10Step3 @@ -37,7 +47,18 @@ def worker #ds-snippet-end:Admin10Step3 #ds-snippet-start:Admin10Step4 - organizations_api.redact_individual_user_data(args[:organization_id], user_data_redaction_request) + results, _status, headers = organizations_api.redact_individual_user_data_with_http_info(args[:organization_id], user_data_redaction_request) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Admin10Step4 + + results end end diff --git a/app/services/admin_api/eg011_delete_user_data_from_account_service.rb b/app/services/admin_api/eg011_delete_user_data_from_account_service.rb index ba02f72..4001765 100644 --- a/app/services/admin_api/eg011_delete_user_data_from_account_service.rb +++ b/app/services/admin_api/eg011_delete_user_data_from_account_service.rb @@ -24,7 +24,18 @@ def worker #ds-snippet-end:Admin11Step3 #ds-snippet-start:Admin11Step4 - accounts_api.redact_individual_membership_data(args[:account_id], membership_redaction_request) + results, _status, headers = accounts_api.redact_individual_membership_data_with_http_info(args[:account_id], membership_redaction_request) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Admin11Step4 + + results end end diff --git a/app/services/admin_api/eg012_clone_account_service.rb b/app/services/admin_api/eg012_clone_account_service.rb index cb1ac61..3b87af7 100644 --- a/app/services/admin_api/eg012_clone_account_service.rb +++ b/app/services/admin_api/eg012_clone_account_service.rb @@ -37,8 +37,19 @@ def worker #ds-snippet-start:Admin12Step5 asset_group_api = DocuSign_Admin::ProvisionAssetGroupApi.new(api_client) - asset_group_api.clone_asset_group_account(args[:organization_id], account_data) + results, _status, headers = asset_group_api.clone_asset_group_account_with_http_info(args[:organization_id], account_data) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Admin12Step5 + + results end def get_account @@ -52,7 +63,18 @@ def get_account asset_group_api = DocuSign_Admin::ProvisionAssetGroupApi.new(api_client) options = DocuSign_Admin::GetAssetGroupAccountsOptions.new options.compliant = true - asset_group_api.get_asset_group_accounts(args[:organization_id], options) + results, _status, headers = asset_group_api.get_asset_group_accounts_with_http_info(args[:organization_id], options) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Admin12Step3 + + results end end diff --git a/app/services/admin_api/eg013_create_account_service.rb b/app/services/admin_api/eg013_create_account_service.rb index 848b0d5..5439555 100644 --- a/app/services/admin_api/eg013_create_account_service.rb +++ b/app/services/admin_api/eg013_create_account_service.rb @@ -40,8 +40,19 @@ def worker #ds-snippet-start:Admin13Step5 asset_group_api = DocuSign_Admin::ProvisionAssetGroupApi.new(api_client) - asset_group_api.create_asset_group_account(args[:organization_id], account_data) + results, _status, headers = asset_group_api.create_asset_group_account_with_http_info(args[:organization_id], account_data) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Admin13Step5 + + results end def get_organization_plan_items @@ -53,7 +64,18 @@ def get_organization_plan_items #ds-snippet-start:Admin13Step3 asset_group_api = DocuSign_Admin::ProvisionAssetGroupApi.new(api_client) - asset_group_api.get_organization_plan_items(args[:organization_id]) + results, _status, headers = asset_group_api.get_organization_plan_items_with_http_info(args[:organization_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Admin13Step3 + + results end end diff --git a/app/services/clickwrap/eg001_create_clickwrap_service.rb b/app/services/clickwrap/eg001_create_clickwrap_service.rb index 3b224bc..794c28b 100644 --- a/app/services/clickwrap/eg001_create_clickwrap_service.rb +++ b/app/services/clickwrap/eg001_create_clickwrap_service.rb @@ -58,7 +58,18 @@ def worker # Step 4. Call the Click API #ds-snippet-start:Click1Step4 account_api = DocuSign_Click::AccountsApi.new(api_client) - account_api.create_clickwrap(args[:account_id], clickwrap_request) + results, _status, headers = account_api.create_clickwrap_with_http_info(args[:account_id], clickwrap_request) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Click1Step4 + + results end end diff --git a/app/services/clickwrap/eg002_activate_clickwrap_service.rb b/app/services/clickwrap/eg002_activate_clickwrap_service.rb index 51cf5f3..ba8908e 100644 --- a/app/services/clickwrap/eg002_activate_clickwrap_service.rb +++ b/app/services/clickwrap/eg002_activate_clickwrap_service.rb @@ -26,13 +26,24 @@ def worker # Step 4. Call the Click API #ds-snippet-start:Click2Step4 accounts_api = DocuSign_Click::AccountsApi.new(api_client) - accounts_api.update_clickwrap_version( + results, _status, headers = accounts_api.update_clickwrap_version_with_http_info( args[:account_id], args[:clickwrap_id], 1, clickwrap_request ) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Click2Step4 + + results end def get_inactive_clickwraps(statuses) @@ -48,10 +59,21 @@ def get_inactive_clickwraps(statuses) statuses.each do |status| options = DocuSign_Click::GetClickwrapsOptions.new options.status = status - clickwraps.concat accounts_api.get_clickwraps( + results, _status, headers = accounts_api.get_clickwraps_with_http_info( args[:ds_account_id], options - ).clickwraps + ) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + + clickwraps.concat results.clickwraps end clickwraps diff --git a/app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb b/app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb index 5272fbc..d30498f 100644 --- a/app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb +++ b/app/services/clickwrap/eg003_create_new_clickwrap_version_service.rb @@ -57,11 +57,22 @@ def worker # Step 4. Call the Click API #ds-snippet-start:Click3Step4 accounts_api = DocuSign_Click::AccountsApi.new(api_client) - accounts_api.create_clickwrap_version( + results, _status, headers = accounts_api.create_clickwrap_version_with_http_info( args[:account_id], args[:clickwrap_id], clickwrap_request ) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Click4Step4 + + results end end diff --git a/app/services/clickwrap/eg004_list_clickwraps_service.rb b/app/services/clickwrap/eg004_list_clickwraps_service.rb index 75c2375..b833054 100644 --- a/app/services/clickwrap/eg004_list_clickwraps_service.rb +++ b/app/services/clickwrap/eg004_list_clickwraps_service.rb @@ -20,9 +20,20 @@ def worker # Step 3. Call the Click API #ds-snippet-start:Click4Step3 accounts_api = DocuSign_Click::AccountsApi.new(api_client) - accounts_api.get_clickwraps( + results, _status, headers = accounts_api.get_clickwraps_with_http_info( args[:account_id] ) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Click4Step3 + + results end end diff --git a/app/services/clickwrap/eg005_clickwrap_responses_service.rb b/app/services/clickwrap/eg005_clickwrap_responses_service.rb index 4a8abba..6f46aa3 100644 --- a/app/services/clickwrap/eg005_clickwrap_responses_service.rb +++ b/app/services/clickwrap/eg005_clickwrap_responses_service.rb @@ -26,11 +26,22 @@ def worker # Get clickwrap responses using SDK accounts_api = DocuSign_Click::AccountsApi.new(api_client) - accounts_api.get_clickwrap_agreements( + results, _status, headers = accounts_api.get_clickwrap_agreements_with_http_info( args[:account_id], args[:clickwrap_id], agreements ) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Click5Step3 + + results end end diff --git a/app/services/clickwrap/eg006_embed_clickwrap_service.rb b/app/services/clickwrap/eg006_embed_clickwrap_service.rb index de25785..2a99f13 100644 --- a/app/services/clickwrap/eg006_embed_clickwrap_service.rb +++ b/app/services/clickwrap/eg006_embed_clickwrap_service.rb @@ -36,7 +36,16 @@ def worker #ds-snippet-start:Click6Step4 accounts_api = DocuSign_Click::AccountsApi.new(api_client) - response = accounts_api.create_has_agreed(args[:account_id], args[:clickwrap_id], userAgreementRequest) + response, _status, headers = accounts_api.create_has_agreed_with_http_info(args[:account_id], args[:clickwrap_id], userAgreementRequest) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end response.as_json #ds-snippet-end:Click6Step4 @@ -54,10 +63,20 @@ def get_active_clickwraps options = DocuSign_Click::GetClickwrapsOptions.new options.status = 'active' - results = accounts_api.get_clickwraps( + results, _status, headers = accounts_api.get_clickwraps_with_http_info( args[:ds_account_id], options ) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + puts results.as_json['clickwraps'] results.as_json['clickwraps'] end @@ -74,10 +93,20 @@ def get_inactive_clickwraps options = DocuSign_Click::GetClickwrapsOptions.new options.status = 'inactive' - results = accounts_api.get_clickwraps( + results, _status, headers = accounts_api.get_clickwraps_with_http_info( args[:ds_account_id], options ) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + results.as_json['clickwraps'] end end diff --git a/app/services/e_sign/eg002_signing_via_email_service.rb b/app/services/e_sign/eg002_signing_via_email_service.rb index 9aae9f4..8c7f447 100644 --- a/app/services/e_sign/eg002_signing_via_email_service.rb +++ b/app/services/e_sign/eg002_signing_via_email_service.rb @@ -17,7 +17,17 @@ def worker # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope args[:account_id], envelope_definition + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope_definition + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + envelope_id = results.envelope_id { 'envelope_id' => envelope_id } end diff --git a/app/services/e_sign/eg003_list_envelopes_service.rb b/app/services/e_sign/eg003_list_envelopes_service.rb index cf56d34..7911fd5 100644 --- a/app/services/e_sign/eg003_list_envelopes_service.rb +++ b/app/services/e_sign/eg003_list_envelopes_service.rb @@ -22,7 +22,18 @@ def worker options = DocuSign_eSign::ListStatusChangesOptions.new options.from_date = (Date.today - 30).strftime('%Y-%m-%d') # Exceptions will be caught by the calling function - envelope_api.list_status_changes args[:account_id], options + results, _status, headers = envelope_api.list_status_changes_with_http_info args[:account_id], options + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign3Step2 + + results end end diff --git a/app/services/e_sign/eg004_envelope_info_service.rb b/app/services/e_sign/eg004_envelope_info_service.rb index 48b1827..c7f343a 100644 --- a/app/services/e_sign/eg004_envelope_info_service.rb +++ b/app/services/e_sign/eg004_envelope_info_service.rb @@ -12,7 +12,18 @@ def initialize(args) def worker #ds-snippet-start:eSign4Step2 envelope_api = create_envelope_api(args) - envelope_api.get_envelope(args[:account_id], args[:envelope_id]) + results, _status, headers = envelope_api.get_envelope_with_http_info(args[:account_id], args[:envelope_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign4Step2 + + results end end diff --git a/app/services/e_sign/eg005_envelope_recipients_service.rb b/app/services/e_sign/eg005_envelope_recipients_service.rb index 0107923..c193deb 100644 --- a/app/services/e_sign/eg005_envelope_recipients_service.rb +++ b/app/services/e_sign/eg005_envelope_recipients_service.rb @@ -12,7 +12,18 @@ def initialize(args) def worker #ds-snippet-start:eSign5Step2 envelope_api = create_envelope_api(args) - envelope_api.list_recipients args[:account_id], args[:envelope_id] + results, _status, headers = envelope_api.list_recipients_with_http_info args[:account_id], args[:envelope_id] + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign5Step2 + + results end end diff --git a/app/services/e_sign/eg006_envelope_docs_service.rb b/app/services/e_sign/eg006_envelope_docs_service.rb index 51e3595..de7a705 100644 --- a/app/services/e_sign/eg006_envelope_docs_service.rb +++ b/app/services/e_sign/eg006_envelope_docs_service.rb @@ -12,7 +12,18 @@ def initialize(args) def worker #ds-snippet-start:eSign6Step3 envelope_api = create_envelope_api(args) - envelope_api.list_documents args[:account_id], args[:envelope_id] + results, _status, headers = envelope_api.list_documents_with_http_info args[:account_id], args[:envelope_id] + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign6Step3 + + results end end diff --git a/app/services/e_sign/eg007_envelope_get_doc_service.rb b/app/services/e_sign/eg007_envelope_get_doc_service.rb index 059c7b8..a28e065 100644 --- a/app/services/e_sign/eg007_envelope_get_doc_service.rb +++ b/app/services/e_sign/eg007_envelope_get_doc_service.rb @@ -15,7 +15,16 @@ def worker document_id = args[:document_id] - temp_file = envelope_api.get_document args[:account_id], document_id, args[:envelope_id] + temp_file, _status, headers = envelope_api.get_document_with_http_info args[:account_id], document_id, args[:envelope_id] + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign7Step3 # Find the matching document information item doc_item = args[:envelope_documents]['documents'].find { |item| item['document_id'] == document_id } diff --git a/app/services/e_sign/eg008_create_template_service.rb b/app/services/e_sign/eg008_create_template_service.rb index fee6169..f25065f 100644 --- a/app/services/e_sign/eg008_create_template_service.rb +++ b/app/services/e_sign/eg008_create_template_service.rb @@ -14,7 +14,17 @@ def worker # Step 1. Does the template exist? Try to look it up by name options = DocuSign_eSign::ListTemplatesOptions.new options.search_text = args[:template_name] - results = templates_api.list_templates(args[:account_id], options) + results, _status, headers = templates_api.list_templates_with_http_info(args[:account_id], options) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + created_new_template = false if results.result_set_size.to_i.positive? @@ -25,7 +35,16 @@ def worker # Step 2 create the template #ds-snippet-start:eSign8Step3 template_req_object = make_template_req - result = templates_api.create_template(args[:account_id], template_req_object) + result, _status, headers = templates_api.create_template_with_http_info(args[:account_id], template_req_object) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign8Step3 created_new_template = true diff --git a/app/services/e_sign/eg009_use_template_service.rb b/app/services/e_sign/eg009_use_template_service.rb index 98b7721..ae01a9e 100644 --- a/app/services/e_sign/eg009_use_template_service.rb +++ b/app/services/e_sign/eg009_use_template_service.rb @@ -17,7 +17,17 @@ def worker # Call Envelopes::create API method # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope args[:account_id], envelope_definition + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope_definition + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + envelope_id = results.envelope_id { envelope_id: envelope_id } end diff --git a/app/services/e_sign/eg011_embedded_sending_service.rb b/app/services/e_sign/eg011_embedded_sending_service.rb index 63b0352..089c9f6 100644 --- a/app/services/e_sign/eg011_embedded_sending_service.rb +++ b/app/services/e_sign/eg011_embedded_sending_service.rb @@ -21,7 +21,17 @@ def worker # Create the sender view view_request = envelope_view_request(args) envelope_api = create_envelope_api(args) - results = envelope_api.create_sender_view args[:account_id], envelope_id, view_request + results, _status, headers = envelope_api.create_sender_view_with_http_info args[:account_id], envelope_id, view_request + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + url = results.url { 'envelope_id' => envelope_id, 'redirect_url' => url } #ds-snippet-end:eSign11Step3 @@ -34,7 +44,17 @@ def create_envelope(args) # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope args[:account_id], envelope_definition + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope_definition + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + envelope_id = results.envelope_id { 'envelope_id' => envelope_id } end diff --git a/app/services/e_sign/eg012_embedded_console_service.rb b/app/services/e_sign/eg012_embedded_console_service.rb index 95332fc..c18cff5 100644 --- a/app/services/e_sign/eg012_embedded_console_service.rb +++ b/app/services/e_sign/eg012_embedded_console_service.rb @@ -19,7 +19,17 @@ def worker view_request.envelope_id = args[:envelope_id] if args[:starting_view] == 'envelope' && args[:envelope_id] # Step 2. Call the API method envelope_api = create_envelope_api(args) - results = envelope_api.create_console_view args[:account_id], view_request + results, _status, headers = envelope_api.create_console_view_with_http_info args[:account_id], view_request + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + #ds-snippet-end:eSign12Step2 { 'redirect_url' => results.url } end diff --git a/app/services/e_sign/eg013_add_doc_to_template_service.rb b/app/services/e_sign/eg013_add_doc_to_template_service.rb index 4d777ea..e3c8b73 100644 --- a/app/services/e_sign/eg013_add_doc_to_template_service.rb +++ b/app/services/e_sign/eg013_add_doc_to_template_service.rb @@ -18,7 +18,17 @@ def worker # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope(args[:account_id], envelope_definition) + results, _status, headers = envelope_api.create_envelope_with_http_info(args[:account_id], envelope_definition) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + envelope_id = results.envelope_id #ds-snippet-end:eSign13Step3 # 3. Create the Recipient View request object @@ -35,8 +45,18 @@ def worker ) # 4. Obtain the recipient_view_url for the embedded signing # Exceptions will be caught by the calling function - results = envelope_api.create_recipient_view(args[:account_id], - envelope_id, recipient_view_request) + results, _status, headers = envelope_api.create_recipient_view_with_http_info(args[:account_id], + envelope_id, recipient_view_request) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + { envelope_id: envelope_id, redirect_url: results.url } end #ds-snippet-end:eSign13Step4 diff --git a/app/services/e_sign/eg014_collect_payment_service.rb b/app/services/e_sign/eg014_collect_payment_service.rb index a0687e4..e529bcc 100644 --- a/app/services/e_sign/eg014_collect_payment_service.rb +++ b/app/services/e_sign/eg014_collect_payment_service.rb @@ -15,7 +15,17 @@ def worker # Create and send the envelope # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope args[:account_id], envelope_definition + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope_definition + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + envelope_id = results.envelope_id { envelope_id: envelope_id } end diff --git a/app/services/e_sign/eg015_get_envelope_tab_data_service.rb b/app/services/e_sign/eg015_get_envelope_tab_data_service.rb index d2d9883..9dc4e17 100644 --- a/app/services/e_sign/eg015_get_envelope_tab_data_service.rb +++ b/app/services/e_sign/eg015_get_envelope_tab_data_service.rb @@ -17,7 +17,18 @@ def worker # Exceptions will be caught by the calling function #ds-snippet-start:eSign15Step3 - create_envelope_api(args).get_form_data args[:account_id], args[:envelope_id] + results, _status, headers = create_envelope_api(args).get_form_data_with_http_info args[:account_id], args[:envelope_id] + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign15Step3 + + results end end diff --git a/app/services/e_sign/eg016_set_envelope_tab_data_service.rb b/app/services/e_sign/eg016_set_envelope_tab_data_service.rb index 4196bbb..cdb9ede 100644 --- a/app/services/e_sign/eg016_set_envelope_tab_data_service.rb +++ b/app/services/e_sign/eg016_set_envelope_tab_data_service.rb @@ -20,7 +20,17 @@ def worker # Call the eSignature REST API #ds-snippet-start:eSign16Step4 - results = create_envelope_api(args).create_envelope args[:account_id], envelope + results, _status, headers = create_envelope_api(args).create_envelope_with_http_info args[:account_id], envelope + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + envelope_id = results.envelope_id #ds-snippet-end:eSign16Step4 @@ -30,7 +40,16 @@ def worker #ds-snippet-end:eSign16Step5 # Call the CreateRecipientView API - results = create_envelope_api(args).create_recipient_view args[:account_id], envelope_id, view_request + results, _status, headers = create_envelope_api(args).create_recipient_view_with_http_info args[:account_id], envelope_id, view_request + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end # Redirect the user to the embedded signing # Don't use an iframe! diff --git a/app/services/e_sign/eg017_set_template_tab_values_service.rb b/app/services/e_sign/eg017_set_template_tab_values_service.rb index 647103e..ac90c23 100644 --- a/app/services/e_sign/eg017_set_template_tab_values_service.rb +++ b/app/services/e_sign/eg017_set_template_tab_values_service.rb @@ -23,7 +23,17 @@ def worker # Step 5. Call the eSignature REST API #ds-snippet-start:eSign17Step5 envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope args[:account_id], envelope_definition + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope_definition + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + envelope_id = results.envelope_id #ds-snippet-end:eSign17Step5 @@ -32,7 +42,16 @@ def worker view_request = make_recipient_view_request(envelope_args[:signer_email], envelope_args[:signer_name], signer_client_id, ds_return_url, ds_ping_url) # Call the CreateRecipientView API - results = envelope_api.create_recipient_view args[:account_id], envelope_id, view_request + results, _status, headers = envelope_api.create_recipient_view_with_http_info args[:account_id], envelope_id, view_request + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end # Redirect the user to the embedded signing # Don't use an iframe! diff --git a/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb b/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb index fead846..8288193 100644 --- a/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb +++ b/app/services/e_sign/eg018_get_envelope_custom_field_data_service.rb @@ -11,7 +11,18 @@ def initialize(args) def worker #ds-snippet-start:eSign18Step3 - create_envelope_api(args).list_custom_fields args[:account_id], args[:envelope_id] + results, _status, headers = create_envelope_api(args).list_custom_fields_with_http_info args[:account_id], args[:envelope_id] + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign18Step3 + + results end end diff --git a/app/services/e_sign/eg019_access_code_authentication_service.rb b/app/services/e_sign/eg019_access_code_authentication_service.rb index 0bd9a8f..d704bce 100644 --- a/app/services/e_sign/eg019_access_code_authentication_service.rb +++ b/app/services/e_sign/eg019_access_code_authentication_service.rb @@ -61,7 +61,18 @@ def worker #ds-snippet-end:eSign19Step3 #ds-snippet-start:eSign19Step4 - envelope_api.create_envelope(args[:account_id], envelope_definition) + results, _status, headers = envelope_api.create_envelope_with_http_info(args[:account_id], envelope_definition) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign19Step4 + + results end end diff --git a/app/services/e_sign/eg020_phone_authentication_service.rb b/app/services/e_sign/eg020_phone_authentication_service.rb index 676175a..def2877 100644 --- a/app/services/e_sign/eg020_phone_authentication_service.rb +++ b/app/services/e_sign/eg020_phone_authentication_service.rb @@ -85,8 +85,19 @@ def worker(workflow_id) # Call the eSignature REST API #ds-snippet-start:eSign20Step5 envelope_api = create_envelope_api(args) - envelope_api.create_envelope args[:account_id], envelope_definition + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope_definition + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign20Step5 + + results end def get_workflow @@ -94,7 +105,16 @@ def get_workflow #ds-snippet-start:eSign20Step3 workflow_details = create_account_api(args) - workflow_response = workflow_details.get_account_identity_verification(args[:account_id]) + workflow_response, _status, headers = workflow_details.get_account_identity_verification_with_http_info(args[:account_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end # Check that idv authentication is enabled if workflow_response.identity_verification diff --git a/app/services/e_sign/eg022_kba_authentication_service.rb b/app/services/e_sign/eg022_kba_authentication_service.rb index abfce8a..7601615 100644 --- a/app/services/e_sign/eg022_kba_authentication_service.rb +++ b/app/services/e_sign/eg022_kba_authentication_service.rb @@ -59,7 +59,18 @@ def worker #ds-snippet-end:eSign22Step3 #ds-snippet-start:eSign22Step4 - envelope_api.create_envelope args[:account_id], envelope_definition + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope_definition + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign22Step4 + + results end end diff --git a/app/services/e_sign/eg023_idv_authentication_service.rb b/app/services/e_sign/eg023_idv_authentication_service.rb index 21f4875..2b8d51c 100644 --- a/app/services/e_sign/eg023_idv_authentication_service.rb +++ b/app/services/e_sign/eg023_idv_authentication_service.rb @@ -15,7 +15,17 @@ def worker # Obtain your workflow ID #ds-snippet-start:eSign23Step3 accounts_api = create_account_api(args) - workflow_response = accounts_api.get_account_identity_verification args[:account_id] + workflow_response, _status, headers = accounts_api.get_account_identity_verification_with_http_info args[:account_id] + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + if workflow_response.identity_verification idv_workflow = workflow_response.identity_verification.find { |item| item.default_name == 'DocuSign ID Verification' } workflow_id = idv_workflow.workflow_id if idv_workflow @@ -83,7 +93,18 @@ def worker # Call the eSignature REST API #ds-snippet-start:eSign23Step5 envelope_api = create_envelope_api(args) - envelope_api.create_envelope args[:account_id], envelope_definition + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope_definition + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign23Step5 + + results end end diff --git a/app/services/e_sign/eg024_permission_create_service.rb b/app/services/e_sign/eg024_permission_create_service.rb index fd6a625..54cbc83 100644 --- a/app/services/e_sign/eg024_permission_create_service.rb +++ b/app/services/e_sign/eg024_permission_create_service.rb @@ -14,9 +14,20 @@ def worker accounts_api = create_account_api(args) permission_profile_name = args[:permission_profile_name] permission_profile_settings = make_permission_profile_settings - accounts_api.create_permission_profile(args[:account_id], { permissionProfileName: permission_profile_name, - settings: permission_profile_settings }, - DocuSign_eSign::CreatePermissionProfileOptions.default) + results, _status, headers = accounts_api.create_permission_profile_with_http_info(args[:account_id], { permissionProfileName: permission_profile_name, + settings: permission_profile_settings }, + DocuSign_eSign::CreatePermissionProfileOptions.default) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + + results #ds-snippet-end:eSign24Step4 end diff --git a/app/services/e_sign/eg025_permissions_set_user_group_service.rb b/app/services/e_sign/eg025_permissions_set_user_group_service.rb index 11005fb..3e3dda4 100644 --- a/app/services/e_sign/eg025_permissions_set_user_group_service.rb +++ b/app/services/e_sign/eg025_permissions_set_user_group_service.rb @@ -19,7 +19,18 @@ def worker # Call the eSignature REST API #ds-snippet-start:eSign25Step4 - group_api.update_groups(args[:account_id], params) + results, _status, headers = group_api.update_groups_with_http_info(args[:account_id], params) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign25Step4 + + results end end diff --git a/app/services/e_sign/eg026_permissions_change_single_setting_service.rb b/app/services/e_sign/eg026_permissions_change_single_setting_service.rb index 7dee3aa..7a6cf5a 100644 --- a/app/services/e_sign/eg026_permissions_change_single_setting_service.rb +++ b/app/services/e_sign/eg026_permissions_change_single_setting_service.rb @@ -14,9 +14,20 @@ def worker accounts_api = create_account_api(args) permission_profile_settings = make_permission_profile_settings permission_profile_id = args[:permission_profile_id] - accounts_api.update_permission_profile(args[:account_id], permission_profile_id, - permission_profile_settings, DocuSign_eSign::UpdatePermissionProfileOptions.default) + results, _status, headers = accounts_api.update_permission_profile_with_http_info(args[:account_id], permission_profile_id, + permission_profile_settings, DocuSign_eSign::UpdatePermissionProfileOptions.default) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign26Step4 + + results end private diff --git a/app/services/e_sign/eg027_permissions_delete_service.rb b/app/services/e_sign/eg027_permissions_delete_service.rb index 6d5df02..a3e2924 100644 --- a/app/services/e_sign/eg027_permissions_delete_service.rb +++ b/app/services/e_sign/eg027_permissions_delete_service.rb @@ -13,7 +13,18 @@ def worker # Call the eSignature REST API #ds-snippet-start:eSign27Step3 accounts_api = create_account_api(args) - accounts_api.delete_permission_profile(args[:account_id], args[:permission_profile_id]) + results, _status, headers = accounts_api.delete_permission_profile_with_http_info(args[:account_id], args[:permission_profile_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign27Step3 + + results end end diff --git a/app/services/e_sign/eg028_brands_creating_service.rb b/app/services/e_sign/eg028_brands_creating_service.rb index afdef4c..089776d 100644 --- a/app/services/e_sign/eg028_brands_creating_service.rb +++ b/app/services/e_sign/eg028_brands_creating_service.rb @@ -26,7 +26,18 @@ def worker # Step 4: Call the eSignature API #ds-snippet-start:eSign28Step4 - accounts_api.create_brand(args[:account_id], params) + results, _status, headers = accounts_api.create_brand_with_http_info(args[:account_id], params) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign28Step4 + + results end end diff --git a/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb b/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb index cf97a85..46045c5 100644 --- a/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb +++ b/app/services/e_sign/eg029_brands_apply_to_envelope_service.rb @@ -19,8 +19,19 @@ def worker #ds-snippet-end:eSign29Step3 # Step 4. Call the eSignature REST API #ds-snippet-start:eSign29Step4 - envelope_api.create_envelope args[:account_id], envelope_definition + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope_definition + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign29Step4 + + results end private diff --git a/app/services/e_sign/eg030_brands_apply_to_template_service.rb b/app/services/e_sign/eg030_brands_apply_to_template_service.rb index 5ea1928..c532d7b 100644 --- a/app/services/e_sign/eg030_brands_apply_to_template_service.rb +++ b/app/services/e_sign/eg030_brands_apply_to_template_service.rb @@ -19,8 +19,19 @@ def worker #ds-snippet-end:eSign30Step3 # Call the eSignature REST API #ds-snippet-start:eSign30Step4 - envelope_api.create_envelope args[:account_id], envelope_definition + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope_definition + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign30Step4 + + results end private diff --git a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb index 7ef43fb..bc4cbc0 100644 --- a/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb +++ b/app/services/e_sign/eg031_bulk_sending_envelopes_service.rb @@ -23,7 +23,17 @@ def worker #ds-snippet-start:eSign31Step3 bulk_envelopes_api = DocuSign_eSign::BulkEnvelopesApi.new api_client bulk_sending_list = create_bulk_sending_list(signers) - bulk_list = bulk_envelopes_api.create_bulk_send_list(args[:account_id], bulk_sending_list) + bulk_list, _status, headers = bulk_envelopes_api.create_bulk_send_list_with_http_info(args[:account_id], bulk_sending_list) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + bulk_list_id = bulk_list.list_id #ds-snippet-end:eSign31Step3 @@ -31,26 +41,66 @@ def worker #ds-snippet-start:eSign31Step4 envelope_api = create_envelope_api(args) envelope_definition = make_envelope - envelope = envelope_api.create_envelope(args[:account_id], envelope_definition, DocuSign_eSign::CreateEnvelopeOptions.default) + envelope, _status, headers = envelope_api.create_envelope_with_http_info(args[:account_id], envelope_definition, DocuSign_eSign::CreateEnvelopeOptions.default) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + envelope_id = envelope.envelope_id #ds-snippet-end:eSign31Step4 # Attach your bulk list ID to the envelope #ds-snippet-start:eSign31Step5 - envelope_api.create_custom_fields(args[:account_id], envelope_id, custom_fields(bulk_list_id)) + _results, _status, headers = envelope_api.create_custom_fields_with_http_info(args[:account_id], envelope_id, custom_fields(bulk_list_id)) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign31Step5 # Initiate bulk send #ds-snippet-start:eSign31Step6 bulk_send_request = DocuSign_eSign::BulkSendRequest.new(envelopeOrTemplateId: envelope_id) - batch = bulk_envelopes_api.create_bulk_send_request(args[:account_id], bulk_list_id, bulk_send_request) + batch, _status, headers = bulk_envelopes_api.create_bulk_send_request_with_http_info(args[:account_id], bulk_list_id, bulk_send_request) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + batch_id = batch.batch_id #ds-snippet-end:eSign31Step6 # Confirm successful batch send #ds-snippet-start:eSign31Step7 - bulk_envelopes_api.get_bulk_send_batch_status(args[:account_id], batch_id) + results, _status, headers = bulk_envelopes_api.get_bulk_send_batch_status_with_http_info(args[:account_id], batch_id) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign31Step7 + + results end private diff --git a/app/services/e_sign/eg032_pauses_signature_workflow_service.rb b/app/services/e_sign/eg032_pauses_signature_workflow_service.rb index 4ad7554..e674019 100644 --- a/app/services/e_sign/eg032_pauses_signature_workflow_service.rb +++ b/app/services/e_sign/eg032_pauses_signature_workflow_service.rb @@ -95,10 +95,21 @@ def worker #ds-snippet-start:eSign32Step4 envelopes_api = DocuSign_eSign::EnvelopesApi.new(api_client) - envelopes_api.create_envelope( + results, _status, headers = envelopes_api.create_envelope_with_http_info( args[:accountId], envelope_definition ) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign32Step4 + + results end end diff --git a/app/services/e_sign/eg033_unpauses_signature_workflow_service.rb b/app/services/e_sign/eg033_unpauses_signature_workflow_service.rb index 6e7e77d..370ea68 100644 --- a/app/services/e_sign/eg033_unpauses_signature_workflow_service.rb +++ b/app/services/e_sign/eg033_unpauses_signature_workflow_service.rb @@ -30,12 +30,23 @@ def worker update_options = DocuSign_eSign::UpdateOptions.new update_options.resend_envelope = true - envelopes_api.update( + results, _status, headers = envelopes_api.update_with_http_info( args[:accountId], args[:envelopeId], envelope_definition, update_options ) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + + results end #ds-snippet-end:eSign33Step4 end diff --git a/app/services/e_sign/eg034_use_conditional_recipients_service.rb b/app/services/e_sign/eg034_use_conditional_recipients_service.rb index ee01a75..c4887cf 100644 --- a/app/services/e_sign/eg034_use_conditional_recipients_service.rb +++ b/app/services/e_sign/eg034_use_conditional_recipients_service.rb @@ -183,10 +183,21 @@ def worker #ds-snippet-start:eSign34Step4 envelopes_api = DocuSign_eSign::EnvelopesApi.new(api_client) - envelopes_api.create_envelope( + results, _status, headers = envelopes_api.create_envelope_with_http_info( args[:accountId], envelope_definition ) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign34Step4 + + results end end diff --git a/app/services/e_sign/eg035_scheduled_sending_service.rb b/app/services/e_sign/eg035_scheduled_sending_service.rb index 36d626a..fc8f959 100644 --- a/app/services/e_sign/eg035_scheduled_sending_service.rb +++ b/app/services/e_sign/eg035_scheduled_sending_service.rb @@ -18,7 +18,16 @@ def worker # Step 3 start #ds-snippet-start:eSign35Step3 - results = envelope_api.create_envelope args[:account_id], envelope_definition + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope_definition + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign35Step3 # Step 3 end diff --git a/app/services/e_sign/eg036_delayed_routing_service.rb b/app/services/e_sign/eg036_delayed_routing_service.rb index 9551f48..6733b2a 100644 --- a/app/services/e_sign/eg036_delayed_routing_service.rb +++ b/app/services/e_sign/eg036_delayed_routing_service.rb @@ -17,7 +17,16 @@ def worker envelope_api = create_envelope_api(args) #ds-snippet-start:eSign36Step3 - results = envelope_api.create_envelope args[:account_id], envelope_definition + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope_definition + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign36Step3 envelope_id = results.envelope_id { 'envelope_id' => envelope_id } diff --git a/app/services/e_sign/eg037_sms_delivery_service.rb b/app/services/e_sign/eg037_sms_delivery_service.rb index 79edddb..3854414 100644 --- a/app/services/e_sign/eg037_sms_delivery_service.rb +++ b/app/services/e_sign/eg037_sms_delivery_service.rb @@ -18,7 +18,16 @@ def worker # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) #ds-snippet-start:eSign37Step3 - results = envelope_api.create_envelope args[:account_id], envelope_definition + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope_definition + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign37Step3 envelope_id = results.envelope_id { 'envelope_id' => envelope_id } diff --git a/app/services/e_sign/eg038_responsive_signing_service.rb b/app/services/e_sign/eg038_responsive_signing_service.rb index 0cd1a4c..0b3307e 100644 --- a/app/services/e_sign/eg038_responsive_signing_service.rb +++ b/app/services/e_sign/eg038_responsive_signing_service.rb @@ -19,7 +19,17 @@ def worker # Call Docusign to create the envelope envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope args[:account_id], envelope + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + envelope_id = results.envelope_id # Save for future use within the example launcher # session[:envelope_id] = envelope_id @@ -28,7 +38,16 @@ def worker view_request = make_recipient_view_request(args, ds_return_url) # Call the CreateRecipientView API - results = envelope_api.create_recipient_view args[:account_id], envelope_id, view_request + results, _status, headers = envelope_api.create_recipient_view_with_http_info args[:account_id], envelope_id, view_request + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end # Step 4. Redirect the user to the embedded signing # Don't use an iframe! diff --git a/app/services/e_sign/eg039_signing_in_person_service.rb b/app/services/e_sign/eg039_signing_in_person_service.rb index 2ba99d5..fc3a5d5 100644 --- a/app/services/e_sign/eg039_signing_in_person_service.rb +++ b/app/services/e_sign/eg039_signing_in_person_service.rb @@ -22,7 +22,16 @@ def worker #ds-snippet-start:eSign39Step3 envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope args[:account_id], envelope + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign39Step3 envelope_id = results.envelope_id @@ -31,7 +40,16 @@ def worker view_request = make_recipient_view_request(ds_return_url, ds_ping_url, host_email, host_name) # Call the CreateRecipientView API - results = envelope_api.create_recipient_view args[:account_id], envelope_id, view_request + results, _status, headers = envelope_api.create_recipient_view_with_http_info args[:account_id], envelope_id, view_request + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign39Step5 # Redirect the user to the embedded signing diff --git a/app/services/e_sign/eg040_set_document_visibility_service.rb b/app/services/e_sign/eg040_set_document_visibility_service.rb index 0049c20..d9c08bb 100644 --- a/app/services/e_sign/eg040_set_document_visibility_service.rb +++ b/app/services/e_sign/eg040_set_document_visibility_service.rb @@ -17,7 +17,17 @@ def worker # Exceptions will be caught by the calling function #ds-snippet-start:eSign40Step4 envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope args[:account_id], envelope_definition + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope_definition + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + envelope_id = results.envelope_id #ds-snippet-end:eSign40Step4 diff --git a/app/services/e_sign/eg041_cfr_embedded_signing_service.rb b/app/services/e_sign/eg041_cfr_embedded_signing_service.rb index 95585c9..23031bc 100644 --- a/app/services/e_sign/eg041_cfr_embedded_signing_service.rb +++ b/app/services/e_sign/eg041_cfr_embedded_signing_service.rb @@ -16,7 +16,16 @@ def worker accounts_api = create_account_api(args) # Obtain your workflow_id - workflow_results = accounts_api.get_account_identity_verification(args[:account_id]) + workflow_results, _status, headers = accounts_api.get_account_identity_verification_with_http_info(args[:account_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end if workflow_results.identity_verification workflow = workflow_results.identity_verification.find { |item| item.default_name == 'SMS for access & signatures' } @@ -30,7 +39,16 @@ def worker envelope_api = create_envelope_api(args) envelope_definition = make_envelope(args[:envelope_args], workflow_id) - envelope = envelope_api.create_envelope(args[:account_id], envelope_definition) + envelope, _status, headers = envelope_api.create_envelope_with_http_info(args[:account_id], envelope_definition) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end envelope_id = envelope.envelope_id #ds-snippet-end:eSign41Step4 @@ -48,7 +66,16 @@ def worker #ds-snippet-end:eSign41Step5 #ds-snippet-start:eSign41Step6 - results = envelope_api.create_recipient_view(args[:account_id], envelope_id, view_request) + results, _status, headers = envelope_api.create_recipient_view_with_http_info(args[:account_id], envelope_id, view_request) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end results.url #ds-snippet-end:eSign41Step6 diff --git a/app/services/e_sign/eg042_document_generation_service.rb b/app/services/e_sign/eg042_document_generation_service.rb index 0b2a3c1..5e9a2ef 100644 --- a/app/services/e_sign/eg042_document_generation_service.rb +++ b/app/services/e_sign/eg042_document_generation_service.rb @@ -17,43 +17,109 @@ def worker envelope_args = args[:envelope_args] #ds-snippet-start:eSign42Step2 - template = template_api.create_template(account_id, template_data) + template, _status, headers = template_api.create_template_with_http_info(account_id, template_data) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + template_id = template.template_id #ds-snippet-end:eSign42Step2 #ds-snippet-start:eSign42Step3 document_id = '1' - template_api.update_document(account_id, document_id, template_id, template_document(envelope_args)) + _results, _status, headers = template_api.update_document_with_http_info(account_id, document_id, template_id, template_document(envelope_args)) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign42Step3 #ds-snippet-start:eSign42Step4 recipient_id = '1' - template_api.create_tabs(account_id, recipient_id, template_id, recipient_tabs) + _results, _status, headers = template_api.create_tabs_with_http_info(account_id, recipient_id, template_id, recipient_tabs) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign42Step4 #ds-snippet-start:eSign42Step5 envelope_definition = make_envelope(template_id, envelope_args) - envelope = envelope_api.create_envelope(account_id, envelope_definition) + envelope, _status, headers = envelope_api.create_envelope_with_http_info(account_id, envelope_definition) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + envelope_id = envelope.envelope_id #ds-snippet-end:eSign42Step5 #ds-snippet-start:eSign42Step6 - doc_gen_form_fields_response = envelope_api.get_envelope_doc_gen_form_fields(account_id, envelope_id) + doc_gen_form_fields_response, _status, headers = envelope_api.get_envelope_doc_gen_form_fields_with_http_info(account_id, envelope_id) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + document_id_guid = doc_gen_form_fields_response.doc_gen_form_fields[0].document_id #ds-snippet-end:eSign42Step6 #ds-snippet-start:eSign42Step7 form_fields_request = form_fields(envelope_args, document_id_guid) - envelope_api.update_envelope_doc_gen_form_fields( + _results, _status, headers = envelope_api.update_envelope_doc_gen_form_fields_with_http_info( account_id, envelope_id, form_fields_request ) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign42Step7 #ds-snippet-start:eSign42Step8 send_envelope_req = DocuSign_eSign::Envelope.new(status: 'sent') - envelope = envelope_api.update(account_id, envelope_id, send_envelope_req) + envelope, _status, headers = envelope_api.update_with_http_info(account_id, envelope_id, send_envelope_req) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign42Step8 { 'envelope_id' => envelope.envelope_id } diff --git a/app/services/e_sign/eg043_shared_access_service.rb b/app/services/e_sign/eg043_shared_access_service.rb index a959392..65b059c 100644 --- a/app/services/e_sign/eg043_shared_access_service.rb +++ b/app/services/e_sign/eg043_shared_access_service.rb @@ -25,7 +25,16 @@ def create_agent begin options = DocuSign_eSign::ListOptions.new options.email = args[:email] - users = users_api.list args[:account_id], options + users, _status, headers = users_api.list_with_http_info args[:account_id], options + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end if users.result_set_size.to_i.positive? user = users.users.find { |u| u.user_status == 'Active' } @@ -38,7 +47,17 @@ def create_agent # Create new user #ds-snippet-start:eSign43Step3 - new_users = users_api.create args[:account_id], new_users_definition(args) + new_users, _status, headers = users_api.create_with_http_info args[:account_id], new_users_definition(args) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + new_users.new_users[0] #ds-snippet-end:eSign43Step3 end @@ -56,15 +75,35 @@ def create_authorization options = DocuSign_eSign::GetAgentUserAuthorizationsOptions.new options.permissions = 'manage' - authorizations = accounts_api.get_agent_user_authorizations(args[:account_id], args[:agent_user_id], options) + authorizations, _status, headers = accounts_api.get_agent_user_authorizations_with_http_info(args[:account_id], args[:agent_user_id], options) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + return if authorizations.result_set_size.to_i.positive? # Create authorization - accounts_api.create_user_authorization( + _results, _status, headers = accounts_api.create_user_authorization_with_http_info( args[:account_id], args[:user_id], user_authorization_request(args) ) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + return unless remaining && reset + + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + #ds-snippet-end:eSign43Step4 end @@ -102,7 +141,18 @@ def get_envelopes options = DocuSign_eSign::ListStatusChangesOptions.new options.from_date = (Date.today - 10).strftime('%Y/%m/%d') - envelopes_api.list_status_changes args[:account_id], options + results, _status, headers = envelopes_api.list_status_changes_with_http_info args[:account_id], options + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign43Step5 + + results end end diff --git a/app/services/e_sign/eg044_focused_view_service.rb b/app/services/e_sign/eg044_focused_view_service.rb index 5750f7a..271d1f2 100644 --- a/app/services/e_sign/eg044_focused_view_service.rb +++ b/app/services/e_sign/eg044_focused_view_service.rb @@ -24,7 +24,17 @@ def worker # Call Docusign to create the envelope envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope args[:account_id], envelope + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + envelope_id = results.envelope_id #ds-snippet-end:eSign44Step3 # Save for future use within the example launcher @@ -35,7 +45,16 @@ def worker view_request = make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, signer_email, signer_name) # Call the CreateRecipientView API - results = envelope_api.create_recipient_view args[:account_id], envelope_id, view_request + results, _status, headers = envelope_api.create_recipient_view_with_http_info args[:account_id], envelope_id, view_request + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end # Redirect the user to the embedded signing # Don't use an iframe! diff --git a/app/services/e_sign/eg045_delete_restore_envelope_service.rb b/app/services/e_sign/eg045_delete_restore_envelope_service.rb index a41a2e3..34fb249 100644 --- a/app/services/e_sign/eg045_delete_restore_envelope_service.rb +++ b/app/services/e_sign/eg045_delete_restore_envelope_service.rb @@ -14,8 +14,19 @@ def delete_envelope(args) #ds-snippet-end:eSign45Step3 #ds-snippet-start:eSign45Step4 - folders_api.move_envelopes(args[:account_id], args[:delete_folder_id], folders_request) + results, _status, headers = folders_api.move_envelopes_with_http_info(args[:account_id], args[:delete_folder_id], folders_request) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign45Step4 + + results end def move_envelope_to_folder(args) @@ -26,15 +37,37 @@ def move_envelope_to_folder(args) folders_request.envelope_ids = [args[:envelope_id]] folders_request.from_folder_id = args[:from_folder_id] - folders_api.move_envelopes(args[:account_id], args[:folder_id], folders_request) + results, _status, headers = folders_api.move_envelopes_with_http_info(args[:account_id], args[:folder_id], folders_request) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign45Step6 + + results end def get_folders(args) folders_api = create_folders_api(args) #ds-snippet-start:eSign45Step5 - folders_api.list(args[:account_id]) + results, _status, headers = folders_api.list_with_http_info(args[:account_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:eSign45Step5 + + results end end diff --git a/app/services/eg001_embedded_signing_service.rb b/app/services/eg001_embedded_signing_service.rb index 24a999b..b837ae9 100644 --- a/app/services/eg001_embedded_signing_service.rb +++ b/app/services/eg001_embedded_signing_service.rb @@ -24,7 +24,17 @@ def worker # Call Docusign to create the envelope envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope args[:account_id], envelope + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + envelope_id = results.envelope_id #ds-snippet-end # Save for future use within the example launcher @@ -35,7 +45,16 @@ def worker view_request = make_recipient_view_request(signer_client_id, ds_return_url, ds_ping_url, signer_email, signer_name) # Call the CreateRecipientView API - results = envelope_api.create_recipient_view args[:account_id], envelope_id, view_request + results, _status, headers = envelope_api.create_recipient_view_with_http_info args[:account_id], envelope_id, view_request + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end # Redirect the user to the embedded signing # Don't use an iframe! diff --git a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb index 26907e0..dd9faf7 100644 --- a/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb +++ b/app/services/monitor_api/eg001_get_monitoring_dataset_service.rb @@ -29,7 +29,17 @@ def worker loop do options.cursor = cursor_value unless cursor_value.empty? - cursored_results = monitor_api.get_stream(args[:data_set_name], args[:version], options) + cursored_results, _status, headers = monitor_api.get_stream_with_http_info(args[:data_set_name], args[:version], options) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + end_cursor = cursored_results.end_cursor break if cursor_value == end_cursor diff --git a/app/services/notary/eg004_send_with_third_party_notary_service.rb b/app/services/notary/eg004_send_with_third_party_notary_service.rb index 074b8cc..5261465 100644 --- a/app/services/notary/eg004_send_with_third_party_notary_service.rb +++ b/app/services/notary/eg004_send_with_third_party_notary_service.rb @@ -17,7 +17,17 @@ def worker # Exceptions will be caught by the calling function envelope_api = create_envelope_api(args) - results = envelope_api.create_envelope args[:account_id], envelope_definition + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope_definition + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + envelope_id = results.envelope_id { 'envelope_id' => envelope_id } #ds-snippet-end:Notary4Step4 diff --git a/app/services/room_api/eg001_create_room_with_data_service.rb b/app/services/room_api/eg001_create_room_with_data_service.rb index aa9e717..511fd8a 100644 --- a/app/services/room_api/eg001_create_room_with_data_service.rb +++ b/app/services/room_api/eg001_create_room_with_data_service.rb @@ -19,8 +19,19 @@ def worker #ds-snippet-start:Rooms1Step4 rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) - rooms_api.create_room(args[:account_id], body(args)) + results, _status, headers = rooms_api.create_room_with_http_info(args[:account_id], body(args)) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Rooms1Step4 + + results end private diff --git a/app/services/room_api/eg002_create_room_with_template_service.rb b/app/services/room_api/eg002_create_room_with_template_service.rb index f6015f4..212eeaf 100644 --- a/app/services/room_api/eg002_create_room_with_template_service.rb +++ b/app/services/room_api/eg002_create_room_with_template_service.rb @@ -18,8 +18,19 @@ def worker #ds-snippet-start:Rooms2Step5 rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) - rooms_api.create_room(args[:account_id], body(args)) + results, _status, headers = rooms_api.create_room_with_http_info(args[:account_id], body(args)) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Rooms2Step5 + + results end private diff --git a/app/services/room_api/eg003_export_data_from_room_service.rb b/app/services/room_api/eg003_export_data_from_room_service.rb index 5107b2b..66fa494 100644 --- a/app/services/room_api/eg003_export_data_from_room_service.rb +++ b/app/services/room_api/eg003_export_data_from_room_service.rb @@ -18,7 +18,18 @@ def worker #ds-snippet-start:Rooms3Step3 rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) - rooms_api.get_room_field_data(args[:room_id], args[:account_id]) + results, _status, headers = rooms_api.get_room_field_data_with_http_info(args[:room_id], args[:account_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Rooms3Step3 + + results end end diff --git a/app/services/room_api/eg004_add_forms_to_room_service.rb b/app/services/room_api/eg004_add_forms_to_room_service.rb index 9f0a932..ded319f 100644 --- a/app/services/room_api/eg004_add_forms_to_room_service.rb +++ b/app/services/room_api/eg004_add_forms_to_room_service.rb @@ -19,8 +19,19 @@ def worker #ds-snippet-start:Rooms4Step4 rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) - rooms_api.add_form_to_room(args[:room_id], args[:account_id], body(args[:form_id])) + results, _status, headers = rooms_api.add_form_to_room_with_http_info(args[:room_id], args[:account_id], body(args[:form_id])) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Rooms4Step4 + + results end def body(form_id) diff --git a/app/services/room_api/eg005_get_rooms_with_filters_service.rb b/app/services/room_api/eg005_get_rooms_with_filters_service.rb index 3ea0496..2941748 100644 --- a/app/services/room_api/eg005_get_rooms_with_filters_service.rb +++ b/app/services/room_api/eg005_get_rooms_with_filters_service.rb @@ -24,7 +24,18 @@ def worker #ds-snippet-start:Rooms5Step4 rooms_api = DocuSign_Rooms::RoomsApi.new(api_client) - rooms_api.get_rooms(args[:account_id], filters) + results, _status, headers = rooms_api.get_rooms_with_http_info(args[:account_id], filters) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Rooms5Step4 + + results end end diff --git a/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb b/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb index 762226c..45183f4 100644 --- a/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb +++ b/app/services/room_api/eg006_create_an_external_form_fill_session_service.rb @@ -17,8 +17,19 @@ def worker #ds-snippet-start:Rooms6Step4 rooms_api = DocuSign_Rooms::ExternalFormFillSessionsApi.new(api_client) - rooms_api.create_external_form_fill_session(args[:account_id], body(args)) + results, _status, headers = rooms_api.create_external_form_fill_session_with_http_info(args[:account_id], body(args)) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Rooms6Step4 + + results end private diff --git a/app/services/room_api/eg007_create_form_group_service.rb b/app/services/room_api/eg007_create_form_group_service.rb index dcc1a22..243e31d 100644 --- a/app/services/room_api/eg007_create_form_group_service.rb +++ b/app/services/room_api/eg007_create_form_group_service.rb @@ -18,8 +18,19 @@ def worker #ds-snippet-start:Rooms7Step4 rooms_api = DocuSign_Rooms::FormGroupsApi.new(api_client) - rooms_api.create_form_group(args[:account_id], body(args)) + results, _status, headers = rooms_api.create_form_group_with_http_info(args[:account_id], body(args)) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end #ds-snippet-end:Rooms7Step4 + + results end private diff --git a/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb b/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb index 04930ad..3ea7d77 100644 --- a/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb +++ b/app/services/room_api/eg008_grant_office_access_to_form_group_service.rb @@ -19,7 +19,16 @@ def worker #ds-snippet-start:Rooms8Step5 form_groups_api = DocuSign_Rooms::FormGroupsApi.new(api_client) begin - response = form_groups_api.grant_office_access_to_form_group(args[:form_group_id], args[:office_id], args[:account_id]) + response, _status, headers = form_groups_api.grant_office_access_to_form_group_with_http_info(args[:form_group_id], args[:office_id], args[:account_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end rescue Exception return { exception: 'Failed to grant office access to a form group' } end diff --git a/app/services/room_api/eg009_assign_form_to_form_group_service.rb b/app/services/room_api/eg009_assign_form_to_form_group_service.rb index 08788f3..7764724 100644 --- a/app/services/room_api/eg009_assign_form_to_form_group_service.rb +++ b/app/services/room_api/eg009_assign_form_to_form_group_service.rb @@ -19,7 +19,16 @@ def worker #ds-snippet-start:Rooms9Step6 form_groups_api = DocuSign_Rooms::FormGroupsApi.new(api_client) begin - response = form_groups_api.assign_form_group_form(args[:form_group_id], args[:account_id], body(args)) + response, _status, headers = form_groups_api.assign_form_group_form_with_http_info(args[:form_group_id], args[:account_id], body(args)) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end rescue Exception return { exception: 'Failed to assign a form to a form group' } end diff --git a/app/services/room_api/get_data_service.rb b/app/services/room_api/get_data_service.rb index 2854333..e4b244d 100644 --- a/app/services/room_api/get_data_service.rb +++ b/app/services/room_api/get_data_service.rb @@ -17,7 +17,17 @@ def get_offices #ds-snippet-start:Rooms8Step3 offices_api = DocuSign_Rooms::OfficesApi.new(@api_client) - offices = offices_api.get_offices(args[:account_id]) + offices, _status, headers = offices_api.get_offices_with_http_info(args[:account_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + offices.as_json['officeSummaries'] #ds-snippet-end:Rooms8Step3 end @@ -26,8 +36,18 @@ def get_default_admin_role_id worker roles_api = DocuSign_Rooms::RolesApi.new(@api_client) - roles = roles_api.get_roles(args[:account_id]).as_json['roles'] - default_admin_role = roles.find { |role| role['name'] == 'Default Admin' } + roles, _status, headers = roles_api.get_roles_with_http_info(args[:account_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + + default_admin_role = roles.as_json['roles'].find { |role| role['name'] == 'Default Admin' } default_admin_role['roleId'] end @@ -35,7 +55,17 @@ def get_rooms worker rooms_api = DocuSign_Rooms::RoomsApi.new(@api_client) - rooms = rooms_api.get_rooms(args[:account_id]) + rooms, _status, headers = rooms_api.get_rooms_with_http_info(args[:account_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + rooms.as_json['rooms'] end @@ -43,7 +73,17 @@ def get_templates worker templates_api = DocuSign_Rooms::RoomTemplatesApi.new(@api_client) - templates = templates_api.get_room_templates(args[:account_id]) + templates, _status, headers = templates_api.get_room_templates_with_http_info(args[:account_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + templates.as_json['roomTemplates'] end @@ -52,7 +92,16 @@ def get_form_libraries form_libraries_api = DocuSign_Rooms::FormLibrariesApi.new(@api_client) begin - form_libraries = form_libraries_api.get_form_libraries(args[:account_id]) + form_libraries, _status, headers = form_libraries_api.get_form_libraries_with_http_info(args[:account_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end rescue Exception return end @@ -60,7 +109,17 @@ def get_form_libraries form_libraries_id = form_libraries.as_json['formsLibrarySummaries'].find { |lib| lib['formCount'].positive? }['formsLibraryId'] forms_api = DocuSign_Rooms::FormLibrariesApi.new(@api_client) - forms = forms_api.get_form_library_forms(form_libraries_id, args[:account_id]) + forms, _status, headers = forms_api.get_form_library_forms_with_http_info(form_libraries_id, args[:account_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + forms.as_json['forms'] end @@ -68,7 +127,17 @@ def get_forms_from_room worker room_forms_api = DocuSign_Rooms::RoomsApi.new(@api_client) - forms = room_forms_api.get_documents(args[:room_id], args[:account_id]) + forms, _status, headers = room_forms_api.get_documents_with_http_info(args[:room_id], args[:account_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + forms.as_json['documents'] end @@ -77,7 +146,17 @@ def get_form_groups #ds-snippet-start:Rooms8Step4 form_groups_api = DocuSign_Rooms::FormGroupsApi.new(@api_client) - form_groups = form_groups_api.get_form_groups(args[:account_id]) + form_groups, _status, headers = form_groups_api.get_form_groups_with_http_info(args[:account_id]) + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + form_groups.as_json['formGroups'] #ds-snippet-end:Rooms8Step4 end From 8e19836cefa2cd22b196496d7eb6ceb2c0ad8dd5 Mon Sep 17 00:00:00 2001 From: karissarjacobsen <73908223+karissarjacobsen@users.noreply.github.com> Date: Thu, 29 Jan 2026 13:24:21 -0800 Subject: [PATCH 363/363] Merge updates (#71) Multiple delivery updates --- .../eeg046_multiple_delivery_controller.rb | 55 +++++ .../e_sign/eg046_multiple_delivery_service.rb | 192 ++++++++++++++++++ .../eeg046_multiple_delivery/get.html.erb | 90 ++++++++ app/views/partials/_country_code_text.erb | 1 + config/routes.rb | 3 + 5 files changed, 341 insertions(+) create mode 100644 app/controllers/e_sign/eeg046_multiple_delivery_controller.rb create mode 100644 app/services/e_sign/eg046_multiple_delivery_service.rb create mode 100644 app/views/e_sign/eeg046_multiple_delivery/get.html.erb create mode 100644 app/views/partials/_country_code_text.erb diff --git a/app/controllers/e_sign/eeg046_multiple_delivery_controller.rb b/app/controllers/e_sign/eeg046_multiple_delivery_controller.rb new file mode 100644 index 0000000..6d391b8 --- /dev/null +++ b/app/controllers/e_sign/eeg046_multiple_delivery_controller.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +class ESign::Eeg046MultipleDeliveryController < EgController + before_action -> { check_auth('eSignature') } + before_action -> { @example = Utils::ManifestUtils.new.get_example(@manifest, 46, 'eSignature') } + + def create + envelope_args = { + delivery_method: param_gsub(params['delivery_method']), + signer_name: param_gsub(params['signer_name']), + signer_email: param_gsub(params['signer_email']), + cc_name: param_gsub(params['cc_name']), + cc_email: param_gsub(params['cc_email']), + cc_phone_number: param_gsub(params['cc_phone_number']), + cc_country_code: param_gsub(params['cc_country_code']), + phone_number: param_gsub(params['phone_number']), + country_code: param_gsub(params['country_code']), + status: 'sent' + } + args = { + account_id: session['ds_account_id'], + base_path: session['ds_base_path'], + access_token: session['ds_access_token'], + envelope_args: envelope_args + } + + results = ESign::Eg046MultipleDeliveryService.new(args).worker + session[:envelope_id] = results['envelope_id'] + @title = @example['ExampleName'] + @message = format_string(@example['ResultsPageText'], results['envelope_id']) + render 'ds_common/example_done' + rescue DocuSign_eSign::ApiError => e + error = JSON.parse e.response_body + error_message = error['error_description'] || error['message'] || error['error'] + + if error_message.include?('ACCOUNT_LACKS_PERMISSIONS') + @error_code = 'ACCOUNT_LACKS_PERMISSIONS' + @error_message = @example['CustomErrorTexts'][0]['ErrorMessage'] + return render 'ds_common/error' + end + + handle_error(e) + end + + def get + enableCFR = ESign::GetDataService.new(session[:ds_access_token], session[:ds_base_path]).cfr?(session[:ds_account_id]) + if enableCFR == 'enabled' + session[:status_cfr] = 'enabled' + @title = 'Not CFR Part 11 compatible' + @error_information = @manifest['SupportingTexts']['CFRError'] + render 'ds_common/error' + end + super + end +end diff --git a/app/services/e_sign/eg046_multiple_delivery_service.rb b/app/services/e_sign/eg046_multiple_delivery_service.rb new file mode 100644 index 0000000..9d23ece --- /dev/null +++ b/app/services/e_sign/eg046_multiple_delivery_service.rb @@ -0,0 +1,192 @@ +# frozen_string_literal: true + +class ESign::Eg046MultipleDeliveryService + attr_reader :args + + include ApiCreator + + def initialize(args) + @args = args + end + + def worker + # Create the envelope request object + envelope_definition = make_envelope(args[:envelope_args]) + + # Create and send the envelope + # Call Envelopes::create API method + # Exceptions will be caught by the calling function + envelope_api = create_envelope_api(args) + #ds-snippet-start:eSign46Step3 + results, _status, headers = envelope_api.create_envelope_with_http_info args[:account_id], envelope_definition + + remaining = headers['X-RateLimit-Remaining'] + reset = headers['X-RateLimit-Reset'] + + if remaining && reset + reset_date = Time.at(reset.to_i).utc + puts "API calls remaining: #{remaining}" + puts "Next Reset: #{reset_date}" + end + envelope_id = results.envelope_id + #ds-snippet-end:eSign46Step3 + { 'envelope_id' => envelope_id } + end + + private + + #ds-snippet-start:eSign46Step2 + def make_envelope(envelope_args) + # 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 via SMS + # After it is signed, a copy is sent to the cc person via SMS + + # Create the envelope definition + envelope_definition = DocuSign_eSign::EnvelopeDefinition.new + + envelope_definition.email_subject = 'Please sign this document set' + + # Add the documents + doc1_b64 = Base64.encode64(create_document1(envelope_args)) + # Read files 2 and 3 from a local directory + # The reads could raise an exception if the file is not available! + doc_docx = Rails.application.config.doc_docx + doc2_b64 = Base64.encode64(File.binread(File.join('data', doc_docx))) + doc_pdf = Rails.application.config.doc_pdf + doc3_b64 = Base64.encode64(File.binread(File.join('data', doc_pdf))) + + # Create the document models + document1 = DocuSign_eSign::Document.new( + # Create the Docusign document object + documentBase64: doc1_b64, + name: 'Order acknowledgement', # Can be different from actual file name + fileExtension: 'html', # Many different document types are accepted + documentId: '1' # A label used to reference the doc + ) + document2 = DocuSign_eSign::Document.new( + # Create the Docusign document object + documentBase64: doc2_b64, + name: 'Battle Plan', # Can be different from actual file name + fileExtension: 'docx', # Many different document types are accepted + documentId: '2' # A label used to reference the do + ) + document3 = DocuSign_eSign::Document.new( + # Create the Docusign document object + documentBase64: doc3_b64, + name: 'Lorem Ipsum', # Can be different from actual file name + fileExtension: 'pdf', # Many different document types are accepted + documentId: '3' # A label used to reference the doc + ) + + # The order in the docs array determines the order in the envelope + envelope_definition.documents = [document1, document2, document3] + + signer_phone_number = DocuSign_eSign::RecipientPhoneNumber.new + signer_phone_number.country_code = envelope_args[:country_code] + signer_phone_number.number = envelope_args[:phone_number] + + signer_additional_notification = DocuSign_eSign::RecipientAdditionalNotification.new + signer_additional_notification.phone_number = signer_phone_number + signer_additional_notification.secondary_delivery_method = envelope_args[:delivery_method] + + # Create the signer recipient model + signer1 = DocuSign_eSign::Signer.new + signer1.name = envelope_args[:signer_name] + signer1.email = envelope_args[:signer_email] + signer1.recipient_id = '1' + signer1.routing_order = '1' + signer1.delivery_method = 'Email' + signer1.additional_notifications = [signer_additional_notification] + + ## 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 + + cc_phone_number = DocuSign_eSign::RecipientPhoneNumber.new + cc_phone_number.country_code = envelope_args[:cc_country_code] + cc_phone_number.number = envelope_args[:cc_phone_number] + + cc_additional_notification = DocuSign_eSign::RecipientAdditionalNotification.new + cc_additional_notification.phone_number = cc_phone_number + cc_additional_notification.secondary_delivery_method = envelope_args[:delivery_method] + + # Create a cc recipient to receive a copy of the documents + cc1 = DocuSign_eSign::CarbonCopy.new + cc1.name = envelope_args[:cc_name] + cc1.email = envelope_args[:cc_email] + cc1.routing_order = '2' + cc1.recipient_id = '2' + cc1.delivery_method = 'Email' + cc1.additional_notifications = [cc_additional_notification] + + # Create signHere fields (also known as tabs) on the documents + # We're using anchor (autoPlace) positioning + # + # The Docusign platform searches throughout your envelope's documents for matching + # anchor strings. So the sign_here_2 tab will be used in both document 2 and 3 + # since they use the same anchor string for their "signer 1" tabs. + sign_here1 = DocuSign_eSign::SignHere.new( + anchorString: '**signature_1**', + anchorYOffset: '10', + anchorUnits: 'pixels', + anchorXOffset: '20' + ) + + sign_here2 = DocuSign_eSign::SignHere.new( + anchorString: '/sn1/', + anchorYOffset: '10', + anchorUnits: 'pixels', + anchorXOffset: '20' + ) + # Add the tabs model (including the sign_here tabs) to the signer + # The Tabs object takes arrays of the different field/tab types + signer1_tabs = DocuSign_eSign::Tabs.new({ + signHereTabs: [sign_here1, sign_here2] + }) + + signer1.tabs = signer1_tabs + + # Add the recipients to the envelope object + recipients = DocuSign_eSign::Recipients.new( + signers: [signer1], + carbonCopies: [cc1] + ) + # Request that the envelope be sent by setting status to "sent". + # To request that the envelope be created as a draft, set status to "created" + envelope_definition.recipients = recipients + envelope_definition.status = envelope_args[:status] + envelope_definition + end + + def create_document1(args) + " + + + + + + +

    World Wide Corp

    +

    Order Processing Division

    +

    Ordered by #{args[:signer_name]}

    +

    Phone number: #{args[:phone_number]}

    +

    Copy to: #{args[:cc_name]}, #{args[:cc_phone_number]}

    +

    + 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**/

    + + " + end + #ds-snippet-end:eSign46Step2 +end diff --git a/app/views/e_sign/eeg046_multiple_delivery/get.html.erb b/app/views/e_sign/eeg046_multiple_delivery/get.html.erb new file mode 100644 index 0000000..5e73c41 --- /dev/null +++ b/app/views/e_sign/eeg046_multiple_delivery/get.html.erb @@ -0,0 +1,90 @@ +<%= render('partials/example_info') %> + +<% form_index = 0 %> +<% delivery_method_index = 0 %> +<% sms_delivery_method_index = 1 %> +<% whatsapp_delivery_method_index = 2 %> +<% signer_name_index = 3 %> +<% signer_email_index = 4 %> +<% signer_code_index = 5 %> +<% signer_phone_index = 6 %> +<% cc_name_index = 7 %> +<% cc_email_index = 8 %> +<% cc_code_index = 9 %> +<% cc_phone_index = 10 %> + +
    + <% if @example["Forms"][form_index]["FormName"] %> + <%= sanitize @example["Forms"][form_index]["FormName"] %> + <% end %> + +
    +
    + + + + + + +
    + +
    + + " name="signer_name" + value="<%= @config.signer_name %>" required /> +
    +
    + + " name="signer_email" + value="<%= @config.signer_email %>" required /> + <%= render('partials/email_will_not_be_shared') %> +
    + +
    + + " required /> + <%= render('partials/country_code_text') %> +
    +
    + + " required /> + <%= render('partials/phone_will_not_be_shared') %> +
    + +
    + + " name="cc_name" + required /> +
    +
    + + " name="cc_email" + required /> + <%= render('partials/email_will_not_be_shared') %> +
    + +
    + + " required /> + <%= render('partials/country_code_text') %> +
    +
    + + " required /> + <%= render('partials/phone_will_not_be_shared') %> +
    + + <%= render('partials/submit_button') %> + diff --git a/app/views/partials/_country_code_text.erb b/app/views/partials/_country_code_text.erb new file mode 100644 index 0000000..315fbe5 --- /dev/null +++ b/app/views/partials/_country_code_text.erb @@ -0,0 +1 @@ +<%= @manifest["SupportingTexts"]["HelpingTexts"]["CountryCodeText"] %> \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 49f49d1..a2300ea 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -236,6 +236,9 @@ post 'eeg045' => 'eeg045_delete_restore_envelope#delete_envelope' get 'eeg045restore' => 'eeg045_delete_restore_envelope#get_restore_envelope' post 'eeg045restore' => 'eeg045_delete_restore_envelope#restore_envelope' + + get 'eeg046' => 'eeg046_multiple_delivery#get' + post 'eeg046' => 'eeg046_multiple_delivery#create' end scope module: 'connect' do
    - +