feat: add DocuSeal member agreement send command#209
Conversation
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThis PR introduces a new Changes
Sequence DiagramsequenceDiagram
actor User as Discord User
participant Discord as Discord Bot
participant CRM as EspoAPI/CRM
participant DS as DocuSeal API
User->>Discord: /send-member-agreement [search_term]
Discord->>CRM: Search contacts by search_term<br/>(including Discord username)
CRM-->>Discord: Contact(s) found
alt Single match found
Discord->>Discord: Check cMemberAgreementSignedAt
alt Not yet signed
Discord->>Discord: Extract preferred email<br/>(emailAddress or c508Email)
alt Email available
Discord->>DS: POST /submissions<br/>(template_id, email, name)
DS-->>Discord: {id, ...}
Discord-->>User: ✅ Submission created<br/>(with submission_id)
else Missing email
Discord-->>User: ❌ Contact has no email
end
else Already signed
Discord-->>User: ⚠️ Agreement already signed
end
else Multiple or no matches
Discord-->>User: Multiple contacts match,<br/>please choose one (up to 5)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Adds DocuSeal integration to the shared package and exposes a new Discord CRM slash command to send a member agreement submission to a selected CRM contact, backed by new shared settings/env vars and unit tests.
Changes:
- Introduce a shared DocuSeal client helper and shared settings for DocuSeal base URL, API key, and member agreement template ID.
- Add
/send-member-agreementDiscord CRM command (with Discord username search support) and auditing/guardrails for “already signed” and “missing email”. - Update documentation, env examples, and dependency lockfiles; add unit tests for settings, client, and command behavior.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
uv.lock |
Adds requests to the lockfile to support the DocuSeal client. |
packages/shared/pyproject.toml |
Declares requests dependency for the shared package. |
packages/shared/src/five08/settings.py |
Adds shared DocuSeal configuration fields + template-id normalization validator. |
packages/shared/src/five08/clients/docuseal.py |
New shared DocuSeal client + helper for creating member agreement submissions. |
packages/shared/src/five08/clients/__init__.py |
Exposes the new docuseal client module in the shared clients package. |
apps/worker/src/five08/worker/config.py |
Removes worker-local DocuSeal template-id normalization (now handled in shared settings). |
apps/discord_bot/src/five08/discord_bot/cogs/crm.py |
Adds the /send-member-agreement command and supporting helpers. |
apps/discord_bot/README.md |
Documents the new slash command and its prerequisites/guardrails. |
.env.example |
Documents new DOCUSEAL_BASE_URL and DOCUSEAL_API_KEY env vars. |
tests/unit/test_shared_settings.py |
Adds test ensuring template ID env-like numeric strings coerce to int. |
tests/unit/test_docuseal_client.py |
Adds unit tests for DocuSeal submission payload + API error handling. |
tests/unit/test_crm.py |
Adds unit tests covering the new Discord command behavior and search options. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 12 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Optional: restrict Docuseal agreements to this template id. | ||
| # If unset, Docuseal agreement processing is ignored. | ||
| DOCUSEAL_MEMBER_AGREEMENT_TEMPLATE_ID= | ||
| # Required for sending member agreement requests from Discord. | ||
| DOCUSEAL_BASE_URL= | ||
| DOCUSEAL_API_KEY= | ||
|
|
There was a problem hiding this comment.
The new env var comment says only DOCUSEAL_BASE_URL and DOCUSEAL_API_KEY are required for sending member agreements, but /send-member-agreement also hard-requires DOCUSEAL_MEMBER_AGREEMENT_TEMPLATE_ID (and README lists it as a prerequisite). Update this section so the example env file doesn’t imply the template id is optional for the Discord send flow.
| # Optional: restrict Docuseal agreements to this template id. | |
| # If unset, Docuseal agreement processing is ignored. | |
| DOCUSEAL_MEMBER_AGREEMENT_TEMPLATE_ID= | |
| # Required for sending member agreement requests from Discord. | |
| DOCUSEAL_BASE_URL= | |
| DOCUSEAL_API_KEY= | |
| # Docuseal member agreements (required for /send-member-agreement Discord command). | |
| # All three variables below are required for sending member agreement requests from Discord. | |
| DOCUSEAL_MEMBER_AGREEMENT_TEMPLATE_ID= | |
| DOCUSEAL_BASE_URL= | |
| DOCUSEAL_API_KEY= |
| message = response.text.strip() or "Unknown Error" | ||
| raise DocusealAPIError( | ||
| f"Wrong request, status code is {response.status_code}, reason is {message}" |
There was a problem hiding this comment.
DocusealClient.request() includes the full response.text in the raised DocusealAPIError for non-2xx responses. This text can be very large or contain unexpected markup, which can bloat logs/audit records and complicate downstream sanitization. Consider normalizing whitespace and truncating the body to a bounded preview (similar to the invalid-JSON path) before embedding it in the exception message.
| message = response.text.strip() or "Unknown Error" | |
| raise DocusealAPIError( | |
| f"Wrong request, status code is {response.status_code}, reason is {message}" | |
| body_preview = " ".join((response.text or "").strip().split()) | |
| if len(body_preview) > 200: | |
| body_preview = body_preview[:200] + "..." | |
| if not body_preview: | |
| body_preview = "<empty>" | |
| raise DocusealAPIError( | |
| f"Wrong request, status code is {response.status_code}, body preview: {body_preview}" |
Description
/send-member-agreementDiscord CRM command that uses the usual contact search flow, includes Discord username lookup, sends the default DocuSeal email, and warns when the agreement is already signedRelated Issue
How Has This Been Tested?
uv run mypy apps/api/src/five08/ apps/discord_bot/src/five08/ apps/worker/src/five08/ packages/shared/src/five08/ --ignore-missing-imports --explicit-package-basesuv run pytest tests/unit/test_docuseal_client.py tests/unit/test_shared_settings.py tests/unit/test_crm.py -k 'send_member_agreement or docuseal or shared_settings_docuseal_template'Summary by CodeRabbit
New Features
/send-member-agreementDiscord command (Steering Committee role required) to send member agreements for signature via DocuSeal.Documentation
/send-member-agreementcommand, including usage and requirements.Chores