settings: Remove create_public_stream_policy.

This commit removes create_public_stream_policy setting
since public channel creation permissions are now handled
by group-based setting.

We still pass "realm_create_public_stream_policy" in
"/register" response though for older clients with its
value being set depending on the value of group based
setting. If we cannot set its value to an appropriate
enum corresponding to the group setting, then we set
it to "Members only" considering that server will not
allow the users without permissions to create public
channels but the client can make sure that UI is
available to the users who have permission.
This commit is contained in:
Sahil Batra 2024-05-30 07:34:44 +05:30 committed by Tim Abbott
parent f98a3fc684
commit 222995b1be
13 changed files with 90 additions and 38 deletions

View File

@ -26,6 +26,14 @@ format used by the Zulip server that they are interacting with.
[`GET /events`](/api/get-events): Added `can_create_public_channel_group` [`GET /events`](/api/get-events): Added `can_create_public_channel_group`
realm setting, which is a [group-setting value](/api/group-setting-values) realm setting, which is a [group-setting value](/api/group-setting-values)
describing the set of users with permission to create channels. describing the set of users with permission to create channels.
* `PATCH /realm`, [`GET /events`](/api/get-events): Removed
`create_public_stream_policy` property, as the permission to create public
channels is now controlled by `can_create_public_channel_group` setting.
* [`POST /register`](/api/register-queue): `realm_create_public_stream_policy`
field is deprecated, having been replaced by `can_create_public_channel_group`.
Notably, this backwards-compatible `realm_create_public_stream_policy` value
now contains the superset of the true value that best approximates the actual
permission setting.
**Feature level 263**: **Feature level 263**:

View File

@ -33,7 +33,7 @@ DESKTOP_WARNING_VERSION = "5.9.3"
# Changes should be accompanied by documentation explaining what the # Changes should be accompanied by documentation explaining what the
# new level means in api_docs/changelog.md, as well as "**Changes**" # new level means in api_docs/changelog.md, as well as "**Changes**"
# entries in the endpoint's documentation in `zulip.yaml`. # entries in the endpoint's documentation in `zulip.yaml`.
API_FEATURE_LEVEL = 263 API_FEATURE_LEVEL = 264
# Bump the minor PROVISION_VERSION to indicate that folks should provision # Bump the minor PROVISION_VERSION to indicate that folks should provision
# only when going from an old version of the code to a newer version. Bump # only when going from an old version of the code to a newer version. Bump

View File

@ -270,13 +270,6 @@ exports.fixtures = {
value: 2, value: 2,
}, },
realm__update__create_public_stream_policy: {
type: "realm",
op: "update",
property: "create_public_stream_policy",
value: 2,
},
realm__update__create_web_public_stream_policy: { realm__update__create_web_public_stream_policy: {
type: "realm", type: "realm",
op: "update", op: "update",

View File

@ -121,9 +121,6 @@ def set_realm_permissions_based_on_org_type(realm: Realm) -> None:
): ):
# Limit user creation to administrators. # Limit user creation to administrators.
realm.invite_to_realm_policy = InviteToRealmPolicyEnum.ADMINS_ONLY realm.invite_to_realm_policy = InviteToRealmPolicyEnum.ADMINS_ONLY
# Restrict public stream creation to staff, but allow private
# streams (useful for study groups, etc.).
realm.create_public_stream_policy = CommonPolicyEnum.ADMINS_ONLY
# Don't allow members (students) to manage user groups or # Don't allow members (students) to manage user groups or
# stream subscriptions. # stream subscriptions.
realm.user_group_edit_policy = CommonPolicyEnum.MODERATORS_ONLY realm.user_group_edit_policy = CommonPolicyEnum.MODERATORS_ONLY

View File

