mirror of https://github.com/zulip/zulip.git
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:
parent
9e699dfc85
commit
03220ba456
|
@ -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.
|
||||||
|
|
|
@ -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",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -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,
|
||||||
|
)
|
||||||
|
]
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue