diff --git a/api_docs/include/rest-endpoints.md b/api_docs/include/rest-endpoints.md index 6dfd3bd2f4..943100c80c 100644 --- a/api_docs/include/rest-endpoints.md +++ b/api_docs/include/rest-endpoints.md @@ -93,6 +93,7 @@ * [Get all invitations](/api/get-invites) * [Send invitations](/api/send-invites) * [Create reusable invitation link](/api/create-invite-link) +* [Revoke an email invitation](/api/revoke-email-invite) #### Server & organizations diff --git a/zerver/openapi/python_examples.py b/zerver/openapi/python_examples.py index 29d6b721bc..8f67335f55 100644 --- a/zerver/openapi/python_examples.py +++ b/zerver/openapi/python_examples.py @@ -344,6 +344,25 @@ def create_reusable_invitation_link(client: Client) -> None: validate_against_openapi_schema(result, "/invites/multiuse", "post", "200") +@openapi_test_function("/invites/{invite_id}:delete") +def revoke_email_invitation(client: Client) -> None: + request = { + "invitee_emails": "delete-invite@zulip.com", + "invite_expires_in_minutes": 14400, # 10 days + "invite_as": 400, + "stream_ids": [1, 8, 9], + } + result = client.call_endpoint(url="/invites", method="POST", request=request) + + # {code_example|start} + # Revoke email invitation + invite_id = 3 + result = client.call_endpoint(url=f"/invites/{invite_id}", method="DELETE") + # {code_example|end} + + validate_against_openapi_schema(result, "/invites/{invite_id}", "delete", "200") + + @openapi_test_function("/users/{user_id}:get") def get_single_user(client: Client) -> None: ensure_users([8], ["cordelia"]) @@ -1701,6 +1720,7 @@ def test_errors(client: Client) -> None: def test_invitations(client: Client) -> None: send_invitations(client) + revoke_email_invitation(client) create_reusable_invitation_link(client) get_invitations(client) diff --git a/zerver/openapi/zulip.yaml b/zerver/openapi/zulip.yaml index ea347180b7..6be158cff3 100644 --- a/zerver/openapi/zulip.yaml +++ b/zerver/openapi/zulip.yaml @@ -12161,6 +12161,44 @@ paths: description: | An example JSON error response for when the user doesn't have permission to subscribe other users to streams and `stream_ids` is not empty. + /invites/{invite_id}: + delete: + operationId: revoke-email-invite + summary: Revoke an email invitation + tags: ["invites"] + description: | + Revoke an [email invitation](/help/invite-new-users#send-email-invitations). + + A user can only revoke [invitations that they can + manage](/help/invite-new-users#manage-pending-invitations). + parameters: + - name: invite_id + in: path + description: | + The ID of the email invitation to be revoked. + schema: + type: integer + example: 1 + required: true + responses: + "200": + $ref: "#/components/responses/SimpleSuccess" + "400": + description: Bad request. + content: + application/json: + schema: + oneOf: + - allOf: + - $ref: "#/components/schemas/CodedError" + - example: + { + "result": "error", + "msg": "No such invitation", + "code": "BAD_REQUEST", + } + description: | + A typical failed JSON response for an invalid `invite_id`: /register: post: operationId: register-queue diff --git a/zerver/tests/test_openapi.py b/zerver/tests/test_openapi.py index b0e72d547a..0591164294 100644 --- a/zerver/tests/test_openapi.py +++ b/zerver/tests/test_openapi.py @@ -239,7 +239,6 @@ class OpenAPIArgumentsTest(ZulipTestCase): "/default_stream_groups/{group_id}", "/default_stream_groups/{group_id}/streams", # Administer invitations - "/invites/{prereg_id}", "/invites/{prereg_id}/resend", "/invites/multiuse/{invite_id}", # Single-stream settings alternative to the bulk endpoint diff --git a/zerver/views/invite.py b/zerver/views/invite.py index 005d0169d4..f22bedc534 100644 --- a/zerver/views/invite.py +++ b/zerver/views/invite.py @@ -123,10 +123,10 @@ def get_user_invites(request: HttpRequest, user_profile: UserProfile) -> HttpRes @require_member_or_admin @has_request_variables def revoke_user_invite( - request: HttpRequest, user_profile: UserProfile, prereg_id: int + request: HttpRequest, user_profile: UserProfile, invite_id: int ) -> HttpResponse: try: - prereg_user = PreregistrationUser.objects.get(id=prereg_id) + prereg_user = PreregistrationUser.objects.get(id=invite_id) except PreregistrationUser.DoesNotExist: raise JsonableError(_("No such invitation")) diff --git a/zproject/urls.py b/zproject/urls.py index 4bb1bf4f79..a6edb14eb6 100644 --- a/zproject/urls.py +++ b/zproject/urls.py @@ -316,7 +316,7 @@ v1_api_and_json_patterns = [ rest_path("bots/", PATCH=patch_bot_backend, DELETE=deactivate_bot_backend), # invites -> zerver.views.invite rest_path("invites", GET=get_user_invites, POST=invite_users_backend), - rest_path("invites/", DELETE=revoke_user_invite), + rest_path("invites/", DELETE=revoke_user_invite), rest_path("invites//resend", POST=resend_user_invite_email), # invites/multiuse -> zerver.views.invite rest_path("invites/multiuse", POST=generate_multiuse_invite_backend),