2019-04-14 15:28:19 +02:00
|
|
|
import os
|
2020-02-28 23:14:47 +01:00
|
|
|
from typing import Any, Dict, List, Optional
|
2019-04-14 15:28:19 +02:00
|
|
|
|
2020-06-11 00:54:34 +02:00
|
|
|
import ujson
|
2019-04-14 15:28:19 +02:00
|
|
|
from django.http import HttpRequest, HttpResponse
|
|
|
|
from django.shortcuts import render
|
|
|
|
from django.test import Client
|
|
|
|
|
|
|
|
from zerver.lib.integrations import WEBHOOK_INTEGRATIONS
|
2020-06-11 00:54:34 +02:00
|
|
|
from zerver.lib.request import REQ, has_request_variables
|
|
|
|
from zerver.lib.response import json_error, json_success
|
2019-11-13 08:17:49 +01:00
|
|
|
from zerver.lib.validator import check_bool
|
2020-06-11 00:54:34 +02:00
|
|
|
from zerver.lib.webhooks.common import get_fixture_http_headers, standardize_headers
|
|
|
|
from zerver.models import UserProfile, get_realm
|
2019-04-14 15:28:19 +02:00
|
|
|
|
|
|
|
ZULIP_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../../')
|
|
|
|
|
|
|
|
|
|
|
|
def get_webhook_integrations() -> List[str]:
|
|
|
|
return [integration.name for integration in WEBHOOK_INTEGRATIONS]
|
|
|
|
|
2020-02-28 23:14:47 +01:00
|
|
|
def get_valid_integration_name(name: str) -> Optional[str]:
|
|
|
|
for integration_name in get_webhook_integrations():
|
|
|
|
if name == integration_name:
|
|
|
|
return integration_name
|
|
|
|
return None
|
2019-04-14 15:28:19 +02:00
|
|
|
|
|
|
|
def dev_panel(request: HttpRequest) -> HttpResponse:
|
|
|
|
integrations = get_webhook_integrations()
|
|
|
|
bots = UserProfile.objects.filter(is_bot=True, bot_type=UserProfile.INCOMING_WEBHOOK_BOT)
|
|
|
|
context = {"integrations": integrations, "bots": bots}
|
|
|
|
return render(request, "zerver/integrations/development/dev_panel.html", context)
|
|
|
|
|
2019-11-13 08:17:49 +01:00
|
|
|
def send_webhook_fixture_message(url: str,
|
|
|
|
body: str,
|
|
|
|
is_json: bool,
|
|
|
|
custom_headers: Dict[str, Any]) -> HttpResponse:
|
2019-05-16 20:29:18 +02:00
|
|
|
client = Client()
|
|
|
|
realm = get_realm("zulip")
|
2019-06-21 04:41:30 +02:00
|
|
|
standardized_headers = standardize_headers(custom_headers)
|
|
|
|
http_host = standardized_headers.pop("HTTP_HOST", realm.host)
|
2019-05-16 20:29:18 +02:00
|
|
|
if is_json:
|
2019-06-21 04:41:30 +02:00
|
|
|
content_type = standardized_headers.pop("HTTP_CONTENT_TYPE", "application/json")
|
2019-05-16 20:29:18 +02:00
|
|
|
else:
|
2019-06-21 04:41:30 +02:00
|
|
|
content_type = standardized_headers.pop("HTTP_CONTENT_TYPE", "text/plain")
|
|
|
|
return client.post(url, body, content_type=content_type, HTTP_HOST=http_host,
|
|
|
|
**standardized_headers)
|
2019-05-16 20:29:18 +02:00
|
|
|
|
2019-04-14 15:28:19 +02:00
|
|
|
@has_request_variables
|
|
|
|
def get_fixtures(request: HttpResponse,
|
|
|
|
integration_name: str=REQ()) -> HttpResponse:
|
2020-02-28 23:14:47 +01:00
|
|
|
valid_integration_name = get_valid_integration_name(integration_name)
|
|
|
|
if not valid_integration_name:
|
2020-06-10 06:40:53 +02:00
|
|
|
return json_error(f"\"{integration_name}\" is not a valid webhook integration.", status=404)
|
2019-04-14 15:28:19 +02:00
|
|
|
|
|
|
|
fixtures = {}
|
2020-06-10 06:40:53 +02:00
|
|
|
fixtures_dir = os.path.join(ZULIP_PATH, f"zerver/webhooks/{valid_integration_name}/fixtures")
|
2019-04-14 15:28:19 +02:00
|
|
|
if not os.path.exists(fixtures_dir):
|
2020-02-28 23:14:47 +01:00
|
|
|
msg = ("The integration \"{valid_integration_name}\" does not have fixtures.").format(
|
|
|
|
valid_integration_name=valid_integration_name)
|
2019-04-14 15:28:19 +02:00
|
|
|
return json_error(msg, status=404)
|
|
|
|
|
|
|
|
for fixture in os.listdir(fixtures_dir):
|
|
|
|
fixture_path = os.path.join(fixtures_dir, fixture)
|
2020-04-09 21:51:58 +02:00
|
|
|
with open(fixture_path) as f:
|
2019-07-14 21:37:08 +02:00
|
|
|
body = f.read()
|
2019-04-14 15:28:19 +02:00
|
|
|
try:
|
2019-06-07 20:06:06 +02:00
|
|
|
body = ujson.loads(body)
|
2019-04-14 15:28:19 +02:00
|
|
|
except ValueError:
|
2019-05-16 20:29:18 +02:00
|
|
|
pass # The file extension will be used to determine the type.
|
2019-06-07 20:06:06 +02:00
|
|
|
|
2020-02-28 23:14:47 +01:00
|
|
|
headers_raw = get_fixture_http_headers(valid_integration_name,
|
2019-06-07 20:06:06 +02:00
|
|
|
"".join(fixture.split(".")[:-1]))
|
2020-03-20 18:16:51 +01:00
|
|
|
|
|
|
|
def fix_name(header: str) -> str:
|
2019-06-07 20:06:06 +02:00
|
|
|
if header.startswith("HTTP_"): # HTTP_ is a prefix intended for Django.
|
2020-03-20 18:16:51 +01:00
|
|
|
return header[len("HTTP_"):]
|
|
|
|
return header
|
2019-06-07 20:06:06 +02:00
|
|
|
|
2020-03-20 18:16:51 +01:00
|
|
|
headers = {fix_name(k): v for k, v in headers_raw.items()}
|
2019-06-07 20:06:06 +02:00
|
|
|
fixtures[fixture] = {"body": body, "headers": headers}
|
2019-04-14 15:28:19 +02:00
|
|
|
|
|
|
|
return json_success({"fixtures": fixtures})
|
|
|
|
|
|
|
|
|
|
|
|
@has_request_variables
|
|
|
|
def check_send_webhook_fixture_message(request: HttpRequest,
|
|
|
|
url: str=REQ(),
|
2019-05-16 09:23:15 +02:00
|
|
|
body: str=REQ(),
|
2019-11-13 08:17:49 +01:00
|
|
|
is_json: bool=REQ(validator=check_bool),
|
2019-05-16 09:23:15 +02:00
|
|
|
custom_headers: str=REQ()) -> HttpResponse:
|
2019-06-25 08:17:10 +02:00
|
|
|
try:
|
|
|
|
custom_headers_dict = ujson.loads(custom_headers)
|
|
|
|
except ValueError as ve:
|
2020-06-09 00:25:09 +02:00
|
|
|
return json_error(f"Custom HTTP headers are not in a valid JSON format. {ve}") # nolint
|
2019-06-25 08:17:10 +02:00
|
|
|
|
|
|
|
response = send_webhook_fixture_message(url, body, is_json,
|
|
|
|
custom_headers_dict)
|
2019-04-14 15:28:19 +02:00
|
|
|
if response.status_code == 200:
|
2019-05-18 20:59:37 +02:00
|
|
|
responses = [{"status_code": response.status_code,
|
2020-08-07 05:41:06 +02:00
|
|
|
"message": response.content.decode()}]
|
2019-05-18 20:59:37 +02:00
|
|
|
return json_success({"responses": responses})
|
2019-04-14 15:28:19 +02:00
|
|
|
else:
|
|
|
|
return response
|
2019-05-16 20:29:18 +02:00
|
|
|
|
|
|
|
|
|
|
|
@has_request_variables
|
|
|
|
def send_all_webhook_fixture_messages(request: HttpRequest,
|
|
|
|
url: str=REQ(),
|
|
|
|
integration_name: str=REQ()) -> HttpResponse:
|
2020-02-28 23:14:47 +01:00
|
|
|
valid_integration_name = get_valid_integration_name(integration_name)
|
|
|
|
if not valid_integration_name:
|
2020-06-10 06:40:53 +02:00
|
|
|
return json_error(f"\"{integration_name}\" is not a valid webhook integration.", status=404)
|
2020-02-28 23:14:47 +01:00
|
|
|
|
2020-06-10 06:40:53 +02:00
|
|
|
fixtures_dir = os.path.join(ZULIP_PATH, f"zerver/webhooks/{valid_integration_name}/fixtures")
|
2019-05-16 20:29:18 +02:00
|
|
|
if not os.path.exists(fixtures_dir):
|
2020-02-28 23:14:47 +01:00
|
|
|
msg = ("The integration \"{valid_integration_name}\" does not have fixtures.").format(
|
|
|
|
valid_integration_name=valid_integration_name)
|
2019-05-16 20:29:18 +02:00
|
|
|
return json_error(msg, status=404)
|
|
|
|
|
|
|
|
responses = []
|
|
|
|
for fixture in os.listdir(fixtures_dir):
|
|
|
|
fixture_path = os.path.join(fixtures_dir, fixture)
|
2020-04-09 21:51:58 +02:00
|
|
|
with open(fixture_path) as f:
|
2019-07-14 21:37:08 +02:00
|
|
|
content = f.read()
|
2019-06-25 08:17:10 +02:00
|
|
|
x = fixture.split(".")
|
|
|
|
fixture_name, fixture_format = "".join(_ for _ in x[:-1]), x[-1]
|
2020-02-28 23:14:47 +01:00
|
|
|
headers = get_fixture_http_headers(valid_integration_name, fixture_name)
|
2019-05-16 20:29:18 +02:00
|
|
|
if fixture_format == "json":
|
|
|
|
is_json = True
|
|
|
|
else:
|
|
|
|
is_json = False
|
2019-06-25 08:17:10 +02:00
|
|
|
response = send_webhook_fixture_message(url, content, is_json, headers)
|
2019-05-16 20:29:18 +02:00
|
|
|
responses.append({"status_code": response.status_code,
|
|
|
|
"fixture_name": fixture,
|
2020-08-07 05:41:06 +02:00
|
|
|
"message": response.content.decode()})
|
2019-05-16 20:29:18 +02:00
|
|
|
return json_success({"responses": responses})
|