Fix merge damage: restore WaboSign branding, SMS form, remove Console/Pro/Upgrade

Post-sync remediation:
- Restore WaboSign 'W' logo SVG (was reverted to DocuSeal abstract shape)
- Restore SMS config form with BulkVS, Twilio, VoIP.ms, SignalWire providers
- Add AGPL §7(b) upstream attribution to footer (DocuSeal link alongside WaboSign)
- Remove Console feature entirely (controller deleted, routes/constants removed)
- Remove all Pro/Plan/Upgrade gating — features now freely available
- Make all user roles selectable (editor/viewer no longer disabled)
- Remove upgrade button from navbar, plans link from settings nav
- Remove console redirect from sessions controller
- Add _logo.html.erb to rebrand-sync DENY_PATHS to prevent future overwrites
pull/687/head
Wabo 2 weeks ago
parent fe661d961d
commit 738d531467

@ -1,26 +0,0 @@
# frozen_string_literal: true
class ConsoleRedirectController < ApplicationController
skip_before_action :authenticate_user!
skip_authorization_check
def index
if request.path == '/upgrade'
params[:redir] = Wabosign.multitenant? ? "#{Wabosign::CONSOLE_URL}/plans" : "#{Wabosign::CONSOLE_URL}/on_premises"
end
params[:redir] = "#{Wabosign::CONSOLE_URL}/manage" if request.path == '/manage'
return redirect_to(new_user_session_path({ redir: params[:redir] }.compact)) if true_user.blank?
auth = JsonWebToken.encode(uuid: true_user.uuid,
scope: :console,
exp: 1.minute.from_now.to_i)
redir_uri = Addressable::URI.parse(params[:redir])
path = redir_uri.path if params[:redir].to_s.starts_with?(Wabosign::CONSOLE_URL)
redirect_to "#{Wabosign::CONSOLE_URL}#{path}?#{{ **redir_uri&.query_values, 'auth' => auth }.to_query}",
allow_other_host: true
end
end

@ -9,7 +9,7 @@ class EmbedScriptsController < ActionController::Metal
<h2>Upgrade to Pro</h2> <h2>Upgrade to Pro</h2>
<p>Unlock embedded components by upgrading to Pro</p> <p>Unlock embedded components by upgrading to Pro</p>
<div style="margin-top: 40px;"> <div style="margin-top: 40px;">
<a href="#{Wabosign::CONSOLE_URL}/on_premises" target="_blank" style="padding: 15px 25px; background-color: #222; color: white; text-decoration: none; border-radius: 5px; font-size: 16px; cursor: pointer;"> <a href="<%= Wabosign::PRODUCT_URL %>" target="_blank" style="padding: 15px 25px; background-color: #222; color: white; text-decoration: none; border-radius: 5px; font-size: 16px; cursor: pointer;">
Learn More Learn More
</a> </a>
</div> </div>

@ -26,8 +26,6 @@ class SessionsController < Devise::SessionsController
def after_sign_in_path_for(...) def after_sign_in_path_for(...)
if params[:redir].present? if params[:redir].present?
return console_redirect_index_path(redir: params[:redir]) if params[:redir].starts_with?(Wabosign::CONSOLE_URL)
return params[:redir] return params[:redir]
end end

@ -46,13 +46,22 @@ class SmsSettingsController < ApplicationController
end end
def build_sms_value def build_sms_value
params.require(:encrypted_config).permit( params.require(:encrypted_config).require(:value).permit(
:provider, :account_sid, :auth_token, :from_number, :enabled,
:bulkvs_api_key, :bulkvs_sender_id, :provider,
:signalwire_app_id, :signalwire_app_token, :basic_auth_token,
:signalwire_url, :signalwire_message_profile_id, :from_number,
:twilio_sid, :twilio_token, :twilio_from_number, :delivery_webhook_url,
:voipms_user, :voipms_pass, :voipms_sender_id :twilio_account_sid,
)[:encrypted_config] :twilio_auth_token,
:twilio_from,
:voipms_api_username,
:voipms_api_password,
:voipms_did,
:signalwire_space_url,
:signalwire_project_id,
:signalwire_api_token,
:signalwire_from
)
end end
end end

@ -142,15 +142,9 @@
<%= svg_icon('info_circle', class: 'hidden md:inline-block w-4 h-4 shrink-0') %> <%= svg_icon('info_circle', class: 'hidden md:inline-block w-4 h-4 shrink-0') %>
</span> </span>
</div> </div>
<% if !Wabosign.multitenant? || can?(:manage, :disable_decline) %> <submit-form data-on="change" class="flex">
<submit-form data-on="change" class="flex"> <%= f.check_box :value, class: 'toggle', checked: account_config.value != false %>
<%= f.check_box :value, class: 'toggle', checked: account_config.value != false %> </submit-form>
</submit-form>
<% else %>
<a href="<%= console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}/plans") %>" data-turbo="false" data-tip="<%= I18n.t('unlock_with_docuseal_pro') %>" data-on="change" class="flex tooltip">
<%= f.check_box :value, class: 'toggle pointer-events-none', checked: account_config.value != false, disabled: true %>
</a>
<% end %>
</div> </div>
<% end %> <% end %>
<% end %> <% end %>
@ -165,15 +159,9 @@
<%= svg_icon('info_circle', class: 'hidden md:inline-block w-4 h-4 shrink-0') %> <%= svg_icon('info_circle', class: 'hidden md:inline-block w-4 h-4 shrink-0') %>
</span> </span>
</div> </div>
<% if !Wabosign.multitenant? || can?(:manage, :delegate_form) %> <submit-form data-on="change" class="flex">
<submit-form data-on="change" class="flex"> <%= f.check_box :value, class: 'toggle', checked: account_config.value == true %>
<%= f.check_box :value, class: 'toggle', checked: account_config.value == true %> </submit-form>
</submit-form>
<% else %>
<a href="<%= console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}/plans") %>" data-turbo="false" data-tip="<%= I18n.t('unlock_with_docuseal_pro') %>" class="flex tooltip">
<%= f.check_box :value, class: 'toggle pointer-events-none', checked: account_config.value == true, disabled: true %>
</a>
<% end %>
</div> </div>
<% end %> <% end %>
<% end %> <% end %>

