mirror of https://github.com/zulip/zulip.git
realm: Add new group setting for web-public stream creation.
This commit is contained in:
parent
c03839f42f
commit
a15bc5e264
|
@ -20,6 +20,13 @@ format used by the Zulip server that they are interacting with.
|
||||||
|
|
||||||
## Changes in Zulip 10.0
|
## Changes in Zulip 10.0
|
||||||
|
|
||||||
|
**Feature level 280**
|
||||||
|
|
||||||
|
* `PATCH /realm`, [`POST /register`](/api/register-queue),
|
||||||
|
[`GET /events`](/api/get-events): Added `can_create_web_public_channel_group`
|
||||||
|
realm setting, which is a [group-setting value](/api/group-setting-values)
|
||||||
|
describing the set of users with permission to create web-public channels.
|
||||||
|
|
||||||
Feature levels 278-279 are reserved for future use in 9.x maintenance
|
Feature levels 278-279 are reserved for future use in 9.x maintenance
|
||||||
releases.
|
releases.
|
||||||
|
|
||||||
|
|
|
@ -1049,6 +1049,7 @@ group_setting_update_data_type = DictType(
|
||||||
("can_access_all_users_group", int),
|
("can_access_all_users_group", int),
|
||||||
("can_create_public_channel_group", group_setting_type),
|
("can_create_public_channel_group", group_setting_type),
|
||||||
("can_create_private_channel_group", group_setting_type),
|
("can_create_private_channel_group", group_setting_type),
|
||||||
|
("can_create_web_public_channel_group", group_setting_type),
|
||||||
("direct_message_initiator_group", group_setting_type),
|
("direct_message_initiator_group", group_setting_type),
|
||||||
("direct_message_permission_group", group_setting_type),
|
("direct_message_permission_group", group_setting_type),
|
||||||
],
|
],
|
||||||
|
|
|
@ -300,9 +300,8 @@ def access_user_group_for_setting(
|
||||||
)
|
)
|
||||||
return named_user_group.usergroup_ptr
|
return named_user_group.usergroup_ptr
|
||||||
|
|
||||||
# The API would not allow passing the setting parameter as a Dict
|
if permission_configuration.require_system_group:
|
||||||
# if require_system_group is true for a setting.
|
raise SystemGroupRequiredError(setting_name)
|
||||||
assert permission_configuration.require_system_group is False
|
|
||||||
|
|
||||||
user_group = update_or_create_user_group_for_setting(
|
user_group = update_or_create_user_group_for_setting(
|
||||||
user_profile.realm,
|
user_profile.realm,
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 5.0.6 on 2024-07-01 11:48
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("zerver", "0558_realmuserdefault_web_animate_image_previews_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="realm",
|
||||||
|
name="can_create_web_public_channel_group",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.RESTRICT,
|
||||||
|
related_name="+",
|
||||||
|
to="zerver.usergroup",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,61 @@
|
||||||
|
# Generated by Django 5.0.6 on 2024-07-01 11:53
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||||
|
from django.db.migrations.state import StateApps
|
||||||
|
from django.db.models import OuterRef
|
||||||
|
|
||||||
|
|
||||||
|
def set_can_create_web_public_channel_group_for_existing_realms(
|
||||||
|
apps: StateApps, schema_editor: BaseDatabaseSchemaEditor
|
||||||
|
) -> None:
|
||||||
|
Realm = apps.get_model("zerver", "Realm")
|
||||||
|
NamedUserGroup = apps.get_model("zerver", "NamedUserGroup")
|
||||||
|
|
||||||
|
ADMINS_ONLY = 2
|
||||||
|
MODERATORS_ONLY = 4
|
||||||
|
NOBODY = 6
|
||||||
|
OWNERS_ONLY = 7
|
||||||
|
|
||||||
|
Realm.objects.filter(
|
||||||
|
can_create_web_public_channel_group=None, create_web_public_stream_policy=ADMINS_ONLY
|
||||||
|
).update(
|
||||||
|
can_create_web_public_channel_group=NamedUserGroup.objects.filter(
|
||||||
|
name="role:administrators", realm=OuterRef("id"), is_system_group=True
|
||||||
|
).values("pk")
|
||||||
|
)
|
||||||
|
Realm.objects.filter(
|
||||||
|
can_create_web_public_channel_group=None, create_web_public_stream_policy=MODERATORS_ONLY
|
||||||
|
).update(
|
||||||
|
can_create_web_public_channel_group=NamedUserGroup.objects.filter(
|
||||||
|
name="role:moderators", realm=OuterRef("id"), is_system_group=True
|
||||||
|
).values("pk")
|
||||||
|
)
|
||||||
|
Realm.objects.filter(
|
||||||
|
can_create_web_public_channel_group=None, create_web_public_stream_policy=NOBODY
|
||||||
|
).update(
|
||||||
|
can_create_web_public_channel_group=NamedUserGroup.objects.filter(
|
||||||
|
name="role:nobody", realm=OuterRef("id"), is_system_group=True
|
||||||
|
).values("pk")
|
||||||
|
)
|
||||||
|
Realm.objects.filter(
|
||||||
|
can_create_web_public_channel_group=None, create_web_public_stream_policy=OWNERS_ONLY
|
||||||
|
).update(
|
||||||
|
can_create_web_public_channel_group=NamedUserGroup.objects.filter(
|
||||||
|
name="role:owners", realm=OuterRef("id"), is_system_group=True
|
||||||
|
).values("pk")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("zerver", "0559_realm_can_create_web_public_channel_group"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(
|
||||||
|
set_can_create_web_public_channel_group_for_existing_realms,
|
||||||
|
elidable=True,
|
||||||
|
reverse_code=migrations.RunPython.noop,
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Generated by Django 5.0.6 on 2024-07-01 12:00
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("zerver", "0560_set_can_create_web_public_channel_group"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="realm",
|
||||||
|
name="can_create_web_public_channel_group",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.RESTRICT,
|
||||||
|
related_name="+",
|
||||||
|
to="zerver.usergroup",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -308,6 +308,9 @@ class Realm(models.Model): # type: ignore[django-manager-missing] # django-stub
|
||||||
can_create_private_channel_group = models.ForeignKey(
|
can_create_private_channel_group = models.ForeignKey(
|
||||||
"UserGroup", on_delete=models.RESTRICT, related_name="+"
|
"UserGroup", on_delete=models.RESTRICT, related_name="+"
|
||||||
)
|
)
|
||||||
|
can_create_web_public_channel_group = models.ForeignKey(
|
||||||
|
"UserGroup", on_delete=models.RESTRICT, related_name="+"
|
||||||
|
)
|
||||||
|
|
||||||
# Who in the organization is allowed to delete messages they themselves sent.
|
# Who in the organization is allowed to delete messages they themselves sent.
|
||||||
delete_own_message_policy = models.PositiveSmallIntegerField(
|
delete_own_message_policy = models.PositiveSmallIntegerField(
|
||||||
|
@ -743,11 +746,27 @@ class Realm(models.Model): # type: ignore[django-manager-missing] # django-stub
|
||||||
default_group_name=SystemGroups.EVERYONE,
|
default_group_name=SystemGroups.EVERYONE,
|
||||||
id_field_name="direct_message_permission_group_id",
|
id_field_name="direct_message_permission_group_id",
|
||||||
),
|
),
|
||||||
|
can_create_web_public_channel_group=GroupPermissionSetting(
|
||||||
|
require_system_group=True,
|
||||||
|
allow_internet_group=False,
|
||||||
|
allow_owners_group=True,
|
||||||
|
allow_nobody_group=True,
|
||||||
|
allow_everyone_group=False,
|
||||||
|
default_group_name=SystemGroups.OWNERS,
|
||||||
|
id_field_name="can_create_web_public_channel_group_id",
|
||||||
|
allowed_system_groups=[
|
||||||
|
SystemGroups.MODERATORS,
|
||||||
|
SystemGroups.ADMINISTRATORS,
|
||||||
|
SystemGroups.OWNERS,
|
||||||
|
SystemGroups.NOBODY,
|
||||||
|
],
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
REALM_PERMISSION_GROUP_SETTINGS_WITH_NEW_API_FORMAT = [
|
REALM_PERMISSION_GROUP_SETTINGS_WITH_NEW_API_FORMAT = [
|
||||||
"can_create_private_channel_group",
|
"can_create_private_channel_group",
|
||||||
"can_create_public_channel_group",
|
"can_create_public_channel_group",
|
||||||
|
"can_create_web_public_channel_group",
|
||||||
"direct_message_initiator_group",
|
"direct_message_initiator_group",
|
||||||
"direct_message_permission_group",
|
"direct_message_permission_group",
|
||||||
]
|
]
|
||||||
|
@ -1115,6 +1134,8 @@ def get_realm_with_settings(realm_id: int) -> Realm:
|
||||||
"can_create_public_channel_group__named_user_group",
|
"can_create_public_channel_group__named_user_group",
|
||||||
"can_create_private_channel_group",
|
"can_create_private_channel_group",
|
||||||
"can_create_private_channel_group__named_user_group",
|
"can_create_private_channel_group__named_user_group",
|
||||||
|
"can_create_web_public_channel_group",
|
||||||
|
"can_create_web_public_channel_group__named_user_group",
|
||||||
"direct_message_initiator_group",
|
"direct_message_initiator_group",
|
||||||
"direct_message_initiator_group__named_user_group",
|
"direct_message_initiator_group__named_user_group",
|
||||||
"direct_message_permission_group",
|
"direct_message_permission_group",
|
||||||
|
|
|
@ -4283,6 +4283,21 @@ paths:
|
||||||
**Changes**: New in Zulip 9.0 (feature level 266). Previously
|
**Changes**: New in Zulip 9.0 (feature level 266). Previously
|
||||||
`realm_create_private_stream_policy` field used to control the
|
`realm_create_private_stream_policy` field used to control the
|
||||||
permission to create private channels.
|
permission to create private channels.
|
||||||
|
can_create_web_public_channel_group:
|
||||||
|
allOf:
|
||||||
|
- $ref: "#/components/schemas/GroupSettingValue"
|
||||||
|
- description: |
|
||||||
|
A [group-setting value](/api/group-setting-values) defining
|
||||||
|
the set of users who have permission to create web-public
|
||||||
|
channels in this organization.
|
||||||
|
|
||||||
|
This setting can only be set to `"role:moderators"`,
|
||||||
|
`"role:administrators"`, `"role:owners"` and
|
||||||
|
`"role:nobody"` system groups.
|
||||||
|
|
||||||
|
**Changes**: New in Zulip 10.0 (feature level 280). Previously
|
||||||
|
`realm_create_web_public_stream_policy` field used to control
|
||||||
|
the permission to create web-public channels.
|
||||||
create_web_public_stream_policy:
|
create_web_public_stream_policy:
|
||||||
type: integer
|
type: integer
|
||||||
description: |
|
description: |
|
||||||
|
@ -15440,6 +15455,26 @@ paths:
|
||||||
**Changes**: New in Zulip 9.0 (feature level 266). Previously
|
**Changes**: New in Zulip 9.0 (feature level 266). Previously
|
||||||
`realm_create_private_stream_policy` field used to control the
|
`realm_create_private_stream_policy` field used to control the
|
||||||
permission to create private channels.
|
permission to create private channels.
|
||||||
|
realm_can_create_web_public_channel_group:
|
||||||
|
allOf:
|
||||||
|
- $ref: "#/components/schemas/GroupSettingValue"
|
||||||
|
- description: |
|
||||||
|
A [group-setting value](/api/group-setting-values) defining
|
||||||
|
the set of users who have permission to create web-public
|
||||||
|
channels in this organization.
|
||||||
|
|
||||||
|
This setting can only be set to `"role:moderators"`,
|
||||||
|
`"role:administrators"`, `"role:owners"` and
|
||||||
|
`"role:nobody"` system groups.
|
||||||
|
|
||||||
|
Has no effect and should not be displayed in settings UI
|
||||||
|
unless the Zulip server has the `WEB_PUBLIC_STREAMS_ENABLED`
|
||||||
|
server-level setting enabled and the organization has enabled
|
||||||
|
the `enable_spectator_access` realm setting.
|
||||||
|
|
||||||
|
**Changes**: New in Zulip 10.0 (feature level 280). Previously
|
||||||
|
`realm_create_web_public_stream_policy` field used to control
|
||||||
|
the permission to create web-public channels.
|
||||||
realm_create_public_stream_policy:
|
realm_create_public_stream_policy:
|
||||||
type: integer
|
type: integer
|
||||||
deprecated: true
|
deprecated: true
|
||||||
|
|
|
@ -3772,6 +3772,8 @@ class RealmPropertyActionTest(BaseAction):
|
||||||
self.do_set_realm_permission_group_setting_test(prop)
|
self.do_set_realm_permission_group_setting_test(prop)
|
||||||
|
|
||||||
for prop in Realm.REALM_PERMISSION_GROUP_SETTINGS_WITH_NEW_API_FORMAT:
|
for prop in Realm.REALM_PERMISSION_GROUP_SETTINGS_WITH_NEW_API_FORMAT:
|
||||||
|
if prop == "can_create_web_public_channel_group":
|
||||||
|
continue
|
||||||
with self.settings(SEND_DIGEST_EMAILs=True):
|
with self.settings(SEND_DIGEST_EMAILs=True):
|
||||||
self.do_set_realm_permission_group_setting_to_anonymous_groups_test(prop)
|
self.do_set_realm_permission_group_setting_to_anonymous_groups_test(prop)
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,7 @@ class HomeTest(ZulipTestCase):
|
||||||
"realm_can_access_all_users_group",
|
"realm_can_access_all_users_group",
|
||||||
"realm_can_create_private_channel_group",
|
"realm_can_create_private_channel_group",
|
||||||
"realm_can_create_public_channel_group",
|
"realm_can_create_public_channel_group",
|
||||||
|
"realm_can_create_web_public_channel_group",
|
||||||
"realm_create_multiuse_invite_group",
|
"realm_create_multiuse_invite_group",
|
||||||
"realm_create_private_stream_policy",
|
"realm_create_private_stream_policy",
|
||||||
"realm_create_public_stream_policy",
|
"realm_create_public_stream_policy",
|
||||||
|
|
|
@ -1664,6 +1664,60 @@ class RealmAPITest(ZulipTestCase):
|
||||||
realm = self.update_with_api(setting_name, value)
|
realm = self.update_with_api(setting_name, value)
|
||||||
self.assertEqual(getattr(realm, setting_name), user_group.usergroup_ptr)
|
self.assertEqual(getattr(realm, setting_name), user_group.usergroup_ptr)
|
||||||
|
|
||||||
|
if setting_permission_configuration.require_system_group:
|
||||||
|
leadership_group = NamedUserGroup.objects.get(name="leadership", realm=realm)
|
||||||
|
|
||||||
|
value = orjson.dumps(leadership_group.id).decode()
|
||||||
|
if setting_name in Realm.REALM_PERMISSION_GROUP_SETTINGS_WITH_NEW_API_FORMAT:
|
||||||
|
value = orjson.dumps(
|
||||||
|
{
|
||||||
|
"new": leadership_group.id,
|
||||||
|
}
|
||||||
|
).decode()
|
||||||
|
|
||||||
|
result = self.client_patch("/json/realm", {setting_name: value})
|
||||||
|
self.assert_json_error(result, f"'{setting_name}' must be a system user group.")
|
||||||
|
|
||||||
|
if setting_name in Realm.REALM_PERMISSION_GROUP_SETTINGS_WITH_NEW_API_FORMAT:
|
||||||
|
admins_group = NamedUserGroup.objects.get(
|
||||||
|
name=SystemGroups.ADMINISTRATORS, realm=realm
|
||||||
|
)
|
||||||
|
moderators_group = NamedUserGroup.objects.get(
|
||||||
|
name=SystemGroups.MODERATORS, realm=realm
|
||||||
|
)
|
||||||
|
value = orjson.dumps(
|
||||||
|
{
|
||||||
|
"new": {
|
||||||
|
"direct_members": [],
|
||||||
|
"direct_subgroups": [admins_group.id, leadership_group.id],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).decode()
|
||||||
|
result = self.client_patch("/json/realm", {setting_name: value})
|
||||||
|
self.assert_json_error(result, f"'{setting_name}' must be a system user group.")
|
||||||
|
|
||||||
|
value = orjson.dumps(
|
||||||
|
{
|
||||||
|
"new": {
|
||||||
|
"direct_members": [],
|
||||||
|
"direct_subgroups": [admins_group.id, moderators_group.id],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).decode()
|
||||||
|
result = self.client_patch("/json/realm", {setting_name: value})
|
||||||
|
self.assert_json_error(result, f"'{setting_name}' must be a system user group.")
|
||||||
|
|
||||||
|
value = orjson.dumps(
|
||||||
|
{
|
||||||
|
"new": {
|
||||||
|
"direct_members": [],
|
||||||
|
"direct_subgroups": [admins_group.id],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).decode()
|
||||||
|
realm = self.update_with_api(setting_name, value)
|
||||||
|
self.assertEqual(getattr(realm, setting_name), admins_group.usergroup_ptr)
|
||||||
|
|
||||||
def do_test_realm_permission_group_setting_update_api_with_anonymous_groups(
|
def do_test_realm_permission_group_setting_update_api_with_anonymous_groups(
|
||||||
self, setting_name: str
|
self, setting_name: str
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -1897,14 +1951,18 @@ class RealmAPITest(ZulipTestCase):
|
||||||
with self.subTest(property=prop):
|
with self.subTest(property=prop):
|
||||||
self.do_test_realm_update_api(prop)
|
self.do_test_realm_update_api(prop)
|
||||||
|
|
||||||
|
check_add_user_group(
|
||||||
|
get_realm("zulip"), "leadership", [self.example_user("hamlet")], acting_user=None
|
||||||
|
)
|
||||||
for prop in Realm.REALM_PERMISSION_GROUP_SETTINGS:
|
for prop in Realm.REALM_PERMISSION_GROUP_SETTINGS:
|
||||||
with self.subTest(property=prop):
|
with self.subTest(property=prop):
|
||||||
self.do_test_realm_permission_group_setting_update_api(prop)
|
self.do_test_realm_permission_group_setting_update_api(prop)
|
||||||
|
|
||||||
check_add_user_group(
|
|
||||||
get_realm("zulip"), "leadership", [self.example_user("hamlet")], acting_user=None
|
|
||||||
)
|
|
||||||
for prop in Realm.REALM_PERMISSION_GROUP_SETTINGS_WITH_NEW_API_FORMAT:
|
for prop in Realm.REALM_PERMISSION_GROUP_SETTINGS_WITH_NEW_API_FORMAT:
|
||||||
|
if prop == "can_create_web_public_channel_group":
|
||||||
|
# This setting supports the new API format but
|
||||||
|
# allows only system groups.
|
||||||
|
continue
|
||||||
with self.subTest(property=prop):
|
with self.subTest(property=prop):
|
||||||
self.do_test_realm_permission_group_setting_update_api_with_anonymous_groups(prop)
|
self.do_test_realm_permission_group_setting_update_api_with_anonymous_groups(prop)
|
||||||
|
|
||||||
|
|
|
@ -144,6 +144,7 @@ def update_realm(
|
||||||
bot_creation_policy: Json[BotCreationPolicyEnum] | None = None,
|
bot_creation_policy: Json[BotCreationPolicyEnum] | None = None,
|
||||||
can_create_public_channel_group: Json[GroupSettingChangeRequest] | None = None,
|
can_create_public_channel_group: Json[GroupSettingChangeRequest] | None = None,
|
||||||
can_create_private_channel_group: Json[GroupSettingChangeRequest] | None = None,
|
can_create_private_channel_group: Json[GroupSettingChangeRequest] | None = None,
|
||||||
|
can_create_web_public_channel_group: Json[GroupSettingChangeRequest] | None = None,
|
||||||
direct_message_initiator_group: Json[GroupSettingChangeRequest] | None = None,
|
direct_message_initiator_group: Json[GroupSettingChangeRequest] | None = None,
|
||||||
direct_message_permission_group: Json[GroupSettingChangeRequest] | None = None,
|
direct_message_permission_group: Json[GroupSettingChangeRequest] | None = None,
|
||||||
create_web_public_stream_policy: Json[CreateWebPublicStreamPolicyEnum] | None = None,
|
create_web_public_stream_policy: Json[CreateWebPublicStreamPolicyEnum] | None = None,
|
||||||
|
|
Loading…
Reference in New Issue