mirror of
https://github.com/zulip/zulip.git
synced 2025-11-10 00:46:03 +00:00
actions: Split out zerver.actions.user_groups.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
(cherry picked from commit 372c10f5f3)
This commit is contained in:
committed by
Tim Abbott
parent
500bd04e11
commit
bf5f006971
166
zerver/actions/user_groups.py
Normal file
166
zerver/actions/user_groups.py
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
import datetime
|
||||||
|
from typing import Dict, List, Sequence, Union
|
||||||
|
|
||||||
|
import django.db.utils
|
||||||
|
from django.db import transaction
|
||||||
|
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, create_user_group
|
||||||
|
from zerver.models import Realm, UserGroup, UserGroupMembership, UserProfile, active_user_ids
|
||||||
|
from zerver.tornado.django_api import send_event
|
||||||
|
|
||||||
|
|
||||||
|
@transaction.atomic(savepoint=False)
|
||||||
|
def update_users_in_full_members_system_group(
|
||||||
|
realm: Realm, affected_user_ids: Sequence[int] = []
|
||||||
|
) -> None:
|
||||||
|
full_members_system_group = UserGroup.objects.get(
|
||||||
|
realm=realm, name="@role:fullmembers", is_system_group=True
|
||||||
|
)
|
||||||
|
members_system_group = UserGroup.objects.get(
|
||||||
|
realm=realm, name="@role:members", is_system_group=True
|
||||||
|
)
|
||||||
|
|
||||||
|
full_member_group_users: List[Dict[str, Union[int, datetime.datetime]]] = list()
|
||||||
|
member_group_users: List[Dict[str, Union[int, datetime.datetime]]] = list()
|
||||||
|
|
||||||
|
if affected_user_ids:
|
||||||
|
full_member_group_users = list(
|
||||||
|
full_members_system_group.direct_members.filter(id__in=affected_user_ids).values(
|
||||||
|
"id", "role", "date_joined"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
member_group_users = list(
|
||||||
|
members_system_group.direct_members.filter(id__in=affected_user_ids).values(
|
||||||
|
"id", "role", "date_joined"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
full_member_group_users = list(
|
||||||
|
full_members_system_group.direct_members.all().values("id", "role", "date_joined")
|
||||||
|
)
|
||||||
|
member_group_users = list(
|
||||||
|
members_system_group.direct_members.all().values("id", "role", "date_joined")
|
||||||
|
)
|
||||||
|
|
||||||
|
def is_provisional_member(user: Dict[str, Union[int, datetime.datetime]]) -> bool:
|
||||||
|
diff = (timezone_now() - user["date_joined"]).days
|
||||||
|
if diff < realm.waiting_period_threshold:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
old_full_members = [
|
||||||
|
user
|
||||||
|
for user in full_member_group_users
|
||||||
|
if is_provisional_member(user) or user["role"] != UserProfile.ROLE_MEMBER
|
||||||
|
]
|
||||||
|
|
||||||
|
full_member_group_user_ids = [user["id"] for user in full_member_group_users]
|
||||||
|
members_excluding_full_members = [
|
||||||
|
user for user in member_group_users if user["id"] not in full_member_group_user_ids
|
||||||
|
]
|
||||||
|
|
||||||
|
new_full_members = [
|
||||||
|
user for user in members_excluding_full_members if not is_provisional_member(user)
|
||||||
|
]
|
||||||
|
|
||||||
|
old_full_member_ids = [user["id"] for user in old_full_members]
|
||||||
|
new_full_member_ids = [user["id"] for user in new_full_members]
|
||||||
|
|
||||||
|
if len(old_full_members) > 0:
|
||||||
|
remove_members_from_user_group(full_members_system_group, old_full_member_ids)
|
||||||
|
|
||||||
|
if len(new_full_members) > 0:
|
||||||
|
bulk_add_members_to_user_group(full_members_system_group, new_full_member_ids)
|
||||||
|
|
||||||
|
|
||||||
|
def promote_new_full_members() -> None:
|
||||||
|
for realm in Realm.objects.filter(deactivated=False).exclude(waiting_period_threshold=0):
|
||||||
|
update_users_in_full_members_system_group(realm)
|
||||||
|
|
||||||
|
|
||||||
|
def do_send_create_user_group_event(user_group: UserGroup, members: List[UserProfile]) -> None:
|
||||||
|
event = dict(
|
||||||
|
type="user_group",
|
||||||
|
op="add",
|
||||||
|
group=dict(
|
||||||
|
name=user_group.name,
|
||||||
|
members=[member.id for member in members],
|
||||||
|
description=user_group.description,
|
||||||
|
id=user_group.id,
|
||||||
|
is_system_group=user_group.is_system_group,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
send_event(user_group.realm, event, active_user_ids(user_group.realm_id))
|
||||||
|
|
||||||
|
|
||||||
|
def check_add_user_group(
|
||||||
|
realm: Realm, name: str, initial_members: List[UserProfile], description: str
|
||||||
|
) -> None:
|
||||||
|
try:
|
||||||
|
user_group = create_user_group(name, initial_members, realm, description=description)
|
||||||
|
do_send_create_user_group_event(user_group, initial_members)
|
||||||
|
except django.db.utils.IntegrityError:
|
||||||
|
raise JsonableError(_("User group '{}' already exists.").format(name))
|
||||||
|
|
||||||
|
|
||||||
|
def do_send_user_group_update_event(user_group: UserGroup, data: Dict[str, str]) -> None:
|
||||||
|
event = dict(type="user_group", op="update", group_id=user_group.id, data=data)
|
||||||
|
send_event(user_group.realm, event, active_user_ids(user_group.realm_id))
|
||||||
|
|
||||||
|
|
||||||
|
def do_update_user_group_name(user_group: UserGroup, name: str) -> None:
|
||||||
|
try:
|
||||||
|
user_group.name = name
|
||||||
|
user_group.save(update_fields=["name"])
|
||||||
|
except django.db.utils.IntegrityError:
|
||||||
|
raise JsonableError(_("User group '{}' already exists.").format(name))
|
||||||
|
do_send_user_group_update_event(user_group, dict(name=name))
|
||||||
|
|
||||||
|
|
||||||
|
def do_update_user_group_description(user_group: UserGroup, description: str) -> None:
|
||||||
|
user_group.description = description
|
||||||
|
user_group.save(update_fields=["description"])
|
||||||
|
do_send_user_group_update_event(user_group, dict(description=description))
|
||||||
|
|
||||||
|
|
||||||
|
def do_send_user_group_members_update_event(
|
||||||
|
event_name: str, user_group: UserGroup, user_ids: List[int]
|
||||||
|
) -> None:
|
||||||
|
event = dict(type="user_group", op=event_name, group_id=user_group.id, user_ids=user_ids)
|
||||||
|
transaction.on_commit(
|
||||||
|
lambda: send_event(user_group.realm, event, active_user_ids(user_group.realm_id))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@transaction.atomic(savepoint=False)
|
||||||
|
def bulk_add_members_to_user_group(user_group: UserGroup, user_profile_ids: List[int]) -> None:
|
||||||
|
memberships = [
|
||||||
|
UserGroupMembership(user_group_id=user_group.id, user_profile_id=user_id)
|
||||||
|
for user_id in user_profile_ids
|
||||||
|
]
|
||||||
|
UserGroupMembership.objects.bulk_create(memberships)
|
||||||
|
|
||||||
|
do_send_user_group_members_update_event("add_members", user_group, user_profile_ids)
|
||||||
|
|
||||||
|
|
||||||
|
@transaction.atomic(savepoint=False)
|
||||||
|
def remove_members_from_user_group(user_group: UserGroup, user_profile_ids: List[int]) -> None:
|
||||||
|
UserGroupMembership.objects.filter(
|
||||||
|
user_group_id=user_group.id, user_profile_id__in=user_profile_ids
|
||||||
|
).delete()
|
||||||
|
|
||||||
|
do_send_user_group_members_update_event("remove_members", user_group, user_profile_ids)
|
||||||
|
|
||||||
|
|
||||||
|
def do_send_delete_user_group_event(realm: Realm, user_group_id: int, realm_id: int) -> None:
|
||||||
|
event = dict(type="user_group", op="remove", group_id=user_group_id)
|
||||||
|
send_event(realm, event, active_user_ids(realm_id))
|
||||||
|
|
||||||
|
|
||||||
|
def check_delete_user_group(user_group_id: int, user_profile: UserProfile) -> None:
|
||||||
|
user_group = access_user_group_by_id(user_group_id, user_profile)
|
||||||
|
user_group.delete()
|
||||||
|
do_send_delete_user_group_event(user_profile.realm, user_group_id, user_profile.realm.id)
|
||||||
@@ -48,6 +48,10 @@ from confirmation.models import (
|
|||||||
create_confirmation_link,
|
create_confirmation_link,
|
||||||
generate_key,
|
generate_key,
|
||||||
)
|
)
|
||||||
|
from zerver.actions.user_groups import (
|
||||||
|
do_send_user_group_members_update_event,
|
||||||
|
update_users_in_full_members_system_group,
|
||||||
|
)
|
||||||
from zerver.decorator import statsd_increment
|
from zerver.decorator import statsd_increment
|
||||||
from zerver.lib import retention as retention
|
from zerver.lib import retention as retention
|
||||||
from zerver.lib.addressee import Addressee
|
from zerver.lib.addressee import Addressee
|
||||||
@@ -196,9 +200,7 @@ from zerver.lib.upload import (
|
|||||||
)
|
)
|
||||||
from zerver.lib.user_counts import realm_user_count, realm_user_count_by_role
|
from zerver.lib.user_counts import realm_user_count, realm_user_count_by_role
|
||||||
from zerver.lib.user_groups import (
|
from zerver.lib.user_groups import (
|
||||||
access_user_group_by_id,
|
|
||||||
create_system_user_groups_for_realm,
|
create_system_user_groups_for_realm,
|
||||||
create_user_group,
|
|
||||||
get_system_user_group_for_user,
|
get_system_user_group_for_user,
|
||||||
)
|
)
|
||||||
from zerver.lib.user_message import UserMessageLite, bulk_insert_ums
|
from zerver.lib.user_message import UserMessageLite, bulk_insert_ums
|
||||||
@@ -839,75 +841,6 @@ def active_humans_in_realm(realm: Realm) -> Sequence[UserProfile]:
|
|||||||
return UserProfile.objects.filter(realm=realm, is_active=True, is_bot=False)
|
return UserProfile.objects.filter(realm=realm, is_active=True, is_bot=False)
|
||||||
|
|
||||||
|
|
||||||
@transaction.atomic(savepoint=False)
|
|
||||||
def update_users_in_full_members_system_group(
|
|
||||||
realm: Realm, affected_user_ids: Sequence[int] = []
|
|
||||||
) -> None:
|
|
||||||
full_members_system_group = UserGroup.objects.get(
|
|
||||||
realm=realm, name="@role:fullmembers", is_system_group=True
|
|
||||||
)
|
|
||||||
members_system_group = UserGroup.objects.get(
|
|
||||||
realm=realm, name="@role:members", is_system_group=True
|
|
||||||
)
|
|
||||||
|
|
||||||
full_member_group_users: List[Dict[str, Union[int, datetime.datetime]]] = list()
|
|
||||||
member_group_users: List[Dict[str, Union[int, datetime.datetime]]] = list()
|
|
||||||
|
|
||||||
if affected_user_ids:
|
|
||||||
full_member_group_users = list(
|
|
||||||
full_members_system_group.direct_members.filter(id__in=affected_user_ids).values(
|
|
||||||
"id", "role", "date_joined"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
member_group_users = list(
|
|
||||||
members_system_group.direct_members.filter(id__in=affected_user_ids).values(
|
|
||||||
"id", "role", "date_joined"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
full_member_group_users = list(
|
|
||||||
full_members_system_group.direct_members.all().values("id", "role", "date_joined")
|
|
||||||
)
|
|
||||||
member_group_users = list(
|
|
||||||
members_system_group.direct_members.all().values("id", "role", "date_joined")
|
|
||||||
)
|
|
||||||
|
|
||||||
def is_provisional_member(user: Dict[str, Union[int, datetime.datetime]]) -> bool:
|
|
||||||
diff = (timezone_now() - user["date_joined"]).days
|
|
||||||
if diff < realm.waiting_period_threshold:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
old_full_members = [
|
|
||||||
user
|
|
||||||
for user in full_member_group_users
|
|
||||||
if is_provisional_member(user) or user["role"] != UserProfile.ROLE_MEMBER
|
|
||||||
]
|
|
||||||
|
|
||||||
full_member_group_user_ids = [user["id"] for user in full_member_group_users]
|
|
||||||
members_excluding_full_members = [
|
|
||||||
user for user in member_group_users if user["id"] not in full_member_group_user_ids
|
|
||||||
]
|
|
||||||
|
|
||||||
new_full_members = [
|
|
||||||
user for user in members_excluding_full_members if not is_provisional_member(user)
|
|
||||||
]
|
|
||||||
|
|
||||||
old_full_member_ids = [user["id"] for user in old_full_members]
|
|
||||||
new_full_member_ids = [user["id"] for user in new_full_members]
|
|
||||||
|
|
||||||
if len(old_full_members) > 0:
|
|
||||||
remove_members_from_user_group(full_members_system_group, old_full_member_ids)
|
|
||||||
|
|
||||||
if len(new_full_members) > 0:
|
|
||||||
bulk_add_members_to_user_group(full_members_system_group, new_full_member_ids)
|
|
||||||
|
|
||||||
|
|
||||||
def promote_new_full_members() -> None:
|
|
||||||
for realm in Realm.objects.filter(deactivated=False).exclude(waiting_period_threshold=0):
|
|
||||||
update_users_in_full_members_system_group(realm)
|
|
||||||
|
|
||||||
|
|
||||||
@transaction.atomic(savepoint=False)
|
@transaction.atomic(savepoint=False)
|
||||||
def do_set_realm_property(
|
def do_set_realm_property(
|
||||||
realm: Realm, name: str, value: Any, *, acting_user: Optional[UserProfile]
|
realm: Realm, name: str, value: Any, *, acting_user: Optional[UserProfile]
|
||||||
@@ -8489,51 +8422,6 @@ def check_remove_custom_profile_field_value(user_profile: UserProfile, field_id:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def do_send_create_user_group_event(user_group: UserGroup, members: List[UserProfile]) -> None:
|
|
||||||
event = dict(
|
|
||||||
type="user_group",
|
|
||||||
op="add",
|
|
||||||
group=dict(
|
|
||||||
name=user_group.name,
|
|
||||||
members=[member.id for member in members],
|
|
||||||
description=user_group.description,
|
|
||||||
id=user_group.id,
|
|
||||||
is_system_group=user_group.is_system_group,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
send_event(user_group.realm, event, active_user_ids(user_group.realm_id))
|
|
||||||
|
|
||||||
|
|
||||||
def check_add_user_group(
|
|
||||||
realm: Realm, name: str, initial_members: List[UserProfile], description: str
|
|
||||||
) -> None:
|
|
||||||
try:
|
|
||||||
user_group = create_user_group(name, initial_members, realm, description=description)
|
|
||||||
do_send_create_user_group_event(user_group, initial_members)
|
|
||||||
except django.db.utils.IntegrityError:
|
|
||||||
raise JsonableError(_("User group '{}' already exists.").format(name))
|
|
||||||
|
|
||||||
|
|
||||||
def do_send_user_group_update_event(user_group: UserGroup, data: Dict[str, str]) -> None:
|
|
||||||
event = dict(type="user_group", op="update", group_id=user_group.id, data=data)
|
|
||||||
send_event(user_group.realm, event, active_user_ids(user_group.realm_id))
|
|
||||||
|
|
||||||
|
|
||||||
def do_update_user_group_name(user_group: UserGroup, name: str) -> None:
|
|
||||||
try:
|
|
||||||
user_group.name = name
|
|
||||||
user_group.save(update_fields=["name"])
|
|
||||||
except django.db.utils.IntegrityError:
|
|
||||||
raise JsonableError(_("User group '{}' already exists.").format(name))
|
|
||||||
do_send_user_group_update_event(user_group, dict(name=name))
|
|
||||||
|
|
||||||
|
|
||||||
def do_update_user_group_description(user_group: UserGroup, description: str) -> None:
|
|
||||||
user_group.description = description
|
|
||||||
user_group.save(update_fields=["description"])
|
|
||||||
do_send_user_group_update_event(user_group, dict(description=description))
|
|
||||||
|
|
||||||
|
|
||||||
def do_update_outgoing_webhook_service(
|
def do_update_outgoing_webhook_service(
|
||||||
bot_profile: UserProfile, service_interface: int, service_payload_url: str
|
bot_profile: UserProfile, service_interface: int, service_payload_url: str
|
||||||
) -> None:
|
) -> None:
|
||||||
@@ -8676,46 +8564,6 @@ def get_owned_bot_dicts(
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def do_send_user_group_members_update_event(
|
|
||||||
event_name: str, user_group: UserGroup, user_ids: List[int]
|
|
||||||
) -> None:
|
|
||||||
event = dict(type="user_group", op=event_name, group_id=user_group.id, user_ids=user_ids)
|
|
||||||
transaction.on_commit(
|
|
||||||
lambda: send_event(user_group.realm, event, active_user_ids(user_group.realm_id))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@transaction.atomic(savepoint=False)
|
|
||||||
def bulk_add_members_to_user_group(user_group: UserGroup, user_profile_ids: List[int]) -> None:
|
|
||||||
memberships = [
|
|
||||||
UserGroupMembership(user_group_id=user_group.id, user_profile_id=user_id)
|
|
||||||
for user_id in user_profile_ids
|
|
||||||
]
|
|
||||||
UserGroupMembership.objects.bulk_create(memberships)
|
|
||||||
|
|
||||||
do_send_user_group_members_update_event("add_members", user_group, user_profile_ids)
|
|
||||||
|
|
||||||
|
|
||||||
@transaction.atomic(savepoint=False)
|
|
||||||
def remove_members_from_user_group(user_group: UserGroup, user_profile_ids: List[int]) -> None:
|
|
||||||
UserGroupMembership.objects.filter(
|
|
||||||
user_group_id=user_group.id, user_profile_id__in=user_profile_ids
|
|
||||||
).delete()
|
|
||||||
|
|
||||||
do_send_user_group_members_update_event("remove_members", user_group, user_profile_ids)
|
|
||||||
|
|
||||||
|
|
||||||
def do_send_delete_user_group_event(realm: Realm, user_group_id: int, realm_id: int) -> None:
|
|
||||||
event = dict(type="user_group", op="remove", group_id=user_group_id)
|
|
||||||
send_event(realm, event, active_user_ids(realm_id))
|
|
||||||
|
|
||||||
|
|
||||||
def check_delete_user_group(user_group_id: int, user_profile: UserProfile) -> None:
|
|
||||||
user_group = access_user_group_by_id(user_group_id, user_profile)
|
|
||||||
user_group.delete()
|
|
||||||
do_send_delete_user_group_event(user_profile.realm, user_group_id, user_profile.realm.id)
|
|
||||||
|
|
||||||
|
|
||||||
def do_send_realm_reactivation_email(realm: Realm, *, acting_user: Optional[UserProfile]) -> None:
|
def do_send_realm_reactivation_email(realm: Realm, *, acting_user: Optional[UserProfile]) -> None:
|
||||||
url = create_confirmation_link(realm, Confirmation.REALM_REACTIVATION)
|
url = create_confirmation_link(realm, Confirmation.REALM_REACTIVATION)
|
||||||
RealmAuditLog.objects.create(
|
RealmAuditLog.objects.create(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from zerver.lib.actions import promote_new_full_members
|
from zerver.actions.user_groups import promote_new_full_members
|
||||||
from zerver.lib.management import ZulipBaseCommand
|
from zerver.lib.management import ZulipBaseCommand
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,14 +13,19 @@ from unittest import mock
|
|||||||
import orjson
|
import orjson
|
||||||
from django.utils.timezone import now as timezone_now
|
from django.utils.timezone import now as timezone_now
|
||||||
|
|
||||||
|
from zerver.actions.user_groups import (
|
||||||
|
bulk_add_members_to_user_group,
|
||||||
|
check_add_user_group,
|
||||||
|
check_delete_user_group,
|
||||||
|
do_update_user_group_description,
|
||||||
|
do_update_user_group_name,
|
||||||
|
remove_members_from_user_group,
|
||||||
|
)
|
||||||
from zerver.actions.video_calls import do_set_zoom_token
|
from zerver.actions.video_calls import do_set_zoom_token
|
||||||
from zerver.lib.actions import (
|
from zerver.lib.actions import (
|
||||||
bulk_add_members_to_user_group,
|
|
||||||
bulk_add_subscriptions,
|
bulk_add_subscriptions,
|
||||||
bulk_remove_subscriptions,
|
bulk_remove_subscriptions,
|
||||||
check_add_realm_emoji,
|
check_add_realm_emoji,
|
||||||
check_add_user_group,
|
|
||||||
check_delete_user_group,
|
|
||||||
check_send_typing_notification,
|
check_send_typing_notification,
|
||||||
do_add_alert_words,
|
do_add_alert_words,
|
||||||
do_add_default_stream,
|
do_add_default_stream,
|
||||||
@@ -92,12 +97,9 @@ from zerver.lib.actions import (
|
|||||||
do_update_message_flags,
|
do_update_message_flags,
|
||||||
do_update_outgoing_webhook_service,
|
do_update_outgoing_webhook_service,
|
||||||
do_update_user_custom_profile_data_if_changed,
|
do_update_user_custom_profile_data_if_changed,
|
||||||
do_update_user_group_description,
|
|
||||||
do_update_user_group_name,
|
|
||||||
do_update_user_presence,
|
do_update_user_presence,
|
||||||
do_update_user_status,
|
do_update_user_status,
|
||||||
lookup_default_stream_groups,
|
lookup_default_stream_groups,
|
||||||
remove_members_from_user_group,
|
|
||||||
try_add_realm_custom_profile_field,
|
try_add_realm_custom_profile_field,
|
||||||
try_update_realm_custom_profile_field,
|
try_update_realm_custom_profile_field,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ from unittest import mock
|
|||||||
import orjson
|
import orjson
|
||||||
from django.utils.timezone import now as timezone_now
|
from django.utils.timezone import now as timezone_now
|
||||||
|
|
||||||
from zerver.lib.actions import do_set_realm_property, ensure_stream, promote_new_full_members
|
from zerver.actions.user_groups import promote_new_full_members
|
||||||
|
from zerver.lib.actions import do_set_realm_property, ensure_stream
|
||||||
from zerver.lib.test_classes import ZulipTestCase
|
from zerver.lib.test_classes import ZulipTestCase
|
||||||
from zerver.lib.test_helpers import most_recent_usermessage
|
from zerver.lib.test_helpers import most_recent_usermessage
|
||||||
from zerver.lib.user_groups import (
|
from zerver.lib.user_groups import (
|
||||||
@@ -757,7 +758,7 @@ class UserGroupAPITestCase(UserGroupTestCase):
|
|||||||
|
|
||||||
current_time = timezone_now()
|
current_time = timezone_now()
|
||||||
with mock.patch(
|
with mock.patch(
|
||||||
"zerver.lib.actions.timezone_now", return_value=current_time + timedelta(days=3)
|
"zerver.actions.user_groups.timezone_now", return_value=current_time + timedelta(days=3)
|
||||||
):
|
):
|
||||||
promote_new_full_members()
|
promote_new_full_members()
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ from typing import Sequence
|
|||||||
from django.http import HttpRequest, HttpResponse
|
from django.http import HttpRequest, HttpResponse
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from zerver.decorator import require_member_or_admin, require_user_group_edit_permission
|
from zerver.actions.user_groups import (
|
||||||
from zerver.lib.actions import (
|
|
||||||
bulk_add_members_to_user_group,
|
bulk_add_members_to_user_group,
|
||||||
check_add_user_group,
|
check_add_user_group,
|
||||||
check_delete_user_group,
|
check_delete_user_group,
|
||||||
@@ -12,6 +11,7 @@ from zerver.lib.actions import (
|
|||||||
do_update_user_group_name,
|
do_update_user_group_name,
|
||||||
remove_members_from_user_group,
|
remove_members_from_user_group,
|
||||||
)
|
)
|
||||||
|
from zerver.decorator import require_member_or_admin, require_user_group_edit_permission
|
||||||
from zerver.lib.exceptions import JsonableError
|
from zerver.lib.exceptions import JsonableError
|
||||||
from zerver.lib.request import REQ, has_request_variables
|
from zerver.lib.request import REQ, has_request_variables
|
||||||
from zerver.lib.response import json_success
|
from zerver.lib.response import json_success
|
||||||
|
|||||||
Reference in New Issue
Block a user