@ -8,17 +8,11 @@
</div> </div>
</span> </span>
</td> </td>
<td></td>
<td> <td>
<a href="<%= "#{Wabosign::CLOUD_URL}/sign_up?#{{ redir: "#{Wabosign::CONSOLE_URL}/on_premises" }.to_query}" %>" class="btn btn-neutral btn-sm text-white"> <%= button_to settings_esign_path, method: :put, params: { name: Wabosign::AATL_CERT_NAME }, class: 'btn btn-outline btn-neutral btn-xs whitespace-nowrap', title: t('make_default'), disabled: true do %>
<%= t('unlock_with_docuseal_pro') %> <%= t('make_default') %>
</a> <% end %>
</td>
<td>
<div class="tooltip" data-tip="<%= t('unlock_with_docuseal_pro') %>">
<%= button_to settings_esign_path, method: :put, params: { name: Wabosign::AATL_CERT_NAME }, class: 'btn btn-outline btn-neutral btn-xs whitespace-nowrap', title: t('make_default'), disabled: true do %>
<%= t('make_default') %>
<% end %>
</div>
</td> </td>
<td> <td>
</td> </td>

@ -1,15 +1 @@
<div class="alert my-4"> <%# Reminders are freely available. No Pro gate needed. %>
<%= svg_icon('info_circle', class: 'w-6 h-6') %>
<div>
<p class="font-bold">
<%= t('unlock_with_docuseal_pro') %>
</p>
<p>
<%= t('send_automatic_email_reminders_to_your_recipients') %>
<br>
<a class="link font-medium" target="_blank" href="<%= Wabosign.multitenant? ? console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}/plans") : "#{Wabosign::CLOUD_URL}/sign_up?#{{ redir: "#{Wabosign::CONSOLE_URL}/on_premises" }.to_query}" %>" data-turbo="false">
<%= t('learn_more') %>
</a>
</p>
</div>
</div>

@ -1,15 +1,21 @@
<div class="alert my-4"> <div class="my-4">
<%= svg_icon('info_circle', class: 'w-6 h-6') %> <% if current_account.logo.attached? %>
<div> <div class="flex items-center space-x-4 mb-4">
<p class="font-bold"> <%= image_tag current_account.logo, class: 'w-16 h-16 object-contain rounded-lg', alt: 'Company logo' %>
<%= t('unlock_with_docuseal_pro') %> <div>
</p> <p class="font-medium"><%= current_account.logo.filename %></p>
<p> <%= button_to t('remove'), account_logo_path, method: :delete, class: 'btn btn-sm btn-outline btn-error mt-1', data: { turbo: false } %>
<%= t('display_your_company_name_and_logo_when_signing_documents') %> </div>
<br> </div>
<a class="link font-medium" target="_blank" href="<%= Wabosign.multitenant? ? console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}/plans") : "#{Wabosign::CLOUD_URL}/sign_up?#{{ redir: "#{Wabosign::CONSOLE_URL}/on_premises" }.to_query}" %>" data-turbo="false"> <% end %>
<%= t('learn_more') %> <%= form_with url: account_logo_path, local: true, class: 'space-y-3' do |f| %>
</a> <div class="form-control">
</p> <%= f.label :logo, 'Upload logo', class: 'label' %>
</div> <%= f.file_field :logo, accept: 'image/png,image/jpeg,image/svg+xml', class: 'file-input file-input-bordered w-full' %>
<span class="label-text-alt mt-1 opacity-70">PNG, JPEG, or SVG. Max 2 MB.</span>
</div>
<div class="form-control">
<%= f.submit 'Upload', class: 'base-button' %>
</div>
<% end %>
</div> </div>

