mirror of https://github.com/zulip/zulip.git
streams: Allow changing can_remove_subscribers_group through API.
This commit adds API support to change can_remove_subscribers_group setting for a stream.
This commit is contained in:
parent
6fa0a83d6b
commit
c3759814be
|
@ -20,6 +20,12 @@ format used by the Zulip server that they are interacting with.
|
||||||
|
|
||||||
## Changes in Zulip 7.0
|
## Changes in Zulip 7.0
|
||||||
|
|
||||||
|
**Feature level 161**
|
||||||
|
|
||||||
|
* [`PATCH /streams/{stream_id}`](/api/update-stream): Added
|
||||||
|
`can_remove_subscribers_group_id` parameter to support
|
||||||
|
changing `can_remove_subscribers_group` setting.
|
||||||
|
|
||||||
**Feature level 160**
|
**Feature level 160**
|
||||||
|
|
||||||
* [`POST /api/v1/jwt/fetch_api_key`]: New API endpoint to fetch API
|
* [`POST /api/v1/jwt/fetch_api_key`]: New API endpoint to fetch API
|
||||||
|
|
|
@ -58,6 +58,33 @@ def access_user_groups_as_potential_subgroups(
|
||||||
return list(user_groups)
|
return list(user_groups)
|
||||||
|
|
||||||
|
|
||||||
|
def access_user_group_for_setting(
|
||||||
|
user_group_id: int,
|
||||||
|
user_profile: UserProfile,
|
||||||
|
*,
|
||||||
|
setting_name: str,
|
||||||
|
require_system_group: bool = False,
|
||||||
|
allow_internet_group: bool = False,
|
||||||
|
allow_owners_group: bool = False,
|
||||||
|
) -> UserGroup:
|
||||||
|
user_group = access_user_group_by_id(user_group_id, user_profile, for_read=True)
|
||||||
|
|
||||||
|
if require_system_group and not user_group.is_system_group:
|
||||||
|
raise JsonableError(_("'{}' must be a system user group.").format(setting_name))
|
||||||
|
|
||||||
|
if not allow_internet_group and user_group.name == UserGroup.EVERYONE_ON_INTERNET_GROUP_NAME:
|
||||||
|
raise JsonableError(
|
||||||
|
_("'{}' setting cannot be set to '@role:internet' group.").format(setting_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
if not allow_owners_group and user_group.name == UserGroup.OWNERS_GROUP_NAME:
|
||||||
|
raise JsonableError(
|
||||||
|
_("'{}' setting cannot be set to '@role:owners' group.").format(setting_name)
|
||||||
|
)
|
||||||
|
|
||||||
|
return user_group
|
||||||
|
|
||||||
|
|
||||||
def user_groups_in_realm_serialized(realm: Realm) -> List[UserGroupDict]:
|
def user_groups_in_realm_serialized(realm: Realm) -> List[UserGroupDict]:
|
||||||
"""This function is used in do_events_register code path so this code
|
"""This function is used in do_events_register code path so this code
|
||||||
should be performant. We need to do 2 database queries because
|
should be performant. We need to do 2 database queries because
|
||||||
|
|
|
@ -8027,14 +8027,23 @@ paths:
|
||||||
Unsubscribe yourself or other users from one or more streams.
|
Unsubscribe yourself or other users from one or more streams.
|
||||||
|
|
||||||
In addition to managing the current user's subscriptions, this
|
In addition to managing the current user's subscriptions, this
|
||||||
endpoint can be used by organization administrators to remove
|
endpoint can be used to remove other users from streams. This
|
||||||
other users from streams, or to remove a bot that the current
|
is possible in 3 situations:
|
||||||
user is the `bot_owner` for from any stream that the current
|
|
||||||
user can access.
|
|
||||||
|
|
||||||
**Changes**: Before Zulip 6.0 (feature level 145), only
|
- Organization administrators can remove any user from any
|
||||||
organization administrators could remove other users from
|
stream.
|
||||||
streams.
|
- Users can remove a bot that they own from any stream that
|
||||||
|
the user can access.
|
||||||
|
- Users who can access a stream and are in the group with ID
|
||||||
|
`can_remove_subscribers_group_id` for that stream can
|
||||||
|
unsubscribe any user from that stream.
|
||||||
|
|
||||||
|
**Changes**: Before Zulip 7.0 (feature level 161),
|
||||||
|
`can_remove_subscribers_group_id` was always the system group
|
||||||
|
for organization administrators.
|
||||||
|
|
||||||
|
Before Zulip 6.0 (feature level 145), users had no special
|
||||||
|
privileges for managing bots that they own.
|
||||||
x-curl-examples-parameters:
|
x-curl-examples-parameters:
|
||||||
oneOf:
|
oneOf:
|
||||||
- type: include
|
- type: include
|
||||||
|
@ -14536,6 +14545,7 @@ paths:
|
||||||
required: false
|
required: false
|
||||||
- $ref: "#/components/parameters/StreamPostPolicy"
|
- $ref: "#/components/parameters/StreamPostPolicy"
|
||||||
- $ref: "#/components/parameters/MessageRetentionDays"
|
- $ref: "#/components/parameters/MessageRetentionDays"
|
||||||
|
- $ref: "#/components/parameters/CanRemoveSubscribersGroupId"
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
$ref: "#/components/responses/SimpleSuccess"
|
$ref: "#/components/responses/SimpleSuccess"
|
||||||
|
@ -17562,6 +17572,22 @@ components:
|
||||||
- type: integer
|
- type: integer
|
||||||
example: "20"
|
example: "20"
|
||||||
required: false
|
required: false
|
||||||
|
CanRemoveSubscribersGroupId:
|
||||||
|
name: can_remove_subscribers_group_id
|
||||||
|
in: query
|
||||||
|
description: |
|
||||||
|
ID of the user group whose members are allowed to unsubscribe others
|
||||||
|
from the stream, if they have access to this stream, even if
|
||||||
|
they are not an organization administrator.
|
||||||
|
|
||||||
|
This setting can currently only be set to system user groups
|
||||||
|
except `@role:internet` and `@role:owners` group.
|
||||||
|
|
||||||
|
**Changes**: New in Zulip 7.0 (feature level 161).
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
example: 20
|
||||||
|
required: false
|
||||||
LinkifierPattern:
|
LinkifierPattern:
|
||||||
name: pattern
|
name: pattern
|
||||||
in: query
|
in: query
|
||||||
|
|
|
@ -1977,6 +1977,80 @@ class StreamAdminTest(ZulipTestCase):
|
||||||
stream = get_stream("stream_name1", realm)
|
stream = get_stream("stream_name1", realm)
|
||||||
self.assertEqual(stream.message_retention_days, 2)
|
self.assertEqual(stream.message_retention_days, 2)
|
||||||
|
|
||||||
|
def test_change_stream_can_remove_subscribers_group(self) -> None:
|
||||||
|
user_profile = self.example_user("iago")
|
||||||
|
realm = user_profile.realm
|
||||||
|
stream = self.subscribe(user_profile, "stream_name1")
|
||||||
|
|
||||||
|
moderators_system_group = UserGroup.objects.get(
|
||||||
|
name="@role:moderators", realm=realm, is_system_group=True
|
||||||
|
)
|
||||||
|
self.login("shiva")
|
||||||
|
result = self.client_patch(
|
||||||
|
f"/json/streams/{stream.id}",
|
||||||
|
{"can_remove_subscribers_group_id": orjson.dumps(moderators_system_group.id).decode()},
|
||||||
|
)
|
||||||
|
self.assert_json_error(result, "Must be an organization administrator")
|
||||||
|
|
||||||
|
self.login("iago")
|
||||||
|
result = self.client_patch(
|
||||||
|
f"/json/streams/{stream.id}",
|
||||||
|
{"can_remove_subscribers_group_id": orjson.dumps(moderators_system_group.id).decode()},
|
||||||
|
)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
stream = get_stream("stream_name1", realm)
|
||||||
|
self.assertEqual(stream.can_remove_subscribers_group.id, moderators_system_group.id)
|
||||||
|
|
||||||
|
# This setting can only be set to system groups.
|
||||||
|
hamletcharacters_group = UserGroup.objects.get(name="hamletcharacters", realm=realm)
|
||||||
|
result = self.client_patch(
|
||||||
|
f"/json/streams/{stream.id}",
|
||||||
|
{"can_remove_subscribers_group_id": orjson.dumps(hamletcharacters_group.id).decode()},
|
||||||
|
)
|
||||||
|
self.assert_json_error(
|
||||||
|
result, "'can_remove_subscribers_group' must be a system user group."
|
||||||
|
)
|
||||||
|
|
||||||
|
internet_group = UserGroup.objects.get(
|
||||||
|
name="@role:internet", is_system_group=True, realm=realm
|
||||||
|
)
|
||||||
|
result = self.client_patch(
|
||||||
|
f"/json/streams/{stream.id}",
|
||||||
|
{"can_remove_subscribers_group_id": orjson.dumps(internet_group.id).decode()},
|
||||||
|
)
|
||||||
|
self.assert_json_error(
|
||||||
|
result,
|
||||||
|
"'can_remove_subscribers_group' setting cannot be set to '@role:internet' group.",
|
||||||
|
)
|
||||||
|
|
||||||
|
owners_group = UserGroup.objects.get(name="@role:owners", is_system_group=True, realm=realm)
|
||||||
|
result = self.client_patch(
|
||||||
|
f"/json/streams/{stream.id}",
|
||||||
|
{"can_remove_subscribers_group_id": orjson.dumps(owners_group.id).decode()},
|
||||||
|
)
|
||||||
|
self.assert_json_error(
|
||||||
|
result,
|
||||||
|
"'can_remove_subscribers_group' setting cannot be set to '@role:owners' group.",
|
||||||
|
)
|
||||||
|
|
||||||
|
# For private streams, even admins must be subscribed to the stream to change
|
||||||
|
# can_remove_subscribers_group setting.
|
||||||
|
stream = self.make_stream("stream_name2", invite_only=True)
|
||||||
|
result = self.client_patch(
|
||||||
|
f"/json/streams/{stream.id}",
|
||||||
|
{"can_remove_subscribers_group_id": orjson.dumps(moderators_system_group.id).decode()},
|
||||||
|
)
|
||||||
|
self.assert_json_error(result, "Invalid stream ID")
|
||||||
|
|
||||||
|
self.subscribe(user_profile, "stream_name2")
|
||||||
|
result = self.client_patch(
|
||||||
|
f"/json/streams/{stream.id}",
|
||||||
|
{"can_remove_subscribers_group_id": orjson.dumps(moderators_system_group.id).decode()},
|
||||||
|
)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
stream = get_stream("stream_name2", realm)
|
||||||
|
self.assertEqual(stream.can_remove_subscribers_group.id, moderators_system_group.id)
|
||||||
|
|
||||||
def test_stream_message_retention_days_on_stream_creation(self) -> None:
|
def test_stream_message_retention_days_on_stream_creation(self) -> None:
|
||||||
"""
|
"""
|
||||||
Only admins can create streams with message_retention_days
|
Only admins can create streams with message_retention_days
|
||||||
|
|
|
@ -30,6 +30,7 @@ from zerver.actions.message_send import (
|
||||||
from zerver.actions.streams import (
|
from zerver.actions.streams import (
|
||||||
bulk_add_subscriptions,
|
bulk_add_subscriptions,
|
||||||
bulk_remove_subscriptions,
|
bulk_remove_subscriptions,
|
||||||
|
do_change_can_remove_subscribers_group,
|
||||||
do_change_stream_description,
|
do_change_stream_description,
|
||||||
do_change_stream_message_retention_days,
|
do_change_stream_message_retention_days,
|
||||||
do_change_stream_permission,
|
do_change_stream_permission,
|
||||||
|
@ -79,6 +80,7 @@ from zerver.lib.topic import (
|
||||||
messages_for_topic,
|
messages_for_topic,
|
||||||
)
|
)
|
||||||
from zerver.lib.types import Validator
|
from zerver.lib.types import Validator
|
||||||
|
from zerver.lib.user_groups import access_user_group_for_setting
|
||||||
from zerver.lib.utils import assert_is_not_none
|
from zerver.lib.utils import assert_is_not_none
|
||||||
from zerver.lib.validator import (
|
from zerver.lib.validator import (
|
||||||
check_bool,
|
check_bool,
|
||||||
|
@ -266,6 +268,7 @@ def update_stream_backend(
|
||||||
message_retention_days: Optional[Union[int, str]] = REQ(
|
message_retention_days: Optional[Union[int, str]] = REQ(
|
||||||
json_validator=check_string_or_int, default=None
|
json_validator=check_string_or_int, default=None
|
||||||
),
|
),
|
||||||
|
can_remove_subscribers_group_id: Optional[int] = REQ(json_validator=check_int, default=None),
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
# We allow realm administrators to to update the stream name and
|
# We allow realm administrators to to update the stream name and
|
||||||
# description even for private streams.
|
# description even for private streams.
|
||||||
|
@ -380,6 +383,20 @@ def update_stream_backend(
|
||||||
if stream_post_policy is not None:
|
if stream_post_policy is not None:
|
||||||
do_change_stream_post_policy(stream, stream_post_policy, acting_user=user_profile)
|
do_change_stream_post_policy(stream, stream_post_policy, acting_user=user_profile)
|
||||||
|
|
||||||
|
if can_remove_subscribers_group_id is not None:
|
||||||
|
if sub is None and stream.invite_only:
|
||||||
|
# Admins cannot change this setting for unsubscribed private streams.
|
||||||
|
raise JsonableError(_("Invalid stream ID"))
|
||||||
|
|
||||||
|
user_group = access_user_group_for_setting(
|
||||||
|
can_remove_subscribers_group_id,
|
||||||
|
user_profile,
|
||||||
|
setting_name="can_remove_subscribers_group",
|
||||||
|
require_system_group=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
do_change_can_remove_subscribers_group(stream, user_group, acting_user=user_profile)
|
||||||
|
|
||||||
return json_success(request)
|
return json_success(request)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue