mirror of https://github.com/zulip/zulip.git
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:
parent
9a96d19315
commit
5e31a6b1c0
|
@ -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),
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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))
|
||||
|
||||
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))
|
||||
for confirmation_obj in multiuse_confirmation_objs:
|
||||
invite = confirmation_obj.content_object
|
||||
assert invite is not None
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,7 +153,8 @@ def revoke_multiuse_invite(
|
|||
if invite.realm != user_profile.realm:
|
||||
raise JsonableError(_("No such invitation"))
|
||||
|
||||
check_role_based_permissions(invite.invited_as, user_profile, require_admin=True)
|
||||
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:
|
||||
raise JsonableError(_("Invitation has already been revoked"))
|
||||
|
|
Loading…
Reference in New Issue