mirror of
https://github.com/zulip/zulip.git
synced 2025-11-03 05:23:35 +00:00
refactor: Simplify how we use base_url.
Before this change, we instantiated base_url into a superclass of subclasses that returned base_url into a dictionary that gets returned to our caller. Now we just pull base_url out of service when we need to make the REST call.
This commit is contained in:
@@ -22,8 +22,7 @@ from zerver.decorator import JsonableError
|
||||
|
||||
class OutgoingWebhookServiceInterface:
|
||||
|
||||
def __init__(self, base_url: str, token: str, user_profile: UserProfile, service_name: str) -> None:
|
||||
self.base_url = base_url # type: str
|
||||
def __init__(self, token: str, user_profile: UserProfile, service_name: str) -> None:
|
||||
self.token = token # type: str
|
||||
self.user_profile = user_profile # type: UserProfile
|
||||
self.service_name = service_name # type: str
|
||||
@@ -34,7 +33,6 @@ class OutgoingWebhookServiceInterface:
|
||||
#
|
||||
# The REST operation is a dictionary with the following keys:
|
||||
# - method
|
||||
# - base_url
|
||||
# - relative_url_path
|
||||
# - request_kwargs
|
||||
def process_event(self, event: Dict[str, Any]) -> Tuple[Dict[str, Any], Any]:
|
||||
@@ -54,7 +52,6 @@ class GenericOutgoingWebhookService(OutgoingWebhookServiceInterface):
|
||||
def process_event(self, event: Dict[str, Any]) -> Tuple[Dict[str, Any], Any]:
|
||||
rest_operation = {'method': 'POST',
|
||||
'relative_url_path': '',
|
||||
'base_url': self.base_url,
|
||||
'request_kwargs': {}}
|
||||
request_data = {"data": event['command'],
|
||||
"message": event['message'],
|
||||
@@ -86,7 +83,6 @@ class SlackOutgoingWebhookService(OutgoingWebhookServiceInterface):
|
||||
def process_event(self, event: Dict[str, Any]) -> Tuple[Dict[str, Any], Any]:
|
||||
rest_operation = {'method': 'POST',
|
||||
'relative_url_path': '',
|
||||
'base_url': self.base_url,
|
||||
'request_kwargs': {}}
|
||||
|
||||
if event['message']['type'] == 'private':
|
||||
@@ -132,8 +128,7 @@ def get_service_interface_class(interface: str) -> Any:
|
||||
def get_outgoing_webhook_service_handler(service: Service) -> Any:
|
||||
|
||||
service_interface_class = get_service_interface_class(service.interface_name())
|
||||
service_interface = service_interface_class(base_url=service.base_url,
|
||||
token=service.token,
|
||||
service_interface = service_interface_class(token=service.token,
|
||||
user_profile=service.user_profile,
|
||||
service_name=service.name)
|
||||
return service_interface
|
||||
@@ -277,7 +272,8 @@ def process_success_response(event: Dict[str, Any],
|
||||
response_data = dict(content=content)
|
||||
send_response_message(bot_id=bot_id, message_info=message_info, response_data=response_data)
|
||||
|
||||
def do_rest_call(rest_operation: Dict[str, Any],
|
||||
def do_rest_call(base_url: str,
|
||||
rest_operation: Dict[str, Any],
|
||||
request_data: Optional[Dict[str, Any]],
|
||||
event: Dict[str, Any],
|
||||
service_handler: Any,
|
||||
@@ -286,7 +282,6 @@ def do_rest_call(rest_operation: Dict[str, Any],
|
||||
('method', check_string),
|
||||
('relative_url_path', check_string),
|
||||
('request_kwargs', check_dict([])),
|
||||
('base_url', check_string),
|
||||
])
|
||||
|
||||
error = rest_operation_validator('rest_operation', rest_operation)
|
||||
@@ -294,7 +289,7 @@ def do_rest_call(rest_operation: Dict[str, Any],
|
||||
raise JsonableError(error)
|
||||
|
||||
http_method = rest_operation['method']
|
||||
final_url = urllib.parse.urljoin(rest_operation['base_url'], rest_operation['relative_url_path'])
|
||||
final_url = urllib.parse.urljoin(base_url, rest_operation['relative_url_path'])
|
||||
request_kwargs = rest_operation['request_kwargs']
|
||||
request_kwargs['timeout'] = timeout
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ class TestGenericOutgoingWebhookService(ZulipTestCase):
|
||||
}
|
||||
self.bot_user = get_user("outgoing-webhook@zulip.com", get_realm("zulip"))
|
||||
self.handler = GenericOutgoingWebhookService(service_name='test-service',
|
||||
base_url='http://example.domain.com',
|
||||
token='abcdef',
|
||||
user_profile=self.bot_user)
|
||||
|
||||
@@ -65,7 +64,6 @@ class TestGenericOutgoingWebhookService(ZulipTestCase):
|
||||
request_data = json.loads(request_data)
|
||||
self.assertEqual(request_data['data'], "@**test**")
|
||||
self.assertEqual(request_data['token'], "abcdef")
|
||||
self.assertEqual(rest_operation['base_url'], "http://example.domain.com")
|
||||
self.assertEqual(rest_operation['method'], "POST")
|
||||
self.assertEqual(request_data['message'], self.event['message'])
|
||||
|
||||
@@ -123,15 +121,13 @@ class TestSlackOutgoingWebhookService(ZulipTestCase):
|
||||
}
|
||||
}
|
||||
|
||||
self.handler = SlackOutgoingWebhookService(base_url='http://example.domain.com',
|
||||
token="abcdef",
|
||||
self.handler = SlackOutgoingWebhookService(token="abcdef",
|
||||
user_profile=None,
|
||||
service_name='test-service')
|
||||
|
||||
def test_process_event_stream_message(self) -> None:
|
||||
rest_operation, request_data = self.handler.process_event(self.stream_message_event)
|
||||
|
||||
self.assertEqual(rest_operation['base_url'], 'http://example.domain.com')
|
||||
self.assertEqual(rest_operation['method'], 'POST')
|
||||
self.assertEqual(request_data[0][1], "abcdef") # token
|
||||
self.assertEqual(request_data[1][1], "zulip") # team_id
|
||||
|
||||
@@ -38,7 +38,7 @@ class MockServiceHandler(OutgoingWebhookServiceInterface):
|
||||
)
|
||||
return success_data
|
||||
|
||||
service_handler = MockServiceHandler(None, None, None, None)
|
||||
service_handler = MockServiceHandler(None, None, None)
|
||||
|
||||
class DoRestCallTests(ZulipTestCase):
|
||||
def setUp(self) -> None:
|
||||
@@ -60,8 +60,7 @@ class DoRestCallTests(ZulipTestCase):
|
||||
|
||||
self.rest_operation = {'method': "POST",
|
||||
'relative_url_path': "",
|
||||
'request_kwargs': {},
|
||||
'base_url': ""}
|
||||
'request_kwargs': {}}
|
||||
self.bot_user = self.example_user('outgoing_webhook_bot')
|
||||
logging.disable(logging.WARNING)
|
||||
|
||||
@@ -69,7 +68,7 @@ class DoRestCallTests(ZulipTestCase):
|
||||
def test_successful_request(self, mock_send: mock.Mock) -> None:
|
||||
response = ResponseMock(200)
|
||||
with mock.patch('requests.request', return_value=response):
|
||||
do_rest_call(self.rest_operation, None, self.mock_event, service_handler, None)
|
||||
do_rest_call('', self.rest_operation, None, self.mock_event, service_handler, None)
|
||||
self.assertTrue(mock_send.called)
|
||||
|
||||
def test_retry_request(self: mock.Mock) -> None:
|
||||
@@ -77,7 +76,7 @@ class DoRestCallTests(ZulipTestCase):
|
||||
|
||||
self.mock_event['failed_tries'] = 3
|
||||
with mock.patch('requests.request', return_value=response):
|
||||
do_rest_call(self.rest_operation, None, self.mock_event, service_handler, None)
|
||||
do_rest_call('', self.rest_operation, None, self.mock_event, service_handler, None)
|
||||
bot_owner_notification = self.get_last_message()
|
||||
self.assertEqual(bot_owner_notification.content,
|
||||
'''[A message](http://zulip.testserver/#narrow/stream/999-Verona/subject/Foo/near/) triggered an outgoing webhook.
|
||||
@@ -89,7 +88,7 @@ The webhook got a response with status code *500*.''')
|
||||
def test_fail_request(self, mock_fail_with_message: mock.Mock) -> None:
|
||||
response = ResponseMock(400)
|
||||
with mock.patch('requests.request', return_value=response):
|
||||
do_rest_call(self.rest_operation, None, self.mock_event, service_handler, None)
|
||||
do_rest_call('', self.rest_operation, None, self.mock_event, service_handler, None)
|
||||
bot_owner_notification = self.get_last_message()
|
||||
self.assertTrue(mock_fail_with_message.called)
|
||||
self.assertEqual(bot_owner_notification.content,
|
||||
@@ -101,7 +100,7 @@ The webhook got a response with status code *400*.''')
|
||||
def helper(side_effect: Any, error_text: str) -> None:
|
||||
with mock.patch('logging.info'):
|
||||
with mock.patch('requests.request', side_effect=side_effect):
|
||||
do_rest_call(self.rest_operation, None, self.mock_event, service_handler, None)
|
||||
do_rest_call('', self.rest_operation, None, self.mock_event, service_handler, None)
|
||||
bot_owner_notification = self.get_last_message()
|
||||
self.assertIn(error_text, bot_owner_notification.content)
|
||||
self.assertIn('triggered', bot_owner_notification.content)
|
||||
@@ -115,7 +114,7 @@ The webhook got a response with status code *400*.''')
|
||||
@mock.patch('zerver.lib.outgoing_webhook.fail_with_message')
|
||||
def test_request_exception(self, mock_fail_with_message: mock.Mock,
|
||||
mock_requests_request: mock.Mock, mock_logger: mock.Mock) -> None:
|
||||
do_rest_call(self.rest_operation, None, self.mock_event, service_handler, None)
|
||||
do_rest_call('', self.rest_operation, None, self.mock_event, service_handler, None)
|
||||
bot_owner_notification = self.get_last_message()
|
||||
self.assertTrue(mock_fail_with_message.called)
|
||||
self.assertEqual(bot_owner_notification.content,
|
||||
|
||||
@@ -483,7 +483,11 @@ class OutgoingWebhookWorker(QueueProcessingWorker):
|
||||
service_handler = get_outgoing_webhook_service_handler(service)
|
||||
rest_operation, request_data = service_handler.process_event(dup_event)
|
||||
if rest_operation:
|
||||
do_rest_call(rest_operation, request_data, dup_event, service_handler)
|
||||
do_rest_call(service.base_url,
|
||||
rest_operation,
|
||||
request_data,
|
||||
dup_event,
|
||||
service_handler)
|
||||
|
||||
@assign_queue('embedded_bots')
|
||||
class EmbeddedBotWorker(QueueProcessingWorker):
|
||||
|
||||
Reference in New Issue
Block a user