diff --git a/templates/zerver/api/deactivate-own-user.md b/templates/zerver/api/deactivate-own-user.md new file mode 100644 index 0000000000..1250d081fb --- /dev/null +++ b/templates/zerver/api/deactivate-own-user.md @@ -0,0 +1,33 @@ +# Deactivate own user + +{generate_api_description(/users/me:delete)} + +## Usage examples + +{start_tabs} +{tab|python} + +{generate_code_example(python)|/users/me:delete|example} + +{tab|curl} + +{generate_code_example(curl)|/users/me:delete|example} + +{end_tabs} + +## Parameters + +{generate_api_arguments_table|zulip.yaml|/users/me:delete} + +## Response + +#### Example response + +A typical successful JSON response may look like: + +{generate_code_example|/users/me:delete|fixture(200)} + +An example JSON error response when attempting to deactivate the only +organization owner in an organization: + +{generate_code_example|/users/me:delete|fixture(400)} diff --git a/templates/zerver/help/include/rest-endpoints.md b/templates/zerver/help/include/rest-endpoints.md index 955ac8f342..d1b9f2d5ce 100644 --- a/templates/zerver/help/include/rest-endpoints.md +++ b/templates/zerver/help/include/rest-endpoints.md @@ -40,6 +40,7 @@ * [Create a user](/api/create-user) * [Deactivate a user](/api/deactivate-user) * [Reactivate a user](/api/reactivate-user) +* [Deactivate own user](/api/deactivate-own-user) * [Set "typing" status](/api/set-typing-status) * [Get user presence](/api/get-user-presence) * [Get attachments](/api/get-attachments) diff --git a/tools/test-api b/tools/test-api index 9950b991bc..249650ed4a 100755 --- a/tools/test-api +++ b/tools/test-api @@ -59,6 +59,18 @@ with test_server_running( site=site, ) + # Prepare the owner client + email = "desdemona@zulip.com" # desdemona is an owner + realm = get_realm("zulip") + user = get_user(email, realm) + api_key = get_api_key(user) + site = "http://zulip.zulipdev.com:9981" + owner_client = Client( + email=email, + api_key=api_key, + site=site, + ) + # Prepare a generic bot client for curl testing email = "default-bot@zulip.com" realm = get_realm("zulip") @@ -82,8 +94,8 @@ with test_server_running( site=site, ) - test_the_api(client, nonadmin_client) - test_generated_curl_examples_for_success(client) + test_the_api(client, nonadmin_client, owner_client) + test_generated_curl_examples_for_success(client, owner_client) test_js_bindings(client) # Test error payloads diff --git a/zerver/openapi/python_examples.py b/zerver/openapi/python_examples.py index bc96499527..9d241e5347 100644 --- a/zerver/openapi/python_examples.py +++ b/zerver/openapi/python_examples.py @@ -392,6 +392,23 @@ def get_profile(client: Client) -> None: validate_against_openapi_schema(result, "/users/me", "get", "200") +@openapi_test_function("/users/me:delete") +def deactivate_own_user(client: Client, owner_client: Client) -> None: + user_id = client.get_profile()["user_id"] + + # {code_example|start} + # Deactivate the account of the current user/bot that requests. + result = client.call_endpoint( + url="/users/me", + method="DELETE", + ) + # {code_example|end} + + # Reactivate the account to avoid polluting other tests. + owner_client.reactivate_user_by_id(user_id) + validate_against_openapi_schema(result, "/users/me", "delete", "200") + + @openapi_test_function("/get_stream_id:get") def get_stream_id(client: Client) -> int: @@ -1295,7 +1312,7 @@ def test_messages(client: Client, nonadmin_client: Client) -> None: test_delete_message_edit_permission_error(client, nonadmin_client) -def test_users(client: Client) -> None: +def test_users(client: Client, owner_client: Client) -> None: create_user(client) get_members(client) @@ -1320,6 +1337,7 @@ def test_users(client: Client) -> None: get_alert_words(client) add_alert_words(client) remove_alert_words(client) + deactivate_own_user(client, owner_client) def test_streams(client: Client, nonadmin_client: Client) -> None: @@ -1371,10 +1389,10 @@ def test_errors(client: Client) -> None: test_invalid_stream_error(client) -def test_the_api(client: Client, nonadmin_client: Client) -> None: +def test_the_api(client: Client, nonadmin_client: Client, owner_client: Client) -> None: get_user_agent(client) - test_users(client) + test_users(client, owner_client) test_streams(client, nonadmin_client) test_messages(client, nonadmin_client) test_queues(client) diff --git a/zerver/openapi/test_curl_examples.py b/zerver/openapi/test_curl_examples.py index 387fda9870..72a0f9b43e 100644 --- a/zerver/openapi/test_curl_examples.py +++ b/zerver/openapi/test_curl_examples.py @@ -22,7 +22,7 @@ from zerver.openapi.curl_param_value_generators import ( ) -def test_generated_curl_examples_for_success(client: Client) -> None: +def test_generated_curl_examples_for_success(client: Client, owner_client: Client) -> None: authentication_line = f"{client.email}:{client.api_key}" # A limited Markdown engine that just processes the code example syntax. realm = get_realm("zulip") @@ -49,11 +49,22 @@ def test_generated_curl_examples_for_success(client: Client) -> None: curl_command_html = md_engine.convert(line.strip()) unescaped_html = html.unescape(curl_command_html) curl_command_text = unescaped_html[len("

curl\n") : -len("

")] - curl_command_text = curl_command_text.replace( "BOT_EMAIL_ADDRESS:BOT_API_KEY", authentication_line ) + # TODO: This needs_reactivation block is a hack. + # However, it's awkward to test the "deactivate + # myself" endpoint with how this system tries to use + # the same account for all tests without some special + # logic for that endpoint; and the hack is better than + # just not documenting the endpoint. + needs_reactivation = False + user_id = 0 + if file_name == "templates/zerver/api/deactivate-own-user.md": + needs_reactivation = True + user_id = client.get_profile()["user_id"] + print("Testing {} ...".format(curl_command_text.split("\n")[0])) # Turn the text into an arguments list. @@ -69,6 +80,8 @@ def test_generated_curl_examples_for_success(client: Client) -> None: ) response = json.loads(response_json) assert response["result"] == "success" + if needs_reactivation: + owner_client.reactivate_user_by_id(user_id) except (AssertionError, Exception): error_template = """ Error verifying the success of the API documentation curl example. diff --git a/zerver/openapi/zulip.yaml b/zerver/openapi/zulip.yaml index 0947c0dd45..db526abaf7 100644 --- a/zerver/openapi/zulip.yaml +++ b/zerver/openapi/zulip.yaml @@ -4552,10 +4552,15 @@ paths: }, } delete: - operationId: deactivate_my_account + operationId: deactivate_own_user tags: ["users"] description: | - Delete the requesting user from the realm. + Deactivates the user's account. See also the administrative endpoint for + [deactivating another user](/api/deactivate-user). + + `DELETE {{ api_url }}/v1/users/me` + + This endpoint is primarily useful to Zulip clients providing a user settings UI. responses: "200": description: Success.