snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
This commit is contained in:
0
zerver/webhooks/greenhouse/__init__.py
Normal file
0
zerver/webhooks/greenhouse/__init__.py
Normal file
32
zerver/webhooks/greenhouse/doc.md
Normal file
32
zerver/webhooks/greenhouse/doc.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Zulip Greenhouse integration
|
||||
|
||||
Receive Greenhouse notifications in Zulip!
|
||||
|
||||
{start_tabs}
|
||||
|
||||
1. {!create-an-incoming-webhook.md!}
|
||||
|
||||
1. {!generate-webhook-url-basic.md!}
|
||||
|
||||
1. On your Greenhouse **Dashboard**, click on the
|
||||
**gear** (<i class="fa fa-cog"></i>) icon in the upper right
|
||||
corner. Click on **Dev Center**, and click **Web Hooks**.
|
||||
Click on **Web Hooks** one more time.
|
||||
|
||||
1. Set **Name this web hook** to a name of your choice, such as
|
||||
`Zulip`. Set **When** to the event you'd like to be notified
|
||||
about. Set **Endpoint URL** to the URL generated above.
|
||||
|
||||
1. Greenhouse requires you to provide a **Secret key**, but Zulip
|
||||
doesn't expect any particular value. Set **Secret key** to any
|
||||
random value, and click **Create Web hook**.
|
||||
|
||||
{end_tabs}
|
||||
|
||||
{!congrats.md!}
|
||||
|
||||

