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/appveyor/__init__.py
Normal file
0
zerver/webhooks/appveyor/__init__.py
Normal file
25
zerver/webhooks/appveyor/doc.md
Normal file
25
zerver/webhooks/appveyor/doc.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Zulip AppVeyor integration
|
||||
|
||||
Receive AppVeyor notifications in Zulip!
|
||||
|
||||
{start_tabs}
|
||||
|
||||
1. {!create-an-incoming-webhook.md!}
|
||||
|
||||
1. {!generate-webhook-url-basic.md!}
|
||||
|
||||
1. Go to your AppVeyor Project Settings, and select **Notifications**.
|
||||
Click on **Add notification**, and then select **Webhook**.
|
||||
|
||||
1. Set **Webhook URL** to the URL generated above. Select the events
|
||||
you'd like to be notified about, and click **Save**.
|
||||
|
||||
{end_tabs}
|
||||
|
||||
{!congrats.md!}
|
||||
|
||||

|
||||
|
||||
### Related documentation
|
||||
|
||||
{!webhooks-url-specification.md!}
|
||||
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"eventName": "build_failure",
|
||||
"eventData": {
|
||||
"passed": false,
|
||||
"failed": true,
|
||||
"status": "failed",
|
||||
"started": "9/9/2018 7:04 PM",
|
||||
"finished": "9/9/2018 7:06 PM",
|
||||
"duration": "00:02:54.1586505",
|
||||
"projectId": 456857,
|
||||
"projectName": "Hubot-DSC-Resource",
|
||||
"buildId": 18638796,
|
||||
"buildNumber": 59,
|
||||
"buildVersion": "2.0.59",
|
||||
"repositoryProvider": "gitHub",
|
||||
"repositoryScm": "git",
|
||||
"repositoryName": "joebloggs/Hubot-DSC-Resource",
|
||||
"branch": "master",
|
||||
"commitId": "c06e208b47",
|
||||
"commitAuthor": "Joe Bloggs",
|
||||
"commitAuthorEmail": "joe.bloggs@example.com",
|
||||
"commitAuthorUsername": "joebloggs",
|
||||
"commitDate": "6/12/2018 6:22 PM",
|
||||
"commitMessage": "Increment version number.",
|
||||
"commitMessageExtended": "Signed-off-by: Joe Bloggs <joe.bloggs@example.com>",
|
||||
"committerName": "Joe Bloggs",
|
||||
"committerEmail": "joe.bloggs@example.com",
|
||||
"buildUrl": "https://ci.appveyor.com/project/joebloggs/hubot-dsc-resource/build/2.0.59",
|
||||
"commitUrl": "https://github.com/joebloggs/Hubot-DSC-Resource/commit/c06e208b47",
|
||||
"notificationSettingsUrl": "https://ci.appveyor.com/notifications",
|
||||
"isPullRequest": false,
|
||||
"messages": [],
|
||||
"jobs": [
|
||||
{
|
||||
"id": "flhhi1o73j0tbbt8",
|
||||
"name": "",
|
||||
"passed": false,
|
||||
"failed": true,
|
||||
"status": "Failed",
|
||||
"started": "9/9/2018 7:04 PM",
|
||||
"finished": "9/9/2018 7:06 PM",
|
||||
"duration": "00:02:54.1117792",
|
||||
"messages": [],
|
||||
"messagesTotal": 0,
|
||||
"messagesError": 0,
|
||||
"compilationMessages": [],
|
||||
"artifacts": [
|
||||
{
|
||||
"permalink": "https://ci.appveyor.com/api/buildjobs/flhhi1o73j0tbbts8/artifacts/InstallHubot-2.0.59.zip",
|
||||
"fileName": "InstallHubot-2.0.59.zip",
|
||||
"type": "Zip",
|
||||
"size": 41423,
|
||||
"url": "https://storage.googleapis.com/appveyor-artifacts/joebloggs-98248/hubot-dsc-resource/2-0-59/flhhi1o73j0tbbt8/InstallHubot-2.0.59.zip?GoogleAccessId=646512516365-bidt3t59mctt8vti6cffe2sbq65pnmb1@developer.gserviceaccount.com&Expires=1536523617&Signature=GDTsHhyTif5UZv6qDOa87DVYD5ubBmUPDk%2bppImEmp9KO%2bFHqt%2b9brLqN7k4wmz7EqIAG9skvNTfIRiOfIBTKvFyhsWaYGswnx6eUIbGdlloHTON%2fJpzsffQqXnA7eOznqizphrcpph0YAql1%2fmLgCk21dL31HB0RhJ5Qiah%2bQhVTyBlu8W7fzvOEJSaDCwqS6GRUYd3DoaUpjvGa9QaGGzBCLVkLLZIizz2xbvtxJfZVUB1EO3Uk6W17Rz4rxE4EFYFyZZsOIv%2bQcizEdmjcyapwJFBST7kpaN%2fK0Kw5LikFIMjyl0sgZa0ycf3V3a35mmdcfvAox5jN%2fLFgWwctg%3d%3d",
|
||||
"created": "0001-01-01T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"permalink": "https://ci.appveyor.com/api/buildjobs/flhhi1o73j0tbbts8/artifacts/InstallHubot.zip",
|
||||
"fileName": "InstallHubot.zip",
|
||||
"type": "Zip",
|
||||
"size": 7335,
|
||||
"url": "https://storage.googleapis.com/appveyor-artifacts/joebloggs-98248/hubot-dsc-resource/2-0-59/flhhi1o73j0tbbt8/InstallHubot.zip?GoogleAccessId=646512516365-bidt3t59mctt8vti6cffe2sbq65pnmb1@developer.gserviceaccount.com&Expires=1536523617&Signature=P9SKuynprwgTm1%2f9PrQtivza39bq%2bA7FyPfN%2fk2DWrXTDoYLJqrePHPQC2fX4FAYhDPBk8YpwsEA8psn%2fI86Ye5fbkN%2f5AEUrdt%2b2jUAcAaysChnX2CGbHWCKl65Tiks8eG2ZuDnKpwLsB0X%2bUGP8q54pO1VuUqK8x5l%2fDV79pHY1p6wH8bF5bX%2bSDOYPmBX6mcpEDbou9NDGDqzox08OYyb76wWnDf0Uqzwzz5sB845TipoKMP4idtT3ODHCIkcojzBGl%2bl9avv6vWzTusZHARvbBm%2bQGdStmzvwaBhtvKOrFMJMS%2bau5YKiKVCDh9z480ok17OyCRIbVHLXSQ5Ew%3d%3d",
|
||||
"created": "0001-01-01T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"permalink": "https://ci.appveyor.com/api/buildjobs/flhhi1o73j0tbbts8/artifacts/InstallHubot.2.0.59.nupkg",
|
||||
"fileName": "InstallHubot.2.0.59.nupkg",
|
||||
"type": "NuGetPackage",
|
||||
"size": 8663,
|
||||
"url": "https://storage.googleapis.com/appveyor-artifacts/joebloggs-98248/hubot-dsc-resource/2-0-59/flhhi1o73j0tbbt8/InstallHubot.2.0.59.nupkg?GoogleAccessId=646512516365-bidt3t59mctt8vti6cffe2sbq65pnmb1@developer.gserviceaccount.com&Expires=1536523617&Signature=B7HYnZRjKkplSCI9rIsY%2bVlp9Fnukinraj4utPNbopzyvKCNtgJ1RVPqr6h1%2bVRZQ2VXPQW6kpNj4PBpG%2bc24hOciFKFy0hkGvAddEKv4Q%2bP18MAS3cx%2bXnQBxPolFJtgq%2bfzA7XeTl6mzDT727WpjAnaByZuWVcLhf%2bXeuNHI2h121Vl8Ppdcd52y2dhhrBI5JPqspMOZ8d346ZQhWqbnfwZfBRuTO2CfG7MNy4pF4cKyMY5fLU2wlnm4VwJnd7xJqwt9qmx7x7vbFcyVdS404uD0Rd5PhPiBuUNVrDGcywL0TcwxMF9%2bd45UKyKBr5%2f31DqIdmUa0DCwaDZV2rYQ%3d%3d",
|
||||
"created": "0001-01-01T00:00:00+00:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"eventName": "build_success",
|
||||
"eventData": {
|
||||
"passed": true,
|
||||
"failed": false,
|
||||
"status": "completed",
|
||||
"started": "9/9/2018 7:04 PM",
|
||||
"finished": "9/9/2018 7:06 PM",
|
||||
"duration": "00:02:54.1586505",
|
||||
"projectId": 456857,
|
||||
"projectName": "Hubot-DSC-Resource",
|
||||
"buildId": 18638796,
|
||||
"buildNumber": 59,
|
||||
"buildVersion": "2.0.59",
|
||||
"repositoryProvider": "gitHub",
|
||||
"repositoryScm": "git",
|
||||
"repositoryName": "joebloggs/Hubot-DSC-Resource",
|
||||
"branch": "master",
|
||||
"commitId": "c06e208b47",
|
||||
"commitAuthor": "Joe Bloggs",
|
||||
"commitAuthorEmail": "joe.bloggs@example.com",
|
||||
"commitAuthorUsername": "joebloggs",
|
||||
"commitDate": "6/12/2018 6:22 PM",
|
||||
"commitMessage": "Increment version number.",
|
||||
"commitMessageExtended": "Signed-off-by: Joe Bloggs <joe.bloggs@example.com>",
|
||||
"committerName": "Joe Bloggs",
|
||||
"committerEmail": "joe.bloggs@example.com",
|
||||
"buildUrl": "https://ci.appveyor.com/project/joebloggs/hubot-dsc-resource/build/2.0.59",
|
||||
"commitUrl": "https://github.com/joebloggs/Hubot-DSC-Resource/commit/c06e208b47",
|
||||
"notificationSettingsUrl": "https://ci.appveyor.com/notifications",
|
||||
"isPullRequest": false,
|
||||
"messages": [],
|
||||
"jobs": [
|
||||
{
|
||||
"id": "flhhi1o73j0tbbt8",
|
||||
"name": "",
|
||||
"passed": true,
|
||||
"failed": false,
|
||||
"status": "Success",
|
||||
"started": "9/9/2018 7:04 PM",
|
||||
"finished": "9/9/2018 7:06 PM",
|
||||
"duration": "00:02:54.1117792",
|
||||
"messages": [],
|
||||
"messagesTotal": 0,
|
||||
"messagesError": 0,
|
||||
"compilationMessages": [],
|
||||
"artifacts": [
|
||||
{
|
||||
"permalink": "https://ci.appveyor.com/api/buildjobs/flhhi1o73j0tbbts8/artifacts/InstallHubot-2.0.59.zip",
|
||||
"fileName": "InstallHubot-2.0.59.zip",
|
||||
"type": "Zip",
|
||||
"size": 41423,
|
||||
"url": "https://storage.googleapis.com/appveyor-artifacts/joebloggs-98248/hubot-dsc-resource/2-0-59/flhhi1o73j0tbbt8/InstallHubot-2.0.59.zip?GoogleAccessId=646512516365-bidt3t59mctt8vti6cffe2sbq65pnmb1@developer.gserviceaccount.com&Expires=1536523617&Signature=GDTsHhyTif5UZv6qDOa87DVYD5ubBmUPDk%2bppImEmp9KO%2bFHqt%2b9brLqN7k4wmz7EqIAG9skvNTfIRiOfIBTKvFyhsWaYGswnx6eUIbGdlloHTON%2fJpzsffQqXnA7eOznqizphrcpph0YAql1%2fmLgCk21dL31HB0RhJ5Qiah%2bQhVTyBlu8W7fzvOEJSaDCwqS6GRUYd3DoaUpjvGa9QaGGzBCLVkLLZIizz2xbvtxJfZVUB1EO3Uk6W17Rz4rxE4EFYFyZZsOIv%2bQcizEdmjcyapwJFBST7kpaN%2fK0Kw5LikFIMjyl0sgZa0ycf3V3a35mmdcfvAox5jN%2fLFgWwctg%3d%3d",
|
||||
"created": "0001-01-01T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"permalink": "https://ci.appveyor.com/api/buildjobs/flhhi1o73j0tbbts8/artifacts/InstallHubot.zip",
|
||||
"fileName": "InstallHubot.zip",
|
||||
"type": "Zip",
|
||||
"size": 7335,
|
||||
"url": "https://storage.googleapis.com/appveyor-artifacts/joebloggs-98248/hubot-dsc-resource/2-0-59/flhhi1o73j0tbbt8/InstallHubot.zip?GoogleAccessId=646512516365-bidt3t59mctt8vti6cffe2sbq65pnmb1@developer.gserviceaccount.com&Expires=1536523617&Signature=P9SKuynprwgTm1%2f9PrQtivza39bq%2bA7FyPfN%2fk2DWrXTDoYLJqrePHPQC2fX4FAYhDPBk8YpwsEA8psn%2fI86Ye5fbkN%2f5AEUrdt%2b2jUAcAaysChnX2CGbHWCKl65Tiks8eG2ZuDnKpwLsB0X%2bUGP8q54pO1VuUqK8x5l%2fDV79pHY1p6wH8bF5bX%2bSDOYPmBX6mcpEDbou9NDGDqzox08OYyb76wWnDf0Uqzwzz5sB845TipoKMP4idtT3ODHCIkcojzBGl%2bl9avv6vWzTusZHARvbBm%2bQGdStmzvwaBhtvKOrFMJMS%2bau5YKiKVCDh9z480ok17OyCRIbVHLXSQ5Ew%3d%3d",
|
||||
"created": "0001-01-01T00:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"permalink": "https://ci.appveyor.com/api/buildjobs/flhhi1o73j0tbbts8/artifacts/InstallHubot.2.0.59.nupkg",
|
||||
"fileName": "InstallHubot.2.0.59.nupkg",
|
||||
"type": "NuGetPackage",
|
||||
"size": 8663,
|
||||
"url": "https://storage.googleapis.com/appveyor-artifacts/joebloggs-98248/hubot-dsc-resource/2-0-59/flhhi1o73j0tbbt8/InstallHubot.2.0.59.nupkg?GoogleAccessId=646512516365-bidt3t59mctt8vti6cffe2sbq65pnmb1@developer.gserviceaccount.com&Expires=1536523617&Signature=B7HYnZRjKkplSCI9rIsY%2bVlp9Fnukinraj4utPNbopzyvKCNtgJ1RVPqr6h1%2bVRZQ2VXPQW6kpNj4PBpG%2bc24hOciFKFy0hkGvAddEKv4Q%2bP18MAS3cx%2bXnQBxPolFJtgq%2bfzA7XeTl6mzDT727WpjAnaByZuWVcLhf%2bXeuNHI2h121Vl8Ppdcd52y2dhhrBI5JPqspMOZ8d346ZQhWqbnfwZfBRuTO2CfG7MNy4pF4cKyMY5fLU2wlnm4VwJnd7xJqwt9qmx7x7vbFcyVdS404uD0Rd5PhPiBuUNVrDGcywL0TcwxMF9%2bd45UKyKBr5%2f31DqIdmUa0DCwaDZV2rYQ%3d%3d",
|
||||
"created": "0001-01-01T00:00:00+00:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
31
zerver/webhooks/appveyor/tests.py
Normal file
31
zerver/webhooks/appveyor/tests.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from zerver.lib.test_classes import WebhookTestCase
|
||||
|
||||
|
||||
class AppveyorHookTests(WebhookTestCase):
|
||||
def test_appveyor_build_success_message(self) -> None:
|
||||
"""
|
||||
Tests if appveyor build success notification is handled correctly
|
||||
"""
|
||||
expected_topic_name = "Hubot-DSC-Resource"
|
||||
expected_message = """
|
||||
[Build Hubot-DSC-Resource 2.0.59 completed](https://ci.appveyor.com/project/joebloggs/hubot-dsc-resource/build/2.0.59):
|
||||
* **Commit**: [c06e208b47: Increment version number.](https://github.com/joebloggs/Hubot-DSC-Resource/commit/c06e208b47) by Joe Bloggs
|
||||
* **Started**: <time:2018-09-09T19:04:00+00:00>
|
||||
* **Finished**: <time:2018-09-09T19:06:00+00:00>
|
||||
""".strip()
|
||||
|
||||
self.check_webhook("appveyor_build_success", expected_topic_name, expected_message)
|
||||
|
||||
def test_appveyor_build_failure_message(self) -> None:
|
||||
"""
|
||||
Tests if appveyor build failure notification is handled correctly
|
||||
"""
|
||||
expected_topic_name = "Hubot-DSC-Resource"
|
||||
expected_message = """
|
||||
[Build Hubot-DSC-Resource 2.0.59 failed](https://ci.appveyor.com/project/joebloggs/hubot-dsc-resource/build/2.0.59):
|
||||
* **Commit**: [c06e208b47: Increment version number.](https://github.com/joebloggs/Hubot-DSC-Resource/commit/c06e208b47) by Joe Bloggs
|
||||
* **Started**: <time:2018-09-09T19:04:00+00:00>
|
||||
* **Finished**: <time:2018-09-09T19:06:00+00:00>
|
||||
""".strip()
|
||||
|
||||
self.check_webhook("appveyor_build_failure", expected_topic_name, expected_message)
|
||||
69
zerver/webhooks/appveyor/view.py
Normal file
69
zerver/webhooks/appveyor/view.py
Normal file
@@ -0,0 +1,69 @@
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from pydantic.alias_generators import to_snake
|
||||
|
||||
from zerver.decorator import webhook_view
|
||||
from zerver.lib.response import json_success
|
||||
from zerver.lib.timestamp import datetime_to_global_time
|
||||
from zerver.lib.typed_endpoint import JsonBodyPayload, typed_endpoint
|
||||
from zerver.lib.validator import WildValue, check_string
|
||||
from zerver.lib.webhooks.common import check_send_webhook_message
|
||||
from zerver.models import UserProfile
|
||||
|
||||
APPVEYOR_TOPIC_TEMPLATE = "{project_name}"
|
||||
APPVEYOR_MESSAGE_TEMPLATE = """
|
||||
[Build {project_name} {build_version} {status}]({build_url}):
|
||||
* **Commit**: [{commit_id}: {commit_message}]({commit_url}) by {committer_name}
|
||||
* **Started**: {started}
|
||||
* **Finished**: {finished}
|
||||
""".strip()
|
||||
|
||||
|
||||
def get_global_time(dt_str: str) -> str:
|
||||
return datetime_to_global_time(
|
||||
datetime.strptime(dt_str, "%m/%d/%Y %I:%M %p").replace(tzinfo=timezone.utc)
|
||||
)
|
||||
|
||||
|
||||
@webhook_view("Appveyor")
|
||||
@typed_endpoint
|
||||
def api_appveyor_webhook(
|
||||
request: HttpRequest,
|
||||
user_profile: UserProfile,
|
||||
*,
|
||||
payload: JsonBodyPayload[WildValue],
|
||||
) -> HttpResponse:
|
||||
body = get_body(payload)
|
||||
topic_name = get_topic_name(payload)
|
||||
|
||||
check_send_webhook_message(request, user_profile, topic_name, body)
|
||||
return json_success(request)
|
||||
|
||||
|
||||
def get_topic_name(payload: WildValue) -> str:
|
||||
event_data = payload["eventData"]
|
||||
return APPVEYOR_TOPIC_TEMPLATE.format(project_name=event_data["projectName"].tame(check_string))
|
||||
|
||||
|
||||
def get_body(payload: WildValue) -> str:
|
||||
event_data = payload["eventData"]
|
||||
fields = [
|
||||
"projectName",
|
||||
"buildVersion",
|
||||
"status",
|
||||
"buildUrl",
|
||||
"commitUrl",
|
||||
"committerName",
|
||||
"commitDate",
|
||||
"commitMessage",
|
||||
"commitId",
|
||||
"started",
|
||||
"finished",
|
||||
]
|
||||
data = {
|
||||
to_snake(field): get_global_time(value) if field in ["started", "finished"] else value
|
||||
for field, value in ((field, event_data[field].tame(check_string)) for field in fields)
|
||||
}
|
||||
|
||||
return APPVEYOR_MESSAGE_TEMPLATE.format(**data)
|
||||
Reference in New Issue
Block a user