* add audience as prefill to template creation
* this is primarily for conversion from ATS to Docuseal, since these fields would normally just be updated through the Docuseal iframe itself
* update manager first and last name label
* use word map to properly display Firstname as First Name, Lastname as Last Name
* add warning log if invalid audience is passed in
* fix line length
* 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
This pull request enhances the audit logging capabilities within DocuSeal to granularly track user actions and data changes.
Key Changes:
* User Attribution: Added user_id to SubmissionEvent to identify exactly who performed an action.
* Granular Change Tracking: Implemented a new form_update event type that records specific field changes, capturing both previous and new values (from -> to).
* Enhanced Exports & Webhooks: Updated ExportSubmissionService and SendFormCompletedWebhookRequestJob to include detailed form values and the full submission event history in their outputs.
* Refactoring: Updated controllers and services to propagate the current_user context for accurate tracking.
* Testing: Added specs to verify the correct recording of form field updates and data integrity in exports.
* 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
* Add download URL generator endpoint for API
* rubocop/spec fixes
* move logic out of view into controller
* move build_signed_urls method logic into new SignedDocumentUrlBuilder service
* slim down controller and its request specs
* Fix download filenames to exclude CloudFront query parameters
- Strip query parameters from URLs before extracting filenames in download buttons
- Add Content-Disposition headers to CloudFront signed URLs for proper browser filename handling
* remove Download combined PDF
* we don't do multiple submissions in the iframe, so this button is not needed
* line length fix
* add fallback filename and tests
* rubocop changes
* refactor build_cloudfront_url
reduce complexity of method by extracting into other methods, also reduces need for more in line comments.
* remove unused buttons
* remove "Resubmit" button and Docuseal logo/header in iframe
* remove template name in preview
* fix line length
* allow there to be no header
* fixed failing tests expecting header
* we don't typically want the header rendered in the iframe
* fix erb_lint violation
* Add partnership template authorization and ability system
* Update template authorization to support partnership context
* Add request context-based authorization for API access
* Implement hybrid partnership/account authorization logic
* Add submission authorization conditions for partnerships
* Support global partnership template access
* Add template cloning services for partnership workflows
* Update template cloning to require explicit target parameters, to allow for cloning for either account or from partnership
* Add Templates::CloneToAccount service for partnership to account cloning
* Add Templates::CloneToPartnership service for global to partnership cloning
* Add logic to detect account vs partnership template cloning with validation
* Add folder assignment logic for cloned templates
* Add external authentication and partnership support
* Update ExternalAuthService to support partnership OR account authentication
* Implement user assignment to accounts when partnership context is provided
* Support pure partnership authentication without account assignment
* Update API controllers for partnership template support
* Add partnership request context to API base controller
* Update submissions controller to support partnership templates
* Add partnership template cloning to templates clone controller
* Refactor template controller webhook logic to reduce complexity
* Support external_account_id parameter for partnership workflows
* Update web controllers and views for partnership template support
* Add tests
* erb_lint fixes
* add local claude file
* shared concern for handling partnership context
* remove overly permissive case
* global templates should be available for partnerships and accounts
* pass through access context in vue
* add tests
* add partnership context and tests to submissions
* add token refresh as last resort for a corrupted token
Remove hardcoded CloudFront domains and key pair IDs from repository.
All CloudFront configuration now loaded from ENV variables for security:
- CF_URL: CloudFront distribution URL
- CF_KEY_PAIR_ID: CloudFront key pair identifier
- CF_KEY_SECRET: AWS Secrets Manager path for private key
- SECURED_STORAGE_BUCKET: S3 bucket name
- SECURED_STORAGE_REGION: AWS region
This prevents exposure of infrastructure identifiers in public repository.
Configuration should be set via cpdocuseal deployment module.