|
||||
|
||||
### Related documentation
|
||||
|
||||
{!webhooks-url-specification.md!}
|
||||
112
zerver/webhooks/greenhouse/fixtures/candidate_created.json
Normal file
112
zerver/webhooks/greenhouse/fixtures/candidate_created.json
Normal file
@@ -0,0 +1,112 @@
|
||||
{
|
||||
"action": "new_candidate_application",
|
||||
"payload": {
|
||||
"application": {
|
||||
"id": 265293,
|
||||
"rejected_at": null,
|
||||
"prospect": false,
|
||||
"status": "active",
|
||||
"applied_at": "2013-03-22T00:00:00Z",
|
||||
"last_activity_at": "2015-03-18T20:28:09Z",
|
||||
"source": {
|
||||
"id": 27,
|
||||
"public_name": "LinkedIn"
|
||||
},
|
||||
"credited_to": null,
|
||||
"rejection_reason": null,
|
||||
"current_stage": {
|
||||
"id": 678901,
|
||||
"name": "Application Review",
|
||||
"interviews": [
|
||||
{
|
||||
"id": 989099,
|
||||
"name":"Application Review",
|
||||
"status": "collect_feedback",
|
||||
"interview_kit": {
|
||||
"url": "http://app.greenhouse.io/guides/67656/people/265788",
|
||||
"content": "",
|
||||
"questions": []
|
||||
},
|
||||
"interviewers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"candidate": {
|
||||
"id": 265788,
|
||||
"created_at": "2013-10-04T01:24:48Z",
|
||||
"first_name": "Hector",
|
||||
"last_name": "Porter",
|
||||
"title": null,
|
||||
"company": null,
|
||||
"phone_numbers": [
|
||||
{
|
||||
"value": "330-281-8004",
|
||||
"type": "home"
|
||||
}
|
||||
],
|
||||
"email_addresses": [
|
||||
{
|
||||
"value": "hector.porter.265788@example.com",
|
||||
"type": "personal"
|
||||
}
|
||||
],
|
||||
"addresses": [],
|
||||
"website_addresses": [],
|
||||
"social_media_addresses": [],
|
||||
"recruiter": null,
|
||||
"coordinator": null,
|
||||
"photo_url": "https://prod-heroku.s3.amazonaws.com/...",
|
||||
"attachments": [
|
||||
{
|
||||
"filename": "resume.pdf",
|
||||
"url": "https://prod-heroku.s3.amazonaws.com/...",
|
||||
"type": "resume"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Import from Previous ATS"
|
||||
],
|
||||
"custom_fields": {
|
||||
"favorite_color": {
|
||||
"name": "Favorite Color",
|
||||
"type": "short_text",
|
||||
"value": "Blue"
|
||||
}
|
||||
}
|
||||
},
|
||||
"jobs": [
|
||||
{
|
||||
"id": 3485,
|
||||
"name": "Designer",
|
||||
"requisition_id": null,
|
||||
"notes": "Digital and print",
|
||||
"job_post_id": 54321,
|
||||
"status": "open",
|
||||
"created_at": "2013-10-02T22:59:29Z",
|
||||
"opened_at": "2015-01-23T00:25:04Z",
|
||||
"closed_at": null,
|
||||
"departments": [
|
||||
{
|
||||
"id": 237,
|
||||
"name": "Community"
|
||||
}
|
||||
],
|
||||
"offices": [
|
||||
{
|
||||
"id": 54,
|
||||
"name": "New York",
|
||||
"location": "New York, NY"
|
||||
}
|
||||
],
|
||||
"custom_fields": {
|
||||
"employment_type": {
|
||||
"name": "Employment Type",
|
||||
"type": "single_select",
|
||||
"value": "Full Time"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
184
zerver/webhooks/greenhouse/fixtures/candidate_hired.json
Normal file
184
zerver/webhooks/greenhouse/fixtures/candidate_hired.json
Normal file
@@ -0,0 +1,184 @@
|
||||
{
|
||||
"action": "hire_candidate",
|
||||
"payload": {
|
||||
"application": {
|
||||
"id": 20,
|
||||
"opening": {
|
||||
"opening_id": "1234-56"
|
||||
},
|
||||
"credited_to": {
|
||||
"id": 57,
|
||||
"email": "bob_johnson1@localhost.com",
|
||||
"name": "Robert Johnson"
|
||||
},
|
||||
"source": {
|
||||
"id": 25,
|
||||
"public_name": "Monster"
|
||||
},
|
||||
"candidate": {
|
||||
"id": 19,
|
||||
"first_name": "Johnny",
|
||||
"last_name": "Smith",
|
||||
"title": "Previous Title",
|
||||
"external_id": "00000",
|
||||
"phone_numbers": [{
|
||||
"value": "518-555-1212",
|
||||
"type": "work"
|
||||
}, {
|
||||
"value": "212-555-1212",
|
||||
"type": "home"
|
||||
}],
|
||||
"email_addresses": [{
|
||||
"value": "personal@example.com",
|
||||
"type": "personal"
|
||||
}, {
|
||||
"value": "work@example.com",
|
||||
"type": "work"
|
||||
}],
|
||||
"addresses": [{
|
||||
"value": "455 Broadway New York, NY 10280",
|
||||
"type": "home"
|
||||
}],
|
||||
"recruiter": {
|
||||
"id": 55,
|
||||
"email": "bob_johnson@localhost.com",
|
||||
"name": "Bob Johnson"
|
||||
},
|
||||
"coordinator": {
|
||||
"id": 56,
|
||||
"email": "bob_johnson_approver1@localhost.com",
|
||||
"name": "Robert J Approver"
|
||||
},
|
||||
"attachments": [{
|
||||
"filename": "resume.pdf",
|
||||
"url": "https://prod-heroku.s3.amazonaws.com/...",
|
||||
"type": "resume"
|
||||
}],
|
||||
"custom_fields": {
|
||||
"desired_level": {
|
||||
"name": "Desired Level",
|
||||
"type": "short_text",
|
||||
"value": "Senior"
|
||||
},
|
||||
"favorite_programming_language": {
|
||||
"name": "Favorite Programming Language",
|
||||
"type": "short_text",
|
||||
"value": "Rails"
|
||||
}
|
||||
}
|
||||
},
|
||||
"job": {
|
||||
"id": 20,
|
||||
"name": "Developer",
|
||||
"open_date": "2014-11-20T22:49:14Z",
|
||||
"close_date": "2014-11-25T22:49:14Z",
|
||||
"requisition_id": null,
|
||||
"departments": [{
|
||||
"id": 7,
|
||||
"name": "Technology"
|
||||
}],
|
||||
"offices": [{
|
||||
"id": 13,
|
||||
"name": "New York City",
|
||||
"location": {
|
||||
"name": "New York, NY"
|
||||
}
|
||||
}, {
|
||||
"id": 14,
|
||||
"name": "St. Louis",
|
||||
"location": null
|
||||
}],
|
||||
"custom_fields": {
|
||||
"approved": {
|
||||
"name": "Approved",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
},
|
||||
"employment_type": {
|
||||
"name": "Employment Type",
|
||||
"type": "single_select",
|
||||
"value": "Full-time"
|
||||
},
|
||||
"salary_range": {
|
||||
"name": "SalaryRange",
|
||||
"type": "currency_range",
|
||||
"value": {
|
||||
"unit": "USD",
|
||||
"min_value": "10000.0",
|
||||
"max_value": "20000.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"jobs": [{
|
||||
"id": 20,
|
||||
"name": "Developer",
|
||||
"opened_at": "2014-11-20T22:49:14Z",
|
||||
"closed_at": "2014-11-25T22:49:14Z",
|
||||
"requisition_id": null,
|
||||
"departments": [{
|
||||
"id": 7,
|
||||
"name": "Technology"
|
||||
}],
|
||||
"offices": [{
|
||||
"id": 13,
|
||||
"name": "New York City",
|
||||
"location": {
|
||||
"name": "New York, NY"
|
||||
}
|
||||
}, {
|
||||
"id": 14,
|
||||
"name": "St. Louis",
|
||||
"location": null
|
||||
}],
|
||||
"custom_fields": {
|
||||
"approved": {
|
||||
"name": "Approved",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
},
|
||||
"employment_type": {
|
||||
"name": "Employment Type",
|
||||
"type": "single_select",
|
||||
"value": "Full-time"
|
||||
},
|
||||
"salary_range": {
|
||||
"name": "SalaryRange",
|
||||
"type": "currency_range",
|
||||
"value": {
|
||||
"unit": "USD",
|
||||
"min_value": "10000.0",
|
||||
"max_value": "20000.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}],
|
||||
"offer": {
|
||||
"id": 13,
|
||||
"version": 2,
|
||||
"created_at": "2014-11-20T22:49:14Z",
|
||||
"sent_at": "2014-11-10",
|
||||
"resolved_at": "2014-11-20T22:49:14Z",
|
||||
"starts_at": "2015-01-23",
|
||||
"custom_fields": {
|
||||
"salary": {
|
||||
"name": "Salary",
|
||||
"type": "currency",
|
||||
"value": {
|
||||
"amount": 80000,
|
||||
"unit": "USD"
|
||||
}
|
||||
},
|
||||
"seasons": {
|
||||
"name": "Seasons",
|
||||
"type": "multi_select",
|
||||
"value": [
|
||||
"Season 1",
|
||||
"Season 2"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
90
zerver/webhooks/greenhouse/fixtures/candidate_rejected.json
Normal file
90
zerver/webhooks/greenhouse/fixtures/candidate_rejected.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"action": "reject_candidate",
|
||||
"payload": {
|
||||
"application": {
|
||||
"id": 265293,
|
||||
"rejected_at": "2015-02-11T15:50:41Z",
|
||||
"prospect": false,
|
||||
"status": "rejected",
|
||||
"applied_at": "2013-03-22T00:00:00Z",
|
||||
"last_activity_at": "2015-02-11T15:50:41Z",
|
||||
"source": {
|
||||
"id": 27,
|
||||
"public_name": "LinkedIn"
|
||||
},
|
||||
"credited_to": null,
|
||||
"rejection_reason": {
|
||||
"id": 14,
|
||||
"name": "Too Junior",
|
||||
"type": {
|
||||
"id": 3,
|
||||
"name": "Wrong skill set"
|
||||
}
|
||||
},
|
||||
"candidate": {
|
||||
"id": 265788,
|
||||
"created_at": "2013-10-04T01:24:48Z",
|
||||
"first_name": "Hector",
|
||||
"last_name": "Porter",
|
||||
"title": null,
|
||||
"company": null,
|
||||
"phone_numbers": [{
|
||||
"value": "330-281-8004",
|
||||
"type": "home"
|
||||
}],
|
||||
"email_addresses": [{
|
||||
"value": "hector.porter.265788@example.com",
|
||||
"type": "personal"
|
||||
}],
|
||||
"addresses": [],
|
||||
"website_addresses": [],
|
||||
"social_media_addresses": [],
|
||||
"recruiter": null,
|
||||
"coordinator": null,
|
||||
"photo_url": "www.example.com/photo.png",
|
||||
"attachments": [{
|
||||
"filename": "resume.pdf",
|
||||
"url": "https://prod-heroku.s3.amazonaws.com/...",
|
||||
"type": "resume"
|
||||
}],
|
||||
"tags": [
|
||||
"Imported"
|
||||
],
|
||||
"custom_fields": {
|
||||
"favorite_color": {
|
||||
"name": "Favorite Color",
|
||||
"type": "short_text",
|
||||
"value": "Blue"
|
||||
}
|
||||
}
|
||||
},
|
||||
"jobs": [{
|
||||
"id": 3485,
|
||||
"name": "Designer",
|
||||
"requisition_id": null,
|
||||
"notes": "Digital and print",
|
||||
"job_post_id": 54321,
|
||||
"status": "open",
|
||||
"created_at": "2013-10-02T22:59:29Z",
|
||||
"opened_at": "2015-01-23T00:25:04Z",
|
||||
"closed_at": null,
|
||||
"departments": [{
|
||||
"id": 237,
|
||||
"name": "Community"
|
||||
}],
|
||||
"offices": [{
|
||||
"id": 54,
|
||||
"name": "New York",
|
||||
"location": "New York, NY"
|
||||
}],
|
||||
"custom_fields": {
|
||||
"employment_type": {
|
||||
"name": "Employment Type",
|
||||
"type": "single_select",
|
||||
"value": "Full Time"
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
130
zerver/webhooks/greenhouse/fixtures/candidate_stage_change.json
Normal file
130
zerver/webhooks/greenhouse/fixtures/candidate_stage_change.json
Normal file
@@ -0,0 +1,130 @@
|
||||
{
|
||||
"action": "candidate_stage_change",
|
||||
"payload": {
|
||||
"application": {
|
||||
"id": 265277,
|
||||
"rejected_at": null,
|
||||
"prospect": false,
|
||||
"status": "active",
|
||||
"applied_at": "2013-03-22T00:00:00Z",
|
||||
"last_activity_at": "2015-02-09T16:38:36Z",
|
||||
"source": {
|
||||
"id": 31,
|
||||
"name": "Agency"
|
||||
},
|
||||
"credited_to": {
|
||||
"id": 15,
|
||||
"email": "ada@example.com",
|
||||
"name": "Ada Lacey"
|
||||
},
|
||||
"rejection_reason": null,
|
||||
"current_stage": {
|
||||
"id": 71416,
|
||||
"name": "Assessment",
|
||||
"interviews": [{
|
||||
"id": 113101,
|
||||
"name": "Assessment",
|
||||
"status": "to_be_scheduled",
|
||||
"interview_kit": {
|
||||
"url": "https://app.greenhouse.io/guides/113153/people/265772",
|
||||
"content": "Assess their skills",
|
||||
"questions": []
|
||||
},
|
||||
"interviewers": [{
|
||||
"id": 2622,
|
||||
"display_name": "Carl Buddha",
|
||||
"status": "tentative"
|
||||
}]
|
||||
}]
|
||||
},
|
||||
"candidate": {
|
||||
"id": 265772,
|
||||
"created_at": "2013-10-04T01:24:44Z",
|
||||
"first_name": "Giuseppe",
|
||||
"last_name": "Hurley",
|
||||
"external_id": "241b399ce4b0fd1c84e5528d",
|
||||
"title": "Great Person",
|
||||
"company": null,
|
||||
"photo_url": "https://prod-heroku.s3.amazonaws.com/...",
|
||||
"phone_numbers": [{
|
||||
"value": "330-281-8004",
|
||||
"type": "home"
|
||||
}],
|
||||
"email_addresses": [{
|
||||
"value": "giuseppe.hurley@example.com",
|
||||
"type": "personal"
|
||||
}],
|
||||
"addresses": [{
|
||||
"value": "123 Fake St.",
|
||||
"type": "home"
|
||||
}],
|
||||
"website_addresses": [{
|
||||
"value": "ghurley.example.com",
|
||||
"type": "personal"
|
||||
}],
|
||||
"social_media_addresses": [{
|
||||
"value": "linkedin.example.com/ghurley"
|
||||
}],
|
||||
"recruiter": {
|
||||
"id": 3128,
|
||||
"email": "alicia.flopple.3128@example.com",
|
||||
"name": "Alicia Flopple"
|
||||
},
|
||||
"coordinator": {
|
||||
"id": 3128,
|
||||
"email": "alicia.flopple.3128@example.com",
|
||||
"name": "Alicia Flopple"
|
||||
},
|
||||
"attachments": [{
|
||||
"filename": "resume.pdf",
|
||||
"url": "https://prod-heroku.s3.amazonaws.com/...",
|
||||
"type": "resume"
|
||||
}, {
|
||||
"filename": "cover_letter.pdf",
|
||||
"url": "https://prod-heroku.s3.amazonaws.com/...",
|
||||
"type": "cover_letter"
|
||||
}, {
|
||||
"filename": "portfolio.pdf",
|
||||
"url": "https://prod-heroku.s3.amazonaws.com/...",
|
||||
"type": "attachment"
|
||||
}],
|
||||
"tags": [
|
||||
"Import from Previous ATS"
|
||||
],
|
||||
"custom_fields": {
|
||||
"favorite_color": {
|
||||
"name": "Favorite Color",
|
||||
"type": "short_text",
|
||||
"value": "Blue"
|
||||
}
|
||||
}
|
||||
},
|
||||
"jobs": [{
|
||||
"id": 3485,
|
||||
"name": "Designer",
|
||||
"requisition_id": null,
|
||||
"notes": "Digital and print",
|
||||
"status": "open",
|
||||
"created_at": "2013-10-02T22:59:29Z",
|
||||
"opened_at": "2015-01-23T00:25:04Z",
|
||||
"closed_at": null,
|
||||
"departments": [{
|
||||
"id": 237,
|
||||
"name": "Community"
|
||||
}],
|
||||
"offices": [{
|
||||
"id": 54,
|
||||
"name": "New York",
|
||||
"location": "New York, NY"
|
||||
}],
|
||||
"custom_fields": {
|
||||
"employment_type": {
|
||||
"name": "Employment Type",
|
||||
"type": "single_select",
|
||||
"value": "Full Time"
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
13
zerver/webhooks/greenhouse/fixtures/ping_event.json
Normal file
13
zerver/webhooks/greenhouse/fixtures/ping_event.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"payload":{
|
||||
"active":true,
|
||||
"created_at":"2018-10-19T16:25:57Z",
|
||||
"web_hook_id":9590,
|
||||
"name":"Zulip",
|
||||
"endpoint_url":"https:\/\/zulip.example.com\/",
|
||||
"content-type":"application\/json",
|
||||
"updated_at":"2018-10-19T16:49:16Z",
|
||||
"event":"Candidate has been hired"
|
||||
},
|
||||
"action":"ping"
|
||||
}
|
||||
104
zerver/webhooks/greenhouse/fixtures/prospect_created.json
Normal file
104
zerver/webhooks/greenhouse/fixtures/prospect_created.json
Normal file
@@ -0,0 +1,104 @@
|
||||
{
|
||||
"action": "new_prospect_application",
|
||||
"payload": {
|
||||
"application": {
|
||||
"id": 979554,
|
||||
"rejected_at": null,
|
||||
"prospect": true,
|
||||
"status": "active",
|
||||
"applied_at": "2014-12-02T23:10:16Z",
|
||||
"last_activity_at": "2014-12-02T23:10:16Z",
|
||||
"current_stage": null,
|
||||
"source": {
|
||||
"id": 13,
|
||||
"public_name": "Referral"
|
||||
},
|
||||
"credited_to": {
|
||||
"id": 2622,
|
||||
"email": "carl.buddha.2622@example.com",
|
||||
"name": "Carl Buddha"
|
||||
},
|
||||
"rejection_reason": null,
|
||||
"candidate": {
|
||||
"id": 968190,
|
||||
"created_at": "2014-12-02T23:10:16Z",
|
||||
"first_name": "Trisha",
|
||||
"last_name": "Troy",
|
||||
"title": null,
|
||||
"company": null,
|
||||
"phone_numbers": [
|
||||
{
|
||||
"value": "123456",
|
||||
"type": "other"
|
||||
}
|
||||
],
|
||||
"email_addresses": [
|
||||
{
|
||||
"value": "t.troy@example.com",
|
||||
"type": "personal"
|
||||
}
|
||||
],
|
||||
"addresses": [],
|
||||
"website_addresses": [],
|
||||
"social_media_addresses": [],
|
||||
"recruiter": {
|
||||
"id": 3128,
|
||||
"email": "alicia.flopple.3128@example.com",
|
||||
"name": "Alicia Flopple"
|
||||
},
|
||||
"coordinator": null,
|
||||
"photo_url": "https://prod-heroku.s3.amazonaws.com/...",
|
||||
"attachments": [
|
||||
{
|
||||
"filename": "resume.pdf",
|
||||
"url": "https://prod-heroku.s3.amazonaws.com/...",
|
||||
"type": "resume"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Import from Previous ATS"
|
||||
],
|
||||
"custom_fields": {
|
||||
"favorite_color": {
|
||||
"name": "Favorite Color",
|
||||
"type": "short_text",
|
||||
"value": "Blue"
|
||||
}
|
||||
}
|
||||
},
|
||||
"jobs": [
|
||||
{
|
||||
"id": 3485,
|
||||
"name": "Designer",
|
||||
"requisition_id": null,
|
||||
"notes": "Digital and print",
|
||||
"job_post_id": 54321,
|
||||
"status": "open",
|
||||
"created_at": "2013-10-02T22:59:29Z",
|
||||
"opened_at": "2015-01-23T00:25:04Z",
|
||||
"closed_at": null,
|
||||
"departments": [
|
||||
{
|
||||
"id": 237,
|
||||
"name": "Community"
|
||||
}
|
||||
],
|
||||
"offices": [
|
||||
{
|
||||
"id": 54,
|
||||
"name": "New York",
|
||||
"location": "New York, NY"
|
||||
}
|
||||
],
|
||||
"custom_fields": {
|
||||
"employment_type": {
|
||||
"name": "Employment Type",
|
||||
"type": "single_select",
|
||||
"value": "Full Time"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
76
zerver/webhooks/greenhouse/tests.py
Normal file
76
zerver/webhooks/greenhouse/tests.py
Normal file
@@ -0,0 +1,76 @@
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from zerver.lib.test_classes import WebhookTestCase
|
||||
|
||||
|
||||
class GreenhouseHookTests(WebhookTestCase):
|
||||
CONTENT_TYPE = "application/x-www-form-urlencoded"
|
||||
|
||||
def test_message_candidate_hired(self) -> None:
|
||||
expected_topic_name = "Hire Candidate - 19"
|
||||
expected_message = """
|
||||
Hire Candidate Johnny Smith (ID: 19), applying for:
|
||||
* **Role**: Developer
|
||||
* **Emails**: personal@example.com (Personal), work@example.com (Work)
|
||||
* **Attachments**: [Resume](https://prod-heroku.s3.amazonaws.com/...)
|
||||
""".strip()
|
||||
|
||||
self.check_webhook(
|
||||
"candidate_hired", expected_topic_name, expected_message, content_type=self.CONTENT_TYPE
|
||||
)
|
||||
|
||||
def test_message_candidate_rejected(self) -> None:
|
||||
expected_topic_name = "Reject Candidate - 265788"
|
||||
expected_message = """
|
||||
Reject Candidate Hector Porter (ID: 265788), applying for:
|
||||
* **Role**: Designer
|
||||
* **Emails**: hector.porter.265788@example.com (Personal)
|
||||
* **Attachments**: [Resume](https://prod-heroku.s3.amazonaws.com/...)
|
||||
""".strip()
|
||||
|
||||
self.check_webhook(
|
||||
"candidate_rejected",
|
||||
expected_topic_name,
|
||||
expected_message,
|
||||
content_type=self.CONTENT_TYPE,
|
||||
)
|
||||
|
||||
def test_message_candidate_stage_change(self) -> None:
|
||||
expected_topic_name = "Candidate Stage Change - 265772"
|
||||
expected_message = """
|
||||
Candidate Stage Change Giuseppe Hurley (ID: 265772), applying for:
|
||||
* **Role**: Designer
|
||||
* **Emails**: giuseppe.hurley@example.com (Personal)
|
||||
* **Attachments**: [Resume](https://prod-heroku.s3.amazonaws.com/...), [Cover_Letter](https://prod-heroku.s3.amazonaws.com/...), [Attachment](https://prod-heroku.s3.amazonaws.com/...)
|
||||
""".strip()
|
||||
|
||||
self.check_webhook(
|
||||
"candidate_stage_change",
|
||||
expected_topic_name,
|
||||
expected_message,
|
||||
content_type=self.CONTENT_TYPE,
|
||||
)
|
||||
|
||||
def test_message_prospect_created(self) -> None:
|
||||
expected_topic_name = "New Prospect Application - 968190"
|
||||
expected_message = """
|
||||
New Prospect Application Trisha Troy (ID: 968190), applying for:
|
||||
* **Role**: Designer
|
||||
* **Emails**: t.troy@example.com (Personal)
|
||||
* **Attachments**: [Resume](https://prod-heroku.s3.amazonaws.com/...)
|
||||
""".strip()
|
||||
|
||||
self.check_webhook(
|
||||
"prospect_created",
|
||||
expected_topic_name,
|
||||
expected_message,
|
||||
content_type=self.CONTENT_TYPE,
|
||||
)
|
||||
|
||||
@patch("zerver.webhooks.greenhouse.view.check_send_webhook_message")
|
||||
def test_ping_message_ignore(self, check_send_webhook_message_mock: MagicMock) -> None:
|
||||
self.url = self.build_webhook_url()
|
||||
payload = self.get_body("ping_event")
|
||||
result = self.client_post(self.url, payload, content_type=self.CONTENT_TYPE)
|
||||
self.assertFalse(check_send_webhook_message_mock.called)
|
||||
self.assert_json_success(result)
|
||||
64
zerver/webhooks/greenhouse/view.py
Normal file
64
zerver/webhooks/greenhouse/view.py
Normal file
@@ -0,0 +1,64 @@
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
|
||||
from zerver.decorator import webhook_view
|
||||
from zerver.lib.response import json_success
|
||||
from zerver.lib.typed_endpoint import JsonBodyPayload, typed_endpoint
|
||||
from zerver.lib.validator import WildValue, check_int, check_none_or, check_string, check_url
|
||||
from zerver.lib.webhooks.common import check_send_webhook_message
|
||||
from zerver.models import UserProfile
|
||||
|
||||
MESSAGE_TEMPLATE = """
|
||||
{action} {first_name} {last_name} (ID: {candidate_id}), applying for:
|
||||
* **Role**: {role}
|
||||
* **Emails**: {emails}
|
||||
* **Attachments**: {attachments}
|
||||
""".strip()
|
||||
|
||||
|
||||
def dict_list_to_string(some_list: WildValue) -> str:
|
||||
response_chunks = []
|
||||
for item in some_list:
|
||||
item_type = item.get("type", "").tame(check_string).title()
|
||||
item_value = item.get("value").tame(check_none_or(check_string))
|
||||
item_url = item.get("url").tame(check_none_or(check_url))
|
||||
if item_type and item_value:
|
||||
response_chunks.append(f"{item_value} ({item_type})")
|
||||
elif item_type and item_url:
|
||||
response_chunks.append(f"[{item_type}]({item_url})")
|
||||
|
||||
return ", ".join(response_chunks)
|
||||
|
||||
|
||||
@webhook_view("Greenhouse")
|
||||
@typed_endpoint
|
||||
def api_greenhouse_webhook(
|
||||
request: HttpRequest,
|
||||
user_profile: UserProfile,
|
||||
*,
|
||||
payload: JsonBodyPayload[WildValue],
|
||||
) -> HttpResponse:
|
||||
action = payload["action"].tame(check_string)
|
||||
if action == "ping":
|
||||
return json_success(request)
|
||||
|
||||
if action == "update_candidate":
|
||||
candidate = payload["payload"]["candidate"]
|
||||
else:
|
||||
candidate = payload["payload"]["application"]["candidate"]
|
||||
action = action.replace("_", " ").title()
|
||||
application = payload["payload"]["application"]
|
||||
|
||||
body = MESSAGE_TEMPLATE.format(
|
||||
action=action,
|
||||
first_name=candidate["first_name"].tame(check_string),
|
||||
last_name=candidate["last_name"].tame(check_string),
|
||||
candidate_id=str(candidate["id"].tame(check_int)),
|
||||
role=application["jobs"][0]["name"].tame(check_string),
|
||||
emails=dict_list_to_string(application["candidate"]["email_addresses"]),
|
||||
attachments=dict_list_to_string(application["candidate"]["attachments"]),
|
||||
)
|
||||
|
||||
topic_name = "{} - {}".format(action, str(candidate["id"].tame(check_int)))
|
||||
|
||||
check_send_webhook_message(request, user_profile, topic_name, body)
|
||||
return json_success(request)
|
||||
Reference in New Issue
Block a user