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:
97
zerver/webhooks/airbyte/view.py
Normal file
97
zerver/webhooks/airbyte/view.py
Normal file
@@ -0,0 +1,97 @@
|
||||
# Webhooks for external integrations.
|
||||
|
||||
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_bool, check_int, check_string
|
||||
from zerver.lib.webhooks.common import check_send_webhook_message
|
||||
from zerver.models import UserProfile
|
||||
|
||||
AIRBYTE_TOPIC_TEMPLATE = "{workspace} - {connection}"
|
||||
|
||||
AIRBYTE_MESSAGE_TEMPLATE = """\
|
||||
{sync_status_emoji} Airbyte sync **{status}** for [{connection_name}]({connection_url}).
|
||||
|
||||
|
||||
* **Source:** [{source_name}]({source_url})
|
||||
* **Destination:** [{destination_name}]({destination_url})
|
||||
* **Records:** {records_emitted} emitted, {records_committed} committed
|
||||
* **Bytes:** {bytes_emitted} emitted, {bytes_committed} committed
|
||||
* **Duration:** {duration}
|
||||
"""
|
||||
|
||||
|
||||
def extract_data_from_payload(payload_data: WildValue) -> dict[str, str | int | bool]:
|
||||
data: dict[str, str | int | bool] = {
|
||||
"workspace_name": payload_data["workspace"]["name"].tame(check_string),
|
||||
"connection_name": payload_data["connection"]["name"].tame(check_string),
|
||||
"source_name": payload_data["source"]["name"].tame(check_string),
|
||||
"destination_name": payload_data["destination"]["name"].tame(check_string),
|
||||
"connection_url": payload_data["connection"]["url"].tame(check_string),
|
||||
"source_url": payload_data["source"]["url"].tame(check_string),
|
||||
"destination_url": payload_data["destination"]["url"].tame(check_string),
|
||||
"successful_sync": payload_data["success"].tame(check_bool),
|
||||
"duration_formatted": payload_data["durationFormatted"].tame(check_string),
|
||||
"records_emitted": payload_data["recordsEmitted"].tame(check_int),
|
||||
"records_committed": payload_data["recordsCommitted"].tame(check_int),
|
||||
"bytes_emitted_formatted": payload_data["bytesEmittedFormatted"].tame(check_string),
|
||||
"bytes_committed_formatted": payload_data["bytesCommittedFormatted"].tame(check_string),
|
||||
}
|
||||
|
||||
if not data["successful_sync"]:
|
||||
data["error_message"] = payload_data["errorMessage"].tame(check_string)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def format_message_from_data(data: dict[str, str | int | bool]) -> str:
|
||||
content = AIRBYTE_MESSAGE_TEMPLATE.format(
|
||||
sync_status_emoji=":green_circle:" if data["successful_sync"] else ":red_circle:",
|
||||
status="succeeded" if data["successful_sync"] else "failed",
|
||||
connection_name=data["connection_name"],
|
||||
connection_url=data["connection_url"],
|
||||
source_name=data["source_name"],
|
||||
source_url=data["source_url"],
|
||||
destination_name=data["destination_name"],
|
||||
destination_url=data["destination_url"],
|
||||
duration=data["duration_formatted"],
|
||||
records_emitted=data["records_emitted"],
|
||||
records_committed=data["records_committed"],
|
||||
bytes_emitted=data["bytes_emitted_formatted"],
|
||||
bytes_committed=data["bytes_committed_formatted"],
|
||||
)
|
||||
|
||||
if not data["successful_sync"]:
|
||||
error_message = data["error_message"]
|
||||
content += f"\n**Error message:** {error_message}"
|
||||
|
||||
return content
|
||||
|
||||
|
||||
def create_topic_from_data(data: dict[str, str | int | bool]) -> str:
|
||||
return AIRBYTE_TOPIC_TEMPLATE.format(
|
||||
workspace=data["workspace_name"],
|
||||
connection=data["connection_name"],
|
||||
)
|
||||
|
||||
|
||||
@webhook_view("Airbyte")
|
||||
@typed_endpoint
|
||||
def api_airbyte_webhook(
|
||||
request: HttpRequest,
|
||||
user_profile: UserProfile,
|
||||
*,
|
||||
payload: JsonBodyPayload[WildValue],
|
||||
) -> HttpResponse:
|
||||
if "data" in payload:
|
||||
data = extract_data_from_payload(payload["data"])
|
||||
content = format_message_from_data(data)
|
||||
topic = create_topic_from_data(data)
|
||||
else:
|
||||
# Test Airbyte notification payloads only contain this field.
|
||||
content = payload["text"].tame(check_string)
|
||||
topic = "Airbyte notification"
|
||||
check_send_webhook_message(request, user_profile, topic, content)
|
||||
return json_success(request)
|
||||
Reference in New Issue
Block a user