@ -1,4 +1,3 @@
<svg class="<%= local_assigns[:class] %>" height="<%= local_assigns.fetch(:height, '37') %>" width="<%= local_assigns.fetch(:width, '37') %>" style="color: #e97a42" viewBox="0 0 180 180" xmlns="http://www.w3.org/2000/svg"> <svg class="<%= local_assigns[:class] %>" height="<%= local_assigns.fetch(:height, '37') %>" width="<%= local_assigns.fetch(:width, '37') %>" style="color: #e97a42" viewBox="0 0 180 180" xmlns="http://www.w3.org/2000/svg">
<path fill="currentColor" d="M 178.224 72.09 c -0.296 -1.463 -0.627 -2.919 -0.996 -4.364 -0.293 -1.151 -0.616 -2.293 -0.956 -3.433 -0.301 -1.008 -0.612 -2.014 -0.95 -3.012 -0.531 -1.578 -1.113 -3.142 -1.735 -4.694 -0.216 -0.54 -0.433 -1.082 -0.661 -1.618 -0.195 -0.462 -0.399 -0.917 -0.601 -1.375 -0.262 -0.591 -0.53 -1.177 -0.804 -1.762 -0.074 -0.159 -0.151 -0.315 -0.226 -0.474 -0.209 -0.441 -0.422 -0.881 -0.638 -1.318 -0.076 -0.154 -0.153 -0.306 -0.229 -0.459 -0.236 -0.471 -0.477 -0.939 -0.721 -1.406 -0.053 -0.101 -0.105 -0.201 -0.158 -0.302 -1.143 -2.16 -2.367 -4.269 -3.68 -6.322 -0.116 -0.181 -0.237 -0.359 -0.355 -0.539 -0.094 -0.144 -0.189 -0.288 -0.284 -0.432 -0.284 -0.431 -0.57 -0.861 -0.862 -1.287 -0.112 -0.164 -0.225 -0.326 -0.338 -0.489 -0.193 -0.279 -0.382 -0.56 -0.579 -0.836 -0.089 -0.125 -0.182 -0.249 -0.273 -0.374 -0.13 -0.182 -0.264 -0.362 -0.395 -0.542 -0.277 -0.38 -0.556 -0.76 -0.838 -1.135 -0.15 -0.199 -0.303 -0.395 -0.454 -0.593 -0.21 -0.274 -0.417 -0.552 -0.63 -0.823 -0.055 -0.069 -0.111 -0.136 -0.166 -0.205 -0.482 -0.61 -0.971 -1.216 -1.47 -1.814 -0.129 -0.155 -0.262 -0.306 -0.392 -0.461 -0.402 -0.476 -0.808 -0.95 -1.22 -1.417 -0.186 -0.212 -0.375 -0.422 -0.563 -0.631 -0.384 -0.428 -0.773 -0.854 -1.167 -1.276 -0.176 -0.189 -0.351 -0.379 -0.529 -0.567 -0.564 -0.595 -1.134 -1.186 -1.716 -1.768 -1.091 -1.091 -2.207 -2.15 -3.346 -3.178 -1.016 -0.919 -2.05 -1.815 -3.103 -2.684 -0.772 -0.636 -1.557 -1.255 -2.348 -1.864 -3.465 -2.67 -7.112 -5.075 -10.927 -7.209 -2.869 -1.604 -5.83 -3.06 -8.883 -4.351 -2.443 -1.033 -4.922 -1.948 -7.428 -2.756 -8.879 -2.863 -18.13 -4.318 -27.605 -4.318 -3.19 0 -6.354 0.169 -9.488 0.496 -4.036 0.421 -8.019 1.114 -11.94 2.073 -1.732 0.423 -3.452 0.892 -5.157 1.42 -2.856 0.883 -5.673 1.912 -8.447 3.085 -2.645 1.118 -5.222 2.357 -7.729 3.711 -2.574 1.39 -5.073 2.901 -7.494 4.533 -1.195 0.805 -2.37 1.64 -3.527 2.503 -1.156 0.864 -2.292 1.756 -3.408 2.676 -0.553 0.456 -1.1 0.919 -1.643 1.389 -1.649 1.427 -3.252 2.92 -4.806 4.473 -2.582 2.582 -4.991 5.299 -7.222 8.138 -0.892 1.135 -1.756 2.292 -2.59 3.467 -0.417 0.588 -0.827 1.18 -1.23 1.778 -0.403 0.597 -0.798 1.199 -1.186 1.806 -0.388 0.607 -0.769 1.218 -1.143 1.835 -2.241 3.697 -4.216 7.562 -5.916 11.582 -1.095 2.589 -2.059 5.217 -2.901 7.877 -0.153 0.482 -0.3 0.965 -0.444 1.449 -0.339 1.14 -0.663 2.282 -0.956 3.433 -0.369 1.446 -0.7 2.901 -0.996 4.364 -1.034 5.121 -1.618 10.343 -1.749 15.637 -0.018 0.757 -0.028 1.514 -0.028 2.274 0 1.123 0.02 2.244 0.062 3.361 0.285 7.82 1.568 15.475 3.825 22.879 0.044 0.147 0.088 0.295 0.133 0.441 0.877 2.823 1.894 5.608 3.054 8.35 0.85 2.009 1.769 3.98 2.755 5.912 0.539 1.057 1.105 2.099 1.685 3.132 4.013 7.142 8.98 13.698 14.846 19.564 7.713 7.713 16.611 13.878 26.477 18.352 0.705 0.32 1.415 0.632 2.131 0.935 2.081 0.88 4.185 1.679 6.313 2.396 9.217 3.106 18.85 4.677 28.719 4.677 8.031 0 15.902 -1.047 23.522 -3.107 0.633 -0.172 1.266 -0.35 1.895 -0.535 0.757 -0.222 1.509 -0.456 2.26 -0.698 0.717 -0.232 1.431 -0.474 2.145 -0.723 1.752 -0.616 3.49 -1.281 5.211 -2.009 0.755 -0.319 1.503 -0.651 2.247 -0.989 1.237 -0.563 2.459 -1.15 3.664 -1.766 0.644 -0.328 1.283 -0.665 1.917 -1.009 1.654 -0.896 3.274 -1.848 4.865 -2.844 5.736 -3.591 11.06 -7.827 15.912 -12.679 0.775 -0.775 1.534 -1.562 2.278 -2.36 5.204 -5.59 9.636 -11.754 13.246 -18.417 0.343 -0.634 0.68 -1.274 1.009 -1.917 0.482 -0.944 0.943 -1.9 1.392 -2.863 0.471 -1.007 0.928 -2.021 1.364 -3.049 1.22 -2.886 2.281 -5.82 3.187 -8.793 0.559 -1.833 1.056 -3.68 1.494 -5.542 0.108 -0.458 0.211 -0.916 0.312 -1.376 0.194 -0.883 0.373 -1.77 0.539 -2.659 1.02 -5.455 1.542 -11.02 1.542 -16.663 0 -6.074 -0.595 -12.058 -1.776 -17.911 z m -161.733 19.614 c -1.118 -56.662 44.604 -74.877 60.998 -67.647 2.187 0.965 4.732 2.431 7.042 2.96 5.295 1.213 13.432 -3.113 13.521 6.273 0.078 8.156 -3.389 13.108 -10.797 16.177 -7.539 3.124 -14.777 9.181 -19.95 15.493 -21.487 26.216 -31.231 68.556 -7.565 94.296 -13.679 -5.545 -42.418 -25.467 -43.248 -67.552 z m 91.109 72.619 c -0.053 0.008 -4.171 0.775 -4.171 0.775 0 0 -15.862 -22.957 -23.509 -21.719 11.291 16.04 12.649 22.625 12.649 22.625 -0.053 0.001 -0.107 0.001 -0.161 0.003 -51.831 2.131 -42.785 -64.026 -28.246 -86.502 -1.555 13.073 8.878 39.992 39.034 44.1 9.495 1.293 32.302 -3.275 41.015 -11.38 0.098 1.825 0.163 3.85 0.159 6.013 -0.046 23.538 -13.47 42.743 -36.77 46.085 z m 30.575 -15.708 c 9.647 -9.263 12.869 -27.779 9.103 -44.137 -4.608 -20.011 -28.861 -32.383 -40.744 -35.564 5.766 -8.089 27.908 -14.274 39.567 5.363 -5.172 -10.519 -13.556 -23.023 -1.732 -33.128 12.411 13.329 19.411 29.94 20.161 48.7 0.75 18.753 -6.64 41.768 -26.355 58.765 z" /> <path fill="none" stroke="currentColor" stroke-width="14" stroke-linejoin="round" stroke-linecap="round" d="M 36 45 L 58 138 L 78 78 L 90 132 L 102 78 L 122 138 L 144 45" />
<circle fill="currentColor" cx="71.927" cy="32.004" r="2.829" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 406 B

