2020-06-11 00:54:34 +02:00
|
|
|
from typing import Any, Dict, List
|
|
|
|
|
2017-09-25 09:47:15 +02:00
|
|
|
from django.db import transaction
|
2017-11-01 10:04:16 +01:00
|
|
|
from django.utils.translation import ugettext as _
|
2020-06-11 00:54:34 +02:00
|
|
|
|
2017-11-01 10:04:16 +01:00
|
|
|
from zerver.lib.exceptions import JsonableError
|
2020-06-11 00:54:34 +02:00
|
|
|
from zerver.models import Realm, UserGroup, UserGroupMembership, UserProfile
|
|
|
|
|
2017-09-25 09:47:15 +02:00
|
|
|
|
2018-02-19 13:38:18 +01:00
|
|
|
def access_user_group_by_id(user_group_id: int, user_profile: UserProfile) -> UserGroup:
|
2017-11-01 10:04:16 +01:00
|
|
|
try:
|
2018-02-19 13:38:18 +01:00
|
|
|
user_group = UserGroup.objects.get(id=user_group_id, realm=user_profile.realm)
|
|
|
|
group_member_ids = get_user_group_members(user_group)
|
|
|
|
msg = _("Only group members and organization administrators can administer this group.")
|
|
|
|
if (not user_profile.is_realm_admin and user_profile.id not in group_member_ids):
|
|
|
|
raise JsonableError(msg)
|
2017-11-01 10:04:16 +01:00
|
|
|
except UserGroup.DoesNotExist:
|
|
|
|
raise JsonableError(_("Invalid user group"))
|
|
|
|
return user_group
|
|
|
|
|
2017-11-05 11:15:10 +01:00
|
|
|
def user_groups_in_realm(realm: Realm) -> List[UserGroup]:
|
2017-09-25 09:47:15 +02:00
|
|
|
user_groups = UserGroup.objects.filter(realm=realm)
|
|
|
|
return list(user_groups)
|
|
|
|
|
2018-05-10 19:13:36 +02:00
|
|
|
def user_groups_in_realm_serialized(realm: Realm) -> List[Dict[str, Any]]:
|
2017-11-30 01:09:23 +01:00
|
|
|
"""This function is used in do_events_register code path so this code
|
|
|
|
should be performant. We need to do 2 database queries because
|
|
|
|
Django's ORM doesn't properly support the left join between
|
|
|
|
UserGroup and UserGroupMembership that we need.
|
2017-11-07 07:56:26 +01:00
|
|
|
"""
|
2017-11-30 01:09:23 +01:00
|
|
|
realm_groups = UserGroup.objects.filter(realm=realm)
|
python: Convert assignment type annotations to Python 3.6 style.
This commit was split by tabbott; this piece covers the vast majority
of files in Zulip, but excludes scripts/, tools/, and puppet/ to help
ensure we at least show the right error messages for Xenial systems.
We can likely further refine the remaining pieces with some testing.
Generated by com2ann, with whitespace fixes and various manual fixes
for runtime issues:
- invoiced_through: Optional[LicenseLedger] = models.ForeignKey(
+ invoiced_through: Optional["LicenseLedger"] = models.ForeignKey(
-_apns_client: Optional[APNsClient] = None
+_apns_client: Optional["APNsClient"] = None
- notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
- signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
+ notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
+ signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
- author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE)
+ author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE)
- bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
+ bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
- default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
- default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
+ default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
+ default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
-descriptors_by_handler_id: Dict[int, ClientDescriptor] = {}
+descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {}
-worker_classes: Dict[str, Type[QueueProcessingWorker]] = {}
-queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {}
+worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {}
+queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {}
-AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None
+AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
|
|
|
group_dicts: Dict[str, Any] = {}
|
2017-11-30 01:09:23 +01:00
|
|
|
for user_group in realm_groups:
|
|
|
|
group_dicts[user_group.id] = dict(
|
|
|
|
id=user_group.id,
|
|
|
|
name=user_group.name,
|
|
|
|
description=user_group.description,
|
|
|
|
members=[],
|
|
|
|
)
|
|
|
|
|
|
|
|
membership = UserGroupMembership.objects.filter(user_group__realm=realm).values_list(
|
|
|
|
'user_group_id', 'user_profile_id')
|
|
|
|
for (user_group_id, user_profile_id) in membership:
|
|
|
|
group_dicts[user_group_id]['members'].append(user_profile_id)
|
|
|
|
for group_dict in group_dicts.values():
|
|
|
|
group_dict['members'] = sorted(group_dict['members'])
|
|
|
|
|
|
|
|
return sorted(group_dicts.values(), key=lambda group_dict: group_dict['id'])
|
2017-11-07 07:56:26 +01:00
|
|
|
|
2017-11-05 11:15:10 +01:00
|
|
|
def get_user_groups(user_profile: UserProfile) -> List[UserGroup]:
|
2017-09-25 09:47:15 +02:00
|
|
|
return list(user_profile.usergroup_set.all())
|
|
|
|
|
2017-11-05 11:15:10 +01:00
|
|
|
def check_add_user_to_user_group(user_profile: UserProfile, user_group: UserGroup) -> bool:
|
2017-09-25 09:47:15 +02:00
|
|
|
member_obj, created = UserGroupMembership.objects.get_or_create(
|
|
|
|
user_group=user_group, user_profile=user_profile)
|
|
|
|
return created
|
|
|
|
|
2017-11-05 11:15:10 +01:00
|
|
|
def remove_user_from_user_group(user_profile: UserProfile, user_group: UserGroup) -> int:
|
2017-09-25 09:47:15 +02:00
|
|
|
num_deleted, _ = UserGroupMembership.objects.filter(
|
|
|
|
user_profile=user_profile, user_group=user_group).delete()
|
|
|
|
return num_deleted
|
|
|
|
|
2017-11-05 11:15:10 +01:00
|
|
|
def check_remove_user_from_user_group(user_profile: UserProfile, user_group: UserGroup) -> bool:
|
2017-09-25 09:47:15 +02:00
|
|
|
try:
|
|
|
|
num_deleted = remove_user_from_user_group(user_profile, user_group)
|
|
|
|
return bool(num_deleted)
|
|
|
|
except Exception:
|
|
|
|
return False
|
|
|
|
|
2018-05-10 19:13:36 +02:00
|
|
|
def create_user_group(name: str, members: List[UserProfile], realm: Realm,
|
|
|
|
description: str='') -> UserGroup:
|
2017-09-25 09:47:15 +02:00
|
|
|
with transaction.atomic():
|
2017-11-01 09:01:38 +01:00
|
|
|
user_group = UserGroup.objects.create(name=name, realm=realm,
|
|
|
|
description=description)
|
2020-09-02 06:20:26 +02:00
|
|
|
UserGroupMembership.objects.bulk_create(
|
2017-09-25 09:47:15 +02:00
|
|
|
UserGroupMembership(user_profile=member, user_group=user_group)
|
|
|
|
for member in members
|
2020-09-02 06:20:26 +02:00
|
|
|
)
|
2017-09-25 09:47:15 +02:00
|
|
|
return user_group
|
2017-11-02 08:53:30 +01:00
|
|
|
|
2018-02-19 13:38:18 +01:00
|
|
|
def get_user_group_members(user_group: UserGroup) -> List[UserProfile]:
|
|
|
|
members = UserGroupMembership.objects.filter(user_group=user_group)
|
|
|
|
return [member.user_profile.id for member in members]
|
|
|
|
|
2017-11-27 05:27:04 +01:00
|
|
|
def get_memberships_of_users(user_group: UserGroup, members: List[UserProfile]) -> List[int]:
|
2017-11-02 08:53:30 +01:00
|
|
|
return list(UserGroupMembership.objects.filter(
|
|
|
|
user_group=user_group,
|
|
|
|
user_profile__in=members).values_list('user_profile_id', flat=True))
|