diff --git a/api_docs/include/rest-endpoints.md b/api_docs/include/rest-endpoints.md index b43c21f61a..34ecfc71a0 100644 --- a/api_docs/include/rest-endpoints.md +++ b/api_docs/include/rest-endpoints.md @@ -95,6 +95,7 @@ * [Get all invitations](/api/get-invites) * [Send invitations](/api/send-invites) * [Create a reusable invitation link](/api/create-invite-link) +* [Resend an email invitation](/api/resend-email-invite) * [Revoke an email invitation](/api/revoke-email-invite) * [Revoke a reusable invitation link](/api/revoke-invite-link) diff --git a/zerver/openapi/python_examples.py b/zerver/openapi/python_examples.py index c395630690..e24752a9e0 100644 --- a/zerver/openapi/python_examples.py +++ b/zerver/openapi/python_examples.py @@ -431,6 +431,20 @@ def revoke_reusable_invitation_link(client: Client) -> None: validate_against_openapi_schema(result, "/invites/multiuse/{invite_id}", "delete", "200") +@openapi_test_function("/invites/{invite_id}/resend:post") +def resend_email_invitation(client: Client) -> None: + invites = client.call_endpoint(url="/invites", method="GET")["invites"] + email_invites = [s for s in invites if not s["is_multiuse"]] + assert len(email_invites) > 0 + invite_id = email_invites[0]["id"] + # {code_example|start} + # Resend email invitation. + result = client.call_endpoint(url=f"/invites/{invite_id}/resend", method="POST") + # {code_example|end} + validate_response_result(result) + validate_against_openapi_schema(result, "/invites/{invite_id}/resend", "post", "200") + + @openapi_test_function("/users/{user_id}:get") def get_single_user(client: Client) -> None: user_id = 8 @@ -1801,6 +1815,7 @@ def test_invitations(client: Client) -> None: create_reusable_invitation_link(client) revoke_reusable_invitation_link(client) get_invitations(client) + resend_email_invitation(client) def test_the_api(client: Client, nonadmin_client: Client, owner_client: Client) -> None: diff --git a/zerver/openapi/zulip.yaml b/zerver/openapi/zulip.yaml index 8653f77b2b..48e983722a 100644 --- a/zerver/openapi/zulip.yaml +++ b/zerver/openapi/zulip.yaml @@ -12794,6 +12794,44 @@ paths: description: | A typical failed JSON response for when the invitation link has already been revoked: + /invites/{invite_id}/resend: + post: + operationId: resend-email-invite + summary: Resend an email invitation + tags: ["invites"] + description: | + Resend an [email invitation](/help/invite-new-users#send-email-invitations). + + A user can only resend [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 resent. + 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 email invitation ID: /register: post: operationId: register-queue diff --git a/zerver/tests/test_openapi.py b/zerver/tests/test_openapi.py index 43c13dbdb3..7e18083c2e 100644 --- a/zerver/tests/test_openapi.py +++ b/zerver/tests/test_openapi.py @@ -237,8 +237,6 @@ class OpenAPIArgumentsTest(ZulipTestCase): "/default_stream_groups/create", "/default_stream_groups/{group_id}", "/default_stream_groups/{group_id}/streams", - # Administer invitations - "/invites/{prereg_id}/resend", # Single-stream settings alternative to the bulk endpoint # users/me/subscriptions/properties; probably should just be a # section of the same page. diff --git a/zerver/views/invite.py b/zerver/views/invite.py index a5542c83cc..0e30797251 100644 --- a/zerver/views/invite.py +++ b/zerver/views/invite.py @@ -181,10 +181,10 @@ def revoke_multiuse_invite( @require_member_or_admin @has_request_variables def resend_user_invite_email( - 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 e5e4f66af2..ff54098353 100644 --- a/zproject/urls.py +++ b/zproject/urls.py @@ -318,7 +318,7 @@ v1_api_and_json_patterns = [ # 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//resend", POST=resend_user_invite_email), + rest_path("invites//resend", POST=resend_user_invite_email), # invites/multiuse -> zerver.views.invite rest_path("invites/multiuse", POST=generate_multiuse_invite_backend), # invites/multiuse -> zerver.views.invite