Files
zulip/zerver/models/groups.py
Shubham Padia b305ca14dd user_groups: Add add_can_members_group to user group.
The default value for this field that we wanted to have was that group
itlself. But we are deferring that to later in order to reach the point
of switching over to the groups system sooner. Till then, we will use
`group_creator` as the default. See
https://chat.zulip.org/#narrow/stream/101-design/topic/Group.20add.20members.20dropdown/near/1952904
for more details.

For migration plan details, see
https://chat.zulip.org/#narrow/stream/101-design/topic/Group.20add.20members.20dropdown/near/1952902

The increase in query count from 7 to 9 in the query count test for
creating a user group is because of group_creator being the default for
the new field.
2024-10-11 16:31:18 -07:00

165 lines
6.5 KiB
Python

from django.db import models
from django.db.models import CASCADE
from django.utils.timezone import now as timezone_now
from django_cte import CTEManager
from zerver.lib.types import GroupPermissionSetting
from zerver.models.users import UserProfile
class SystemGroups:
FULL_MEMBERS = "role:fullmembers"
EVERYONE_ON_INTERNET = "role:internet"
OWNERS = "role:owners"
ADMINISTRATORS = "role:administrators"
MODERATORS = "role:moderators"
MEMBERS = "role:members"
EVERYONE = "role:everyone"
NOBODY = "role:nobody"
class UserGroup(models.Model): # type: ignore[django-manager-missing] # django-stubs cannot resolve the custom CTEManager yet https://github.com/typeddjango/django-stubs/issues/1023
objects: CTEManager = CTEManager()
direct_members = models.ManyToManyField(
UserProfile, through="zerver.UserGroupMembership", related_name="direct_groups"
)
direct_subgroups = models.ManyToManyField(
"zerver.NamedUserGroup",
symmetrical=False,
through="zerver.GroupGroupMembership",
through_fields=("supergroup", "subgroup"),
related_name="direct_supergroups",
)
realm = models.ForeignKey("zerver.Realm", on_delete=CASCADE)
class NamedUserGroup(UserGroup): # type: ignore[django-manager-missing] # django-stubs cannot resolve the custom CTEManager yet https://github.com/typeddjango/django-stubs/issues/1023
MAX_NAME_LENGTH = 100
INVALID_NAME_PREFIXES = ["@", "role:", "user:", "stream:", "channel:"]
# This field is automatically created by django, but we still need
# to add this here to keep mypy happy when accessing usergroup_ptr.
usergroup_ptr = models.OneToOneField(
auto_created=True,
on_delete=CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to=UserGroup,
# We are not using the auto-generated name here to avoid
# duplicate backward relation name because "can_mention_group"
# setting also points to a UserGroup object.
related_name="named_user_group",
)
name = models.CharField(max_length=MAX_NAME_LENGTH, db_column="name")
description = models.TextField(default="", db_column="description")
date_created = models.DateTimeField(default=timezone_now, null=True)
creator = models.ForeignKey(
UserProfile, null=True, on_delete=models.SET_NULL, related_name="+", db_column="creator_id"
)
is_system_group = models.BooleanField(default=False, db_column="is_system_group")
can_add_members_group = models.ForeignKey(
UserGroup, on_delete=models.RESTRICT, related_name="+"
)
can_join_group = models.ForeignKey(UserGroup, on_delete=models.RESTRICT, related_name="+")
can_manage_group = models.ForeignKey(UserGroup, on_delete=models.RESTRICT, related_name="+")
can_mention_group = models.ForeignKey(
UserGroup, on_delete=models.RESTRICT, db_column="can_mention_group_id"
)
realm_for_sharding = models.ForeignKey("zerver.Realm", on_delete=CASCADE, db_column="realm_id")
deactivated = models.BooleanField(default=False, db_default=False)
# We do not have "Full members" and "Everyone on the internet"
# group here since there isn't a separate role value for full
# members and spectators.
SYSTEM_USER_GROUP_ROLE_MAP = {
UserProfile.ROLE_REALM_OWNER: {
"name": SystemGroups.OWNERS,
"description": "Owners of this organization",
},
UserProfile.ROLE_REALM_ADMINISTRATOR: {
"name": SystemGroups.ADMINISTRATORS,
"description": "Administrators of this organization, including owners",
},
UserProfile.ROLE_MODERATOR: {
"name": SystemGroups.MODERATORS,
"description": "Moderators of this organization, including administrators",
},
UserProfile.ROLE_MEMBER: {
"name": SystemGroups.MEMBERS,
"description": "Members of this organization, not including guests",
},
UserProfile.ROLE_GUEST: {
"name": SystemGroups.EVERYONE,
"description": "Everyone in this organization, including guests",
},
}
GROUP_PERMISSION_SETTINGS = {
"can_add_members_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="group_creator",
default_for_system_groups=SystemGroups.NOBODY,
id_field_name="can_add_members_group_id",
),
"can_join_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_join_group_id",
),
"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="group_creator",
default_for_system_groups=SystemGroups.NOBODY,
id_field_name="can_manage_group_id",
),
"can_mention_group": GroupPermissionSetting(
require_system_group=False,
allow_internet_group=False,
allow_owners_group=False,
allow_nobody_group=True,
allow_everyone_group=True,
default_group_name=SystemGroups.EVERYONE,
default_for_system_groups=SystemGroups.NOBODY,
id_field_name="can_mention_group_id",
),
}
class Meta:
unique_together = (("realm_for_sharding", "name"),)
class UserGroupMembership(models.Model):
user_group = models.ForeignKey(UserGroup, on_delete=CASCADE, related_name="+")
user_profile = models.ForeignKey(UserProfile, on_delete=CASCADE, related_name="+")
class Meta:
unique_together = (("user_group", "user_profile"),)
class GroupGroupMembership(models.Model):
supergroup = models.ForeignKey(UserGroup, on_delete=CASCADE, related_name="+")
subgroup = models.ForeignKey(NamedUserGroup, on_delete=CASCADE, related_name="+")
class Meta:
constraints = [
models.UniqueConstraint(
fields=["supergroup", "subgroup"], name="zerver_groupgroupmembership_uniq"
)
]