2020-09-15 00:24:01 +02:00
|
|
|
# Zulip's OpenAPI-based API documentation system is documented at
|
|
|
|
# https://zulip.readthedocs.io/en/latest/documentation/api.html
|
|
|
|
#
|
|
|
|
# This file contains helper functions for generating cURL examples
|
|
|
|
# based on Zulip's OpenAPI definitions, as well as test setup and
|
|
|
|
# fetching of appropriate parameter values to use when running the
|
|
|
|
# cURL examples as part of the tools/test-api test suite.
|
|
|
|
|
2019-10-21 12:43:00 +02:00
|
|
|
from functools import wraps
|
2020-06-11 00:54:34 +02:00
|
|
|
from typing import Any, Callable, Dict, List, Optional, Set, Tuple
|
2019-10-21 12:43:00 +02:00
|
|
|
|
2019-10-23 13:09:06 +02:00
|
|
|
from django.utils.timezone import now as timezone_now
|
|
|
|
|
2020-09-14 17:23:17 +02:00
|
|
|
from zerver.lib.actions import (
|
|
|
|
do_add_reaction,
|
|
|
|
do_add_realm_filter,
|
|
|
|
do_create_user,
|
|
|
|
update_user_presence,
|
|
|
|
)
|
2019-10-23 10:18:10 +02:00
|
|
|
from zerver.lib.events import do_events_register
|
2020-06-11 00:54:34 +02:00
|
|
|
from zerver.lib.test_classes import ZulipTestCase
|
|
|
|
from zerver.models import Client, Message, UserGroup, UserPresence, get_realm
|
2019-10-21 12:43:00 +02:00
|
|
|
|
2020-09-02 08:14:51 +02:00
|
|
|
GENERATOR_FUNCTIONS: Dict[str, Callable[[], Dict[str, object]]] = {}
|
python: Convert assignment type annotations to Python 3.6 style.
This commit was split by tabbott; this piece covers the vast majority
of files in Zulip, but excludes scripts/, tools/, and puppet/ to help
ensure we at least show the right error messages for Xenial systems.
We can likely further refine the remaining pieces with some testing.
Generated by com2ann, with whitespace fixes and various manual fixes
for runtime issues:
- invoiced_through: Optional[LicenseLedger] = models.ForeignKey(
+ invoiced_through: Optional["LicenseLedger"] = models.ForeignKey(
-_apns_client: Optional[APNsClient] = None
+_apns_client: Optional["APNsClient"] = None
- notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
- signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
+ notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
+ signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
- author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE)
+ author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE)
- bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
+ bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
- default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
- default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
+ default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
+ default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
-descriptors_by_handler_id: Dict[int, ClientDescriptor] = {}
+descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {}
-worker_classes: Dict[str, Type[QueueProcessingWorker]] = {}
-queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {}
+worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {}
+queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {}
-AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None
+AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
|
|
|
REGISTERED_GENERATOR_FUNCTIONS: Set[str] = set()
|
|
|
|
CALLED_GENERATOR_FUNCTIONS: Set[str] = set()
|
2019-10-21 12:43:00 +02:00
|
|
|
|
|
|
|
helpers = ZulipTestCase()
|
|
|
|
|
2020-06-30 22:47:16 +02:00
|
|
|
def openapi_param_value_generator(
|
|
|
|
endpoints: List[str],
|
|
|
|
) -> Callable[[Callable[[], Dict[str, object]]], Callable[[], Dict[str, object]]]:
|
2019-10-21 12:43:00 +02:00
|
|
|
"""This decorator is used to register openapi param value genarator functions
|
|
|
|
with endpoints. Example usage:
|
|
|
|
|
|
|
|
@openapi_param_value_generator(["/messages/render:post"])
|
|
|
|
def ...
|
|
|
|
"""
|
2020-06-30 22:47:16 +02:00
|
|
|
def wrapper(generator_func: Callable[[], Dict[str, object]]) -> Callable[[], Dict[str, object]]:
|
2019-10-21 12:43:00 +02:00
|
|
|
@wraps(generator_func)
|
2020-06-30 22:47:16 +02:00
|
|
|
def _record_calls_wrapper() -> Dict[str, object]:
|
2019-10-21 12:43:00 +02:00
|
|
|
CALLED_GENERATOR_FUNCTIONS.add(generator_func.__name__)
|
2020-06-30 22:47:16 +02:00
|
|
|
return generator_func()
|
2019-10-21 12:43:00 +02:00
|
|
|
|
|
|
|
REGISTERED_GENERATOR_FUNCTIONS.add(generator_func.__name__)
|
|
|
|
for endpoint in endpoints:
|
|
|
|
GENERATOR_FUNCTIONS[endpoint] = _record_calls_wrapper
|
|
|
|
|
|
|
|
return _record_calls_wrapper
|
|
|
|
return wrapper
|
|
|
|
|
2020-06-30 22:47:16 +02:00
|
|
|
def patch_openapi_example_values(
|
|
|
|
entry: str, params: List[Dict[str, Any]],
|
|
|
|
request_body: Optional[Dict[str, Any]] = None,
|
|
|
|
) -> Tuple[List[Dict[str, object]], Optional[Dict[str, object]]]:
|
2019-11-18 15:48:49 +01:00
|
|
|
if entry not in GENERATOR_FUNCTIONS:
|
|
|
|
return params, request_body
|
|
|
|
func = GENERATOR_FUNCTIONS[entry]
|
2020-06-30 22:47:16 +02:00
|
|
|
realm_example_values: Dict[str, object] = func()
|
2019-11-18 15:48:49 +01:00
|
|
|
|
|
|
|
for param in params:
|
2019-10-21 12:43:00 +02:00
|
|
|
param_name = param["name"]
|
2019-11-18 15:48:49 +01:00
|
|
|
if param_name in realm_example_values:
|
2020-06-27 19:23:50 +02:00
|
|
|
if 'content' in param:
|
|
|
|
param['content']['application/json']['example'] = realm_example_values[param_name]
|
|
|
|
else:
|
|
|
|
param["example"] = realm_example_values[param_name]
|
2019-11-18 15:48:49 +01:00
|
|
|
|
|
|
|
if request_body is not None:
|
|
|
|
properties = request_body["content"]["multipart/form-data"]["schema"]["properties"]
|
|
|
|
for key, property in properties.items():
|
|
|
|
if key in realm_example_values:
|
|
|
|
property["example"] = realm_example_values[key]
|
|
|
|
return params, request_body
|
2019-10-21 12:43:00 +02:00
|
|
|
|
2019-11-14 06:03:17 +01:00
|
|
|
@openapi_param_value_generator(["/messages/{message_id}:get", "/messages/{message_id}/history:get",
|
2019-11-14 06:19:45 +01:00
|
|
|
"/messages/{message_id}:patch", "/messages/{message_id}:delete"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def iago_message_id() -> Dict[str, object]:
|
2019-10-21 12:43:00 +02:00
|
|
|
return {
|
python: Use trailing commas consistently.
Automatically generated by the following script, based on the output
of lint with flake8-comma:
import re
import sys
last_filename = None
last_row = None
lines = []
for msg in sys.stdin:
m = re.match(
r"\x1b\[35mflake8 \|\x1b\[0m \x1b\[1;31m(.+):(\d+):(\d+): (\w+)", msg
)
if m:
filename, row_str, col_str, err = m.groups()
row, col = int(row_str), int(col_str)
if filename == last_filename:
assert last_row != row
else:
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
with open(filename) as f:
lines = f.readlines()
last_filename = filename
last_row = row
line = lines[row - 1]
if err in ["C812", "C815"]:
lines[row - 1] = line[: col - 1] + "," + line[col - 1 :]
elif err in ["C819"]:
assert line[col - 2] == ","
lines[row - 1] = line[: col - 2] + line[col - 1 :].lstrip(" ")
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-10 05:23:40 +02:00
|
|
|
"message_id": helpers.send_stream_message(helpers.example_user("iago"), "Denmark"),
|
2019-10-21 12:43:00 +02:00
|
|
|
}
|
2019-10-21 13:00:25 +02:00
|
|
|
|
2020-03-07 11:20:57 +01:00
|
|
|
@openapi_param_value_generator(["/messages/{message_id}/reactions:delete"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def add_emoji_to_message() -> Dict[str, object]:
|
2020-03-07 11:20:57 +01:00
|
|
|
user_profile = helpers.example_user('iago')
|
|
|
|
|
|
|
|
# from OpenAPI format data in zulip.yaml
|
|
|
|
message_id = 41
|
|
|
|
emoji_name = 'octopus'
|
|
|
|
emoji_code = '1f419'
|
|
|
|
reaction_type = 'unicode_emoji'
|
|
|
|
|
|
|
|
message = Message.objects.select_related().get(id=message_id)
|
|
|
|
do_add_reaction(user_profile, message, emoji_name, emoji_code, reaction_type)
|
|
|
|
|
|
|
|
return {}
|
|
|
|
|
2019-10-21 13:54:46 +02:00
|
|
|
@openapi_param_value_generator(["/messages/flags:post"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def update_flags_message_ids() -> Dict[str, object]:
|
2019-10-21 13:54:46 +02:00
|
|
|
stream_name = "Venice"
|
2019-11-14 06:03:17 +01:00
|
|
|
helpers.subscribe(helpers.example_user("iago"), stream_name)
|
2019-10-21 13:54:46 +02:00
|
|
|
|
|
|
|
messages = []
|
|
|
|
for _ in range(3):
|
2020-03-07 11:43:05 +01:00
|
|
|
messages.append(helpers.send_stream_message(helpers.example_user("iago"), stream_name))
|
2019-10-21 13:54:46 +02:00
|
|
|
return {
|
|
|
|
"messages": messages,
|
|
|
|
}
|
2019-10-23 09:01:17 +02:00
|
|
|
|
2019-10-23 09:33:43 +02:00
|
|
|
@openapi_param_value_generator(["/mark_stream_as_read:post", "/users/me/{stream_id}/topics:get"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def get_venice_stream_id() -> Dict[str, object]:
|
2019-10-23 09:01:17 +02:00
|
|
|
return {
|
|
|
|
"stream_id": helpers.get_stream_id("Venice"),
|
|
|
|
}
|
|
|
|
|
2019-11-14 09:48:21 +01:00
|
|
|
@openapi_param_value_generator(["/streams/{stream_id}:patch"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def update_stream() -> Dict[str, object]:
|
2019-11-14 09:48:21 +01:00
|
|
|
stream = helpers.subscribe(helpers.example_user("iago"), "temp_stream 1")
|
|
|
|
return {
|
|
|
|
"stream_id": stream.id,
|
|
|
|
}
|
|
|
|
|
2019-11-14 09:09:48 +01:00
|
|
|
@openapi_param_value_generator(["/streams/{stream_id}:delete"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def create_temp_stream_and_get_id() -> Dict[str, object]:
|
2019-11-14 09:48:21 +01:00
|
|
|
stream = helpers.subscribe(helpers.example_user("iago"), "temp_stream 2")
|
2019-11-14 09:09:48 +01:00
|
|
|
return {
|
|
|
|
"stream_id": stream.id,
|
|
|
|
}
|
|
|
|
|
2019-10-23 09:01:17 +02:00
|
|
|
@openapi_param_value_generator(["/mark_topic_as_read:post"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def get_denmark_stream_id_and_topic() -> Dict[str, object]:
|
2019-10-23 09:01:17 +02:00
|
|
|
stream_name = "Denmark"
|
|
|
|
topic_name = "Tivoli Gardens"
|
|
|
|
|
2019-11-14 06:03:17 +01:00
|
|
|
helpers.subscribe(helpers.example_user("iago"), stream_name)
|
2020-03-07 11:43:05 +01:00
|
|
|
helpers.send_stream_message(helpers.example_user("hamlet"), stream_name, topic_name=topic_name)
|
2019-10-23 09:01:17 +02:00
|
|
|
|
|
|
|
return {
|
|
|
|
"stream_id": helpers.get_stream_id(stream_name),
|
|
|
|
"topic_name": topic_name,
|
|
|
|
}
|
2019-10-23 09:16:46 +02:00
|
|
|
|
|
|
|
@openapi_param_value_generator(["/users/me/subscriptions/properties:post"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def update_subscription_data() -> Dict[str, object]:
|
2019-11-14 06:03:17 +01:00
|
|
|
profile = helpers.example_user("iago")
|
|
|
|
helpers.subscribe(profile, "Verona")
|
|
|
|
helpers.subscribe(profile, "social")
|
2019-10-23 09:16:46 +02:00
|
|
|
return {
|
|
|
|
"subscription_data": [
|
|
|
|
{"stream_id": helpers.get_stream_id("Verona"), "property": "pin_to_top", "value": True},
|
python: Use trailing commas consistently.
Automatically generated by the following script, based on the output
of lint with flake8-comma:
import re
import sys
last_filename = None
last_row = None
lines = []
for msg in sys.stdin:
m = re.match(
r"\x1b\[35mflake8 \|\x1b\[0m \x1b\[1;31m(.+):(\d+):(\d+): (\w+)", msg
)
if m:
filename, row_str, col_str, err = m.groups()
row, col = int(row_str), int(col_str)
if filename == last_filename:
assert last_row != row
else:
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
with open(filename) as f:
lines = f.readlines()
last_filename = filename
last_row = row
line = lines[row - 1]
if err in ["C812", "C815"]:
lines[row - 1] = line[: col - 1] + "," + line[col - 1 :]
elif err in ["C819"]:
assert line[col - 2] == ","
lines[row - 1] = line[: col - 2] + line[col - 1 :].lstrip(" ")
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-10 05:23:40 +02:00
|
|
|
{"stream_id": helpers.get_stream_id("social"), "property": "color", "value": "#f00f00"},
|
|
|
|
],
|
2019-10-23 09:16:46 +02:00
|
|
|
}
|
2019-10-23 10:18:10 +02:00
|
|
|
|
2019-11-14 06:34:39 +01:00
|
|
|
@openapi_param_value_generator(["/users/me/subscriptions:delete"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def delete_subscription_data() -> Dict[str, object]:
|
2019-11-14 06:34:39 +01:00
|
|
|
iago = helpers.example_user("iago")
|
|
|
|
zoe = helpers.example_user("ZOE")
|
|
|
|
helpers.subscribe(iago, "Verona")
|
|
|
|
helpers.subscribe(iago, "social")
|
|
|
|
helpers.subscribe(zoe, "Verona")
|
|
|
|
helpers.subscribe(zoe, "social")
|
|
|
|
return {}
|
|
|
|
|
2019-10-23 10:18:10 +02:00
|
|
|
@openapi_param_value_generator(["/events:get"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def get_events() -> Dict[str, object]:
|
2019-11-14 06:03:17 +01:00
|
|
|
profile = helpers.example_user("iago")
|
|
|
|
helpers.subscribe(profile, "Verona")
|
2019-10-23 10:18:10 +02:00
|
|
|
client = Client.objects.create(name="curl-test-client-1")
|
2019-11-14 06:03:17 +01:00
|
|
|
response = do_events_register(profile, client, event_types=['message', 'realm_emoji'])
|
2020-03-07 11:43:05 +01:00
|
|
|
helpers.send_stream_message(helpers.example_user("hamlet"), "Verona")
|
2019-10-23 10:18:10 +02:00
|
|
|
return {
|
|
|
|
"queue_id": response["queue_id"],
|
|
|
|
"last_event_id": response["last_event_id"],
|
|
|
|
}
|
2019-10-23 10:21:41 +02:00
|
|
|
|
|
|
|
@openapi_param_value_generator(["/events:delete"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def delete_event_queue() -> Dict[str, object]:
|
2019-11-14 06:03:17 +01:00
|
|
|
profile = helpers.example_user("iago")
|
2019-10-23 10:21:41 +02:00
|
|
|
client = Client.objects.create(name="curl-test-client-2")
|
2019-11-14 06:03:17 +01:00
|
|
|
response = do_events_register(profile, client, event_types=['message'])
|
2019-10-23 10:21:41 +02:00
|
|
|
return {
|
|
|
|
"queue_id": response["queue_id"],
|
|
|
|
"last_event_id": response["last_event_id"],
|
|
|
|
}
|
2019-10-23 13:09:06 +02:00
|
|
|
|
|
|
|
@openapi_param_value_generator(["/users/{email}/presence:get"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def get_user_presence() -> Dict[str, object]:
|
2019-10-23 13:09:06 +02:00
|
|
|
iago = helpers.example_user("iago")
|
|
|
|
client = Client.objects.create(name="curl-test-client-3")
|
|
|
|
update_user_presence(iago, client, timezone_now(), UserPresence.ACTIVE, False)
|
|
|
|
return {}
|
2019-11-14 09:16:11 +01:00
|
|
|
|
2019-11-18 04:57:21 +01:00
|
|
|
@openapi_param_value_generator(["/users:post"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def create_user() -> Dict[str, object]:
|
2019-11-18 04:57:21 +01:00
|
|
|
return {
|
python: Use trailing commas consistently.
Automatically generated by the following script, based on the output
of lint with flake8-comma:
import re
import sys
last_filename = None
last_row = None
lines = []
for msg in sys.stdin:
m = re.match(
r"\x1b\[35mflake8 \|\x1b\[0m \x1b\[1;31m(.+):(\d+):(\d+): (\w+)", msg
)
if m:
filename, row_str, col_str, err = m.groups()
row, col = int(row_str), int(col_str)
if filename == last_filename:
assert last_row != row
else:
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
with open(filename) as f:
lines = f.readlines()
last_filename = filename
last_row = row
line = lines[row - 1]
if err in ["C812", "C815"]:
lines[row - 1] = line[: col - 1] + "," + line[col - 1 :]
elif err in ["C819"]:
assert line[col - 2] == ","
lines[row - 1] = line[: col - 2] + line[col - 1 :].lstrip(" ")
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-10 05:23:40 +02:00
|
|
|
"email": helpers.nonreg_email("test"),
|
2019-11-18 04:57:21 +01:00
|
|
|
}
|
|
|
|
|
2019-11-14 09:16:11 +01:00
|
|
|
@openapi_param_value_generator(["/user_groups/create:post"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def create_user_group_data() -> Dict[str, object]:
|
2019-11-14 09:16:11 +01:00
|
|
|
return {
|
python: Use trailing commas consistently.
Automatically generated by the following script, based on the output
of lint with flake8-comma:
import re
import sys
last_filename = None
last_row = None
lines = []
for msg in sys.stdin:
m = re.match(
r"\x1b\[35mflake8 \|\x1b\[0m \x1b\[1;31m(.+):(\d+):(\d+): (\w+)", msg
)
if m:
filename, row_str, col_str, err = m.groups()
row, col = int(row_str), int(col_str)
if filename == last_filename:
assert last_row != row
else:
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
with open(filename) as f:
lines = f.readlines()
last_filename = filename
last_row = row
line = lines[row - 1]
if err in ["C812", "C815"]:
lines[row - 1] = line[: col - 1] + "," + line[col - 1 :]
elif err in ["C819"]:
assert line[col - 2] == ","
lines[row - 1] = line[: col - 2] + line[col - 1 :].lstrip(" ")
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-10 05:23:40 +02:00
|
|
|
"members": [helpers.example_user("hamlet").id, helpers.example_user("othello").id],
|
2019-11-14 09:16:11 +01:00
|
|
|
}
|
2019-11-14 09:35:28 +01:00
|
|
|
|
2020-07-16 20:39:53 +02:00
|
|
|
@openapi_param_value_generator(["/user_groups/{user_group_id}:patch", "/user_groups/{user_group_id}:delete"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def get_temp_user_group_id() -> Dict[str, object]:
|
2019-11-14 09:41:39 +01:00
|
|
|
user_group, _ = UserGroup.objects.get_or_create(name="temp", realm=get_realm("zulip"))
|
2019-11-14 09:35:28 +01:00
|
|
|
return {
|
2020-07-16 20:39:53 +02:00
|
|
|
"user_group_id": user_group.id,
|
2019-11-14 09:35:28 +01:00
|
|
|
}
|
2019-11-18 05:47:32 +01:00
|
|
|
|
|
|
|
@openapi_param_value_generator(["/realm/filters/{filter_id}:delete"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def remove_realm_filters() -> Dict[str, object]:
|
2019-11-18 05:47:32 +01:00
|
|
|
filter_id = do_add_realm_filter(get_realm("zulip"), "#(?P<id>[0-9]{2,8})", "https://github.com/zulip/zulip/pull/%(id)s")
|
|
|
|
return {
|
python: Use trailing commas consistently.
Automatically generated by the following script, based on the output
of lint with flake8-comma:
import re
import sys
last_filename = None
last_row = None
lines = []
for msg in sys.stdin:
m = re.match(
r"\x1b\[35mflake8 \|\x1b\[0m \x1b\[1;31m(.+):(\d+):(\d+): (\w+)", msg
)
if m:
filename, row_str, col_str, err = m.groups()
row, col = int(row_str), int(col_str)
if filename == last_filename:
assert last_row != row
else:
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
with open(filename) as f:
lines = f.readlines()
last_filename = filename
last_row = row
line = lines[row - 1]
if err in ["C812", "C815"]:
lines[row - 1] = line[: col - 1] + "," + line[col - 1 :]
elif err in ["C819"]:
assert line[col - 2] == ","
lines[row - 1] = line[: col - 2] + line[col - 1 :].lstrip(" ")
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-10 05:23:40 +02:00
|
|
|
"filter_id": filter_id,
|
2019-11-18 05:47:32 +01:00
|
|
|
}
|
2019-11-18 16:46:06 +01:00
|
|
|
|
2019-11-18 16:47:41 +01:00
|
|
|
@openapi_param_value_generator(["/realm/emoji/{emoji_name}:post", "/user_uploads:post"])
|
2020-06-30 22:47:16 +02:00
|
|
|
def upload_custom_emoji() -> Dict[str, object]:
|
2019-11-18 16:46:06 +01:00
|
|
|
return {
|
|
|
|
"filename": "zerver/tests/images/animated_img.gif",
|
|
|
|
}
|
2020-09-14 17:23:17 +02:00
|
|
|
|
|
|
|
@openapi_param_value_generator(["/users/{user_id}:delete"])
|
|
|
|
def deactivate_user() -> Dict[str, object]:
|
|
|
|
user_profile = do_create_user(
|
|
|
|
email='testuser@zulip.com', password=None,
|
|
|
|
full_name='test_user', realm=get_realm('zulip')
|
|
|
|
)
|
|
|
|
return {
|
|
|
|
"user_id": user_profile.id
|
|
|
|
}
|