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
|
to create reusable invitation links. Previously, this endpoint was
|
||||||
restricted to admin users only.
|
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**
|
**Feature level 208**
|
||||||
|
|
||||||
* [`POST /users/me/subscriptions`](/api/subscribe),
|
* [`POST /users/me/subscriptions`](/api/subscribe),
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
{{#if is_multiuse}}
|
{{#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>
|
<p>{{#tr}}Are you sure you want to revoke this invitation link created by <strong>{referred_by}</strong>?{{/tr}}</p>
|
||||||
{{else}}
|
{{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>
|
<p>{{#tr}}Are you sure you want to revoke the invitation to <strong>{email}</strong>?{{/tr}}</p>
|
||||||
{{/if}}
|
{{/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:
|
if user_profile.is_realm_admin:
|
||||||
# We do not return multiuse invites to non-admin users.
|
multiuse_confirmation_objs = Confirmation.objects.filter(
|
||||||
return invites
|
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:
|
for confirmation_obj in multiuse_confirmation_objs:
|
||||||
invite = confirmation_obj.content_object
|
invite = confirmation_obj.content_object
|
||||||
assert invite is not None
|
assert invite is not None
|
||||||
|
|
|
@ -1747,8 +1747,11 @@ class InvitationsTestCase(InviteUserBase):
|
||||||
do_create_multiuse_invite_link(
|
do_create_multiuse_invite_link(
|
||||||
user_profile, PreregistrationUser.INVITE_AS["MEMBER"], invite_expires_in_minutes
|
user_profile, PreregistrationUser.INVITE_AS["MEMBER"], invite_expires_in_minutes
|
||||||
)
|
)
|
||||||
self.assert_length(do_get_invites_controlled_by_user(user_profile), 5)
|
do_create_multiuse_invite_link(
|
||||||
self.assert_length(do_get_invites_controlled_by_user(hamlet), 1)
|
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)
|
self.assert_length(do_get_invites_controlled_by_user(othello), 1)
|
||||||
|
|
||||||
def test_successful_get_open_invitations(self) -> None:
|
def test_successful_get_open_invitations(self) -> None:
|
||||||
|
@ -1999,6 +2002,26 @@ class InvitationsTestCase(InviteUserBase):
|
||||||
confirmation_settings.STATUS_REVOKED,
|
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
|
# Test deleting multiuse invite from another realm
|
||||||
mit_realm = get_realm("zephyr")
|
mit_realm = get_realm("zephyr")
|
||||||
multiuse_invite_in_mit = MultiuseInvite.objects.create(
|
multiuse_invite_in_mit = MultiuseInvite.objects.create(
|
||||||
|
|
|
@ -14,7 +14,7 @@ from zerver.actions.invites import (
|
||||||
do_revoke_multi_use_invite,
|
do_revoke_multi_use_invite,
|
||||||
do_revoke_user_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.exceptions import JsonableError, OrganizationOwnerRequiredError
|
||||||
from zerver.lib.request import REQ, has_request_variables
|
from zerver.lib.request import REQ, has_request_variables
|
||||||
from zerver.lib.response import json_success
|
from zerver.lib.response import json_success
|
||||||
|
@ -140,7 +140,7 @@ def revoke_user_invite(
|
||||||
return json_success(request)
|
return json_success(request)
|
||||||
|
|
||||||
|
|
||||||
@require_realm_admin
|
@require_member_or_admin
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def revoke_multiuse_invite(
|
def revoke_multiuse_invite(
|
||||||
request: HttpRequest, user_profile: UserProfile, invite_id: int
|
request: HttpRequest, user_profile: UserProfile, invite_id: int
|
||||||
|
@ -153,7 +153,8 @@ def revoke_multiuse_invite(
|
||||||
if invite.realm != user_profile.realm:
|
if invite.realm != user_profile.realm:
|
||||||
raise JsonableError(_("No such invitation"))
|
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:
|
if invite.status == confirmation_settings.STATUS_REVOKED:
|
||||||
raise JsonableError(_("Invitation has already been revoked"))
|
raise JsonableError(_("Invitation has already been revoked"))
|
||||||
|
|
Loading…
Reference in New Issue