def create_user_groups() -> None: zulip = get_realm("zulip") members = [ get_user_by_delivery_email("*****@*****.**", zulip), get_user_by_delivery_email("*****@*****.**", zulip), ] create_user_group("hamletcharacters", members, zulip, description="Characters of Hamlet")
def create_user_groups() -> None: zulip = get_realm('zulip') members = [ get_user('*****@*****.**', zulip), get_user('*****@*****.**', zulip) ] create_user_group("hamletcharacters", members, zulip, description="Characters of Hamlet")
def test_user_group_update_to_already_existing_name(self) -> None: hamlet = self.example_user("hamlet") self.login_user(hamlet) realm = get_realm("zulip") support_user_group = create_user_group("support", [hamlet], realm) marketing_user_group = create_user_group("marketing", [hamlet], realm) params = { "name": marketing_user_group.name, } result = self.client_patch(f"/json/user_groups/{support_user_group.id}", info=params) self.assert_json_error(result, f"User group '{marketing_user_group.name}' already exists.")
def test_user_group_update_to_already_existing_name(self) -> None: hamlet = self.example_user('hamlet') self.login(hamlet.email) realm = get_realm('zulip') support_user_group = create_user_group('support', [hamlet], realm) marketing_user_group = create_user_group('marketing', [hamlet], realm) params = { 'name': marketing_user_group.name, } result = self.client_patch('/json/user_groups/{}'.format(support_user_group.id), info=params) self.assert_json_error( result, "User group '{}' already exists.".format(marketing_user_group.name))
def test_user_group_update_to_already_existing_name(self) -> None: hamlet = self.example_user('hamlet') self.login(hamlet.email) realm = get_realm('zulip') support_user_group = create_user_group('support', [hamlet], realm) marketing_user_group = create_user_group('marketing', [hamlet], realm) params = { 'name': marketing_user_group.name, } result = self.client_patch('/json/user_groups/{}'.format(support_user_group.id), info=params) self.assert_json_error( result, "User group '{}' already exists.".format(marketing_user_group.name))
def test_mentions(self) -> None: cordelia = self.example_user('cordelia') hamlet = self.example_user('hamlet') othello = self.example_user('othello') zoe = self.example_user('ZOE') realm = cordelia.realm group_name = 'support' stream_name = 'Dev Help' content_with_group_mention = 'hey @*support* can you help us with this?' ensure_stream(realm, stream_name) all_users = {cordelia, hamlet, othello, zoe} support_team = {hamlet, zoe} sender = cordelia other_users = all_users - support_team for user in all_users: self.subscribe(user, stream_name) create_user_group( name=group_name, members=list(support_team), realm=realm, ) payload = dict( type="stream", to=stream_name, sender=sender.email, client='test suite', topic='whatever', content=content_with_group_mention, ) with mock.patch('logging.info'): result = self.api_post(sender.email, "/json/messages", payload) self.assert_json_success(result) for user in support_team: um = most_recent_usermessage(user) self.assertTrue(um.flags.mentioned) for user in other_users: um = most_recent_usermessage(user) self.assertFalse(um.flags.mentioned)
def test_mentions(self) -> None: cordelia = self.example_user('cordelia') hamlet = self.example_user('hamlet') othello = self.example_user('othello') zoe = self.example_user('ZOE') realm = cordelia.realm group_name = 'support' stream_name = 'Dev Help' content_with_group_mention = 'hey @*support* can you help us with this?' ensure_stream(realm, stream_name) all_users = {cordelia, hamlet, othello, zoe} support_team = {hamlet, zoe} sender = cordelia other_users = all_users - support_team for user in all_users: self.subscribe(user, stream_name) create_user_group( name=group_name, members=list(support_team), realm=realm, ) payload = dict( type="stream", to=stream_name, sender=sender.email, client='test suite', subject='whatever', content=content_with_group_mention, ) with mock.patch('logging.info'): result = self.api_post(sender.email, "/json/messages", payload) self.assert_json_success(result) for user in support_team: um = most_recent_usermessage(user) self.assertTrue(um.flags.mentioned) for user in other_users: um = most_recent_usermessage(user) self.assertFalse(um.flags.mentioned)
def test_mentions(self) -> None: cordelia = self.example_user("cordelia") hamlet = self.example_user("hamlet") othello = self.example_user("othello") zoe = self.example_user("ZOE") realm = cordelia.realm group_name = "support" stream_name = "Dev Help" content_with_group_mention = "hey @*support* can you help us with this?" ensure_stream(realm, stream_name) all_users = {cordelia, hamlet, othello, zoe} support_team = {hamlet, zoe} sender = cordelia other_users = all_users - support_team for user in all_users: self.subscribe(user, stream_name) create_user_group( name=group_name, members=list(support_team), realm=realm, ) payload = dict( type="stream", to=stream_name, client="test suite", topic="whatever", content=content_with_group_mention, ) result = self.api_post(sender, "/json/messages", payload) self.assert_json_success(result) for user in support_team: um = most_recent_usermessage(user) self.assertTrue(um.flags.mentioned) for user in other_users: um = most_recent_usermessage(user) self.assertFalse(um.flags.mentioned)
def test_user_group_delete(self) -> None: hamlet = self.example_user("hamlet") self.login("hamlet") params = { "name": "support", "members": orjson.dumps([hamlet.id]).decode(), "description": "Support team", } self.client_post("/json/user_groups/create", info=params) user_group = UserGroup.objects.get(name="support") # Test success self.assertEqual(UserGroup.objects.filter(realm=hamlet.realm).count(), 9) self.assertEqual(UserGroupMembership.objects.count(), 19) result = self.client_delete(f"/json/user_groups/{user_group.id}") self.assert_json_success(result) self.assertEqual(UserGroup.objects.filter(realm=hamlet.realm).count(), 8) self.assertEqual(UserGroupMembership.objects.count(), 18) # Test when invalid user group is supplied result = self.client_delete("/json/user_groups/1111") self.assert_json_error(result, "Invalid user group") lear_realm = get_realm("lear") lear_test_group = create_user_group("test", [self.lear_user("cordelia")], lear_realm) result = self.client_delete(f"/json/user_groups/{lear_test_group.id}") self.assert_json_error(result, "Invalid user group")
def test_user_groups_in_realm_serialized(self) -> None: realm = get_realm("zulip") user_group = UserGroup.objects.first() assert user_group is not None membership = UserGroupMembership.objects.filter(user_group=user_group) membership = membership.values_list("user_profile_id", flat=True) empty_user_group = create_user_group("newgroup", [], realm) user_groups = user_groups_in_realm_serialized(realm) self.assert_length(user_groups, 9) self.assertEqual(user_groups[0]["id"], user_group.id) self.assertEqual(user_groups[0]["name"], "@role:owners") self.assertEqual(user_groups[0]["description"], "Owners of this organization") self.assertEqual(set(user_groups[0]["members"]), set(membership)) self.assertEqual(user_groups[0]["subgroups"], []) admins_system_group = UserGroup.objects.get(name="@role:administrators", realm=realm) self.assertEqual(user_groups[1]["id"], admins_system_group.id) # Check that owners system group is present in "subgroups" self.assertEqual(user_groups[1]["subgroups"], [user_group.id]) self.assertEqual(user_groups[8]["id"], empty_user_group.id) self.assertEqual(user_groups[8]["name"], "newgroup") self.assertEqual(user_groups[8]["description"], "") self.assertEqual(user_groups[8]["members"], [])
def test_user_group_update(self) -> None: hamlet = self.example_user("hamlet") self.login("hamlet") params = { "name": "support", "members": orjson.dumps([hamlet.id]).decode(), "description": "Support team", } self.client_post("/json/user_groups/create", info=params) user_group = UserGroup.objects.get(name="support") # Test success params = { "name": "help", "description": "Troubleshooting team", } result = self.client_patch(f"/json/user_groups/{user_group.id}", info=params) self.assert_json_success(result) # Test when new data is not supplied. result = self.client_patch(f"/json/user_groups/{user_group.id}", info={}) self.assert_json_error(result, "No new data supplied") # Test when invalid user group is supplied params = {"name": "help"} result = self.client_patch("/json/user_groups/1111", info=params) self.assert_json_error(result, "Invalid user group") lear_realm = get_realm("lear") lear_test_group = create_user_group("test", [self.lear_user("cordelia")], lear_realm) result = self.client_patch(f"/json/user_groups/{lear_test_group.id}", info=params) self.assert_json_error(result, "Invalid user group")
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 test_get_subgroups_of_user_group(self) -> None: realm = get_realm("zulip") owners_group = UserGroup.objects.get(name="@role:owners", realm=realm, is_system_group=True) admins_group = UserGroup.objects.get(name="@role:administrators", realm=realm, is_system_group=True) moderators_group = UserGroup.objects.get(name="@role:moderators", realm=realm, is_system_group=True) self.login("iago") # Test invalid user group id result = self.client_get("/json/user_groups/1111/subgroups") self.assert_json_error(result, "Invalid user group") lear_realm = get_realm("lear") lear_test_group = create_user_group("test", [self.lear_user("cordelia")], lear_realm) result = self.client_get( f"/json/user_groups/{lear_test_group.id}/subgroups") self.assert_json_error(result, "Invalid user group") result_dict = orjson.loads( self.client_get( f"/json/user_groups/{moderators_group.id}/subgroups").content) self.assertEqual(result_dict["subgroups"], [admins_group.id, owners_group.id]) params = {"direct_subgroup_only": orjson.dumps(True).decode()} result_dict = orjson.loads( self.client_get( f"/json/user_groups/{moderators_group.id}/subgroups", info=params).content) self.assertCountEqual(result_dict["subgroups"], [admins_group.id]) # User not part of a group can also get its subgroups. self.login("hamlet") result_dict = orjson.loads( self.client_get( f"/json/user_groups/{moderators_group.id}/subgroups").content) self.assertEqual(result_dict["subgroups"], [admins_group.id, owners_group.id]) params = {"direct_subgroup_only": orjson.dumps(True).decode()} result_dict = orjson.loads( self.client_get( f"/json/user_groups/{moderators_group.id}/subgroups", info=params).content) self.assertCountEqual(result_dict["subgroups"], [admins_group.id])
def test_get_user_group_members(self) -> None: realm = get_realm("zulip") iago = self.example_user("iago") desdemona = self.example_user("desdemona") shiva = self.example_user("shiva") moderators_group = UserGroup.objects.get(name="@role:moderators", realm=realm, is_system_group=True) self.login("iago") # Test invalid user group id result = self.client_get("/json/user_groups/1111/members") self.assert_json_error(result, "Invalid user group") lear_realm = get_realm("lear") lear_test_group = create_user_group("test", [self.lear_user("cordelia")], lear_realm) result = self.client_get( f"/json/user_groups/{lear_test_group.id}/members") self.assert_json_error(result, "Invalid user group") result_dict = orjson.loads( self.client_get( f"/json/user_groups/{moderators_group.id}/members").content) self.assertCountEqual(result_dict["members"], [desdemona.id, iago.id, shiva.id]) params = {"direct_member_only": orjson.dumps(True).decode()} result_dict = orjson.loads( self.client_get(f"/json/user_groups/{moderators_group.id}/members", info=params).content) self.assertCountEqual(result_dict["members"], [shiva.id]) # User not part of a group can also get its members. self.login("hamlet") result_dict = orjson.loads( self.client_get( f"/json/user_groups/{moderators_group.id}/members").content) self.assertCountEqual(result_dict["members"], [desdemona.id, iago.id, shiva.id]) params = {"direct_member_only": orjson.dumps(True).decode()} result_dict = orjson.loads( self.client_get(f"/json/user_groups/{moderators_group.id}/members", info=params).content) self.assertCountEqual(result_dict["members"], [shiva.id])
def test_user_groups_in_realm_serialized(self) -> None: realm = get_realm('zulip') user_group = UserGroup.objects.first() membership = UserGroupMembership.objects.filter(user_group=user_group) membership = membership.values_list('user_profile_id', flat=True) empty_user_group = create_user_group('newgroup', [], realm) user_groups = user_groups_in_realm_serialized(realm) self.assertEqual(len(user_groups), 2) self.assertEqual(user_groups[0]['id'], user_group.id) self.assertEqual(user_groups[0]['name'], 'hamletcharacters') self.assertEqual(user_groups[0]['description'], 'Characters of Hamlet') self.assertEqual(set(user_groups[0]['members']), set(membership)) self.assertEqual(user_groups[1]['id'], empty_user_group.id) self.assertEqual(user_groups[1]['name'], 'newgroup') self.assertEqual(user_groups[1]['description'], '') self.assertEqual(user_groups[1]['members'], [])
def test_user_groups_in_realm_serialized(self) -> None: realm = get_realm('zulip') user_group = UserGroup.objects.first() membership = UserGroupMembership.objects.filter(user_group=user_group) membership = membership.values_list('user_profile_id', flat=True) empty_user_group = create_user_group('newgroup', [], realm) user_groups = user_groups_in_realm_serialized(realm) self.assertEqual(len(user_groups), 2) self.assertEqual(user_groups[0]['id'], user_group.id) self.assertEqual(user_groups[0]['name'], 'hamletcharacters') self.assertEqual(user_groups[0]['description'], 'Characters of Hamlet') self.assertEqual(set(user_groups[0]['members']), set(membership)) self.assertEqual(user_groups[1]['id'], empty_user_group.id) self.assertEqual(user_groups[1]['name'], 'newgroup') self.assertEqual(user_groups[1]['description'], '') self.assertEqual(user_groups[1]['members'], [])
def test_user_groups_in_realm_serialized(self) -> None: realm = get_realm("zulip") user_group = UserGroup.objects.first() membership = UserGroupMembership.objects.filter(user_group=user_group) membership = membership.values_list("user_profile_id", flat=True) empty_user_group = create_user_group("newgroup", [], realm) user_groups = user_groups_in_realm_serialized(realm) self.assertEqual(len(user_groups), 2) self.assertEqual(user_groups[0]["id"], user_group.id) self.assertEqual(user_groups[0]["name"], "hamletcharacters") self.assertEqual(user_groups[0]["description"], "Characters of Hamlet") self.assertEqual(set(user_groups[0]["members"]), set(membership)) self.assertEqual(user_groups[1]["id"], empty_user_group.id) self.assertEqual(user_groups[1]["name"], "newgroup") self.assertEqual(user_groups[1]["description"], "") self.assertEqual(user_groups[1]["members"], [])
def test_editing_system_user_groups(self) -> None: desdemona = self.example_user("desdemona") iago = self.example_user("iago") othello = self.example_user("othello") aaron = self.example_user("aaron") members = [iago, othello] user_group = create_user_group( "Full members", members, iago.realm, description="Full members user group", is_system_group=True, ) def check_support_group_permission(acting_user: UserProfile) -> None: self.login_user(acting_user) params = { "name": "Full members user group", "description": "Full members system user group.", } result = self.client_patch(f"/json/user_groups/{user_group.id}", info=params) self.assert_json_error(result, "Insufficient permission") params = {"add": orjson.dumps([aaron.id]).decode()} result = self.client_post( f"/json/user_groups/{user_group.id}/members", info=params) self.assert_json_error(result, "Insufficient permission") params = {"delete": orjson.dumps([othello.id]).decode()} result = self.client_post( f"/json/user_groups/{user_group.id}/members", info=params) self.assert_json_error(result, "Insufficient permission") check_support_group_permission(desdemona) check_support_group_permission(iago) check_support_group_permission(othello)
def create_user_groups() -> None: zulip = get_realm('zulip') members = [get_user('*****@*****.**', zulip), get_user('*****@*****.**', zulip)] create_user_group("hamletcharacters", members, zulip, description="Characters of Hamlet")
def test_end_to_end_missedmessage_hook(self) -> None: """Tests what arguments missedmessage_hook passes into maybe_enqueue_notifications. Combined with the previous test, this ensures that the missedmessage_hook is correct""" user_profile = self.example_user("hamlet") cordelia = self.example_user("cordelia") user_profile.enable_online_push_notifications = False user_profile.save() iago = self.example_user("iago") # Fetch the Denmark stream for testing stream = get_stream("Denmark", user_profile.realm) sub = Subscription.objects.get( user_profile=user_profile, recipient__type=Recipient.STREAM, recipient__type_id=stream.id, ) self.login_user(user_profile) def change_subscription_properties( user_profile: UserProfile, stream: Stream, sub: Subscription, properties: Dict[str, bool], ) -> None: for property_name, value in properties.items(): do_change_subscription_property( user_profile, sub, stream, property_name, value, acting_user=None ) def allocate_event_queue() -> ClientDescriptor: result = self.tornado_call( get_events, user_profile, { "apply_markdown": orjson.dumps(True).decode(), "client_gravatar": orjson.dumps(True).decode(), "event_types": orjson.dumps(["message"]).decode(), "user_client": "website", "dont_block": orjson.dumps(True).decode(), }, ) self.assert_json_success(result) queue_id = orjson.loads(result.content)["queue_id"] return get_client_descriptor(queue_id) def destroy_event_queue(queue_id: str) -> None: result = self.tornado_call(cleanup_event_queue, user_profile, {"queue_id": queue_id}) self.assert_json_success(result) def assert_maybe_enqueue_notifications_call_args( args_dict: Collection[Any], message_id: int, **kwargs: Any, ) -> None: expected_args_dict = self.get_maybe_enqueue_notifications_parameters( user_id=user_profile.id, acting_user_id=iago.id, message_id=message_id, **kwargs, ) self.assertEqual(args_dict, expected_args_dict) client_descriptor = allocate_event_queue() with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: # To test the missed_message hook, we first need to send a message msg_id = self.send_stream_message(iago, "Denmark") # Verify that nothing happens if you call it as not the # "last client descriptor", in which case the function # short-circuits, since the `missedmessage_hook` handler # for garbage-collection is only for the user's last queue. missedmessage_hook(user_profile.id, client_descriptor, False) mock_enqueue.assert_not_called() # Now verify that we called the appropriate enqueue function missedmessage_hook(user_profile.id, client_descriptor, True) mock_enqueue.assert_called_once() args_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, already_notified={"email_notified": False, "push_notified": False}, ) destroy_event_queue(client_descriptor.event_queue.id) # Test the hook with a private message; this should trigger notifications client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_personal_message(iago, user_profile) with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: missedmessage_hook(user_profile.id, client_descriptor, True) mock_enqueue.assert_called_once() args_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, pm_email_notify=True, pm_push_notify=True, already_notified={"email_notified": True, "push_notified": True}, ) destroy_event_queue(client_descriptor.event_queue.id) # If `enable_offline_email_notifications` is disabled, email otifications shouldn't # be sent even for PMs user_profile.enable_offline_email_notifications = False user_profile.save() client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_personal_message(iago, user_profile) with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: missedmessage_hook(user_profile.id, client_descriptor, True) mock_enqueue.assert_called_once() args_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, pm_email_notify=False, pm_push_notify=True, already_notified={"email_notified": False, "push_notified": True}, ) destroy_event_queue(client_descriptor.event_queue.id) user_profile.enable_offline_email_notifications = True user_profile.save() # Test the hook with a mention; this should trigger notifications client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message( self.example_user("iago"), "Denmark", content="@**King Hamlet** what's up?" ) with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: missedmessage_hook(user_profile.id, client_descriptor, True) mock_enqueue.assert_called_once() args_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, mention_push_notify=True, mention_email_notify=True, already_notified={"email_notified": True, "push_notified": True}, ) destroy_event_queue(client_descriptor.event_queue.id) # If `enable_offline_push_notifications` is disabled, push otifications shouldn't # be sent even for mentions user_profile.enable_offline_push_notifications = False user_profile.save() client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_personal_message(iago, user_profile) with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: missedmessage_hook(user_profile.id, client_descriptor, True) mock_enqueue.assert_called_once() args_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, pm_email_notify=True, pm_push_notify=False, already_notified={"email_notified": True, "push_notified": False}, ) destroy_event_queue(client_descriptor.event_queue.id) user_profile.enable_offline_push_notifications = True user_profile.save() # Test the hook with a wildcard mention; this should trigger notifications client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message(iago, "Denmark", content="@**all** what's up?") with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: missedmessage_hook(user_profile.id, client_descriptor, True) mock_enqueue.assert_called_once() args_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, wildcard_mention_email_notify=True, wildcard_mention_push_notify=True, already_notified={"email_notified": True, "push_notified": True}, ) destroy_event_queue(client_descriptor.event_queue.id) # Wildcard mentions in muted streams don't notify. change_subscription_properties(user_profile, stream, sub, {"is_muted": True}) client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message(iago, "Denmark", content="@**all** what's up?") with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: missedmessage_hook(user_profile.id, client_descriptor, True) mock_enqueue.assert_called_once() args_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, wildcard_mention_email_notify=False, wildcard_mention_push_notify=False, message_id=msg_id, already_notified={"email_notified": False, "push_notified": False}, ) destroy_event_queue(client_descriptor.event_queue.id) change_subscription_properties(user_profile, stream, sub, {"is_muted": False}) # With wildcard_mentions_notify=False, we treat the user as not mentioned. user_profile.wildcard_mentions_notify = False user_profile.save() client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message(iago, "Denmark", content="@**all** what's up?") with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: missedmessage_hook(user_profile.id, client_descriptor, True) mock_enqueue.assert_called_once() args_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, wildcard_mention_email_notify=False, wildcard_mention_push_notify=False, already_notified={"email_notified": False, "push_notified": False}, ) destroy_event_queue(client_descriptor.event_queue.id) user_profile.wildcard_mentions_notify = True user_profile.save() # If wildcard_mentions_notify=True for a stream and False for a user, we treat the user # as mentioned for that stream. user_profile.wildcard_mentions_notify = False sub.wildcard_mentions_notify = True user_profile.save() sub.save() client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message(iago, "Denmark", content="@**all** what's up?") with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: missedmessage_hook(user_profile.id, client_descriptor, True) mock_enqueue.assert_called_once() args_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, wildcard_mention_email_notify=True, wildcard_mention_push_notify=True, already_notified={"email_notified": True, "push_notified": True}, ) destroy_event_queue(client_descriptor.event_queue.id) user_profile.wildcard_mentions_notify = True sub.wildcard_mentions_notify = None user_profile.save() sub.save() # If notifications for personal mentions themselves have been turned off, # even turning on `wildcard_mentions_notify` should not send notifications user_profile.enable_offline_email_notifications = False user_profile.wildcard_mentions_notify = True user_profile.save() client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message(iago, "Denmark", content="@**all** what's up?") with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: missedmessage_hook(user_profile.id, client_descriptor, True) mock_enqueue.assert_called_once() args_dict = mock_enqueue.call_args_list[0][1] # We've turned off email notifications for personal mentions, but push notifications # for personal mentions are still on. # Because `wildcard_mentions_notify` is True, a message with `@all` should follow the # personal mention settings assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, wildcard_mention_email_notify=False, wildcard_mention_push_notify=True, already_notified={"email_notified": False, "push_notified": True}, ) destroy_event_queue(client_descriptor.event_queue.id) user_profile.enable_offline_email_notifications = True user_profile.wildcard_mentions_notify = True user_profile.save() # Test with a user group mention hamlet_and_cordelia = create_user_group( "hamlet_and_cordelia", [user_profile, cordelia], cordelia.realm ) client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message( iago, "Denmark", content="@*hamlet_and_cordelia* what's up?" ) with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: missedmessage_hook(user_profile.id, client_descriptor, True) mock_enqueue.assert_called_once() args_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, mention_push_notify=True, mention_email_notify=True, mentioned_user_group_id=hamlet_and_cordelia.id, already_notified={"email_notified": True, "push_notified": True}, ) destroy_event_queue(client_descriptor.event_queue.id) remove_user_from_user_group(user_profile, hamlet_and_cordelia) remove_user_from_user_group(cordelia, hamlet_and_cordelia) # Test the hook with a stream message with stream_push_notify change_subscription_properties(user_profile, stream, sub, {"push_notifications": True}) client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message(iago, "Denmark", content="what's up everyone?") with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: missedmessage_hook(user_profile.id, client_descriptor, True) mock_enqueue.assert_called_once() args_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, stream_push_notify=True, stream_email_notify=False, already_notified={"email_notified": False, "push_notified": True}, ) destroy_event_queue(client_descriptor.event_queue.id) # Test the hook with a stream message with stream_email_notify client_descriptor = allocate_event_queue() change_subscription_properties( user_profile, stream, sub, {"push_notifications": False, "email_notifications": True} ) self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message(iago, "Denmark", content="what's up everyone?") with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: missedmessage_hook(user_profile.id, client_descriptor, True) mock_enqueue.assert_called_once() args_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, stream_push_notify=False, stream_email_notify=True, already_notified={"email_notified": True, "push_notified": False}, ) destroy_event_queue(client_descriptor.event_queue.id) # Test the hook with stream message with stream_push_notify on # a muted topic, which we should not push notify for client_descriptor = allocate_event_queue() change_subscription_properties( user_profile, stream, sub, {"push_notifications": True, "email_notifications": False} ) self.assertTrue(client_descriptor.event_queue.empty()) do_mute_topic(user_profile, stream, "mutingtest") msg_id = self.send_stream_message( iago, "Denmark", content="what's up everyone?", topic_name="mutingtest", ) with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: missedmessage_hook(user_profile.id, client_descriptor, True) mock_enqueue.assert_called_once() args_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, already_notified={"email_notified": False, "push_notified": False}, ) destroy_event_queue(client_descriptor.event_queue.id) # Test the hook with stream message with stream_email_notify on # a muted stream, which we should not push notify for client_descriptor = allocate_event_queue() change_subscription_properties( user_profile, stream, sub, {"push_notifications": False, "email_notifications": True} ) self.assertTrue(client_descriptor.event_queue.empty()) change_subscription_properties(user_profile, stream, sub, {"is_muted": True}) msg_id = self.send_stream_message(iago, "Denmark", content="what's up everyone?") with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: missedmessage_hook(user_profile.id, client_descriptor, True) mock_enqueue.assert_called_once() args_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, already_notified={"email_notified": False, "push_notified": False}, ) destroy_event_queue(client_descriptor.event_queue.id) # Clean up the state we just changed (not necessary unless we add more test code below) change_subscription_properties( user_profile, stream, sub, {"push_notifications": True, "is_muted": False} ) # Test the hook when the sender has been muted result = self.api_post(user_profile, f"/api/v1/users/me/muted_users/{iago.id}") self.assert_json_success(result) client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_personal_message(iago, user_profile) with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: missedmessage_hook(user_profile.id, client_descriptor, True) mock_enqueue.assert_called_once() args_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, sender_is_muted=True, pm_email_notify=True, pm_push_notify=True, already_notified={"email_notified": False, "push_notified": False}, ) destroy_event_queue(client_descriptor.event_queue.id) result = self.api_delete(user_profile, f"/api/v1/users/me/muted_users/{iago.id}") self.assert_json_success(result)
def test_user_group_mentions_map(self) -> None: hamlet = self.example_user("hamlet") cordelia = self.example_user("cordelia") realm = hamlet.realm hamlet_only = create_user_group("hamlet_only", [hamlet], realm) hamlet_and_cordelia = create_user_group("hamlet_and_cordelia", [hamlet, cordelia], realm) # Base case. No user/user group mentions result = get_user_group_mentions_data( mentioned_user_ids=set(), mentioned_user_group_ids=[], mention_data=MentionData(realm.id, "no group mentioned"), ) self.assertDictEqual(result, {}) # Only user group mentions, no personal mentions result = get_user_group_mentions_data( mentioned_user_ids=set(), mentioned_user_group_ids=[hamlet_and_cordelia.id], mention_data=MentionData(realm.id, "hey @*hamlet_and_cordelia*!"), ) self.assertDictEqual( result, { hamlet.id: hamlet_and_cordelia.id, cordelia.id: hamlet_and_cordelia.id, }, ) # Hamlet is mentioned in two user groups # Test that we consider the smaller user group result = get_user_group_mentions_data( mentioned_user_ids=set(), mentioned_user_group_ids=[hamlet_and_cordelia.id, hamlet_only.id], mention_data=MentionData(realm.id, "hey @*hamlet_and_cordelia* and @*hamlet_only*"), ) self.assertDictEqual( result, { hamlet.id: hamlet_only.id, cordelia.id: hamlet_and_cordelia.id, }, ) # To make sure we aren't getting the expected data from over-writing in a loop, # test the same setup as above, but with reversed group ids. result = get_user_group_mentions_data( mentioned_user_ids=set(), mentioned_user_group_ids=[hamlet_only.id, hamlet_and_cordelia.id], mention_data=MentionData(realm.id, "hey @*hamlet_only* and @*hamlet_and_cordelia*"), ) self.assertDictEqual( result, { hamlet.id: hamlet_only.id, cordelia.id: hamlet_and_cordelia.id, }, ) # Personal and user group mentioned. Test that we don't consider the user # group mention for Hamlet in this case. result = get_user_group_mentions_data( mentioned_user_ids={hamlet.id}, mentioned_user_group_ids=[hamlet_and_cordelia.id], mention_data=MentionData(realm.id, "hey @*hamlet_and_cordelia*!"), ) self.assertDictEqual( result, { cordelia.id: hamlet_and_cordelia.id, }, )
def create_user_group_for_test( self, group_name: str, realm: Realm = get_realm('zulip')) -> UserGroup: members = [self.example_user('othello')] return create_user_group(group_name, members, realm)
def test_only_admin_manage_groups(self) -> None: iago = self.example_user('iago') hamlet = self.example_user('hamlet') cordelia = self.example_user('cordelia') self.login_user(iago) do_set_realm_property(iago.realm, 'user_group_edit_policy', Realm.USER_GROUP_EDIT_POLICY_ADMINS) params = { 'name': 'support', 'members': orjson.dumps([iago.id, hamlet.id]).decode(), 'description': 'Support team', } result = self.client_post('/json/user_groups/create', info=params) self.assert_json_success(result) user_group = UserGroup.objects.get(name='support') # Test add member params = {'add': orjson.dumps([cordelia.id]).decode()} result = self.client_post(f'/json/user_groups/{user_group.id}/members', info=params) self.assert_json_success(result) # Test remove member params = {'delete': orjson.dumps([cordelia.id]).decode()} result = self.client_post(f'/json/user_groups/{user_group.id}/members', info=params) self.assert_json_success(result) # Test changing groups name params = { 'name': 'help', 'description': 'Troubleshooting', } result = self.client_patch(f'/json/user_groups/{user_group.id}', info=params) self.assert_json_success(result) # Test delete a group result = self.client_delete(f'/json/user_groups/{user_group.id}') self.assert_json_success(result) user_group = create_user_group( name='support', members=[hamlet, iago], realm=iago.realm, ) self.logout() self.login('hamlet') # Test creating a group params = { 'name': 'support2', 'members': orjson.dumps([hamlet.id]).decode(), 'description': 'Support team', } result = self.client_post('/json/user_groups/create', info=params) self.assert_json_error(result, "Must be an organization administrator") # Test add member params = {'add': orjson.dumps([cordelia.id]).decode()} result = self.client_post(f'/json/user_groups/{user_group.id}/members', info=params) self.assert_json_error(result, "Must be an organization administrator") # Test delete a group result = self.client_delete(f'/json/user_groups/{user_group.id}') self.assert_json_error(result, "Must be an organization administrator") # Test changing groups name params = { 'name': 'help', 'description': 'Troubleshooting', } result = self.client_patch(f'/json/user_groups/{user_group.id}', info=params) self.assert_json_error(result, "Must be an organization administrator")
def test_only_admin_manage_groups(self) -> None: iago = self.example_user("iago") hamlet = self.example_user("hamlet") cordelia = self.example_user("cordelia") self.login_user(iago) do_set_realm_property( iago.realm, "user_group_edit_policy", Realm.USER_GROUP_EDIT_POLICY_ADMINS, acting_user=None, ) params = { "name": "support", "members": orjson.dumps([iago.id, hamlet.id]).decode(), "description": "Support team", } result = self.client_post("/json/user_groups/create", info=params) self.assert_json_success(result) user_group = UserGroup.objects.get(name="support") # Test add member params = {"add": orjson.dumps([cordelia.id]).decode()} result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params) self.assert_json_success(result) # Test remove member params = {"delete": orjson.dumps([cordelia.id]).decode()} result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params) self.assert_json_success(result) # Test changing groups name params = { "name": "help", "description": "Troubleshooting", } result = self.client_patch(f"/json/user_groups/{user_group.id}", info=params) self.assert_json_success(result) # Test delete a group result = self.client_delete(f"/json/user_groups/{user_group.id}") self.assert_json_success(result) user_group = create_user_group( name="support", members=[hamlet, iago], realm=iago.realm, ) self.logout() self.login("hamlet") # Test creating a group params = { "name": "support2", "members": orjson.dumps([hamlet.id]).decode(), "description": "Support team", } result = self.client_post("/json/user_groups/create", info=params) self.assert_json_error(result, "Must be an organization administrator") # Test add member params = {"add": orjson.dumps([cordelia.id]).decode()} result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params) self.assert_json_error(result, "Must be an organization administrator") # Test delete a group result = self.client_delete(f"/json/user_groups/{user_group.id}") self.assert_json_error(result, "Must be an organization administrator") # Test changing groups name params = { "name": "help", "description": "Troubleshooting", } result = self.client_patch(f"/json/user_groups/{user_group.id}", info=params) self.assert_json_error(result, "Must be an organization administrator")
def test_updating_subgroups_of_user_group(self) -> None: realm = get_realm("zulip") desdemona = self.example_user("desdemona") iago = self.example_user("iago") hamlet = self.example_user("hamlet") othello = self.example_user("othello") leadership_group = create_user_group("leadership", [desdemona, iago, hamlet], realm) support_group = create_user_group("support", [hamlet, othello], realm) self.login("cordelia") # Non-admin and non-moderators who are not a member of group cannot add or remove subgroups. params = {"add": orjson.dumps([leadership_group.id]).decode()} result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) self.assert_json_error(result, "Insufficient permission") self.login("iago") result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) self.assert_json_success(result) params = {"delete": orjson.dumps([leadership_group.id]).decode()} result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) self.assert_json_success(result) self.login("shiva") params = {"add": orjson.dumps([leadership_group.id]).decode()} result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) self.assert_json_success(result) params = {"delete": orjson.dumps([leadership_group.id]).decode()} result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) self.assert_json_success(result) self.login("hamlet") # Non-admin and non-moderators who are a member of the user group can add or remove subgroups. params = {"add": orjson.dumps([leadership_group.id]).decode()} result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) self.assert_json_success(result) params = {"delete": orjson.dumps([leadership_group.id]).decode()} result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) self.assert_json_success(result) # Users need not be part of the subgroup to add or remove it from a user group. self.login("othello") params = {"add": orjson.dumps([leadership_group.id]).decode()} result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) self.assert_json_success(result) params = {"delete": orjson.dumps([leadership_group.id]).decode()} result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) self.assert_json_success(result) result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) self.assert_json_error( result, ("User group {group_id} is not a subgroup of this group.").format( group_id=leadership_group.id ), ) params = {"add": orjson.dumps([leadership_group.id]).decode()} self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) self.assert_json_error( result, ("User group {group_id} is already a subgroup of this group.").format( group_id=leadership_group.id ), ) lear_realm = get_realm("lear") lear_test_group = create_user_group("test", [self.lear_user("cordelia")], lear_realm) result = self.client_post(f"/json/user_groups/{lear_test_group.id}/subgroups", info=params) self.assert_json_error(result, "Invalid user group") # Invalid subgroup id will raise an error. params = {"add": orjson.dumps([leadership_group.id, 1111]).decode()} result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info=params) self.assert_json_error(result, "Invalid user group ID: 1111") # Test when nothing is provided result = self.client_post(f"/json/user_groups/{support_group.id}/subgroups", info={}) self.assert_json_error(result, 'Nothing to do. Specify at least one of "add" or "delete".')
def create_user_group_for_test(self, group_name, realm=get_realm('zulip')): # type: (Text, Realm) -> UserGroup members = [self.example_user('othello')] return create_user_group(group_name, members, realm)
def test_get_is_user_group_member_status(self) -> None: self.login("iago") realm = get_realm("zulip") desdemona = self.example_user("desdemona") iago = self.example_user("iago") othello = self.example_user("othello") admins_group = UserGroup.objects.get( realm=realm, name="@role:administrators", is_system_group=True ) # Invalid user ID. result = self.client_get(f"/json/user_groups/{admins_group.id}/members/1111") self.assert_json_error(result, "No such user") # Invalid user group ID. result = self.client_get(f"/json/user_groups/1111/members/{iago.id}") self.assert_json_error(result, "Invalid user group") lear_realm = get_realm("lear") lear_cordelia = self.lear_user("cordelia") lear_test_group = create_user_group("test", [lear_cordelia], lear_realm) result = self.client_get( f"/json/user_groups/{lear_test_group.id}/members/{lear_cordelia.id}" ) self.assert_json_error(result, "Invalid user group") result_dict = orjson.loads( self.client_get(f"/json/user_groups/{admins_group.id}/members/{othello.id}").content ) self.assertFalse(result_dict["is_user_group_member"]) result_dict = orjson.loads( self.client_get(f"/json/user_groups/{admins_group.id}/members/{iago.id}").content ) self.assertTrue(result_dict["is_user_group_member"]) # Checking membership of not a direct member but member of a subgroup. result_dict = orjson.loads( self.client_get(f"/json/user_groups/{admins_group.id}/members/{desdemona.id}").content ) self.assertTrue(result_dict["is_user_group_member"]) # Checking membership of not a direct member but member of a subgroup when passing # recursive parameter as False. params = {"direct_member_only": orjson.dumps(True).decode()} result_dict = orjson.loads( self.client_get( f"/json/user_groups/{admins_group.id}/members/{desdemona.id}", info=params ).content ) self.assertFalse(result_dict["is_user_group_member"]) # Logging in with a user not part of the group. self.login("hamlet") result_dict = orjson.loads( self.client_get(f"/json/user_groups/{admins_group.id}/members/{iago.id}").content ) self.assertTrue(result_dict["is_user_group_member"]) result_dict = orjson.loads( self.client_get(f"/json/user_groups/{admins_group.id}/members/{othello.id}").content ) self.assertFalse(result_dict["is_user_group_member"])
def create_user_group_for_test(self, group_name, realm=get_realm('zulip')): # type: (Text, Realm) -> UserGroup members = [self.example_user('othello')] return create_user_group(group_name, members, realm)
def create_user_group_for_test(self, group_name: str, realm: Realm=get_realm('zulip')) -> UserGroup: members = [self.example_user('othello')] return create_user_group(group_name, members, realm)