* add named signing order values and defer to template signing order
* the enum changes and the default in submission.rb don't REALLY matter since almost all of our changes in future commits defer to templates.
* add template methods to know how many actual submitters there are and add complex default logic based on when fields are added or removed.
For example: If only 1 employee field it's single sided. If we add a manager field it automatically changes to employee_then_manager unless manually changed to a different dual sided. If either field is removed, it automatically switches back to single_sided
* enforce new signing order logic
- replace submitters_order_preserved? with signing_order_enforced? in send_signature_requests
- add manager_then_employee branch to send_signature_requests to send to second submitter first, while we don't send out emails with Docuseal, there are changes further down the line required
- skip submitters without fields for single_sided in create_from_submitters, this is mostly necessary for single_sided manager forms
- refactor current_submitter_order? to reverse submitter_items for manager_then_employee instead of special-casing index
* wire up named signing order through controllers
* when saving a template, check if preferences have changed, if it has changed, fire webhook event.
* changes in templates_controller.rb are for automatic updates based on field types. So if only 1 field type (employee fields only) this automatically updates
* template_preferences_controller.rb handles manual updates to signing order from user
* add signing order UI
- add SigningOrderModal component for selecting signing order from within the template builder
- show signing order button in builder toolbar only when template has 2+ submitter fields
* add template.preferences_updated webhook job
* add template.preferences_updated webhook support
- add template.preferences_updated to account default webhook events
- guard account create_careerplug_webhook against missing CAREERPLUG_WEBHOOK_URL env var
- create partnership-scoped webhook for template.preferences_updated on partnership creation
- add template.preferences_updated to WebhookUrl::EVENTS
- update PARTNERSHIP_EVENTS to only include template.preferences_updated
- return WebhookUrl.none instead of raising for templates with neither account nor partnership
- extend webhooks:setup_development rake task to create partnership webhooks
* rubocop and rspec fixes
* erb_lint violation fixes
* harden webhooks with account_id and partnership_id in payload
* we're requiring two points of contact in the db for multitenancy
* use external account id to match correctly in webhook payload
* PR comments
* handle submitter UUID not matching correctly with flash alert that surfaces to user
* add more testing for simultaneous and single sided orders
* add comment for skipping Devise auth for Iframe auth
* refactor template webhook enqueue to a shared concern
* use safe navigation for first_party name
* make default submitters_order value consistent between `lib/submissions.rb` and `submission.rb`
* more descriptive error message for signing order error
* update to non-predicate method for rubocop
we used to just return true or false, but we are using nil to signify that the submitter uuid is not found for the controller so the error can be surfaced to the user.
* erb_lint formatting fix
* PR comment changes
* change current_submitter_order to validate_submitter_order for clarity
* add translations
* add partnership_id to webhook_urls
- add migration to make account_id OR partnership_id required, you can use either, but can and must use at least one
- add PARTNERSHIP_EVENTS constant to constrain webhook firing to just template events
* extract duplicated webhook retry logic for webhook jobs
- 11 webhook jobs all used the same retry logic (except one file that had 12 max retries instead of 10.
- remove and replace duplicated code
- add retry logic for partnership templates
* refactor WebhookUrls to support partnerships
- add for_template method to support account/partnership templates.
- for_account_id will still work for submissions
- update controllers with new method
- I'm not great with Arel, so I refactored since I wanted account/partnership to use a shared method.
* a automatic webhook creation for new partnerships
* fix rubocop violations
* update spec to expect raised error instead of empty array
* fix rubocop/rspec for HTTP requests in test
* remove after commit partnership webhook temporarily
The immediately following PR will add this `after_commit` back. We only really need the upcoming template.preferences_updated webhook event that will be in the next PR, so even though it's unlikely anyone will be testing this at the Partnership level right now, better to just remove it for the time being for a cleaner PR.
* validate incoming events against WebhookUrl::EVENTS constant
* safety against SQL injection
This method does not accept user input, but adding this just to be safe.
* add form.changes_requested to events
* since we added the events constant checker, we need to make sure this event is part of the constant list
This ensures that CareerPlug webhooks are only created after the account
transaction has been successfully committed to the database. This prevents
orphaned webhook records if account creation fails or is rolled back.
The change improves data consistency and follows Rails best practices for
callbacks that create associated records or have external side effects.
Includes tests to verify that:
- Webhooks are created after successful account creation
- Webhooks are not created if account creation fails/rolls back
- Webhooks are not created when CAREERPLUG_WEBHOOK_SECRET is blank
* Fix PDF regeneration after change requests
Allow PDFs to be regenerated when a submitter re-completes after a change
request by using timestamp-based detection. This ensures new PDFs are
generated while preserving old ones for audit trail.
Changes:
- Allow multiple 'complete' events per submitter (remove unique constraint)
- Compare event timestamps with completion time to detect stale events
- Add current_documents method to get latest PDF generation
- Prevent waiting forever on stale retry/start events from previous attempts
* Update audit trail generation for change requests
Regenerate audit trail PDF when submitter re-completes after a change request.
Remove DocuSeal branding from audit trail header and add missing translations
for request_changes events.
Changes:
- Regenerate audit trail when created before latest completion timestamp
- Remove DocuSeal logo and branding from audit trail header
- Add request_changes_by_html translations (English and Spanish)
- Generate new audit trail before cleaning up old ones (safer approach)
- Clean up old audit trail PDFs, keeping only the newest
* Change 'Request Changes' button text to 'Submit'
* Remove Download button from submissions view
* Fix download endpoint to return current documents after re-completion
* Add comprehensive tests and apply rubocop fixes
- Add tests for Submitter#current_documents method
- Add tests for PDF regeneration on re-completion
- Add tests for audit trail regeneration logic
- Apply rubocop fixes: use Rails range syntax, fix indentation
- Extract generate_and_record_documents to reduce method length
* fix potential NoMethodError and rubocop fixes
* Use ActiveStorage::Attachment directly instead of `#audit_trail`
* Fix line length in `process`
* Scope email and external_user_id uniqueness to account
Allow the same email and external_user_id to exist across different accounts
while maintaining uniqueness within each account.
Changes:
- Scope external_user_id uniqueness to account_id
- Scope email uniqueness to account_id
- Remove Devise :validatable to avoid global email uniqueness
- Update ExternalAuthService to use account-scoped queries
- Update TokenRefreshService to use account-scoped queries
- Add custom email validation with account scope
* Add and update tests for account-scoped user uniqueness
* Run migrations and update schema
* Document account-scoped user lookup behavior
* skip password test
* we use access token validation via iframe, not passwords so this test is not necessary.
* update test for rubocop
* account group to partnership rename
* this is mostly converting the name account_group => partnership
* partnership user relationships are API request based
* so we don't need to maintain relational information in two databases, this many to many relationship is now handled via API context
* rubocop and test fixes
- Add account_groups table and model
- Add account_group references to accounts, users, templates, template_folders
- Make account_id nullable on users, templates, template_folders
- Add controllers and specs
* Consolidate account groups migrations
- Replace 8 separate migrations with 2 consolidated ones
- Create account groups and relationships in one migration
- Make account_id columns nullable in second migration
* this logic is being handled in external_auth_controller
* remove unnecessary controllers
* remove unnecessary routes
* refactor account_group.default_template_folder
* align method with Account version of this method
* refactor controllers to move complex logic to service
* move account/account group validation to concern
* this method is not yet needed
* we may implement this differently in next ticket to handle account and account group syncing for templates.
* rubocop violation fixes
* a few more refactors and add tests
* Change external_account_group_id to integer type
* Refactored external_account_group_id from string to integer in models, migrations, factories, and specs for consistency.
* Merged account_id nullability changes into a single migration and removed the obsolete migrations.
* Updated authentication logic to require either account or account_group presence for user activation.
* Add external_id fields to accounts and users tables
Adds external_account_id and external_user_id fields to support
integration with external ATS systems. These fields will map
DocuSeal accounts/users to their corresponding ATS entities.
* Add external ID support to Account and User models
Implements find_or_create_by_external_id methods for both Account
and User models to support automatic provisioning from external
ATS systems. Users now have access tokens for authentication.
* Add external authentication API endpoint
Creates /api/external_auth/get_user_token endpoint for external API systems
to authenticate users and receive access tokens.
* Refactor authentication to support token-based login
Replaces demo user authentication and setup redirect logic with token-based authentication via params, session, or X-Auth-Token header.
Users do not login, they are just authenticated via token.
* Replace authenticate_user! with authenticate_via_token!
Refactored controllers to use authenticate_via_token! instead of authenticate_user! for authentication. Added authenticate_via_token! method to ApiBaseController.
* Update controller authentication and authorization logic
Removed and replaced several before_action and authorization checks in ExportController, SetupController, and TemplateDocumentsController.
* Add external authentication API endpoint
* Add IframeAuthentication concern for AJAX requests in iframe context
* Create shared concern to handle authentication from HTTP referer
* Extracts auth token from referer URL when AJAX requests don't include token
* Supports Vue component requests within iframes
* Remove old user authentication from dashboard controller
* Quick fix for request changes
Now that we have scoped users, we're changing this to compare to the template authot
* rubocop fixes
* Add and update authentication and model specs
Introduces new specs for iframe authentication, account, user, application controller, and external auth API.
* add safe navigation and remove dead method
* new controller to handle change requests
* add button and modal on completed submission view to request changes
* webhook job will send out to external API when submission is updated for changes_requested_at
* email will be sent to user that need to make changes
* submission status steps back from "completed"