invites: Make it possible for non-admins to revoke multiuse invites.

This commit makes changes to allow non-admins to revoke multiuse
invitations created by them.
This commit is contained in:
Ujjawal Modi 2023-08-05 16:11:47 +05:30 committed by Tim Abbott
parent 9a96d19315
commit 5e31a6b1c0
5 changed files with 54 additions and 11 deletions

View File

@ -33,6 +33,15 @@ format used by the Zulip server that they are interacting with.
to create reusable invitation links. Previously, this endpoint was
restricted to admin users only.
* `GET /invites`: Endpoint response for non-admin users now includes both
email invitations and reusable invitation links that they have created.
Previously, non-admin users could only create email invitations, and
therefore the response did not include reusable invitation links for these users.
* `DELETE /invites/multiuse/{invite_id}`: Non-admin users can now revoke
reusable invitation links they have created. Previously, only admin users could
create and revoke reusable invitation links.
**Feature level 208**
* [`POST /users/me/subscriptions`](/api/subscribe),

View File

@ -1,5 +1,9 @@
{{#if is_multiuse}}
{{#if referred_by}}
<p>{{#tr}}Are you sure you want to revoke this invitation link created by <strong>{referred_by}</strong>?{{/tr}}</p>
{{else}}
<p>{{#tr}}Are you sure you want to revoke this invitation link?{{/tr}}</p>
{{/if}}
{{else}}
<p>{{#tr}}Are you sure you want to revoke the invitation to <strong>{email}</strong>?{{/tr}}</p>
{{/if}}

View File

@ -362,13 +362,19 @@ def do_get_invites_controlled_by_user(user_profile: UserProfile) -> List[Dict[st
)
)
if not user_profile.is_realm_admin:
# We do not return multiuse invites to non-admin users.
return invites
if user_profile.is_realm_admin:
multiuse_confirmation_objs = Confirmation.objects.filter(
realm=user_profile.realm, type=Confirmation.MULTIUSE_INVITE
).filter(Q(expiry_date__gte=timezone_now()) | Q(expiry_date=None))
else:
multiuse_invite_ids = MultiuseInvite.objects.filter(referred_by=user_profile).values_list(
"id", flat=True
)
multiuse_confirmation_objs = Confirmation.objects.filter(
type=Confirmation.MULTIUSE_INVITE,
object_id__in=multiuse_invite_ids,
).filter(Q(expiry_date__gte=timezone_now()) | Q(expiry_date=None))
for confirmation_obj in multiuse_confirmation_objs:
invite = confirmation_obj.content_object
assert invite is not None

View File

@ -1747,8 +1747,11 @@ class InvitationsTestCase(InviteUserBase):
do_create_multiuse_invite_link(
user_profile, PreregistrationUser.INVITE_AS["MEMBER"], invite_expires_in_minutes
)
self.assert_length(do_get_invites_controlled_by_user(user_profile), 5)
self.assert_length(do_get_invites_controlled_by_user(hamlet), 1)
do_create_multiuse_invite_link(
hamlet, PreregistrationUser.INVITE_AS["MEMBER"], invite_expires_in_minutes
)
self.assert_length(do_get_invites_controlled_by_user(user_profile), 6)
self.assert_length(do_get_invites_controlled_by_user(hamlet), 2)
self.assert_length(do_get_invites_controlled_by_user(othello), 1)
def test_successful_get_open_invitations(self) -> None:
@ -1999,6 +2002,26 @@ class InvitationsTestCase(InviteUserBase):
confirmation_settings.STATUS_REVOKED,
)
# Test non-admins can only delete invitations created by them.
multiuse_invite = MultiuseInvite.objects.create(
referred_by=self.example_user("hamlet"), realm=zulip_realm
)
create_confirmation_link(
multiuse_invite, Confirmation.MULTIUSE_INVITE, validity_in_minutes=validity_in_minutes
)
self.login("cordelia")
error_result = self.client_delete("/json/invites/multiuse/" + str(multiuse_invite.id))
self.assert_json_error(error_result, "Must be an organization administrator")
self.login("hamlet")
result = self.client_delete("/json/invites/multiuse/" + str(multiuse_invite.id))
self.assertEqual(result.status_code, 200)
self.assertEqual(
MultiuseInvite.objects.get(id=multiuse_invite.id).status,
confirmation_settings.STATUS_REVOKED,
)
# Test deleting multiuse invite from another realm
mit_realm = get_realm("zephyr")
multiuse_invite_in_mit = MultiuseInvite.objects.create(

View File

@ -14,7 +14,7 @@ from zerver.actions.invites import (
do_revoke_multi_use_invite,
do_revoke_user_invite,
)
from zerver.decorator import require_member_or_admin, require_realm_admin
from zerver.decorator import require_member_or_admin
from zerver.lib.exceptions import JsonableError, OrganizationOwnerRequiredError
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_success
@ -140,7 +140,7 @@ def revoke_user_invite(
return json_success(request)
@require_realm_admin
@require_member_or_admin
@has_request_variables
def revoke_multiuse_invite(
request: HttpRequest, user_profile: UserProfile, invite_id: int
@ -153,6 +153,7 @@ def revoke_multiuse_invite(
if invite.realm != user_profile.realm:
raise JsonableError(_("No such invitation"))
if invite.referred_by_id != user_profile.id:
check_role_based_permissions(invite.invited_as, user_profile, require_admin=True)
if invite.status == confirmation_settings.STATUS_REVOKED: