Files
zulip/zerver/models/groups.py
Sahil Batra fa099f7ce7 mention: Allow silent mentioning system user groups.
Previously, we do not allow mentioning system user groups
at all. Now we want to use silent mention syntax for system
groups in the message sent when updating the posting permission
for a stream, so it is important to allowing silent mentioning
system groups at least. And there is no problem in allowing
silent mentions of system groups for all users.

We do not allow mentioning system groups as can_mention_group
for them is set to "Nobody" group.
2025-01-07 11:28:44 -08:00

189 lines
7.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.utils.translation import gettext_lazy
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"
GROUP_DISPLAY_NAME_MAP = {
NOBODY: gettext_lazy("Nobody"),
OWNERS: gettext_lazy("Owners"),
ADMINISTRATORS: gettext_lazy("Administrators"),
MODERATORS: gettext_lazy("Moderators"),
FULL_MEMBERS: gettext_lazy("Full members"),
MEMBERS: gettext_lazy("Members"),
EVERYONE: gettext_lazy("Everyone"),
EVERYONE_ON_INTERNET: gettext_lazy("Everyone on the internet"),
}
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_leave_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"
)
can_remove_members_group = models.ForeignKey(
UserGroup, on_delete=models.RESTRICT, related_name="+"
)
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_nobody_group=True,
allow_everyone_group=False,
default_group_name="group_creator",
default_for_system_groups=SystemGroups.NOBODY,
),
"can_join_group": GroupPermissionSetting(
require_system_group=False,
allow_internet_group=False,
allow_nobody_group=True,
allow_everyone_group=False,
default_group_name=SystemGroups.NOBODY,
default_for_system_groups=SystemGroups.NOBODY,
),
"can_leave_group": GroupPermissionSetting(
require_system_group=False,
allow_internet_group=False,
allow_nobody_group=True,
allow_everyone_group=True,
default_group_name=SystemGroups.EVERYONE,
default_for_system_groups=SystemGroups.NOBODY,
),
"can_manage_group": GroupPermissionSetting(
require_system_group=False,
allow_internet_group=False,
allow_nobody_group=True,
allow_everyone_group=False,
default_group_name="group_creator",
default_for_system_groups=SystemGroups.NOBODY,
),
"can_mention_group": GroupPermissionSetting(
require_system_group=False,
allow_internet_group=False,
allow_nobody_group=True,
allow_everyone_group=True,
default_group_name=SystemGroups.EVERYONE,
default_for_system_groups=SystemGroups.NOBODY,
),
"can_remove_members_group": GroupPermissionSetting(
require_system_group=False,
allow_internet_group=False,
allow_nobody_group=True,
allow_everyone_group=False,
default_group_name=SystemGroups.NOBODY,
default_for_system_groups=SystemGroups.NOBODY,
),
}
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"
)
]