@ -89,7 +89,12 @@ from zerver.models.custom_profile_fields import custom_profile_fields_for_realm
from zerver.models.linkifiers import linkifiers_for_realm from zerver.models.linkifiers import linkifiers_for_realm
from zerver.models.realm_emoji import get_all_custom_emoji_for_realm from zerver.models.realm_emoji import get_all_custom_emoji_for_realm
from zerver.models.realm_playgrounds import get_realm_playgrounds from zerver.models.realm_playgrounds import get_realm_playgrounds
from zerver.models.realms import CommonMessagePolicyEnum, EditTopicPolicyEnum, get_realm_domains from zerver.models.realms import (
CommonMessagePolicyEnum,
EditTopicPolicyEnum,
get_corresponding_policy_value_for_group_setting,
get_realm_domains,
)
from zerver.models.streams import get_default_stream_groups from zerver.models.streams import get_default_stream_groups
from zerver.tornado.django_api import get_user_events, request_event_queue from zerver.tornado.django_api import get_user_events, request_event_queue
from zproject.backends import email_auth_enabled, password_auth_enabled from zproject.backends import email_auth_enabled, password_auth_enabled
@ -287,6 +292,12 @@ def fetch_initial_state_data(
state["realm_" + setting_name] = getattr(realm, permission_configuration.id_field_name) state["realm_" + setting_name] = getattr(realm, permission_configuration.id_field_name)
state["realm_create_public_stream_policy"] = (
get_corresponding_policy_value_for_group_setting(
realm, "can_create_public_channel_group", Realm.COMMON_POLICY_TYPES
)
)
# Most state is handled via the property_types framework; # Most state is handled via the property_types framework;
# these manual entries are for those realm settings that don't # these manual entries are for those realm settings that don't
# fit into that framework. # fit into that framework.
@ -1235,6 +1246,13 @@ def apply_event(
state["realm_email_auth_enabled"] = value["Email"]["enabled"] state["realm_email_auth_enabled"] = value["Email"]["enabled"]
if key == "can_create_public_channel_group": if key == "can_create_public_channel_group":
state["realm_create_public_stream_policy"] = (
get_corresponding_policy_value_for_group_setting(
user_profile.realm,
"can_create_public_channel_group",
Realm.COMMON_POLICY_TYPES,
)
)
state["can_create_public_streams"] = user_profile.has_permission(key) state["can_create_public_streams"] = user_profile.has_permission(key)
state["can_create_streams"] = ( state["can_create_streams"] = (
state["can_create_private_streams"] state["can_create_private_streams"]

View File

@ -0,0 +1,16 @@
# Generated by Django 5.0.6 on 2024-05-30 08:58
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("zerver", "0534_alter_realm_can_create_public_channel_group"),
]
operations = [
migrations.RemoveField(
model_name="realm",
name="create_public_stream_policy",
),
]

View File

@ -263,6 +263,16 @@ class Realm(models.Model): # type: ignore[django-manager-missing] # django-stub
POLICY_NOBODY = 6 POLICY_NOBODY = 6
POLICY_OWNERS_ONLY = 7 POLICY_OWNERS_ONLY = 7
SYSTEM_GROUPS_ENUM_MAP = {
SystemGroups.OWNERS: POLICY_OWNERS_ONLY,
SystemGroups.ADMINISTRATORS: POLICY_ADMINS_ONLY,
SystemGroups.MODERATORS: POLICY_MODERATORS_ONLY,
SystemGroups.FULL_MEMBERS: POLICY_FULL_MEMBERS_ONLY,
SystemGroups.MEMBERS: POLICY_MEMBERS_ONLY,
SystemGroups.EVERYONE: POLICY_EVERYONE,
SystemGroups.NOBODY: POLICY_NOBODY,
}
COMMON_POLICY_TYPES = [field.value for field in CommonPolicyEnum] COMMON_POLICY_TYPES = [field.value for field in CommonPolicyEnum]
COMMON_MESSAGE_POLICY_TYPES = [field.value for field in CommonMessagePolicyEnum] COMMON_MESSAGE_POLICY_TYPES = [field.value for field in CommonMessagePolicyEnum]
@ -293,9 +303,6 @@ class Realm(models.Model): # type: ignore[django-manager-missing] # django-stub
) )
# Who in the organization is allowed to create streams. # Who in the organization is allowed to create streams.
create_public_stream_policy = models.PositiveSmallIntegerField(
default=CommonPolicyEnum.MEMBERS_ONLY
)
create_private_stream_policy = models.PositiveSmallIntegerField( create_private_stream_policy = models.PositiveSmallIntegerField(
default=CommonPolicyEnum.MEMBERS_ONLY default=CommonPolicyEnum.MEMBERS_ONLY
) )
@ -638,7 +645,6 @@ class Realm(models.Model): # type: ignore[django-manager-missing] # django-stub
avatar_changes_disabled=bool, avatar_changes_disabled=bool,
bot_creation_policy=int, bot_creation_policy=int,
create_private_stream_policy=int, create_private_stream_policy=int,
create_public_stream_policy=int,
create_web_public_stream_policy=int, create_web_public_stream_policy=int,
default_code_block_language=str, default_code_block_language=str,
default_language=str, default_language=str,
@ -1093,6 +1099,27 @@ def get_org_type_display_name(org_type: int) -> str:
return "" return ""
def get_corresponding_policy_value_for_group_setting(
realm: Realm,
group_setting_name: str,
valid_policy_enums: List[int],
) -> int:
setting_group = getattr(realm, group_setting_name)
if (
hasattr(setting_group, "named_user_group")
and setting_group.named_user_group.is_system_group
):
enum_policy_value = Realm.SYSTEM_GROUPS_ENUM_MAP[setting_group.named_user_group.name]
if enum_policy_value in valid_policy_enums:
return enum_policy_value
# If the group setting is not set to one of the role based groups
# that the previous enum setting allowed, then just return the
# enum value corresponding to largest group.
assert valid_policy_enums == Realm.COMMON_POLICY_TYPES
return Realm.POLICY_MEMBERS_ONLY
class RealmDomain(models.Model): class RealmDomain(models.Model):
"""For an organization with emails_restricted_to_domains enabled, the list of """For an organization with emails_restricted_to_domains enabled, the list of
allowed domains""" allowed domains"""

View File

@ -752,7 +752,6 @@ class UserProfile(AbstractBaseUser, PermissionsMixin, UserBaseSettings):
"can_create_public_channel_group", "can_create_public_channel_group",
"create_multiuse_invite_group", "create_multiuse_invite_group",
"create_private_stream_policy", "create_private_stream_policy",
"create_public_stream_policy",
"create_web_public_stream_policy", "create_web_public_stream_policy",
"delete_own_message_policy", "delete_own_message_policy",
"edit_topic_policy", "edit_topic_policy",

View File

@ -4240,14 +4240,6 @@ paths:
**Changes**: New in Zulip 9.0 (feature level 264). Previously **Changes**: New in Zulip 9.0 (feature level 264). Previously
`realm_create_public_stream_policy` field used to control the `realm_create_public_stream_policy` field used to control the
permission to create public channels. permission to create public channels.
create_public_stream_policy:
type: integer
description: |
The [policy](/api/roles-and-permissions#permission-levels)
for which users can create public channels in this organization.
**Changes**: Before Zulip 5.0 (feature level 102), permission to
create channels was controlled by the `create_stream_policy` setting.
create_private_stream_policy: create_private_stream_policy:
type: integer type: integer
description: | description: |
@ -15252,19 +15244,30 @@ paths:
permission to create public channels. permission to create public channels.
realm_create_public_stream_policy: realm_create_public_stream_policy:
type: integer type: integer
deprecated: true
description: | description: |
Present if `realm` is present in `fetch_event_types`. Present if `realm` is present in `fetch_event_types`.
The [policy][permission-level] for which users can create public channels A deprecated representation of a superset of the users who
in this organization. have permission to create public channels in the organization,
available for backwards-compatibility. Clients should use
`can_create_public_channel_group` instead.
It is an enum with the following possible values, corresponding
to roles/system groups:
- 1 = Members only - 1 = Members only
- 2 = Admins only - 2 = Admins only
- 3 = [Full members][calc-full-member] only - 3 = [Full members][calc-full-member] only
- 4 = Admins and moderators only - 4 = Admins and moderators only
**Changes**: Before Zulip 5.0 (feature level 102), permission to **Changes**: Deprecated in Zulip 9.0 (feature level 264) and
create channels was controlled by the `realm_create_stream_policy` setting. replaced by `realm_can_create_public_channel_group`, which
supports finer resolution of configurations, resulting in this
property being inaccurate following that transition.
Before Zulip 5.0 (feature level 102), permission to create
channels was controlled by the `realm_create_stream_policy` setting.
[permission-level]: /api/roles-and-permissions#permission-levels [permission-level]: /api/roles-and-permissions#permission-levels
[calc-full-member]: /api/roles-and-permissions#determining-if-a-user-is-a-full-member [calc-full-member]: /api/roles-and-permissions#determining-if-a-user-is-a-full-member

View File

@ -3397,7 +3397,6 @@ class RealmPropertyActionTest(BaseAction):
message_retention_days=[10, 20], message_retention_days=[10, 20],
name=["Zulip", "New Name"], name=["Zulip", "New Name"],
waiting_period_threshold=[1000, 2000], waiting_period_threshold=[1000, 2000],
create_public_stream_policy=Realm.COMMON_POLICY_TYPES,
create_private_stream_policy=Realm.COMMON_POLICY_TYPES, create_private_stream_policy=Realm.COMMON_POLICY_TYPES,
create_web_public_stream_policy=Realm.CREATE_WEB_PUBLIC_STREAM_POLICY_TYPES, create_web_public_stream_policy=Realm.CREATE_WEB_PUBLIC_STREAM_POLICY_TYPES,
invite_to_stream_policy=Realm.COMMON_POLICY_TYPES, invite_to_stream_policy=Realm.COMMON_POLICY_TYPES,

View File

@ -111,7 +111,6 @@ class RealmTest(ZulipTestCase):
) )
self.assertEqual(realm.can_create_public_channel_group_id, admins_group.id) self.assertEqual(realm.can_create_public_channel_group_id, admins_group.id)
self.assertEqual(realm.create_public_stream_policy, CommonPolicyEnum.ADMINS_ONLY)
self.assertEqual(realm.create_private_stream_policy, CommonPolicyEnum.MEMBERS_ONLY) self.assertEqual(realm.create_private_stream_policy, CommonPolicyEnum.MEMBERS_ONLY)
self.assertEqual(realm.invite_to_realm_policy, InviteToRealmPolicyEnum.ADMINS_ONLY) self.assertEqual(realm.invite_to_realm_policy, InviteToRealmPolicyEnum.ADMINS_ONLY)
self.assertEqual( self.assertEqual(
@ -133,7 +132,6 @@ class RealmTest(ZulipTestCase):
) )
self.assertEqual(realm.can_create_public_channel_group_id, admins_group.id) self.assertEqual(realm.can_create_public_channel_group_id, admins_group.id)
self.assertEqual(realm.create_public_stream_policy, CommonPolicyEnum.ADMINS_ONLY)
self.assertEqual(realm.create_private_stream_policy, CommonPolicyEnum.MEMBERS_ONLY) self.assertEqual(realm.create_private_stream_policy, CommonPolicyEnum.MEMBERS_ONLY)
self.assertEqual(realm.invite_to_realm_policy, InviteToRealmPolicyEnum.ADMINS_ONLY) self.assertEqual(realm.invite_to_realm_policy, InviteToRealmPolicyEnum.ADMINS_ONLY)
self.assertEqual( self.assertEqual(
@ -763,7 +761,6 @@ class RealmTest(ZulipTestCase):
invalid_values = dict( invalid_values = dict(
bot_creation_policy=10, bot_creation_policy=10,
create_public_stream_policy=10,
create_private_stream_policy=10, create_private_stream_policy=10,
create_web_public_stream_policy=10, create_web_public_stream_policy=10,
invite_to_stream_policy=10, invite_to_stream_policy=10,
@ -1484,7 +1481,6 @@ class RealmAPITest(ZulipTestCase):
name=["Zulip", "New Name"], name=["Zulip", "New Name"],
waiting_period_threshold=[10, 20], waiting_period_threshold=[10, 20],
create_private_stream_policy=Realm.COMMON_POLICY_TYPES, create_private_stream_policy=Realm.COMMON_POLICY_TYPES,
create_public_stream_policy=Realm.COMMON_POLICY_TYPES,
create_web_public_stream_policy=Realm.CREATE_WEB_PUBLIC_STREAM_POLICY_TYPES, create_web_public_stream_policy=Realm.CREATE_WEB_PUBLIC_STREAM_POLICY_TYPES,
user_group_edit_policy=Realm.COMMON_POLICY_TYPES, user_group_edit_policy=Realm.COMMON_POLICY_TYPES,
private_message_policy=Realm.PRIVATE_MESSAGE_POLICY_TYPES, private_message_policy=Realm.PRIVATE_MESSAGE_POLICY_TYPES,

View File

@ -4613,9 +4613,6 @@ class SubscriptionAPITest(ZulipTestCase):
invitee_user_id = user_profile.id invitee_user_id = user_profile.id
realm = user_profile.realm realm = user_profile.realm
do_set_realm_property(
realm, "create_public_stream_policy", CommonPolicyEnum.MEMBERS_ONLY, acting_user=None
)
do_set_realm_property( do_set_realm_property(
realm, "invite_to_stream_policy", CommonPolicyEnum.ADMINS_ONLY, acting_user=None realm, "invite_to_stream_policy", CommonPolicyEnum.ADMINS_ONLY, acting_user=None
) )

View File

@ -148,7 +148,6 @@ def update_realm(
message_content_allowed_in_email_notifications: Optional[Json[bool]] = None, message_content_allowed_in_email_notifications: Optional[Json[bool]] = None,
bot_creation_policy: Optional[Json[BotCreationPolicyEnum]] = None, bot_creation_policy: Optional[Json[BotCreationPolicyEnum]] = None,
can_create_public_channel_group: Optional[Json[GroupSettingChangeRequest]] = None, can_create_public_channel_group: Optional[Json[GroupSettingChangeRequest]] = None,
create_public_stream_policy: Optional[Json[CommonPolicyEnum]] = None,
create_private_stream_policy: Optional[Json[CommonPolicyEnum]] = None, create_private_stream_policy: Optional[Json[CommonPolicyEnum]] = None,
create_web_public_stream_policy: Optional[Json[CreateWebPublicStreamPolicyEnum]] = None, create_web_public_stream_policy: Optional[Json[CreateWebPublicStreamPolicyEnum]] = None,
invite_to_stream_policy: Optional[Json[CommonPolicyEnum]] = None, invite_to_stream_policy: Optional[Json[CommonPolicyEnum]] = None,