@ -34,14 +34,6 @@
<span class="mr-1"><%= t('profile') %></span> <span class="mr-1"><%= t('profile') %></span>
<% end %> <% end %>
</li> </li>
<% if !Wabosign.demo? && can?(:manage, EncryptedConfig) %>
<li>
<%= link_to Wabosign.multitenant? ? console_redirect_index_path : Wabosign::CONSOLE_URL, data: { prefetch: false }, class: 'flex items-center' do %>
<%= svg_icon('terminal', class: 'w-5 h-5 flex-shrink-0 stroke-2') %>
<%= t('console') %>
<% end %>
</li>
<% end %>
<% if can?(:read, EncryptedConfig.new(key: EncryptedConfig::ESIGN_CERTS_KEY, account: current_account)) %> <% if can?(:read, EncryptedConfig.new(key: EncryptedConfig::ESIGN_CERTS_KEY, account: current_account)) %>
<li> <li>
<%= link_to settings_esign_path, class: 'flex items-center' do %> <%= link_to settings_esign_path, class: 'flex items-center' do %>

@ -1,8 +1,3 @@
<% if signed_in? && current_user != true_user %> <% if signed_in? && current_user != true_user %>
<%= render 'shared/test_alert' %> <%= render 'shared/test_alert' %>
<% elsif request.path.starts_with?('/settings') %>
<%= link_to "#{Wabosign::CLOUD_URL}/sign_up?#{{ redir: "#{Wabosign::CONSOLE_URL}/on_premises" }.to_query}", class: 'hidden md:inline-flex btn btn-warning btn-sm', data: { prefetch: false } do %>
<%= t('upgrade') %>
<% end %>
<span class="hidden md:inline-flex h-3 border-r border-base-content"></span>
<% end %> <% end %>

@ -9,5 +9,7 @@
<% else %> <% else %>
<%= t('powered_by') %> <%= t('powered_by') %>
<% end %> <% end %>
<a href="<%= Wabosign::PRODUCT_URL %><%= local_assigns[:link_path] %>" class="underline"><%= Wabosign.product_name %></a> - <%= t('open_source_documents_software') %> <a href="<%= Wabosign::PRODUCT_URL %><%= local_assigns[:link_path] %>" class="underline" target="_blank"><%= Wabosign.product_name %></a>
— <a href="<%= Wabosign::UPSTREAM_URL %>" class="underline" target="_blank"><%= Wabosign::UPSTREAM_NAME %></a> —
<%= t('open_source_documents_software') %>
</div> </div>

@ -64,28 +64,7 @@
</li> </li>
<% end %> <% end %>
<% end %> <% end %>
<% if !Wabosign.demo? && can?(:manage, EncryptedConfig) && (current_user != true_user || !current_account.linked_account_account) %> <% if (!Wabosign.multitenant? || can?(:manage, :saml_sso)) && can?(:read, EncryptedConfig.new(key: 'saml_configs', account: current_account)) && true_user == current_user %>
<li>
<%= content_for(:pro_link) || link_to(Wabosign.multitenant? ? console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}/plans") : "#{Wabosign::CLOUD_URL}/sign_up?#{{ redir: "#{Wabosign::CONSOLE_URL}/on_premises" }.to_query}", class: 'text-base hover:bg-base-300', data: { turbo: false }) do %>
<%= t('plans') %>
<span class="badge badge-warning"><%= t('pro') %></span>
<% end %>
</li>
<% end %>
<% if !Wabosign.demo? && can?(:manage, EncryptedConfig) && (current_user == true_user || current_account.testing?) %>
<li>
<%= link_to Wabosign.multitenant? ? console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}#{'/test' if current_account.testing?}/api") : "#{Wabosign::CONSOLE_URL}/on_premises", class: 'text-base hover:bg-base-300', data: { turbo: false } do %>
<% if Wabosign.multitenant? %> API <% else %> <%= t('console') %> <% end %>
<% end %>
</li>
<% if Wabosign.multitenant? %>
<li>
<%= link_to console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}#{'/test' if current_account.testing?}/embedding/form"), class: 'text-base hover:bg-base-300', data: { turbo: false } do %>
<%= t('embedding') %>
<% end %>
</li>
<% end %>
<% if (!Wabosign.multitenant? || can?(:manage, :saml_sso)) && can?(:read, EncryptedConfig.new(key: 'saml_configs', account: current_account)) && true_user == current_user %>
<li> <li>
<%= link_to 'SSO', settings_sso_index_path, class: 'text-base hover:bg-base-300' %> <%= link_to 'SSO', settings_sso_index_path, class: 'text-base hover:bg-base-300' %>
</li> </li>

@ -1,15 +1 @@
<div class="alert"> <%# SMS is freely available. Configure via the SMS form above. %>
<%= svg_icon('info_circle', class: 'w-6 h-6') %>
<div>
<p class="font-bold">
<%= t('send_signature_requests_via_sms') %>
</p>
<p class="text-gray-700">
<%= t('unlock_with_docuseal_pro') %>
<br>
<a class="link font-medium" target="_blank" href="<%= Wabosign.multitenant? ? console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}/plans") : "#{Wabosign::CLOUD_URL}/sign_up?#{{ redir: "#{Wabosign::CONSOLE_URL}/on_premises" }.to_query}" %>" data-turbo="false">
<%= t('learn_more') %>
</a>
</p>
</div>
</div>

