mirror of https://github.com/zulip/zulip.git
webhooks/hellosign: Rewrite the integration from scratch.
After discovering a couple of bugs, I decided to thoroughly test and rewrite this integration from scratch. The older code wasn't generating coherent messages. This also commit gets this integration up to 100% test coverage.
This commit is contained in:
parent
5039f6dfb5
commit
316f9aa78b
|
@ -102,7 +102,6 @@ not_yet_fully_covered = {
|
|||
# Webhook integrations with incomplete coverage
|
||||
'zerver/webhooks/github_legacy/view.py',
|
||||
'zerver/webhooks/greenhouse/view.py',
|
||||
'zerver/webhooks/hellosign/view.py',
|
||||
'zerver/webhooks/ifttt/view.py',
|
||||
'zerver/webhooks/jira/view.py',
|
||||
'zerver/webhooks/librato/view.py',
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"signature_request": {
|
||||
"signature_request_id": "2b388914e3ae3b738bd4e2ee2850c677e6dc53d2",
|
||||
"title": "NDA with Acme Co.",
|
||||
"subject": "The NDA we talked about",
|
||||
"message": "Please sign this NDA and then we can discuss more. Let me know if you have any questions.",
|
||||
"test_mode": true,
|
||||
"metadata": {
|
||||
"custom_id": "1234",
|
||||
"custom_text": "NDA #9"
|
||||
},
|
||||
"is_complete": false,
|
||||
"is_declined": false,
|
||||
"has_error": false,
|
||||
"custom_fields": [],
|
||||
"response_data": [],
|
||||
"signing_url": "https://www.hellosign.com/sign/2b388914e3ae3b738bd4e2ee2850c677e6dc53d2",
|
||||
"signing_redirect_url": null,
|
||||
"final_copy_uri": "/v3/signature_request/final_copy/2b388914e3ae3b738bd4e2ee2850c677e6dc53d2",
|
||||
"files_url": "https://api.hellosign.com/v3/signature_request/files/2b388914e3ae3b738bd4e2ee2850c677e6dc53d2",
|
||||
"details_url": "https://www.hellosign.com/home/manage?guid=2b388914e3ae3b738bd4e2ee2850c677e6dc53d2",
|
||||
"requester_email_address": "me@hellosign.com",
|
||||
"signatures": [{
|
||||
"signature_id": "616629ed37f8588d28600be17ab5d6b7",
|
||||
"signer_email_address": "jill@example.com",
|
||||
"signer_name": "Jill",
|
||||
"order": 1,
|
||||
"status_code": "signed",
|
||||
"signed_at": null,
|
||||
"last_viewed_at": null,
|
||||
"last_reminded_at": null,
|
||||
"has_pin": false
|
||||
}],
|
||||
"cc_email_addresses": [
|
||||
"lawyer1@hellosign.com",
|
||||
"lawyer2@example.com"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
{
|
||||
"event":{
|
||||
"event_type":"signature_request_sent",
|
||||
"event_time":"1538590065",
|
||||
"event_hash":"a755305281fde7bee3517cfd6858e5300bc12c85a2c0f51b47babe98800258d4",
|
||||
"event_metadata":{
|
||||
"related_signature_id":null,
|
||||
"reported_for_account_id":"4686cb274933adf9c9b3a450c4131b0105a2ac14",
|
||||
"reported_for_app_id":null
|
||||
}
|
||||
},
|
||||
"account_guid":"4686cb274933adf9c9b3a450c4131b0105a2ac14",
|
||||
"client_id":null,
|
||||
"signature_request":{
|
||||
"signature_request_id":"a6ce6526d1e7496c96a1cdd11276efb5c4504084",
|
||||
"test_mode":false,
|
||||
"title":"Signature doc",
|
||||
"original_title":"Signature doc",
|
||||
"subject":"Signature doc",
|
||||
"message":null,
|
||||
"metadata":{
|
||||
|
||||
},
|
||||
"is_complete":false,
|
||||
"is_declined":false,
|
||||
"has_error":false,
|
||||
"custom_fields":[
|
||||
|
||||
],
|
||||
"response_data":[
|
||||
|
||||
],
|
||||
"signing_url":"https:\/\/app.hellosign.com\/sign\/a6ce6526d1e7496c96a1cdd11276efb5c4504084",
|
||||
"signing_redirect_url":null,
|
||||
"final_copy_uri":"\/\/signature_request\/final_copy\/a6ce6526d1e7496c96a1cdd11276efb5c4504084",
|
||||
"files_url":"https:\/\/api.hellosign.com\/signature_request\/files\/a6ce6526d1e7496c96a1cdd11276efb5c4504084",
|
||||
"details_url":"https:\/\/app.hellosign.com\/home\/manage?guid=a6ce6526d1e7496c96a1cdd11276efb5c4504084",
|
||||
"requester_email_address":"jerryguitarist@gmail.com",
|
||||
"signatures":[
|
||||
{
|
||||
"signature_id":"1d3e6160c86ce2ffadc5032f449ccc7f",
|
||||
"has_pin":false,
|
||||
"signer_email_address":"jerryguitarist@gmail.com",
|
||||
"signer_name":"Eeshan Garg",
|
||||
"order":null,
|
||||
"status_code":"awaiting_signature",
|
||||
"signed_at":null,
|
||||
"last_viewed_at":null,
|
||||
"last_reminded_at":null,
|
||||
"error":null
|
||||
},
|
||||
{
|
||||
"signature_id":"4f6270cc1df39ffe86a47fd9293bc49c",
|
||||
"has_pin":false,
|
||||
"signer_email_address":"johnsmith@example.com",
|
||||
"signer_name":"John Smith",
|
||||
"order":null,
|
||||
"status_code":"awaiting_signature",
|
||||
"signed_at":null,
|
||||
"last_viewed_at":null,
|
||||
"last_reminded_at":null,
|
||||
"error":null
|
||||
},
|
||||
{
|
||||
"signature_id":"4f532706f781664d50bca2c88da81361",
|
||||
"has_pin":false,
|
||||
"signer_email_address":"janedoe@example.com",
|
||||
"signer_name":"Jane Doe",
|
||||
"order":null,
|
||||
"status_code":"awaiting_signature",
|
||||
"signed_at":null,
|
||||
"last_viewed_at":null,
|
||||
"last_reminded_at":null,
|
||||
"error":null
|
||||
},
|
||||
{
|
||||
"signature_id":"d13912af43be9cfc8119597b0d6e9c68",
|
||||
"has_pin":false,
|
||||
"signer_email_address":"drstrange@example.com",
|
||||
"signer_name":"Stephen Strange",
|
||||
"order":null,
|
||||
"status_code":"awaiting_signature",
|
||||
"signed_at":null,
|
||||
"last_viewed_at":null,
|
||||
"last_reminded_at":null,
|
||||
"error":null
|
||||
}
|
||||
],
|
||||
"cc_email_addresses":[
|
||||
|
||||
]
|
||||
}
|
||||
}
|
|
@ -9,16 +9,30 @@ class HelloSignHookTests(WebhookTestCase):
|
|||
|
||||
def test_signatures_message(self) -> None:
|
||||
expected_subject = "NDA with Acme Co."
|
||||
expected_message = ("The NDA with Acme Co. is awaiting the signature of "
|
||||
"Jack and was just signed by Jill.")
|
||||
expected_message = ("The `NDA with Acme Co.` document is awaiting the signature of "
|
||||
"Jack, and was just signed by Jill.")
|
||||
self.send_and_test_stream_message('signatures', expected_subject, expected_message,
|
||||
content_type="application/x-www-form-urlencoded")
|
||||
|
||||
def test_signatures_message_signed_by_one(self) -> None:
|
||||
expected_subject = "NDA with Acme Co."
|
||||
expected_message = ("The `NDA with Acme Co.` document was just signed by Jill.")
|
||||
self.send_and_test_stream_message('signatures_signed_by_one_signatory',
|
||||
expected_subject, expected_message,
|
||||
content_type="application/x-www-form-urlencoded")
|
||||
|
||||
def test_signatures_message_with_four_signatories(self) -> None:
|
||||
expected_subject = "Signature doc"
|
||||
expected_message = ("The `Signature doc` document is awaiting the signature of "
|
||||
"Eeshan Garg, John Smith, Jane Doe, and Stephen Strange.")
|
||||
self.send_and_test_stream_message('signatures_with_four_signatories', expected_subject, expected_message,
|
||||
content_type="application/x-www-form-urlencoded")
|
||||
|
||||
def test_signatures_message_with_own_subject(self) -> None:
|
||||
expected_subject = "Our own subject."
|
||||
self.url = self.build_webhook_url(topic=expected_subject)
|
||||
expected_message = ("The NDA with Acme Co. is awaiting the signature of "
|
||||
"Jack and was just signed by Jill.")
|
||||
expected_message = ("The `NDA with Acme Co.` document is awaiting the signature of "
|
||||
"Jack, and was just signed by Jill.")
|
||||
self.send_and_test_stream_message('signatures_with_own_subject', expected_subject, expected_message,
|
||||
content_type="application/x-www-form-urlencoded", topic=expected_subject)
|
||||
|
||||
|
|
|
@ -9,41 +9,55 @@ from zerver.lib.response import json_error, json_success
|
|||
from zerver.lib.webhooks.common import check_send_webhook_message
|
||||
from zerver.models import UserProfile
|
||||
|
||||
def format_body(signatories: List[Dict[str, Any]], model_payload: Dict[str, Any]) -> str:
|
||||
def append_separator(i: int) -> None:
|
||||
if i + 1 == len(signatories):
|
||||
result.append('.')
|
||||
elif i + 2 == len(signatories):
|
||||
result.append(' and')
|
||||
elif i + 3 != len(signatories):
|
||||
result.append(',')
|
||||
|
||||
result = ["The {}".format(model_payload['contract_title'])] # type: Any
|
||||
for i, signatory in enumerate(signatories):
|
||||
name = model_payload['name_{}'.format(i)]
|
||||
if signatory['status_code'] == 'awaiting_signature':
|
||||
result.append(" is awaiting the signature of {}".format(name))
|
||||
elif signatory['status_code'] in ['signed', 'declined']:
|
||||
status = model_payload['status_{}'.format(i)]
|
||||
result.append(" was just {} by {}".format(status, name))
|
||||
IS_AWAITING_SIGNATURE = "is awaiting the signature of {awaiting_recipients}"
|
||||
WAS_JUST_SIGNED_BY = "was just signed by {signed_recipients}"
|
||||
BODY = "The `{contract_title}` document {actions}."
|
||||
|
||||
append_separator(i)
|
||||
return ''.join(result)
|
||||
def get_message_body(payload: Dict[str, Dict[str, Any]]) -> str:
|
||||
contract_title = payload['signature_request']['title']
|
||||
recipients = {} # type: Dict[str, List[str]]
|
||||
signatures = payload['signature_request']['signatures']
|
||||
|
||||
def ready_payload(signatories: List[Dict[str, Any]],
|
||||
payload: Dict[str, Dict[str, Any]]) -> Dict[str, Any]:
|
||||
model_payload = {'contract_title': payload['signature_request']['title']}
|
||||
for i, signatory in enumerate(signatories):
|
||||
model_payload['name_{}'.format(i)] = signatory['signer_name']
|
||||
model_payload['status_{}'.format(i)] = signatory['status_code']
|
||||
return model_payload
|
||||
for signature in signatures:
|
||||
recipients.setdefault(signature['status_code'], [])
|
||||
recipients[signature['status_code']].append(signature['signer_name'])
|
||||
|
||||
recipients_text = ""
|
||||
if recipients.get('awaiting_signature'):
|
||||
recipients_text += IS_AWAITING_SIGNATURE.format(
|
||||
awaiting_recipients=get_recipients_text(recipients['awaiting_signature'])
|
||||
)
|
||||
|
||||
if recipients.get('signed'):
|
||||
text = WAS_JUST_SIGNED_BY.format(
|
||||
signed_recipients=get_recipients_text(recipients['signed'])
|
||||
)
|
||||
|
||||
if recipients_text:
|
||||
recipients_text = "{}, and {}".format(recipients_text, text)
|
||||
else:
|
||||
recipients_text = text
|
||||
|
||||
return BODY.format(contract_title=contract_title,
|
||||
actions=recipients_text).strip()
|
||||
|
||||
def get_recipients_text(recipients: List[str]) -> str:
|
||||
recipients_text = ""
|
||||
if len(recipients) == 1:
|
||||
recipients_text = "{}".format(*recipients)
|
||||
else:
|
||||
for recipient in recipients[:-1]:
|
||||
recipients_text += "{}, ".format(recipient)
|
||||
recipients_text += "and {}".format(recipients[-1])
|
||||
|
||||
return recipients_text
|
||||
|
||||
@api_key_only_webhook_view('HelloSign')
|
||||
@has_request_variables
|
||||
def api_hellosign_webhook(request: HttpRequest, user_profile: UserProfile,
|
||||
payload: Dict[str, Dict[str, Any]]=REQ(argument_type='body')) -> HttpResponse:
|
||||
model_payload = ready_payload(payload['signature_request']['signatures'], payload)
|
||||
body = format_body(payload['signature_request']['signatures'], model_payload)
|
||||
topic = model_payload['contract_title']
|
||||
body = get_message_body(payload)
|
||||
topic = payload['signature_request']['title']
|
||||
check_send_webhook_message(request, user_profile, topic, body)
|
||||
return json_success()
|
||||
|
|
Loading…
Reference in New Issue