mirror of
https://github.com/zulip/zulip.git
synced 2025-10-23 16:14:02 +00:00
user_groups: Add can_manage_group field in database.
This commit adds a new group level setting can_manage_group for configuring who can manage a group. This commit only adds the field in database and make changes to automatically create single user groups corresponsing to acting user which will be the default value for this setting. Fixes part of #25928.
This commit is contained in:
@@ -754,6 +754,7 @@ def bulk_import_named_user_groups(data: TableData) -> None:
|
|||||||
group["name"],
|
group["name"],
|
||||||
group["description"],
|
group["description"],
|
||||||
group["is_system_group"],
|
group["is_system_group"],
|
||||||
|
group["can_manage_group_id"],
|
||||||
group["can_mention_group_id"],
|
group["can_mention_group_id"],
|
||||||
)
|
)
|
||||||
for group in data["zerver_namedusergroup"]
|
for group in data["zerver_namedusergroup"]
|
||||||
@@ -761,7 +762,7 @@ def bulk_import_named_user_groups(data: TableData) -> None:
|
|||||||
|
|
||||||
query = SQL(
|
query = SQL(
|
||||||
"""
|
"""
|
||||||
INSERT INTO zerver_namedusergroup (usergroup_ptr_id, realm_id, name, description, is_system_group, can_mention_group_id)
|
INSERT INTO zerver_namedusergroup (usergroup_ptr_id, realm_id, name, description, is_system_group, can_manage_group_id, can_mention_group_id)
|
||||||
VALUES %s
|
VALUES %s
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
@@ -598,19 +598,20 @@ def bulk_create_system_user_groups(groups: list[dict[str, str]], realm: Realm) -
|
|||||||
user_group_ids = [id for (id,) in cursor.fetchall()]
|
user_group_ids = [id for (id,) in cursor.fetchall()]
|
||||||
|
|
||||||
rows = [
|
rows = [
|
||||||
SQL("({},{},{},{},{},{})").format(
|
SQL("({},{},{},{},{},{},{})").format(
|
||||||
Literal(user_group_ids[idx]),
|
Literal(user_group_ids[idx]),
|
||||||
Literal(realm.id),
|
Literal(realm.id),
|
||||||
Literal(group["name"]),
|
Literal(group["name"]),
|
||||||
Literal(group["description"]),
|
Literal(group["description"]),
|
||||||
Literal(True),
|
Literal(True),
|
||||||
Literal(initial_group_setting_value),
|
Literal(initial_group_setting_value),
|
||||||
|
Literal(initial_group_setting_value),
|
||||||
)
|
)
|
||||||
for idx, group in enumerate(groups)
|
for idx, group in enumerate(groups)
|
||||||
]
|
]
|
||||||
query = SQL(
|
query = SQL(
|
||||||
"""
|
"""
|
||||||
INSERT INTO zerver_namedusergroup (usergroup_ptr_id, realm_id, name, description, is_system_group, can_mention_group_id)
|
INSERT INTO zerver_namedusergroup (usergroup_ptr_id, realm_id, name, description, is_system_group, can_manage_group_id, can_mention_group_id)
|
||||||
VALUES {rows}
|
VALUES {rows}
|
||||||
"""
|
"""
|
||||||
).format(rows=SQL(", ").join(rows))
|
).format(rows=SQL(", ").join(rows))
|
||||||
@@ -691,7 +692,9 @@ def create_system_user_groups_for_realm(realm: Realm) -> dict[int, NamedUserGrou
|
|||||||
for group in system_user_groups_list:
|
for group in system_user_groups_list:
|
||||||
user_group = set_defaults_for_group_settings(group, {}, system_groups_name_dict)
|
user_group = set_defaults_for_group_settings(group, {}, system_groups_name_dict)
|
||||||
groups_with_updated_settings.append(user_group)
|
groups_with_updated_settings.append(user_group)
|
||||||
NamedUserGroup.objects.bulk_update(groups_with_updated_settings, ["can_mention_group"])
|
NamedUserGroup.objects.bulk_update(
|
||||||
|
groups_with_updated_settings, ["can_manage_group", "can_mention_group"]
|
||||||
|
)
|
||||||
|
|
||||||
subgroup_objects: list[GroupGroupMembership] = []
|
subgroup_objects: list[GroupGroupMembership] = []
|
||||||
# "Nobody" system group is not a subgroup of any user group, since it is already empty.
|
# "Nobody" system group is not a subgroup of any user group, since it is already empty.
|
||||||
|
23
zerver/migrations/0570_namedusergroup_can_manage_group.py
Normal file
23
zerver/migrations/0570_namedusergroup_can_manage_group.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 4.2.2 on 2023-07-15 16:28
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("zerver", "0569_remove_userprofile_tutorial_status"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="namedusergroup",
|
||||||
|
name="can_manage_group",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.RESTRICT,
|
||||||
|
related_name="+",
|
||||||
|
to="zerver.usergroup",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
55
zerver/migrations/0571_set_default_for_can_manage_group.py
Normal file
55
zerver/migrations/0571_set_default_for_can_manage_group.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# Generated by Django 4.2.2 on 2023-07-15 17:08
|
||||||
|
|
||||||
|
from django.db import migrations, transaction
|
||||||
|
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||||
|
from django.db.migrations.state import StateApps
|
||||||
|
from django.db.models import Max, Min, OuterRef
|
||||||
|
|
||||||
|
|
||||||
|
def set_default_value_for_can_manage_group(
|
||||||
|
apps: StateApps, schema_editor: BaseDatabaseSchemaEditor
|
||||||
|
) -> None:
|
||||||
|
NamedUserGroup = apps.get_model("zerver", "NamedUserGroup")
|
||||||
|
|
||||||
|
BATCH_SIZE = 1000
|
||||||
|
max_id = NamedUserGroup.objects.filter(can_manage_group=None).aggregate(Max("id"))["id__max"]
|
||||||
|
|
||||||
|
if max_id is None:
|
||||||
|
# Do nothing if there are no user groups on the server.
|
||||||
|
return
|
||||||
|
|
||||||
|
lower_bound = NamedUserGroup.objects.filter(can_manage_group=None).aggregate(Min("id"))[
|
||||||
|
"id__min"
|
||||||
|
]
|
||||||
|
while lower_bound <= max_id:
|
||||||
|
upper_bound = lower_bound + BATCH_SIZE - 1
|
||||||
|
print(f"Processing batch {lower_bound} to {upper_bound} for NamedUserGroup")
|
||||||
|
|
||||||
|
with transaction.atomic():
|
||||||
|
NamedUserGroup.objects.filter(
|
||||||
|
id__range=(lower_bound, upper_bound), can_manage_group=None
|
||||||
|
).update(
|
||||||
|
can_manage_group=NamedUserGroup.objects.filter(
|
||||||
|
name="role:nobody",
|
||||||
|
realm_for_sharding=OuterRef("realm_for_sharding"),
|
||||||
|
is_system_group=True,
|
||||||
|
).values("pk")
|
||||||
|
)
|
||||||
|
|
||||||
|
lower_bound += BATCH_SIZE
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
atomic = False
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("zerver", "0570_namedusergroup_can_manage_group"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(
|
||||||
|
set_default_value_for_can_manage_group,
|
||||||
|
elidable=True,
|
||||||
|
reverse_code=migrations.RunPython.noop,
|
||||||
|
)
|
||||||
|
]
|
22
zerver/migrations/0572_alter_usergroup_can_manage_group.py
Normal file
22
zerver/migrations/0572_alter_usergroup_can_manage_group.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Generated by Django 4.2.2 on 2023-07-16 12:57
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("zerver", "0571_set_default_for_can_manage_group"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="namedusergroup",
|
||||||
|
name="can_manage_group",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.RESTRICT,
|
||||||
|
related_name="+",
|
||||||
|
to="zerver.usergroup",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
@@ -54,6 +54,7 @@ class NamedUserGroup(UserGroup): # type: ignore[django-manager-missing] # djang
|
|||||||
description = models.TextField(default="", db_column="description")
|
description = models.TextField(default="", db_column="description")
|
||||||
is_system_group = models.BooleanField(default=False, db_column="is_system_group")
|
is_system_group = models.BooleanField(default=False, db_column="is_system_group")
|
||||||
|
|
||||||
|
can_manage_group = models.ForeignKey(UserGroup, on_delete=models.RESTRICT, related_name="+")
|
||||||
can_mention_group = models.ForeignKey(
|
can_mention_group = models.ForeignKey(
|
||||||
UserGroup, on_delete=models.RESTRICT, db_column="can_mention_group_id"
|
UserGroup, on_delete=models.RESTRICT, db_column="can_mention_group_id"
|
||||||
)
|
)
|
||||||
@@ -87,6 +88,16 @@ class NamedUserGroup(UserGroup): # type: ignore[django-manager-missing] # djang
|
|||||||
}
|
}
|
||||||
|
|
||||||
GROUP_PERMISSION_SETTINGS = {
|
GROUP_PERMISSION_SETTINGS = {
|
||||||
|
"can_manage_group": GroupPermissionSetting(
|
||||||
|
require_system_group=False,
|
||||||
|
allow_internet_group=False,
|
||||||
|
allow_owners_group=True,
|
||||||
|
allow_nobody_group=True,
|
||||||
|
allow_everyone_group=False,
|
||||||
|
default_group_name=SystemGroups.NOBODY,
|
||||||
|
default_for_system_groups=SystemGroups.NOBODY,
|
||||||
|
id_field_name="can_manage_group_id",
|
||||||
|
),
|
||||||
"can_mention_group": GroupPermissionSetting(
|
"can_mention_group": GroupPermissionSetting(
|
||||||
require_system_group=False,
|
require_system_group=False,
|
||||||
allow_internet_group=False,
|
allow_internet_group=False,
|
||||||
|
@@ -266,6 +266,7 @@ def get_temp_user_group_id() -> dict[str, object]:
|
|||||||
user_group, _ = NamedUserGroup.objects.get_or_create(
|
user_group, _ = NamedUserGroup.objects.get_or_create(
|
||||||
name="temp",
|
name="temp",
|
||||||
realm=get_realm("zulip"),
|
realm=get_realm("zulip"),
|
||||||
|
can_manage_group_id=11,
|
||||||
can_mention_group_id=11,
|
can_mention_group_id=11,
|
||||||
realm_for_sharding=get_realm("zulip"),
|
realm_for_sharding=get_realm("zulip"),
|
||||||
)
|
)
|
||||||
|
@@ -343,11 +343,15 @@ class UserGroupAPITestCase(UserGroupTestCase):
|
|||||||
self.assert_json_success(result)
|
self.assert_json_success(result)
|
||||||
self.assert_length(NamedUserGroup.objects.filter(realm=hamlet.realm), 10)
|
self.assert_length(NamedUserGroup.objects.filter(realm=hamlet.realm), 10)
|
||||||
|
|
||||||
# Check default value of can_mention_group setting.
|
# Check default value of settings.
|
||||||
everyone_system_group = NamedUserGroup.objects.get(
|
everyone_system_group = NamedUserGroup.objects.get(
|
||||||
name="role:everyone", realm=hamlet.realm, is_system_group=True
|
name="role:everyone", realm=hamlet.realm, is_system_group=True
|
||||||
)
|
)
|
||||||
|
nobody_system_group = NamedUserGroup.objects.get(
|
||||||
|
name=SystemGroups.NOBODY, realm=hamlet.realm, is_system_group=True
|
||||||
|
)
|
||||||
support_group = NamedUserGroup.objects.get(name="support", realm=hamlet.realm)
|
support_group = NamedUserGroup.objects.get(name="support", realm=hamlet.realm)
|
||||||
|
self.assertEqual(support_group.can_manage_group, nobody_system_group.usergroup_ptr)
|
||||||
self.assertEqual(support_group.can_mention_group, everyone_system_group.usergroup_ptr)
|
self.assertEqual(support_group.can_mention_group, everyone_system_group.usergroup_ptr)
|
||||||
|
|
||||||
# Test invalid member error
|
# Test invalid member error
|
||||||
|
Reference in New Issue
Block a user