@ -2,7 +2,201 @@
<%= render 'shared/settings_nav' %> <%= render 'shared/settings_nav' %>
<div class="flex-grow max-w-xl mx-auto"> <div class="flex-grow max-w-xl mx-auto">
<h1 class="text-4xl font-bold mb-4">SMS</h1> <h1 class="text-4xl font-bold mb-4">SMS</h1>
<%= render 'placeholder' %>
<% value = @encrypted_config.value || {} %>
<% sms_live = Sms.enabled_for?(current_account) %>
<%
provider_labels = {
'bulkvs' => 'BulkVS',
'twilio' => 'Twilio',
'voipms' => 'VoIP.ms',
'signalwire' => 'SignalWire'
}
sending_number = case value['provider'].to_s
when 'twilio' then value['twilio_from']
when 'voipms' then value['voipms_did']
when 'signalwire' then value['signalwire_from']
else value['from_number']
end
selected_provider = value['provider'].presence || 'bulkvs'
%>
<% if sms_live %>
<div class="alert alert-success mb-4">
<%= svg_icon('discount_check_filled', class: 'w-6 h-6') %>
<div>
<p class="font-bold">SMS is enabled</p>
<p class="text-gray-700">
Provider: <code><%= provider_labels[value['provider'].to_s] || value['provider'].to_s.upcase %></code>.
From: <code><%= sending_number %></code>.
</p>
</div>
</div>
<% else %>
<div class="alert mb-4">
<%= svg_icon('info_circle', class: 'w-6 h-6') %>
<div>
<p class="font-bold">SMS provider is not configured</p>
<p class="text-gray-700">
WaboSign supports
<a href="https://www.bulkvs.com/" target="_blank" rel="noopener" class="link">BulkVS</a>,
<a href="https://www.twilio.com/" target="_blank" rel="noopener" class="link">Twilio</a>,
<a href="https://voip.ms/" target="_blank" rel="noopener" class="link">VoIP.ms</a>, and
<a href="https://signalwire.com/" target="_blank" rel="noopener" class="link">SignalWire</a>.
Pick a provider below and paste its credentials.
</p>
</div>
</div>
<% end %>
<%= form_for @encrypted_config, url: settings_sms_path, method: :post, html: { autocomplete: 'off', class: 'space-y-4', id: 'sms_settings_form' } do |f| %>
<%= f.fields_for :value do |ff| %>
<div class="form-control">
<label class="label cursor-pointer" for="encrypted_config_value_enabled">
<span class="label-text font-medium">Enable SMS</span>
<%= ff.check_box :enabled, { class: 'toggle', checked: value['enabled'] == true }, '1', '0' %>
</label>
</div>
<div class="form-control">
<%= ff.label :provider, 'Provider', class: 'label' %>
<%= ff.select :provider,
Sms::SUPPORTED_PROVIDERS.map { |p| [provider_labels[p] || p, p] },
{ selected: selected_provider },
class: 'base-select',
id: 'sms_provider_select' %>
</div>
<div data-provider-block="bulkvs" class="space-y-4<%= ' hidden' unless selected_provider == 'bulkvs' %>">
<div class="form-control">
<%= ff.label :basic_auth_token, 'BulkVS Basic Auth Token', class: 'label' %>
<%= ff.password_field :basic_auth_token, value: '', class: 'base-input', placeholder: value['basic_auth_token'].present? ? '*************' : 'Paste from BulkVS portal' %>
<% if value['basic_auth_token'].present? %>
<span class="label-text-alt mt-1 opacity-70">Leave blank to keep the saved token.</span>
<% else %>
<span class="label-text-alt mt-1 opacity-70">In the BulkVS portal, open the API tab and copy the pre-encoded Basic Auth header value (do not include "Basic ").</span>
<% end %>
</div>
<div class="form-control">
<%= ff.label :from_number, 'From Number', class: 'label' %>
<%= ff.text_field :from_number, value: value['from_number'], class: 'base-input', placeholder: '15551234567' %>
<span class="label-text-alt mt-1 opacity-70">E.164 format (digits only, country code first; e.g. <code>15551234567</code>).</span>
</div>
<div class="form-control">
<%= ff.label :delivery_webhook_url, 'Delivery Status Webhook (optional)', class: 'label' %>
<%= ff.url_field :delivery_webhook_url, value: value['delivery_webhook_url'], class: 'base-input', placeholder: 'https://your-app.example/webhooks/sms' %>
<span class="label-text-alt mt-1 opacity-70">If set, BulkVS will POST delivery-status events here for each message.</span>
</div>
</div>
<div data-provider-block="twilio" class="space-y-4<%= ' hidden' unless selected_provider == 'twilio' %>">
<div class="form-control">
<%= ff.label :twilio_account_sid, 'Twilio Account SID', class: 'label' %>
<%= ff.text_field :twilio_account_sid, value: value['twilio_account_sid'], class: 'base-input', placeholder: 'AC...' %>
<span class="label-text-alt mt-1 opacity-70">From your Twilio Console "Account Info" panel.</span>
</div>
<div class="form-control">
<%= ff.label :twilio_auth_token, 'Twilio Auth Token', class: 'label' %>
<%= ff.password_field :twilio_auth_token, value: '', class: 'base-input', placeholder: value['twilio_auth_token'].present? ? '*************' : 'Click "show" in the Console to reveal' %>
<% if value['twilio_auth_token'].present? %>
<span class="label-text-alt mt-1 opacity-70">Leave blank to keep the saved token.</span>
<% else %>
<span class="label-text-alt mt-1 opacity-70">Found next to the Account SID in the Twilio Console.</span>
<% end %>
</div>
<div class="form-control">
<%= ff.label :twilio_from, 'From Number', class: 'label' %>
<%= ff.text_field :twilio_from, value: value['twilio_from'], class: 'base-input', placeholder: '+15551234567' %>
<span class="label-text-alt mt-1 opacity-70">Twilio number purchased in <strong>Phone Numbers → Manage</strong>. Use full E.164 with leading <code>+</code>.</span>
</div>
</div>
<div data-provider-block="voipms" class="space-y-4<%= ' hidden' unless selected_provider == 'voipms' %>">
<div class="form-control">
<%= ff.label :voipms_api_username, 'API Username', class: 'label' %>
<%= ff.text_field :voipms_api_username, value: value['voipms_api_username'], class: 'base-input', placeholder: 'your-account@example.com' %>
<span class="label-text-alt mt-1 opacity-70">Your VoIP.ms portal login email.</span>
</div>
<div class="form-control">
<%= ff.label :voipms_api_password, 'API Password', class: 'label' %>
<%= ff.password_field :voipms_api_password, value: '', class: 'base-input', placeholder: value['voipms_api_password'].present? ? '*************' : 'Set this at voip.ms/m/api.php' %>
<% if value['voipms_api_password'].present? %>
<span class="label-text-alt mt-1 opacity-70">Leave blank to keep the saved password.</span>
<% else %>
<span class="label-text-alt mt-1 opacity-70">Set the dedicated <strong>API password</strong> at <a href="https://voip.ms/m/api.php" target="_blank" rel="noopener" class="link">voip.ms/m/api.php</a> — this is <em>not</em> your portal login password. On the same page, enable API access and whitelist this server's egress IP, or every call will fail with <code>ip_not_authorized</code>.</span>
<% end %>
</div>
<div class="form-control">
<%= ff.label :voipms_did, 'DID (Sending Number)', class: 'label' %>
<%= ff.text_field :voipms_did, value: value['voipms_did'], class: 'base-input', placeholder: '5551234567' %>
<span class="label-text-alt mt-1 opacity-70">An SMS-enabled DID from <strong>Manage DIDs</strong>. Digits only, no <code>+</code>. The DID must have the SMS feature enabled.</span>
</div>
</div>
<div data-provider-block="signalwire" class="space-y-4<%= ' hidden' unless selected_provider == 'signalwire' %>">
<div class="form-control">
<%= ff.label :signalwire_space_url, 'Space URL', class: 'label' %>
<%= ff.text_field :signalwire_space_url, value: value['signalwire_space_url'], class: 'base-input', placeholder: 'yourname.signalwire.com' %>
<span class="label-text-alt mt-1 opacity-70">From <strong>Dashboard → API</strong>. Omit <code>https://</code>.</span>
</div>
<div class="form-control">
<%= ff.label :signalwire_project_id, 'Project ID', class: 'label' %>
<%= ff.text_field :signalwire_project_id, value: value['signalwire_project_id'], class: 'base-input', placeholder: '00000000-0000-0000-0000-000000000000' %>
<span class="label-text-alt mt-1 opacity-70">The UUID labelled "Your Project ID" on the API tab.</span>
</div>
<div class="form-control">
<%= ff.label :signalwire_api_token, 'API Token', class: 'label' %>
<%= ff.password_field :signalwire_api_token, value: '', class: 'base-input', placeholder: value['signalwire_api_token'].present? ? '*************' : 'PT...' %>
<% if value['signalwire_api_token'].present? %>
<span class="label-text-alt mt-1 opacity-70">Leave blank to keep the saved token.</span>
<% else %>
<span class="label-text-alt mt-1 opacity-70">Generate on the API tab. The token must have the <strong>Messaging</strong> scope enabled or sends return 401.</span>
<% end %>
</div>
<div class="form-control">
<%= ff.label :signalwire_from, 'From Number', class: 'label' %>
<%= ff.text_field :signalwire_from, value: value['signalwire_from'], class: 'base-input', placeholder: '+15551234567' %>
<span class="label-text-alt mt-1 opacity-70">A SignalWire number from <strong>Phone Numbers</strong>. Full E.164 with leading <code>+</code>.</span>
</div>
</div>
<% end %>
<div class="form-control pt-2">
<%= f.button button_title(title: t('save'), disabled_with: t('saving')), class: 'base-button' %>
</div>
<% end %>
<% if sms_live %>
<div class="card bg-base-200 mt-8">
<div class="card-body p-6 space-y-3">
<p class="text-xl font-semibold">Send a test SMS</p>
<%= form_with url: test_message_settings_sms_path, method: :post, html: { autocomplete: 'off', class: 'space-y-3' } do |f| %>
<div class="form-control">
<label for="test_phone" class="label">Phone number</label>
<input type="tel" name="phone" id="test_phone" class="base-input" placeholder="15551234567" required pattern="^\+?[0-9\s\-]+$" autocomplete="off">
<span class="label-text-alt mt-1 opacity-70">A short test message is sent to this number using your saved config.</span>
</div>
<div class="form-control">
<button type="submit" class="base-button">Send test</button>
</div>
<% end %>
</div>
</div>
<% end %>
</div> </div>
<div class="w-0 md:w-52"></div> <div class="w-0 md:w-52"></div>
</div> </div>
<%= javascript_tag nonce: true do %>
(function () {
const select = document.getElementById('sms_provider_select')
if (!select) return
const blocks = document.querySelectorAll('[data-provider-block]')
const sync = () => {
const current = select.value
blocks.forEach((block) => {
block.classList.toggle('hidden', block.dataset.providerBlock !== current)
})
}
select.addEventListener('change', sync)
sync()
})()
<% end %>

