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
Rubocop:
- lib/sms/providers/{signalwire,twilio}.rb: collapse the
Net::HTTPSuccess success-path `if` into modifier form
(Style/IfUnlessModifier).
- lib/sms/providers/signalwire.rb: `delete_suffix('/')` instead of
`sub(%r{/\z}, '')` (Performance/DeleteSuffix).
- app/controllers/sms_settings_controller.rb: move SECRET_KEYS to
the top of the class so it isn't sandwiched under `private`
(Lint/UselessConstantScoping). Ruby constants aren't actually
privatised by a preceding `private` keyword anyway.
Erblint:
- app/views/sms_settings/index.html.erb: replace `javascript_tag do`
with a raw `<script nonce=...>` block so erblint's
AvoidUsingJavascriptTag rule is satisfied. CSP nonce comes from
Rails' content_security_policy_nonce helper, same source as before.
- Inline the ERB block-opener so Ruby doesn't see a leading empty
line (Layout/LeadingEmptyLines).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds three new selectable providers behind the existing
Sms.send_message interface. Per-account credentials are namespaced in
the encrypted sms_configs hash (twilio_*, voipms_*, signalwire_*) so
existing BulkVS configs keep working unchanged.
- lib/sms.rb: dispatch via per-provider classes and delegate the
"is this configured" check to each provider, replacing the BulkVS-only
hardcoded gate in enabled_for?.
- lib/sms/providers/twilio.rb: form-encoded POST to the Messages API,
Basic Auth with SID:Token, treats 201-with-error_code as failure.
- lib/sms/providers/voipms.rb: GET with query-string auth, treats
status != "success" as failure even on HTTP 200, enforces the API's
160-byte hard cap up front.
- lib/sms/providers/signalwire.rb: Twilio-shaped client targeting the
per-account Space URL host; strips https:// and trailing / from the
user-supplied space URL.
- app/controllers/sms_settings_controller.rb: extend the
preserve-secret-on-blank-edit pattern to all four providers' password
fields via a SECRET_KEYS array.
- app/views/sms_settings/index.html.erb: dynamic provider select sourced
from Sms::SUPPORTED_PROVIDERS with per-provider field blocks toggled by
a nonce'd inline script (the app's CSP requires nonces on inline JS).
- SMS.md: new "Configuring …" sections for each provider, wire-format
quick-reference table, and updated extension/code-map sections.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Account admins can now replace "WaboSign" in the UI, emails, audit-trail
PDFs, and authenticator-app issuer with their own product name. The
brand override is stored as an AccountConfig row (brand_name key),
managed from /settings/personalization above the logo upload.
Resolution flows through Wabosign.branded_product_name(account = nil):
1. account&.brand_name if a record is passed
2. else the deployment's oldest non-archived account's brand_name
(so anonymous surfaces like the landing page, PWA manifest, and
og:title get the operator's brand on single-tenant installs)
3. else Wabosign::PRODUCT_NAME ("WaboSign")
AGPL §7(b) DocuSeal attribution stays untouched:
- _powered_by.html.erb second line keeps Wabosign::UPSTREAM_NAME
- _email_attribution.html.erb second paragraph keeps it
- completed.vue keeps its hardcoded DocuSeal link
The Wabosign::UPSTREAM_NAME and UPSTREAM_URL constants stay constants —
they are never overridable.
Swapped 41 direct Wabosign.product_name callers to pass the most-local
account in scope (current_account, @template.account,
@submitter.submission.account, submission.account, or nil for chrome
without account context). Mailers' default `from:` is now a lambda that
reads @current_account per message. SIGN_REASON constant in
generate_result_attachments became sign_reason_template(account) so
PDF signature reasons reflect the brand.
The two i18n keys actually rendered with literal "WaboSign"
(welcome_to_wabosign in templates_dashboard, connect_to_wabosign_mcp
in mcp_settings) are parameterized to %{product_name} across the 7
locales that defined them. The other ~9 WaboSign-branded i18n keys
are unreferenced dead code from the Pro paywall and stay as-is.
Specs:
spec/models/account_spec.rb (new) — Account#brand_name
spec/lib/wabosign_spec.rb (new) — branded_product_name precedence
spec/requests/personalization_settings_spec.rb (new) — end-to-end
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces the SMS placeholder with an actual provider integration. v1
ships BulkVS only; the architecture leaves room for additional
providers behind the same Sms.send_message interface.
Storage:
- EncryptedConfig key `sms_configs` (added to CONFIG_KEYS):
{ provider, enabled, basic_auth_token, from_number,
delivery_webhook_url }
- AccountConfig key `submitter_invitation_sms` for the per-account
SMS body template override.
Service layer:
- lib/sms.rb — Sms.enabled_for?(account), Sms.send_message
(account:, to:, text:), Sms.normalize_phone
- lib/sms/providers/bulkvs.rb — POST to
https://portal.bulkvs.com/api/v1.0/messageSend with the
pre-encoded Basic Auth header from the BulkVS portal. Surfaces
non-2xx responses as Sms::ProviderError with the upstream message.
Background sending:
- app/jobs/send_submitter_invitation_sms_job.rb — mirrors
SendSubmitterInvitationEmailJob; substitutes account-template
variables via the existing ReplaceEmailVariables module so
{account.name} / {submitter.link} / etc. work in the SMS body.
- submitters_controller#maybe_resend_email_sms already enqueues
this job when params[:send_sms] == '1', so the existing
"Send SMS" toggle in the submitter edit form now does what it
says on the tin.
Controllers/routes:
- SmsSettingsController gains create + test_message; the test_message
action lets an admin verify their config with a one-off SMS
against any phone number.
- SubmittersSendSmsController#create powers the per-submitter
"Send SMS" button (mirrors SubmittersSendEmailController).
- Routes: resources :sms with create + test_message; submitters
nested resources :send_sms.
Views:
- app/views/sms_settings/index.html.erb — real form replacing the
"not bundled" placeholder. Status banner reflects live config.
Test-send card renders only when SMS is enabled.
- app/views/submissions/_send_sms_button.html.erb — was a permanently
disabled stub; now button_to the new send_sms endpoint when SMS
is configured and the submitter has a phone number. Falls back to
a tooltip explaining what's missing otherwise.
- app/views/submissions/_send_sms.html.erb — was a placeholder render;
now shows a real "send SMS on save" toggle when SMS is configured.
- app/views/personalization_settings/_signature_request_sms_form.html.erb
+ show.html.erb — per-account SMS body override with variable
documentation.
Smoke-tested in a built image:
- /settings/sms renders 200, all form fields present.
- /settings/personalization renders the SMS body field.
- With saved (bogus) creds, Sms.send_message hits BulkVS over HTTPS
and surfaces the real 401 as Sms::ProviderError — proves the
transport is wired, not just the boot path.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>