2023-12-15 01:55:59 +01:00
|
|
|
from django.db import models
|
|
|
|
from django.db.models import CASCADE
|
|
|
|
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(
|
2024-04-20 17:03:33 +02:00
|
|
|
"zerver.NamedUserGroup",
|
2023-12-15 01:55:59 +01:00
|
|
|
symmetrical=False,
|
|
|
|
through="zerver.GroupGroupMembership",
|
|
|
|
through_fields=("supergroup", "subgroup"),
|
|
|
|
related_name="direct_supergroups",
|
|
|
|
)
|
|
|
|
realm = models.ForeignKey("zerver.Realm", on_delete=CASCADE)
|
2024-04-18 10:50:51 +02:00
|
|
|
|
|
|
|
|
|
|
|
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",
|
|
|
|
)
|
2024-04-18 18:59:50 +02:00
|
|
|
name = models.CharField(max_length=MAX_NAME_LENGTH, db_column="name")
|
|
|
|
description = models.TextField(default="", db_column="description")
|
|
|
|
is_system_group = models.BooleanField(default=False, db_column="is_system_group")
|
2024-04-18 10:50:51 +02:00
|
|
|
|
2023-08-21 12:06:41 +02:00
|
|
|
can_manage_group = models.ForeignKey(UserGroup, on_delete=models.RESTRICT, related_name="+")
|
2024-04-18 18:59:50 +02:00
|
|
|
can_mention_group = models.ForeignKey(
|
2024-04-18 10:50:51 +02:00
|
|
|
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")
|
|
|
|
|
2023-12-15 01:55:59 +01:00
|
|
|
# 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 = {
|
2023-08-21 12:06:41 +02:00
|
|
|
"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",
|
|
|
|
),
|
2023-12-15 01:55:59 +01:00
|
|
|
"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",
|
|
|
|
),
|
|
|
|
}
|
|
|
|
|
2024-04-16 13:55:21 +02:00
|
|
|
class Meta:
|
2024-04-18 18:59:50 +02:00
|
|
|
unique_together = (("realm_for_sharding", "name"),)
|
2024-04-16 13:55:21 +02:00
|
|
|
|
|
|
|
|
2023-12-15 01:55:59 +01:00
|
|
|
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="+")
|
2024-04-20 17:03:33 +02:00
|
|
|
subgroup = models.ForeignKey(NamedUserGroup, on_delete=CASCADE, related_name="+")
|
2023-12-15 01:55:59 +01:00
|
|
|
|
|
|
|
class Meta:
|
|
|
|
constraints = [
|
|
|
|
models.UniqueConstraint(
|
|
|
|
fields=["supergroup", "subgroup"], name="zerver_groupgroupmembership_uniq"
|
|
|
|
)
|
|
|
|
]
|