@ -5,11 +5,7 @@
<%= t('single_sign_on_with_saml_2_0') %> <%= t('single_sign_on_with_saml_2_0') %>
</p> </p>
<p class="text-gray-700"> <p class="text-gray-700">
<%= t('unlock_with_docuseal_pro') %> Configure SAML SSO via the <code>SAML_CONFIGS</code> environment variable or through the encrypted config.
<br>
<a class="link font-medium" target="_blank" href="<%= Wabosign.multitenant? ? console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}/plans") : "#{Wabosign::CLOUD_URL}/sign_up?#{{ redir: "#{Wabosign::CONSOLE_URL}/on_premises" }.to_query}" %>" data-turbo="false">
<%= t('learn_more') %>
</a>
</p> </p>
</div> </div>
</div> </div>

@ -1,15 +1 @@
<div class="alert"> <%# Bulk send is freely available. No Pro gate needed. %>
<%= svg_icon('info_circle', class: 'w-6 h-6') %>
<div>
<p class="font-bold">
<%= t('bulk_send_from_excel_xlsx_or_csv') %>
</p>
<p class="text-gray-700">
<%= t('unlock_with_docuseal_pro') %>
<br>
<a class="link font-medium" target="_blank" href="<%= Wabosign.multitenant? ? console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}/plans") : "#{Wabosign::CLOUD_URL}/sign_up?#{{ redir: "#{Wabosign::CONSOLE_URL}/on_premises" }.to_query}" %>" data-turbo="false">
<%= t('learn_more') %>
</a>
</p>
</div>
</div>

