-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9cbb80f
commit e18631c
Showing
19 changed files
with
1,644 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
[flake8] | ||
ignore = E501, E123 | ||
exclude = __init__.py | ||
exclude = __init__.py, venv |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
from .contract import ContractController | ||
from .base_controller import BaseController | ||
from .health import HealthController | ||
from .me import MeController | ||
from .me import MeController | ||
from .docusign_webhook import DocusignWebhookController |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
from .base_controller import BaseController | ||
from managers import DocusignWebhookManager | ||
from fastapi_cloudauth.cognito import Cognito | ||
from fastapi import status, Response | ||
from fastapi.responses import JSONResponse | ||
from pydantic import BaseModel, Field | ||
from utilities.types.fields import DocusignWebhookEventEnum | ||
from datetime import datetime | ||
from typing import Dict, Any | ||
import logging | ||
from config.env import DOCUSIGN_API_VERSION | ||
|
||
|
||
class PostItem(BaseModel): | ||
event: DocusignWebhookEventEnum | ||
api_version: str = Field(alias="apiVersion", examples=['v2.1']) | ||
url: str = Field(examples=["/restapi/v2.1/accounts/6f7fcdd0-bc7f-484b-8a15-ed3af04c16ff/envelopes/29e66716-238b-459e-a29d-5371be2bef80"]) | ||
retry_count: int = Field(alias="retryCount", examples=[0]) | ||
configuration_id: int = Field(alias="configurationId", examples=[10352224]) | ||
generated_date_time: datetime = Field(alias="generatedDateTime", examples=["2023-11-01T03:20:28.1366172Z"]) | ||
data: Dict[str, Any] | ||
|
||
|
||
class DocusignWebhookController(BaseController): | ||
|
||
def __init__(self, auth: Cognito): # type: ignore[no-any-unimported] | ||
super().__init__(auth) | ||
self.router.add_api_route("/docusign/webhook", self.post, methods=["POST"], response_model=None) | ||
|
||
def post(self, key: str, item: PostItem) -> Response: | ||
mgr = DocusignWebhookManager() | ||
if not mgr.is_webhook_key(key): | ||
return JSONResponse( | ||
status_code=status.HTTP_403_FORBIDDEN, | ||
content=None | ||
) | ||
|
||
if item.api_version != DOCUSIGN_API_VERSION: | ||
logging.warn(f"Webhook API Version doesn't match. Current: {item.api_version}, Expected: {DOCUSIGN_API_VERSION}") | ||
|
||
try: | ||
mgr.handle_webhook_event(item.event, item.retry_count, item.generated_date_time, item.data) | ||
except NotImplementedError: | ||
return JSONResponse( | ||
status_code=status.HTTP_501_NOT_IMPLEMENTED, | ||
content=None | ||
) | ||
|
||
return JSONResponse( | ||
status_code=status.HTTP_200_OK, | ||
content=None | ||
) |
141 changes: 140 additions & 1 deletion
141
docs/docusign-events/creation-workflow/20231031232049-envelope-created.json
Large diffs are not rendered by default.
Oops, something went wrong.
142 changes: 141 additions & 1 deletion
142
docs/docusign-events/creation-workflow/20231031232106-recipient-sent.json
Large diffs are not rendered by default.
Oops, something went wrong.
141 changes: 140 additions & 1 deletion
141
docs/docusign-events/creation-workflow/20231031232108-envelope-sent.json
Large diffs are not rendered by default.
Oops, something went wrong.
142 changes: 141 additions & 1 deletion
142
docs/docusign-events/creation-workflow/20231031232209-recipient-delivered.json
Large diffs are not rendered by default.
Oops, something went wrong.
142 changes: 141 additions & 1 deletion
142
docs/docusign-events/creation-workflow/20231031232305-recipient-completed.json
Large diffs are not rendered by default.
Oops, something went wrong.
142 changes: 141 additions & 1 deletion
142
docs/docusign-events/creation-workflow/20231031232307-recipient-sent.json
Large diffs are not rendered by default.
Oops, something went wrong.
143 changes: 142 additions & 1 deletion
143
docs/docusign-events/creation-workflow/20231031232411-recipient-delivered.json
Large diffs are not rendered by default.
Oops, something went wrong.
143 changes: 142 additions & 1 deletion
143
docs/docusign-events/creation-workflow/20231031232414-envelope-delivered.json
Large diffs are not rendered by default.
Oops, something went wrong.
144 changes: 143 additions & 1 deletion
144
docs/docusign-events/creation-workflow/20231031232433-recipient-completed.json
Large diffs are not rendered by default.
Oops, something went wrong.
143 changes: 142 additions & 1 deletion
143
docs/docusign-events/creation-workflow/20231031232435-envelope-completed.json
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
from .contract import ContractManager | ||
from .me import MeManager | ||
from .me import MeManager | ||
from .docusign_webhook import DocusignWebhookManager |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
from config.env import DOCUSIGN_QUERY_PARAM_KEY | ||
from utilities.types.fields import DocusignWebhookEventEnum | ||
from datetime import datetime | ||
from typing import Dict, Any | ||
|
||
|
||
class DocusignWebhookManager(): | ||
|
||
def is_webhook_key(self, key: str) -> bool: | ||
return key == DOCUSIGN_QUERY_PARAM_KEY | ||
|
||
def handle_webhook_event(self, event: DocusignWebhookEventEnum, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
match event: | ||
case DocusignWebhookEventEnum.envelope_created: | ||
self._handle_envelope_created(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.envelope_sent: | ||
self._handle_envelope_sent(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.envelope_delivered: | ||
self._handle_envelope_delivered(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.envelope_completed: | ||
self._handle_envelope_completed(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.envelope_purge: | ||
self._handle_envelope_purge(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.envelope_resent: | ||
self._handle_envelope_resent(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.envelope_corrected: | ||
self._handle_envelope_corrected(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.envelope_discard: | ||
self._handle_envelope_discard(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.envelope_voided: | ||
self._handle_envelope_voided(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.envelope_deleted: | ||
self._handle_envelope_deleted(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.envelope_declined: | ||
self._handle_envelope_declined(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.recipient_sent: | ||
self._handle_recipient_sent(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.recipient_auto_responded: | ||
self._handle_recipient_auto_responded(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.recipient_delivered: | ||
self._handle_recipient_delivered(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.recipient_completed: | ||
self._handle_recipient_completed(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.recipient_declined: | ||
self._handle_recipient_declined(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.recipient_authentication_failure: | ||
self._handle_recipient_authentication_failure(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.recipient_resent: | ||
self._handle_recipient_resent(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.recipient_reassign: | ||
self._handle_recipient_reassign(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.recipient_finish_later: | ||
self._handle_recipient_finish_later(retry_count, generated_date_time, data) | ||
case DocusignWebhookEventEnum.recipient_delegate: | ||
self._handle_recipient_delegate(retry_count, generated_date_time, data) | ||
case _ as unknown: | ||
raise Exception(f"Unknown docusign event '{unknown}'") | ||
|
||
def _handle_envelope_created(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# TODO Here we have more info about the contract compared to our initial post route, so update contract and users DB | ||
raise NotImplementedError | ||
|
||
def _handle_envelope_sent(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# TODO Email is sent to signer/approver. Update contract state (and maybe users db if needed). | ||
raise NotImplementedError | ||
|
||
def _handle_envelope_delivered(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# An envelope has been signed from both parties but it's not done yet. We can do nothing here | ||
return | ||
|
||
def _handle_envelope_completed(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# TODO update contract state (and maybe users db if needed) | ||
# TODO send contract PDF to google drive | ||
raise NotImplementedError | ||
|
||
def _handle_envelope_purge(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# TODO at this point we need to delete the contracts and any kind of it's history from our DB. | ||
raise NotImplementedError | ||
|
||
def _handle_envelope_resent(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# An envelope email is being sent to the signer/approver. We can do nothing here | ||
return | ||
|
||
def _handle_envelope_corrected(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# TODO update contract data (and maybe users db if needed) | ||
raise NotImplementedError | ||
|
||
def _handle_envelope_discard(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# TODO it is unknown when this event will occur | ||
raise NotImplementedError | ||
|
||
def _handle_envelope_voided(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# TODO update contract state (and maybe users db if needed) | ||
raise NotImplementedError | ||
|
||
def _handle_envelope_deleted(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# TODO update contract state (and maybe users db if needed). DO NOT DELETE IT. Purge deletes. | ||
raise NotImplementedError | ||
|
||
def _handle_envelope_declined(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# TODO update contract state (and maybe users db if needed) | ||
raise NotImplementedError | ||
|
||
def _handle_recipient_sent(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# An envelope email is being sent to the signer/approver. We can do nothing here | ||
return | ||
|
||
def _handle_recipient_auto_responded(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# TODO it is unknown when this event will occur | ||
raise NotImplementedError | ||
|
||
def _handle_recipient_delivered(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# Signer/approver has filled out all fields, but has not confirmed the contract yet. We can do nothing here | ||
return | ||
|
||
def _handle_recipient_completed(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# TODO Signer/approver has finished the contract. Update contract DB (and maybe users db if needed) | ||
raise NotImplementedError | ||
|
||
def _handle_recipient_declined(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# TODO update contract state (and maybe users db if needed) | ||
raise NotImplementedError | ||
|
||
def _handle_recipient_authentication_failure(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# TODO it is unknown when this event will occur | ||
raise NotImplementedError | ||
|
||
def _handle_recipient_resent(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# An envelope email is being sent to the signer/approver. We can do nothing here | ||
return | ||
|
||
def _handle_recipient_reassign(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# TODO update contract state and users db | ||
raise NotImplementedError | ||
|
||
def _handle_recipient_finish_later(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# TODO update contract state (and maybe users db if needed) | ||
raise NotImplementedError | ||
|
||
def _handle_recipient_delegate(self, retry_count: int, generated_date_time: datetime, data: Dict[str, Any]) -> None: | ||
# TODO it is unknown when this event will occur | ||
raise NotImplementedError |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters