mirror of https://github.com/zulip/zulip.git
user_groups: Add can_mention_group setting.
This commit adds a new can_mention_group setting which will be used to determine who can mention a particular group. Fixes a part of #25927.
This commit is contained in:
parent
9265954fd2
commit
2763f9b575
|
@ -7,7 +7,11 @@ from django.utils.timezone import now as timezone_now
|
|||
from django.utils.translation import gettext as _
|
||||
|
||||
from zerver.lib.exceptions import JsonableError
|
||||
from zerver.lib.user_groups import access_user_group_by_id
|
||||
from zerver.lib.user_groups import (
|
||||
access_user_group_by_id,
|
||||
get_role_based_system_groups_dict,
|
||||
set_defaults_for_group_settings,
|
||||
)
|
||||
from zerver.models import (
|
||||
GroupGroupMembership,
|
||||
Realm,
|
||||
|
@ -35,9 +39,14 @@ def create_user_group_in_database(
|
|||
description: str = "",
|
||||
is_system_group: bool = False,
|
||||
) -> UserGroup:
|
||||
user_group = UserGroup.objects.create(
|
||||
user_group = UserGroup(
|
||||
name=name, realm=realm, description=description, is_system_group=is_system_group
|
||||
)
|
||||
system_groups_name_dict = get_role_based_system_groups_dict(realm)
|
||||
user_group = set_defaults_for_group_settings(user_group, system_groups_name_dict)
|
||||
|
||||
user_group.save()
|
||||
|
||||
UserGroupMembership.objects.bulk_create(
|
||||
UserGroupMembership(user_profile=member, user_group=user_group) for member in members
|
||||
)
|
||||
|
|
|
@ -969,6 +969,10 @@ def do_import_realm(import_dir: Path, subdomain: str, processes: int = 1) -> Rea
|
|||
if "zerver_usergroup" in data:
|
||||
update_model_ids(UserGroup, data, "usergroup")
|
||||
re_map_foreign_keys(data, "zerver_usergroup", "realm", related_table="realm")
|
||||
for setting_name in UserGroup.GROUP_PERMISSION_SETTINGS:
|
||||
re_map_foreign_keys(
|
||||
data, "zerver_usergroup", setting_name, related_table="usergroup"
|
||||
)
|
||||
bulk_import_model(data, UserGroup)
|
||||
|
||||
# We expect Zulip server exports to contain these system groups,
|
||||
|
|
|
@ -281,3 +281,4 @@ class GroupPermissionSetting:
|
|||
allow_owners_group: bool
|
||||
allow_nobody_group: bool
|
||||
default_group_name: str
|
||||
default_for_system_groups: Optional[str] = None
|
||||
|
|
|
@ -226,6 +226,31 @@ def get_recursive_subgroups_for_groups(user_group_ids: List[int]) -> List[int]:
|
|||
return list(recursive_subgroups.values_list("id", flat=True))
|
||||
|
||||
|
||||
def get_role_based_system_groups_dict(realm: Realm) -> Dict[str, UserGroup]:
|
||||
system_groups = UserGroup.objects.filter(realm=realm, is_system_group=True)
|
||||
system_groups_name_dict = {}
|
||||
for group in system_groups:
|
||||
system_groups_name_dict[group.name] = group
|
||||
|
||||
return system_groups_name_dict
|
||||
|
||||
|
||||
def set_defaults_for_group_settings(
|
||||
user_group: UserGroup,
|
||||
system_groups_name_dict: Dict[str, UserGroup],
|
||||
) -> UserGroup:
|
||||
for setting_name, permission_config in UserGroup.GROUP_PERMISSION_SETTINGS.items():
|
||||
if user_group.is_system_group and permission_config.default_for_system_groups is not None:
|
||||
default_group_name = permission_config.default_for_system_groups
|
||||
else:
|
||||
default_group_name = permission_config.default_group_name
|
||||
|
||||
default_group = system_groups_name_dict[default_group_name]
|
||||
setattr(user_group, setting_name, default_group)
|
||||
|
||||
return user_group
|
||||
|
||||
|
||||
@transaction.atomic(savepoint=False)
|
||||
def create_system_user_groups_for_realm(realm: Realm) -> Dict[int, UserGroup]:
|
||||
"""Any changes to this function likely require a migration to adjust
|
||||
|
@ -233,6 +258,12 @@ def create_system_user_groups_for_realm(realm: Realm) -> Dict[int, UserGroup]:
|
|||
which is a copy of this function from when we introduced system groups.
|
||||
"""
|
||||
role_system_groups_dict: Dict[int, UserGroup] = {}
|
||||
|
||||
# This value will be used to set the temporary initial value for different
|
||||
# settings since we can only set them to the correct values after the groups
|
||||
# are created.
|
||||
initial_group_setting_value = -1
|
||||
|
||||
for role in UserGroup.SYSTEM_USER_GROUP_ROLE_MAP:
|
||||
user_group_params = UserGroup.SYSTEM_USER_GROUP_ROLE_MAP[role]
|
||||
user_group = UserGroup(
|
||||
|
@ -240,6 +271,7 @@ def create_system_user_groups_for_realm(realm: Realm) -> Dict[int, UserGroup]:
|
|||
description=user_group_params["description"],
|
||||
realm=realm,
|
||||
is_system_group=True,
|
||||
can_mention_group_id=initial_group_setting_value,
|
||||
)
|
||||
role_system_groups_dict[role] = user_group
|
||||
|
||||
|
@ -248,18 +280,21 @@ def create_system_user_groups_for_realm(realm: Realm) -> Dict[int, UserGroup]:
|
|||
description="Members of this organization, not including new accounts and guests",
|
||||
realm=realm,
|
||||
is_system_group=True,
|
||||
can_mention_group_id=initial_group_setting_value,
|
||||
)
|
||||
everyone_on_internet_system_group = UserGroup(
|
||||
name=UserGroup.EVERYONE_ON_INTERNET_GROUP_NAME,
|
||||
description="Everyone on the Internet",
|
||||
realm=realm,
|
||||
is_system_group=True,
|
||||
can_mention_group_id=initial_group_setting_value,
|
||||
)
|
||||
nobody_system_group = UserGroup(
|
||||
name=UserGroup.NOBODY_GROUP_NAME,
|
||||
description="Nobody",
|
||||
realm=realm,
|
||||
is_system_group=True,
|
||||
can_mention_group_id=initial_group_setting_value,
|
||||
)
|
||||
# Order of this list here is important to create correct GroupGroupMembership objects
|
||||
system_user_groups_list = [
|
||||
|
@ -275,6 +310,13 @@ def create_system_user_groups_for_realm(realm: Realm) -> Dict[int, UserGroup]:
|
|||
|
||||
UserGroup.objects.bulk_create(system_user_groups_list)
|
||||
|
||||
groups_with_updated_settings = []
|
||||
system_groups_name_dict = get_role_based_system_groups_dict(realm)
|
||||
for group in system_user_groups_list:
|
||||
user_group = set_defaults_for_group_settings(group, system_groups_name_dict)
|
||||
groups_with_updated_settings.append(group)
|
||||
UserGroup.objects.bulk_update(groups_with_updated_settings, ["can_mention_group"])
|
||||
|
||||
subgroup_objects = []
|
||||
# "Nobody" system group is not a subgroup of any user group, since it is already empty.
|
||||
subgroup, remaining_groups = system_user_groups_list[1], system_user_groups_list[2:]
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 4.2.1 on 2023-06-12 10:47
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("zerver", "0453_followed_topic_notifications"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="usergroup",
|
||||
name="can_mention_group",
|
||||
field=models.ForeignKey(
|
||||
null=True, on_delete=django.db.models.deletion.RESTRICT, to="zerver.usergroup"
|
||||
),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,44 @@
|
|||
# Generated by Django 4.2.1 on 2023-06-12 10:47
|
||||
|
||||
from django.db import migrations
|
||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||
from django.db.migrations.state import StateApps
|
||||
|
||||
|
||||
def set_default_value_for_can_mention_group(
|
||||
apps: StateApps, schema_editor: BaseDatabaseSchemaEditor
|
||||
) -> None:
|
||||
Realm = apps.get_model("zerver", "Realm")
|
||||
UserGroup = apps.get_model("zerver", "UserGroup")
|
||||
|
||||
groups_to_update = []
|
||||
for realm in Realm.objects.all():
|
||||
# The default value of `can_mention_group` is everyone group for
|
||||
# all groups except role-based system groups. For role-based system
|
||||
# groups, we set the value of `can_mention_group` to nobody group.
|
||||
nobody_group = UserGroup.objects.get(name="@role:nobody", realm=realm, is_system_group=True)
|
||||
everyone_group = UserGroup.objects.get(
|
||||
name="@role:everyone", realm=realm, is_system_group=True
|
||||
)
|
||||
for group in UserGroup.objects.filter(realm=realm):
|
||||
if group.is_system_group:
|
||||
group.can_mention_group = nobody_group
|
||||
else:
|
||||
group.can_mention_group = everyone_group
|
||||
groups_to_update.append(group)
|
||||
|
||||
UserGroup.objects.bulk_update(groups_to_update, ["can_mention_group"])
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("zerver", "0454_usergroup_can_mention_group"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(
|
||||
set_default_value_for_can_mention_group,
|
||||
elidable=True,
|
||||
reverse_code=migrations.RunPython.noop,
|
||||
)
|
||||
]
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 4.2.1 on 2023-06-12 10:58
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("zerver", "0455_set_default_for_can_mention_group"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="usergroup",
|
||||
name="can_mention_group",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.RESTRICT, to="zerver.usergroup"
|
||||
),
|
||||
),
|
||||
]
|
|
@ -2256,6 +2256,8 @@ class UserGroup(models.Model): # type: ignore[django-manager-missing] # django-
|
|||
description = models.TextField(default="")
|
||||
is_system_group = models.BooleanField(default=False)
|
||||
|
||||
can_mention_group = models.ForeignKey("self", on_delete=models.RESTRICT)
|
||||
|
||||
# Names for system groups.
|
||||
FULL_MEMBERS_GROUP_NAME = "@role:fullmembers"
|
||||
EVERYONE_ON_INTERNET_GROUP_NAME = "@role:internet"
|
||||
|
@ -2292,6 +2294,17 @@ class UserGroup(models.Model): # type: ignore[django-manager-missing] # django-
|
|||
},
|
||||
}
|
||||
|
||||
GROUP_PERMISSION_SETTINGS = {
|
||||
"can_mention_group": GroupPermissionSetting(
|
||||
require_system_group=False,
|
||||
allow_internet_group=False,
|
||||
allow_owners_group=False,
|
||||
allow_nobody_group=True,
|
||||
default_group_name=EVERYONE_GROUP_NAME,
|
||||
default_for_system_groups=NOBODY_GROUP_NAME,
|
||||
),
|
||||
}
|
||||
|
||||
class Meta:
|
||||
unique_together = (("realm", "name"),)
|
||||
|
||||
|
|
|
@ -263,7 +263,9 @@ def create_user_group_data() -> Dict[str, object]:
|
|||
["/user_groups/{user_group_id}:patch", "/user_groups/{user_group_id}:delete"]
|
||||
)
|
||||
def get_temp_user_group_id() -> Dict[str, object]:
|
||||
user_group, _ = UserGroup.objects.get_or_create(name="temp", realm=get_realm("zulip"))
|
||||
user_group, _ = UserGroup.objects.get_or_create(
|
||||
name="temp", realm=get_realm("zulip"), can_mention_group_id=11
|
||||
)
|
||||
return {
|
||||
"user_group_id": user_group.id,
|
||||
}
|
||||
|
|
|
@ -1231,6 +1231,11 @@ class RealmImportExportTest(ExportFile):
|
|||
direct_subgroup_names = {group.name for group in direct_subgroups}
|
||||
return direct_subgroup_names
|
||||
|
||||
@getter
|
||||
def get_user_group_can_mention_group_setting(r: Realm) -> Set[str]:
|
||||
user_group = UserGroup.objects.get(realm=r, name="hamletcharacters")
|
||||
return user_group.can_mention_group.name
|
||||
|
||||
# test botstoragedata and botconfigdata
|
||||
@getter
|
||||
def get_botstoragedata(r: Realm) -> Dict[str, object]:
|
||||
|
|
|
@ -240,6 +240,13 @@ class UserGroupAPITestCase(UserGroupTestCase):
|
|||
self.assert_json_success(result)
|
||||
self.assert_length(UserGroup.objects.filter(realm=hamlet.realm), 10)
|
||||
|
||||
# Check default value of can_mention_group setting.
|
||||
everyone_system_group = UserGroup.objects.get(
|
||||
name="@role:everyone", realm=hamlet.realm, is_system_group=True
|
||||
)
|
||||
support_group = UserGroup.objects.get(name="support", realm=hamlet.realm)
|
||||
self.assertEqual(support_group.can_mention_group, everyone_system_group)
|
||||
|
||||
# Test invalid member error
|
||||
params = {
|
||||
"name": "backend",
|
||||
|
|
Loading…
Reference in New Issue