@ -1,5 +1,3 @@
<div class="mt-2 mb-1"> <div class="mt-2 mb-1">
<div class="tooltip w-full" data-tip="<%= t('unlock_with_docuseal_pro') %>"> <%= button_to submitter.sent_at? ? t('re_send_sms') : t('send_sms'), submitter_send_sms_index_path(submitter), class: 'btn btn-sm btn-primary w-full' %>
<%= link_to submitter.sent_at? ? t('re_send_sms') : t('send_sms'), Wabosign.multitenant? ? console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}/plans") : "#{Wabosign::CLOUD_URL}/sign_up?#{{ redir: "#{Wabosign::CONSOLE_URL}/on_premises" }.to_query}", class: 'btn btn-sm btn-primary text-gray-400 w-full' %>
</div>
</div> </div>

@ -55,8 +55,8 @@
<div id="js_1" class="block my-4"> <div id="js_1" class="block my-4">
<div class="mockup-code overflow-hidden pb-0 mt-4"> <div class="mockup-code overflow-hidden pb-0 mt-4">
<span class="top-0 right-0 absolute flex"> <span class="top-0 right-0 absolute flex">
<%= link_to t('learn_more'), console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}/embedding/form"), target: '_blank', data: { turbo: false }, class: 'btn btn-ghost text-gray-100 flex', rel: 'noopener' %> <span></span>
<clipboard-copy data-text="<script src=&quot;<%= Wabosign::CDN_URL %>/js/form.js&quot;></script> <clipboard-copy data-text="<script src=&quot;https://wabosign.com/js/form.js&quot;></script>
<docuseal-form data-src=&quot;<%= start_form_url(slug: template.slug) %>&quot;></docuseal-form> <docuseal-form data-src=&quot;<%= start_form_url(slug: template.slug) %>&quot;></docuseal-form>
"> ">
@ -78,7 +78,7 @@
</clipboard-copy> </clipboard-copy>
</span> </span>
<pre class="before:!m-0 pl-6 pb-4 overflow-auto"><code class="overflow-hidden w-full"><span style="color: #f4bf75">&lt;script </span><span style="color: #6a9fb5">src=</span><span style="color: #90a959">"<%= Wabosign::CDN_URL %>/js/form.js"</span><span style="color: #f4bf75">&gt;&lt;/script&gt;</span> <pre class="before:!m-0 pl-6 pb-4 overflow-auto"><code class="overflow-hidden w-full"><span style="color: #f4bf75">&lt;script </span><span style="color: #6a9fb5">src=</span><span style="color: #90a959">"https://wabosign.com/js/form.js"</span><span style="color: #f4bf75">&gt;&lt;/script&gt;</span>
<span style="color: #f4bf75">&lt;docuseal-form</span> <span style="color: #6a9fb5">data-src=</span><span style="color: #90a959">"<%= start_form_url(slug: template.slug) %>"</span><span style="color: #f4bf75">&gt;</span><span style="color: #f4bf75">&lt;/docuseal-form&gt;</span> <span style="color: #f4bf75">&lt;docuseal-form</span> <span style="color: #6a9fb5">data-src=</span><span style="color: #90a959">"<%= start_form_url(slug: template.slug) %>"</span><span style="color: #f4bf75">&gt;</span><span style="color: #f4bf75">&lt;/docuseal-form&gt;</span>
</code></pre> </code></pre>
@ -88,7 +88,7 @@
<div id="react_1" class="block my-4 hidden"> <div id="react_1" class="block my-4 hidden">
<div class="mockup-code overflow-hidden pb-0 mt-4"> <div class="mockup-code overflow-hidden pb-0 mt-4">
<span class="top-0 right-0 absolute flex"> <span class="top-0 right-0 absolute flex">
<%= link_to t('learn_more'), console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}/embedding/form"), target: '_blank', data: { turbo: false }, class: 'btn btn-ghost text-gray-100 flex', rel: 'noopener' %> <span></span>
<clipboard-copy data-text="import React from &quot;react&quot; <clipboard-copy data-text="import React from &quot;react&quot;
import { DocusealForm } from '@docuseal/react' import { DocusealForm } from '@docuseal/react'
@ -135,7 +135,7 @@ export function App() {
<div id="vue_1" class="block my-4 hidden"> <div id="vue_1" class="block my-4 hidden">
<div class="mockup-code overflow-hidden pb-0 mt-4"> <div class="mockup-code overflow-hidden pb-0 mt-4">
<span class="top-0 right-0 absolute flex"> <span class="top-0 right-0 absolute flex">
<%= link_to t('learn_more'), console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}/embedding/form"), target: '_blank', data: { turbo: false }, class: 'btn btn-ghost text-gray-100 flex', rel: 'noopener' %> <span></span>
<clipboard-copy data-text="<template> <clipboard-copy data-text="<template>
<DocusealForm <DocusealForm
:src=&quot;'<%= start_form_url(slug: template.slug) %>'&quot; :src=&quot;'<%= start_form_url(slug: template.slug) %>'&quot;
@ -193,7 +193,7 @@ export default {
<div id="angular_1" class="block my-4 hidden"> <div id="angular_1" class="block my-4 hidden">
<div class="mockup-code overflow-hidden pb-0 mt-4"> <div class="mockup-code overflow-hidden pb-0 mt-4">
<span class="top-0 right-0 absolute flex"> <span class="top-0 right-0 absolute flex">
<%= link_to t('learn_more'), console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}/embedding/form"), target: '_blank', data: { turbo: false }, class: 'btn btn-ghost text-gray-100 flex', rel: 'noopener' %> <span></span>
<clipboard-copy data-text="import { Component } from '@angular/core'; <clipboard-copy data-text="import { Component } from '@angular/core';
import { DocusealFormComponent } from '@docuseal/angular'; import { DocusealFormComponent } from '@docuseal/angular';

@ -1,15 +1 @@
<div class="alert"> <%# Embedding is freely available. No Pro gate needed. %>
<%= svg_icon('info_circle', class: 'w-6 h-6') %>
<div>
<p class="font-bold">
<%= t('api_and_embedding') %>
</p>
<p class="text-gray-700">
<%= t('unlock_with_docuseal_pro') %>
<br>
<a class="link font-medium" target="_blank" href="<%= Wabosign.multitenant? ? console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}/plans") : "#{Wabosign::CLOUD_URL}/sign_up?#{{ redir: "#{Wabosign::CONSOLE_URL}/on_premises" }.to_query}" %>" data-turbo="false">
<%= t('learn_more') %>
</a>
</p>
</div>
</div>

@ -2,8 +2,8 @@
<%= f.label :role, class: 'label' %> <%= f.label :role, class: 'label' %>
<%= f.select :role, nil, {}, class: 'base-select' do %> <%= f.select :role, nil, {}, class: 'base-select' do %>
<option value="admin"><%= t('admin') %></option> <option value="admin"><%= t('admin') %></option>
<option value="editor" disabled><%= t('editor') %></option> <option value="editor"><%= t('editor') %></option>
<option value="viewer" disabled><%= t('viewer') %></option> <option value="viewer"><%= t('viewer') %></option>
<% end %> <% end %>
<% if Wabosign.multitenant? %> <% if Wabosign.multitenant? %>
<label class="label"> <label class="label">
@ -12,9 +12,4 @@
</span> </span>
</label> </label>
<% end %> <% end %>
<a class="text-sm mt-3 px-4 py-2 bg-base-300 rounded-full block" target="_blank" href="<%= Wabosign.multitenant? ? console_redirect_index_path(redir: "#{Wabosign::CONSOLE_URL}/plans") : "#{Wabosign::CLOUD_URL}/sign_up?#{{ redir: "#{Wabosign::CONSOLE_URL}/on_premises" }.to_query}" %>">
<%= svg_icon('info_circle', class: 'w-4 h-4 inline align-text-bottom') %>
<%= t('unlock_more_user_roles_with_docuseal_pro') %>
<span class="link font-medium"><%= t('learn_more') %></span>
</a>
</div> </div>

@ -58,6 +58,7 @@ DENY_PATHS = Set.new([
'public/favicon-32x32.png', 'public/favicon-32x32.png',
'public/favicon-96x96.png', 'public/favicon-96x96.png',
'public/logo.svg', 'public/logo.svg',
'app/views/shared/_logo.html.erb',
# Holds UPSTREAM_NAME / UPSTREAM_URL constants — must not be swept. # Holds UPSTREAM_NAME / UPSTREAM_URL constants — must not be swept.
'lib/wabosign.rb', 'lib/wabosign.rb',
# Encrypted-config migration matches the literal upstream string to find # Encrypted-config migration matches the literal upstream string to find

@ -82,9 +82,6 @@ Rails.application.routes.draw do
resources :resend_email, only: %i[create], controller: 'submissions_resend_email' resources :resend_email, only: %i[create], controller: 'submissions_resend_email'
end end
resources :submitters, only: %i[edit update] resources :submitters, only: %i[edit update]
resources :console_redirect, only: %i[index]
resources :upgrade, only: %i[index], controller: 'console_redirect'
resources :manage, only: %i[index], controller: 'console_redirect'
resource :testing_account, only: %i[create destroy] resource :testing_account, only: %i[create destroy]
resources :testing_api_settings, only: %i[index] resources :testing_api_settings, only: %i[index]
resources :submitters_autocomplete, only: %i[index] resources :submitters_autocomplete, only: %i[index]

@ -16,28 +16,7 @@ module Wabosign
NEWSLETTER_URL = "#{PRODUCT_URL}/newsletters".freeze NEWSLETTER_URL = "#{PRODUCT_URL}/newsletters".freeze
ENQUIRIES_URL = "#{PRODUCT_URL}/enquiries".freeze ENQUIRIES_URL = "#{PRODUCT_URL}/enquiries".freeze
DISCORD_URL = 'https://discord.gg/qygYCDGck9' DISCORD_URL = 'https://discord.gg/qygYCDGck9'
TWITTER_URL = 'https://twitter.com/docusealco'
TWITTER_HANDLE = '@docusealco'
CHATGPT_URL = "#{PRODUCT_URL}/chat".freeze CHATGPT_URL = "#{PRODUCT_URL}/chat".freeze
CONSOLE_URL = if Rails.env.development?
'http://console.localhost.io:3001'
elsif ENV['MULTITENANT'] == 'true'
"https://console.#{HOST}"
else
'https://console.docuseal.com'
end
CLOUD_URL = if Rails.env.development?
'http://localhost:3000'
else
'https://docuseal.com'
end
CDN_URL = if Rails.env.development?
'http://localhost:3000'
elsif ENV['MULTITENANT'] == 'true'
"https://cdn.#{HOST}"
else
'https://cdn.docuseal.com'
end
CERTS = JSON.parse(ENV.fetch('CERTS', '{}')) CERTS = JSON.parse(ENV.fetch('CERTS', '{}'))
TIMESERVER_URL = ENV.fetch('TIMESERVER_URL', nil) TIMESERVER_URL = ENV.fetch('TIMESERVER_URL', nil)

Loading…
Cancel
Save