2014-01-29 22:03:40 +01:00
# -*- coding: utf-8 -*-
2019-02-02 23:53:44 +01:00
from typing import Any , Dict , List , Mapping , Optional , Set
2016-06-03 07:57:07 +02:00
2017-04-27 00:03:21 +02:00
from django . conf import settings
2018-05-16 03:36:18 +02:00
from django . core . exceptions import ValidationError
2016-09-12 17:21:49 +02:00
from django . http import HttpRequest , HttpResponse
2017-05-29 19:54:06 +02:00
from django . utils . timezone import now as timezone_now
2016-09-12 17:21:49 +02:00
2014-01-29 22:03:40 +01:00
from zerver . lib import cache
from zerver . lib . test_helpers import (
2017-01-30 04:31:24 +01:00
get_subscription , queries_captured , tornado_redirected_to_list
2016-11-10 19:30:09 +01:00
)
from zerver . lib . test_classes import (
ZulipTestCase ,
2014-01-29 22:03:40 +01:00
)
from zerver . decorator import (
JsonableError
)
2016-09-12 17:21:49 +02:00
from zerver . lib . response import (
json_error ,
json_success ,
)
2017-01-30 06:44:31 +01:00
from zerver . lib . streams import (
2018-06-12 17:34:59 +02:00
access_stream_by_id , access_stream_by_name , filter_stream_authorization ,
list_to_streams ,
2017-01-30 06:44:31 +01:00
)
2017-10-29 15:40:07 +01:00
from zerver . lib . stream_subscription import (
get_active_subscriptions_for_stream_id ,
num_subscribers_for_stream_id ,
)
2014-01-29 22:03:40 +01:00
from zerver . lib . test_runner import (
slow
)
from zerver . models import (
2019-02-02 23:53:44 +01:00
Realm , Recipient , Stream , Subscription ,
2018-06-03 19:11:52 +02:00
DefaultStream , UserProfile , get_user_profile_by_id , active_non_guest_user_ids ,
get_default_stream_groups , flush_per_request_caches , DefaultStreamGroup ,
2018-12-07 00:05:57 +01:00
get_client , get_user
2014-01-29 22:03:40 +01:00
)
from zerver . lib . actions import (
2017-03-21 18:08:40 +01:00
do_add_default_stream , do_change_is_admin , do_set_realm_property ,
2018-08-15 21:03:05 +02:00
do_create_realm , do_remove_default_stream , bulk_get_subscriber_user_ids ,
2016-10-20 20:12:39 +02:00
gather_subscriptions_helper , bulk_add_subscriptions , bulk_remove_subscriptions ,
2017-01-04 05:30:48 +01:00
gather_subscriptions , get_default_streams_for_realm , get_realm , get_stream ,
2019-02-02 23:53:44 +01:00
set_default_streams , do_get_streams ,
2017-09-16 21:44:03 +02:00
create_stream_if_needed , create_streams_if_needed ,
2018-03-21 22:05:21 +01:00
ensure_stream ,
2017-02-18 18:01:00 +01:00
do_deactivate_stream ,
2018-05-21 03:54:42 +02:00
do_deactivate_user ,
2017-04-27 00:03:21 +02:00
stream_welcome_message ,
2017-11-01 18:20:34 +01:00
do_create_default_stream_group ,
do_add_streams_to_default_stream_group , do_remove_streams_from_default_stream_group ,
do_remove_default_stream_group ,
2017-11-14 20:51:34 +01:00
do_change_default_stream_group_description ,
2017-11-14 21:06:02 +01:00
do_change_default_stream_group_name ,
2017-11-14 20:33:09 +01:00
lookup_default_stream_groups ,
2018-04-13 02:42:30 +02:00
can_access_stream_user_ids ,
2018-06-20 23:03:03 +02:00
validate_user_access_to_subscribers_helper ,
get_average_weekly_stream_traffic , round_to_2_significant_digits
2014-01-29 22:03:40 +01:00
)
2016-09-12 17:21:49 +02:00
from zerver . views . streams import (
compose_views
)
2017-11-13 21:24:51 +01:00
from zerver . lib . message import (
aggregate_unread_data ,
get_raw_unread_data ,
)
2018-08-15 21:03:05 +02:00
from zerver . lib . stream_recipient import StreamRecipientMap
2017-11-13 21:24:51 +01:00
2018-06-20 23:03:03 +02:00
from datetime import timedelta
2016-07-27 22:09:33 +02:00
import mock
2014-01-29 22:03:40 +01:00
import random
import ujson
2018-08-15 21:03:05 +02:00
class TestMiscStuff ( ZulipTestCase ) :
def test_empty_results ( self ) - > None :
# These are essentially just tests to ensure line
# coverage for codepaths that won't ever really be
# called in practice.
user_profile = self . example_user ( ' cordelia ' )
result = bulk_get_subscriber_user_ids (
stream_dicts = [ ] ,
user_profile = user_profile ,
sub_dict = { } ,
stream_recipient = StreamRecipientMap ( ) ,
)
self . assertEqual ( result , { } )
streams = do_get_streams (
user_profile = user_profile ,
include_public = False ,
include_subscribed = False ,
include_all_active = False ,
include_default = False ,
)
self . assertEqual ( streams , [ ] )
2016-09-15 16:22:09 +02:00
class TestCreateStreams ( ZulipTestCase ) :
2017-11-05 10:51:25 +01:00
def test_creating_streams ( self ) - > None :
2016-09-15 16:22:09 +02:00
stream_names = [ u ' new1 ' , u ' new2 ' , u ' new3 ' ]
2016-11-27 15:31:53 +01:00
stream_descriptions = [ u ' des1 ' , u ' des2 ' , u ' des3 ' ]
2017-01-04 05:30:48 +01:00
realm = get_realm ( ' zulip ' )
2016-09-15 16:22:09 +02:00
2018-03-16 10:57:17 +01:00
# Test stream creation events.
events = [ ] # type: List[Mapping[str, Any]]
with tornado_redirected_to_list ( events ) :
2018-03-21 22:05:21 +01:00
ensure_stream ( realm , " Public stream " , invite_only = False )
2018-03-16 10:57:17 +01:00
self . assert_length ( events , 1 )
self . assertEqual ( events [ 0 ] [ ' event ' ] [ ' type ' ] , ' stream ' )
self . assertEqual ( events [ 0 ] [ ' event ' ] [ ' op ' ] , ' create ' )
# Send public stream creation event to all active users.
2018-06-03 19:11:52 +02:00
self . assertEqual ( events [ 0 ] [ ' users ' ] , active_non_guest_user_ids ( realm . id ) )
2018-03-16 10:57:17 +01:00
self . assertEqual ( events [ 0 ] [ ' event ' ] [ ' streams ' ] [ 0 ] [ ' name ' ] , " Public stream " )
events = [ ]
with tornado_redirected_to_list ( events ) :
2018-03-21 22:05:21 +01:00
ensure_stream ( realm , " Private stream " , invite_only = True )
2018-03-16 10:57:17 +01:00
self . assert_length ( events , 1 )
self . assertEqual ( events [ 0 ] [ ' event ' ] [ ' type ' ] , ' stream ' )
self . assertEqual ( events [ 0 ] [ ' event ' ] [ ' op ' ] , ' create ' )
# Send private stream creation event to only realm admins.
self . assertEqual ( events [ 0 ] [ ' users ' ] , [ self . example_user ( " iago " ) . id ] )
self . assertEqual ( events [ 0 ] [ ' event ' ] [ ' streams ' ] [ 0 ] [ ' name ' ] , " Private stream " )
2016-09-15 16:22:09 +02:00
new_streams , existing_streams = create_streams_if_needed (
realm ,
2016-11-27 15:31:53 +01:00
[ { " name " : stream_name ,
" description " : stream_description ,
2018-05-30 15:32:51 +02:00
" invite_only " : True ,
" is_announcement_only " : True }
2016-11-27 15:31:53 +01:00
for ( stream_name , stream_description ) in zip ( stream_names , stream_descriptions ) ] )
2016-11-21 00:16:52 +01:00
2016-09-15 16:22:09 +02:00
self . assertEqual ( len ( new_streams ) , 3 )
self . assertEqual ( len ( existing_streams ) , 0 )
actual_stream_names = { stream . name for stream in new_streams }
self . assertEqual ( actual_stream_names , set ( stream_names ) )
2016-11-27 15:31:53 +01:00
actual_stream_descriptions = { stream . description for stream in new_streams }
self . assertEqual ( actual_stream_descriptions , set ( stream_descriptions ) )
for stream in new_streams :
self . assertTrue ( stream . invite_only )
2018-05-30 15:32:51 +02:00
self . assertTrue ( stream . is_announcement_only )
2016-09-15 16:22:09 +02:00
new_streams , existing_streams = create_streams_if_needed (
realm ,
2016-11-27 15:31:53 +01:00
[ { " name " : stream_name ,
" description " : stream_description ,
" invite_only " : True }
for ( stream_name , stream_description ) in zip ( stream_names , stream_descriptions ) ] )
2016-11-21 00:16:52 +01:00
2016-09-15 16:22:09 +02:00
self . assertEqual ( len ( new_streams ) , 0 )
self . assertEqual ( len ( existing_streams ) , 3 )
actual_stream_names = { stream . name for stream in existing_streams }
self . assertEqual ( actual_stream_names , set ( stream_names ) )
2016-11-27 15:31:53 +01:00
actual_stream_descriptions = { stream . description for stream in existing_streams }
self . assertEqual ( actual_stream_descriptions , set ( stream_descriptions ) )
for stream in existing_streams :
self . assertTrue ( stream . invite_only )
2014-01-29 22:03:40 +01:00
2018-04-27 01:00:26 +02:00
def test_history_public_to_subscribers_on_stream_creation ( self ) - > None :
realm = get_realm ( ' zulip ' )
stream_dicts = [
{
" name " : " publicstream " ,
" description " : " Public stream with public history "
} ,
{
" name " : " privatestream " ,
" description " : " Private stream with non-public history " ,
" invite_only " : True
} ,
{
" name " : " privatewithhistory " ,
" description " : " Private stream with public history " ,
" invite_only " : True ,
" history_public_to_subscribers " : True
} ,
{
" name " : " publictrywithouthistory " ,
" description " : " Public stream without public history (disallowed) " ,
" invite_only " : False ,
" history_public_to_subscribers " : False
} ,
] # type: List[Mapping[str, Any]]
created , existing = create_streams_if_needed ( realm , stream_dicts )
self . assertEqual ( len ( created ) , 4 )
self . assertEqual ( len ( existing ) , 0 )
for stream in created :
if stream . name == ' publicstream ' :
self . assertTrue ( stream . history_public_to_subscribers )
if stream . name == ' privatestream ' :
self . assertFalse ( stream . history_public_to_subscribers )
if stream . name == ' privatewithhistory ' :
self . assertTrue ( stream . history_public_to_subscribers )
if stream . name == ' publictrywithouthistory ' :
self . assertTrue ( stream . history_public_to_subscribers )
def test_history_public_to_subscribers_zephyr_realm ( self ) - > None :
realm = get_realm ( ' zephyr ' )
stream , created = create_stream_if_needed ( realm , " private_stream " , invite_only = True )
self . assertTrue ( created )
self . assertTrue ( stream . invite_only )
self . assertFalse ( stream . history_public_to_subscribers )
stream , created = create_stream_if_needed ( realm , " public_stream " , invite_only = False )
self . assertTrue ( created )
self . assertFalse ( stream . invite_only )
self . assertFalse ( stream . history_public_to_subscribers )
2017-11-05 10:51:25 +01:00
def test_welcome_message ( self ) - > None :
2017-04-27 00:03:21 +02:00
realm = get_realm ( ' zulip ' )
name = u ' New Stream '
2018-03-21 22:05:21 +01:00
new_stream = ensure_stream (
2017-04-27 00:03:21 +02:00
realm = realm ,
stream_name = name
)
welcome_message = stream_welcome_message ( new_stream )
self . assertEqual (
welcome_message ,
u ' Welcome to #**New Stream**. '
)
new_stream . description = ' Talk about **stuff**. '
welcome_message = stream_welcome_message ( new_stream )
self . assertEqual (
welcome_message ,
' Welcome to #**New Stream**. '
' \n \n '
' **Description**: Talk about **stuff**. '
)
2016-09-20 02:40:52 +02:00
class RecipientTest ( ZulipTestCase ) :
2017-11-05 10:51:25 +01:00
def test_recipient ( self ) - > None :
2017-01-04 05:30:48 +01:00
realm = get_realm ( ' zulip ' )
2016-09-20 02:40:52 +02:00
stream = get_stream ( ' Verona ' , realm )
recipient = Recipient . objects . get (
type_id = stream . id ,
type = Recipient . STREAM ,
)
self . assertEqual ( str ( recipient ) , ' <Recipient: Verona ( %d , %d )> ' % (
stream . id , Recipient . STREAM ) )
2016-08-23 02:08:42 +02:00
class StreamAdminTest ( ZulipTestCase ) :
2017-11-05 10:51:25 +01:00
def test_make_stream_public ( self ) - > None :
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' hamlet ' )
email = user_profile . email
2014-01-29 22:03:40 +01:00
self . login ( email )
2016-10-21 23:22:25 +02:00
self . make_stream ( ' private_stream ' , invite_only = True )
2014-01-29 22:03:40 +01:00
do_change_is_admin ( user_profile , True )
params = {
2016-12-23 09:15:30 +01:00
' stream_name ' : ujson . dumps ( ' private_stream ' ) ,
' is_private ' : ujson . dumps ( False )
2014-01-29 22:03:40 +01:00
}
2017-01-13 15:50:17 +01:00
stream_id = get_stream ( ' private_stream ' , user_profile . realm ) . id
2016-12-30 11:42:59 +01:00
result = self . client_patch ( " /json/streams/ %d " % ( stream_id , ) , params )
2017-01-30 01:51:43 +01:00
self . assert_json_error ( result , ' Invalid stream id ' )
2014-01-29 22:03:40 +01:00
2017-10-08 21:16:51 +02:00
stream = self . subscribe ( user_profile , ' private_stream ' )
self . assertFalse ( stream . is_in_zephyr_realm )
2014-01-29 22:03:40 +01:00
do_change_is_admin ( user_profile , True )
params = {
2016-12-23 09:15:30 +01:00
' stream_name ' : ujson . dumps ( ' private_stream ' ) ,
' is_private ' : ujson . dumps ( False )
2014-01-29 22:03:40 +01:00
}
2016-12-30 11:42:59 +01:00
result = self . client_patch ( " /json/streams/ %d " % ( stream_id , ) , params )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2016-10-20 00:50:09 +02:00
realm = user_profile . realm
2017-01-13 15:50:17 +01:00
stream = get_stream ( ' private_stream ' , realm )
2014-01-29 22:03:40 +01:00
self . assertFalse ( stream . invite_only )
2018-04-27 01:00:26 +02:00
self . assertTrue ( stream . history_public_to_subscribers )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_make_stream_private ( self ) - > None :
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' hamlet ' )
email = user_profile . email
2014-01-29 22:03:40 +01:00
self . login ( email )
realm = user_profile . realm
2016-10-21 23:22:25 +02:00
self . make_stream ( ' public_stream ' , realm = realm )
2014-01-29 22:03:40 +01:00
do_change_is_admin ( user_profile , True )
params = {
2016-12-23 09:15:30 +01:00
' stream_name ' : ujson . dumps ( ' public_stream ' ) ,
' is_private ' : ujson . dumps ( True )
2014-01-29 22:03:40 +01:00
}
2017-01-13 15:50:17 +01:00
stream_id = get_stream ( ' public_stream ' , realm ) . id
2016-12-30 11:42:59 +01:00
result = self . client_patch ( " /json/streams/ %d " % ( stream_id , ) , params )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2017-01-13 15:50:17 +01:00
stream = get_stream ( ' public_stream ' , realm )
2014-01-29 22:03:40 +01:00
self . assertTrue ( stream . invite_only )
2018-04-27 01:00:26 +02:00
self . assertFalse ( stream . history_public_to_subscribers )
def test_make_stream_public_zephyr_mirror ( self ) - > None :
user_profile = self . mit_user ( ' starnine ' )
email = user_profile . email
self . login ( email , realm = get_realm ( " zephyr " ) )
realm = user_profile . realm
self . make_stream ( ' target_stream ' , realm = realm , invite_only = True )
self . subscribe ( user_profile , ' target_stream ' )
do_change_is_admin ( user_profile , True )
params = {
' stream_name ' : ujson . dumps ( ' target_stream ' ) ,
' is_private ' : ujson . dumps ( False )
}
stream_id = get_stream ( ' target_stream ' , realm ) . id
result = self . client_patch ( " /json/streams/ %d " % ( stream_id , ) , params ,
subdomain = " zephyr " )
self . assert_json_success ( result )
stream = get_stream ( ' target_stream ' , realm )
self . assertFalse ( stream . invite_only )
self . assertFalse ( stream . history_public_to_subscribers )
def test_make_stream_private_with_public_history ( self ) - > None :
user_profile = self . example_user ( ' hamlet ' )
email = user_profile . email
self . login ( email )
realm = user_profile . realm
self . make_stream ( ' public_history_stream ' , realm = realm )
do_change_is_admin ( user_profile , True )
params = {
' stream_name ' : ujson . dumps ( ' public_history_stream ' ) ,
' is_private ' : ujson . dumps ( True ) ,
' history_public_to_subscribers ' : ujson . dumps ( True ) ,
}
stream_id = get_stream ( ' public_history_stream ' , realm ) . id
result = self . client_patch ( " /json/streams/ %d " % ( stream_id , ) , params )
self . assert_json_success ( result )
stream = get_stream ( ' public_history_stream ' , realm )
self . assertTrue ( stream . invite_only )
self . assertTrue ( stream . history_public_to_subscribers )
def test_try_make_stream_public_with_private_history ( self ) - > None :
user_profile = self . example_user ( ' hamlet ' )
email = user_profile . email
self . login ( email )
realm = user_profile . realm
self . make_stream ( ' public_stream ' , realm = realm )
do_change_is_admin ( user_profile , True )
params = {
' stream_name ' : ujson . dumps ( ' public_stream ' ) ,
' is_private ' : ujson . dumps ( False ) ,
' history_public_to_subscribers ' : ujson . dumps ( False ) ,
}
stream_id = get_stream ( ' public_stream ' , realm ) . id
result = self . client_patch ( " /json/streams/ %d " % ( stream_id , ) , params )
self . assert_json_success ( result )
stream = get_stream ( ' public_stream ' , realm )
self . assertFalse ( stream . invite_only )
self . assertTrue ( stream . history_public_to_subscribers )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_deactivate_stream_backend ( self ) - > None :
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' hamlet ' )
email = user_profile . email
2014-01-29 22:03:40 +01:00
self . login ( email )
2016-10-21 23:22:25 +02:00
stream = self . make_stream ( ' new_stream ' )
2017-08-25 06:01:29 +02:00
self . subscribe ( user_profile , stream . name )
2014-01-29 22:03:40 +01:00
do_change_is_admin ( user_profile , True )
2016-12-30 11:42:59 +01:00
result = self . client_delete ( ' /json/streams/ %d ' % ( stream . id , ) )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2017-10-29 15:40:07 +01:00
subscription_exists = get_active_subscriptions_for_stream_id ( stream . id ) . filter (
2014-01-29 22:03:40 +01:00
user_profile = user_profile ,
) . exists ( )
self . assertFalse ( subscription_exists )
2017-11-05 10:51:25 +01:00
def test_deactivate_stream_removes_default_stream ( self ) - > None :
2017-02-18 18:01:00 +01:00
stream = self . make_stream ( ' new_stream ' )
do_add_default_stream ( stream )
2017-09-17 19:53:38 +02:00
self . assertEqual ( 1 , DefaultStream . objects . filter ( stream_id = stream . id ) . count ( ) )
2017-02-18 18:01:00 +01:00
do_deactivate_stream ( stream )
2017-09-17 19:53:38 +02:00
self . assertEqual ( 0 , DefaultStream . objects . filter ( stream_id = stream . id ) . count ( ) )
2017-02-18 18:01:00 +01:00
2017-11-05 10:51:25 +01:00
def test_vacate_private_stream_removes_default_stream ( self ) - > None :
2017-06-04 19:32:41 +02:00
stream = self . make_stream ( ' new_stream ' , invite_only = True )
2017-08-25 06:01:29 +02:00
self . subscribe ( self . example_user ( " hamlet " ) , stream . name )
2017-06-04 19:32:41 +02:00
do_add_default_stream ( stream )
2017-09-17 19:53:38 +02:00
self . assertEqual ( 1 , DefaultStream . objects . filter ( stream_id = stream . id ) . count ( ) )
2017-08-25 06:23:11 +02:00
self . unsubscribe ( self . example_user ( " hamlet " ) , stream . name )
2017-09-17 19:53:38 +02:00
self . assertEqual ( 0 , DefaultStream . objects . filter ( stream_id = stream . id ) . count ( ) )
2017-06-04 19:32:41 +02:00
# Fetch stream again from database.
stream = Stream . objects . get ( id = stream . id )
self . assertTrue ( stream . deactivated )
2017-11-05 10:51:25 +01:00
def test_deactivate_stream_backend_requires_existing_stream ( self ) - > None :
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' hamlet ' )
email = user_profile . email
2016-07-16 18:50:41 +02:00
self . login ( email )
2016-10-21 23:22:25 +02:00
self . make_stream ( ' new_stream ' )
2016-07-16 18:50:41 +02:00
do_change_is_admin ( user_profile , True )
2016-12-30 11:42:59 +01:00
result = self . client_delete ( ' /json/streams/999999999 ' )
self . assert_json_error ( result , u ' Invalid stream id ' )
2016-07-16 18:50:41 +02:00
2017-11-05 10:51:25 +01:00
def test_deactivate_stream_backend_requires_realm_admin ( self ) - > None :
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' hamlet ' )
2017-08-25 06:01:29 +02:00
self . login ( user_profile . email )
self . subscribe ( user_profile , ' new_stream ' )
2014-01-29 22:03:40 +01:00
2017-01-13 15:50:17 +01:00
stream_id = get_stream ( ' new_stream ' , user_profile . realm ) . id
2016-12-30 11:42:59 +01:00
result = self . client_delete ( ' /json/streams/ %d ' % ( stream_id , ) )
2018-03-08 01:47:17 +01:00
self . assert_json_error ( result , ' Must be an organization administrator ' )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_private_stream_live_updates ( self ) - > None :
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' hamlet ' )
2017-08-25 06:01:29 +02:00
self . login ( user_profile . email )
2016-11-04 07:02:24 +01:00
do_change_is_admin ( user_profile , True )
self . make_stream ( ' private_stream ' , invite_only = True )
2017-08-25 06:01:29 +02:00
self . subscribe ( user_profile , ' private_stream ' )
self . subscribe ( self . example_user ( " cordelia " ) , ' private_stream ' )
2016-11-04 07:02:24 +01:00
2017-08-04 02:25:38 +02:00
events = [ ] # type: List[Mapping[str, Any]]
2016-11-04 07:02:24 +01:00
with tornado_redirected_to_list ( events ) :
2017-01-13 15:50:17 +01:00
stream_id = get_stream ( ' private_stream ' , user_profile . realm ) . id
2016-12-30 11:42:59 +01:00
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
2016-11-04 07:02:24 +01:00
{ ' description ' : ujson . dumps ( ' Test description ' ) } )
self . assert_json_success ( result )
2017-01-29 01:38:25 +01:00
# Should be just a description change event
self . assert_length ( events , 1 )
2016-11-04 07:02:24 +01:00
2017-05-07 17:21:26 +02:00
cordelia = self . example_user ( ' cordelia ' )
prospero = self . example_user ( ' prospero ' )
2016-11-04 07:02:24 +01:00
notified_user_ids = set ( events [ - 1 ] [ ' users ' ] )
self . assertIn ( user_profile . id , notified_user_ids )
self . assertIn ( cordelia . id , notified_user_ids )
self . assertNotIn ( prospero . id , notified_user_ids )
events = [ ]
with tornado_redirected_to_list ( events ) :
2017-01-13 15:50:17 +01:00
stream_id = get_stream ( ' private_stream ' , user_profile . realm ) . id
2016-12-30 11:42:59 +01:00
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
2016-11-04 07:02:24 +01:00
{ ' new_name ' : ujson . dumps ( ' whatever ' ) } )
self . assert_json_success ( result )
2019-01-05 12:47:38 +01:00
# Should be a name event, an email address event and a notification event
self . assert_length ( events , 3 )
2016-11-04 07:02:24 +01:00
2019-01-05 12:47:38 +01:00
notified_user_ids = set ( events [ 0 ] [ ' users ' ] )
2016-11-04 07:02:24 +01:00
self . assertIn ( user_profile . id , notified_user_ids )
self . assertIn ( cordelia . id , notified_user_ids )
self . assertNotIn ( prospero . id , notified_user_ids )
2019-01-05 12:47:38 +01:00
notified_with_bot_users = events [ - 1 ] [ ' users ' ]
notified_with_bot_user_ids = [ ]
notified_with_bot_user_ids . append ( notified_with_bot_users [ 0 ] [ ' id ' ] )
notified_with_bot_user_ids . append ( notified_with_bot_users [ 1 ] [ ' id ' ] )
self . assertIn ( user_profile . id , notified_with_bot_user_ids )
self . assertIn ( cordelia . id , notified_with_bot_user_ids )
self . assertNotIn ( prospero . id , notified_with_bot_user_ids )
2017-11-05 10:51:25 +01:00
def test_rename_stream ( self ) - > None :
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' hamlet ' )
email = user_profile . email
2014-01-29 22:03:40 +01:00
self . login ( email )
realm = user_profile . realm
2017-08-25 06:01:29 +02:00
stream = self . subscribe ( user_profile , ' stream_name1 ' )
2014-01-29 22:03:40 +01:00
do_change_is_admin ( user_profile , True )
2017-01-30 04:44:40 +01:00
result = self . client_patch ( ' /json/streams/ %d ' % ( stream . id , ) ,
{ ' new_name ' : ujson . dumps ( ' stream_name1 ' ) } )
self . assert_json_error ( result , " Stream already has that name! " )
result = self . client_patch ( ' /json/streams/ %d ' % ( stream . id , ) ,
{ ' new_name ' : ujson . dumps ( ' Denmark ' ) } )
2018-01-08 19:54:19 +01:00
self . assert_json_error ( result , " Stream name ' Denmark ' is already taken. " )
2017-01-30 04:44:40 +01:00
result = self . client_patch ( ' /json/streams/ %d ' % ( stream . id , ) ,
{ ' new_name ' : ujson . dumps ( ' denmark ' ) } )
2018-01-08 19:54:19 +01:00
self . assert_json_error ( result , " Stream name ' denmark ' is already taken. " )
2017-01-30 04:44:40 +01:00
2017-02-01 23:20:46 +01:00
# Do a rename that is case-only--this should succeed.
result = self . client_patch ( ' /json/streams/ %d ' % ( stream . id , ) ,
{ ' new_name ' : ujson . dumps ( ' sTREAm_name1 ' ) } )
self . assert_json_success ( result )
2017-08-04 02:25:38 +02:00
events = [ ] # type: List[Mapping[str, Any]]
2014-01-29 22:03:40 +01:00
with tornado_redirected_to_list ( events ) :
2017-01-13 15:50:17 +01:00
stream_id = get_stream ( ' stream_name1 ' , user_profile . realm ) . id
2016-12-30 11:42:59 +01:00
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
2016-09-28 09:07:09 +02:00
{ ' new_name ' : ujson . dumps ( ' stream_name2 ' ) } )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2014-02-02 15:30:33 +01:00
event = events [ 1 ] [ ' event ' ]
2014-01-29 22:03:40 +01:00
self . assertEqual ( event , dict (
op = ' update ' ,
type = ' stream ' ,
property = ' name ' ,
value = ' stream_name2 ' ,
2017-03-05 01:50:25 +01:00
stream_id = stream_id ,
2017-02-01 23:20:46 +01:00
name = ' sTREAm_name1 '
2014-01-29 22:03:40 +01:00
) )
2016-11-04 07:02:24 +01:00
notified_user_ids = set ( events [ 1 ] [ ' users ' ] )
2014-01-29 22:03:40 +01:00
2017-03-23 07:22:28 +01:00
self . assertRaises ( Stream . DoesNotExist , get_stream , ' stream_name1 ' , realm )
2016-09-28 09:07:09 +02:00
stream_name2_exists = get_stream ( ' stream_name2 ' , realm )
2014-01-29 22:03:40 +01:00
self . assertTrue ( stream_name2_exists )
2018-06-03 19:11:52 +02:00
self . assertEqual ( notified_user_ids , set ( active_non_guest_user_ids ( realm . id ) ) )
2016-11-04 07:02:24 +01:00
self . assertIn ( user_profile . id ,
notified_user_ids )
2017-05-07 17:21:26 +02:00
self . assertIn ( self . example_user ( ' prospero ' ) . id ,
2016-11-04 07:02:24 +01:00
notified_user_ids )
2018-06-03 19:11:52 +02:00
self . assertNotIn ( self . example_user ( ' polonius ' ) . id ,
notified_user_ids )
2016-11-04 07:02:24 +01:00
2016-09-28 09:07:09 +02:00
# Test case to handle unicode stream name change
# *NOTE: Here Encoding is needed when Unicode string is passed as an argument*
with tornado_redirected_to_list ( events ) :
2016-12-30 11:42:59 +01:00
stream_id = stream_name2_exists . id
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
2016-09-28 09:07:09 +02:00
{ ' new_name ' : ujson . dumps ( u ' नया नाम ' . encode ( ' utf-8 ' ) ) } )
self . assert_json_success ( result )
# While querying, system can handle unicode strings.
stream_name_uni_exists = get_stream ( u ' नया नाम ' , realm )
self . assertTrue ( stream_name_uni_exists )
# Test case to handle changing of unicode stream name to newer name
# NOTE: Unicode string being part of URL is handled cleanly
# by client_patch call, encoding of URL is not needed.
with tornado_redirected_to_list ( events ) :
2016-12-30 11:42:59 +01:00
stream_id = stream_name_uni_exists . id
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
2016-09-28 09:07:09 +02:00
{ ' new_name ' : ujson . dumps ( u ' नाम में क्या रक्खा हे ' . encode ( ' utf-8 ' ) ) } )
self . assert_json_success ( result )
# While querying, system can handle unicode strings.
2017-03-23 07:22:28 +01:00
self . assertRaises ( Stream . DoesNotExist , get_stream , u ' नया नाम ' , realm )
2016-09-28 09:07:09 +02:00
stream_name_new_uni_exists = get_stream ( u ' नाम में क्या रक्खा हे ' , realm )
self . assertTrue ( stream_name_new_uni_exists )
# Test case to change name from one language to other.
with tornado_redirected_to_list ( events ) :
2016-12-30 11:42:59 +01:00
stream_id = stream_name_new_uni_exists . id
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
2016-09-28 09:07:09 +02:00
{ ' new_name ' : ujson . dumps ( u ' français ' . encode ( ' utf-8 ' ) ) } )
self . assert_json_success ( result )
stream_name_fr_exists = get_stream ( u ' français ' , realm )
self . assertTrue ( stream_name_fr_exists )
# Test case to change name to mixed language name.
with tornado_redirected_to_list ( events ) :
2016-12-30 11:42:59 +01:00
stream_id = stream_name_fr_exists . id
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
2016-09-28 09:07:09 +02:00
{ ' new_name ' : ujson . dumps ( u ' français name ' . encode ( ' utf-8 ' ) ) } )
self . assert_json_success ( result )
stream_name_mixed_exists = get_stream ( u ' français name ' , realm )
self . assertTrue ( stream_name_mixed_exists )
2018-04-13 02:42:30 +02:00
# Test case for notified users in private streams.
stream_private = self . make_stream ( ' stream_private_name1 ' , realm = user_profile . realm , invite_only = True )
self . subscribe ( self . example_user ( ' cordelia ' ) , ' stream_private_name1 ' )
del events [ : ]
with tornado_redirected_to_list ( events ) :
stream_id = get_stream ( ' stream_private_name1 ' , realm ) . id
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
{ ' new_name ' : ujson . dumps ( ' stream_private_name2 ' ) } )
self . assert_json_success ( result )
notified_user_ids = set ( events [ 1 ] [ ' users ' ] )
self . assertEqual ( notified_user_ids , can_access_stream_user_ids ( stream_private ) )
self . assertIn ( self . example_user ( ' cordelia ' ) . id , notified_user_ids )
# An important corner case is that all organization admins are notified.
self . assertIn ( self . example_user ( ' iago ' ) . id , notified_user_ids )
# The current user, Hamlet was made an admin and thus should be notified too.
self . assertIn ( user_profile . id , notified_user_ids )
self . assertNotIn ( self . example_user ( ' prospero ' ) . id ,
notified_user_ids )
2017-11-05 10:51:25 +01:00
def test_rename_stream_requires_realm_admin ( self ) - > None :
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' hamlet ' )
email = user_profile . email
2014-01-29 22:03:40 +01:00
self . login ( email )
2016-10-21 23:22:25 +02:00
self . make_stream ( ' stream_name1 ' )
2014-01-29 22:03:40 +01:00
2017-01-13 15:50:17 +01:00
stream_id = get_stream ( ' stream_name1 ' , user_profile . realm ) . id
2016-12-30 11:42:59 +01:00
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
2016-09-28 09:07:09 +02:00
{ ' new_name ' : ujson . dumps ( ' stream_name2 ' ) } )
2018-03-08 01:47:17 +01:00
self . assert_json_error ( result , ' Must be an organization administrator ' )
2014-01-29 22:03:40 +01:00
2019-01-05 12:47:38 +01:00
def test_notify_on_stream_rename ( self ) - > None :
user_profile = self . example_user ( ' hamlet ' )
self . login ( user_profile . email )
self . make_stream ( ' stream_name1 ' )
stream = self . subscribe ( user_profile , ' stream_name1 ' )
do_change_is_admin ( user_profile , True )
result = self . client_patch ( ' /json/streams/ %d ' % ( stream . id , ) ,
{ ' new_name ' : ujson . dumps ( ' stream_name2 ' ) } )
self . assert_json_success ( result )
# Inspect the notification message sent
message = self . get_last_message ( )
actual_stream = Stream . objects . get ( id = message . recipient . type_id )
2019-02-20 10:15:33 +01:00
message_content = ' @_**King Hamlet| {} ** renamed stream **stream_name1** to **stream_name2** ' . format ( user_profile . id )
2019-01-05 12:47:38 +01:00
self . assertEqual ( message . sender . realm , user_profile . realm )
self . assertEqual ( actual_stream . name , ' stream_name2 ' )
self . assertEqual ( message . recipient . type , Recipient . STREAM )
self . assertEqual ( message . content , message_content )
self . assertEqual ( message . sender . email , ' notification-bot@zulip.com ' )
2018-02-12 16:02:19 +01:00
def test_realm_admin_can_update_unsub_private_stream ( self ) - > None :
iago = self . example_user ( ' iago ' )
self . login ( iago . email )
result = self . common_subscribe_to_streams ( iago . email , [ " private_stream " ] ,
dict ( principals = ujson . dumps ( [ self . example_email ( " hamlet " ) ] ) ) ,
invite_only = True )
self . assert_json_success ( result )
stream_id = get_stream ( ' private_stream ' , iago . realm ) . id
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
{ ' new_name ' : ujson . dumps ( ' new_private_stream ' ) } )
self . assert_json_success ( result )
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
{ ' new_description ' : ujson . dumps ( ' new description ' ) } )
self . assert_json_success ( result )
2018-04-03 00:36:31 +02:00
# But cannot change stream type.
2018-02-12 16:02:19 +01:00
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
{ ' stream_name ' : ujson . dumps ( ' private_stream ' ) ,
' is_private ' : ujson . dumps ( True ) } )
self . assert_json_error ( result , " Invalid stream id " )
2017-11-05 10:51:25 +01:00
def test_change_stream_description ( self ) - > None :
2018-04-30 08:59:51 +02:00
user_profile = self . example_user ( ' iago ' )
2017-05-07 19:39:30 +02:00
email = user_profile . email
2014-01-29 22:03:40 +01:00
self . login ( email )
realm = user_profile . realm
2017-08-25 06:01:29 +02:00
self . subscribe ( user_profile , ' stream_name1 ' )
2014-01-29 22:03:40 +01:00
2017-08-04 02:25:38 +02:00
events = [ ] # type: List[Mapping[str, Any]]
2014-01-29 22:03:40 +01:00
with tornado_redirected_to_list ( events ) :
2017-01-13 15:50:17 +01:00
stream_id = get_stream ( ' stream_name1 ' , realm ) . id
2016-12-30 11:42:59 +01:00
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
2016-12-03 00:04:17 +01:00
{ ' description ' : ujson . dumps ( ' Test description ' ) } )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
event = events [ 0 ] [ ' event ' ]
self . assertEqual ( event , dict (
op = ' update ' ,
type = ' stream ' ,
property = ' description ' ,
value = ' Test description ' ,
2019-01-11 13:48:22 +01:00
rendered_description = ' <p>Test description</p> ' ,
2017-03-05 01:50:25 +01:00
stream_id = stream_id ,
2014-01-29 22:03:40 +01:00
name = ' stream_name1 '
) )
2016-11-04 07:02:24 +01:00
notified_user_ids = set ( events [ 0 ] [ ' users ' ] )
2014-01-29 22:03:40 +01:00
2017-01-13 15:50:17 +01:00
stream = get_stream ( ' stream_name1 ' , realm )
2018-06-03 19:11:52 +02:00
self . assertEqual ( notified_user_ids , set ( active_non_guest_user_ids ( realm . id ) ) )
2016-11-04 07:02:24 +01:00
self . assertIn ( user_profile . id ,
notified_user_ids )
2017-05-07 17:21:26 +02:00
self . assertIn ( self . example_user ( ' prospero ' ) . id ,
2016-11-04 07:02:24 +01:00
notified_user_ids )
2018-06-03 19:11:52 +02:00
self . assertNotIn ( self . example_user ( ' polonius ' ) . id ,
notified_user_ids )
2016-11-04 07:02:24 +01:00
2014-01-29 22:03:40 +01:00
self . assertEqual ( ' Test description ' , stream . description )
2018-04-30 08:59:51 +02:00
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
{ ' description ' : ujson . dumps ( ' a ' * 1025 ) } )
2018-05-03 23:21:16 +02:00
self . assert_json_error ( result , " description is too long (limit: %s characters) "
2018-04-30 08:59:51 +02:00
% ( Stream . MAX_DESCRIPTION_LENGTH ) )
2017-11-05 10:51:25 +01:00
def test_change_stream_description_requires_realm_admin ( self ) - > None :
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' hamlet ' )
email = user_profile . email
2014-01-29 22:03:40 +01:00
self . login ( email )
2017-08-25 06:01:29 +02:00
self . subscribe ( user_profile , ' stream_name1 ' )
2014-01-29 22:03:40 +01:00
do_change_is_admin ( user_profile , False )
2017-01-13 15:50:17 +01:00
stream_id = get_stream ( ' stream_name1 ' , user_profile . realm ) . id
2016-12-30 11:42:59 +01:00
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
2016-12-03 00:04:17 +01:00
{ ' description ' : ujson . dumps ( ' Test description ' ) } )
2018-03-08 01:47:17 +01:00
self . assert_json_error ( result , ' Must be an organization administrator ' )
2014-01-29 22:03:40 +01:00
2018-05-12 07:25:42 +02:00
def test_change_stream_announcement_only ( self ) - > None :
user_profile = self . example_user ( ' hamlet ' )
self . login ( user_profile . email )
self . subscribe ( user_profile , ' stream_name1 ' )
do_change_is_admin ( user_profile , True )
stream_id = get_stream ( ' stream_name1 ' , user_profile . realm ) . id
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
{ ' is_announcement_only ' : ujson . dumps ( True ) } )
self . assert_json_success ( result )
stream = get_stream ( ' stream_name1 ' , user_profile . realm )
self . assertEqual ( True , stream . is_announcement_only )
def test_change_stream_announcement_only_requires_realm_admin ( self ) - > None :
user_profile = self . example_user ( ' hamlet ' )
self . login ( user_profile . email )
self . subscribe ( user_profile , ' stream_name1 ' )
do_change_is_admin ( user_profile , False )
stream_id = get_stream ( ' stream_name1 ' , user_profile . realm ) . id
result = self . client_patch ( ' /json/streams/ %d ' % ( stream_id , ) ,
{ ' is_announcement_only ' : ujson . dumps ( True ) } )
self . assert_json_error ( result , ' Must be an organization administrator ' )
2017-11-20 03:22:57 +01:00
def set_up_stream_for_deletion ( self , stream_name : str , invite_only : bool = False ,
subscribed : bool = True ) - > Stream :
2014-01-29 22:03:40 +01:00
"""
Create a stream for deletion by an administrator .
"""
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' hamlet ' )
email = user_profile . email
2014-01-29 22:03:40 +01:00
self . login ( email )
2016-10-21 23:22:25 +02:00
stream = self . make_stream ( stream_name , invite_only = invite_only )
2014-01-29 22:03:40 +01:00
# For testing deleting streams you aren't on.
if subscribed :
2017-08-25 06:01:29 +02:00
self . subscribe ( user_profile , stream_name )
2014-01-29 22:03:40 +01:00
do_change_is_admin ( user_profile , True )
return stream
2017-11-05 10:51:25 +01:00
def delete_stream ( self , stream : Stream ) - > None :
2014-01-29 22:03:40 +01:00
"""
Delete the stream and assess the result .
"""
active_name = stream . name
2016-12-04 01:04:55 +01:00
realm = stream . realm
2016-12-30 11:42:59 +01:00
stream_id = stream . id
2014-01-29 22:03:40 +01:00
2018-08-11 17:28:52 +02:00
# Simulate that a stream by the same name has already been
# deactivated, just to exercise our renaming logic:
ensure_stream ( realm , " !DEACTIVATED: " + active_name )
2017-08-04 02:25:38 +02:00
events = [ ] # type: List[Mapping[str, Any]]
2014-01-29 22:03:40 +01:00
with tornado_redirected_to_list ( events ) :
2016-12-30 11:42:59 +01:00
result = self . client_delete ( ' /json/streams/ ' + str ( stream_id ) )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2017-02-15 17:38:44 +01:00
# We no longer send subscription events for stream deactivations.
sub_events = [ e for e in events if e [ ' event ' ] [ ' type ' ] == ' subscription ' ]
self . assertEqual ( sub_events , [ ] )
stream_events = [ e for e in events if e [ ' event ' ] [ ' type ' ] == ' stream ' ]
self . assertEqual ( len ( stream_events ) , 1 )
event = stream_events [ 0 ] [ ' event ' ]
self . assertEqual ( event [ ' op ' ] , ' delete ' )
self . assertEqual ( event [ ' streams ' ] [ 0 ] [ ' stream_id ' ] , stream . id )
2014-01-29 22:03:40 +01:00
with self . assertRaises ( Stream . DoesNotExist ) :
2017-01-04 05:30:48 +01:00
Stream . objects . get ( realm = get_realm ( " zulip " ) , name = active_name )
2014-01-29 22:03:40 +01:00
# A deleted stream's name is changed, is deactivated, is invite-only,
# and has no subscribers.
2018-08-11 17:28:52 +02:00
deactivated_stream_name = " !!DEACTIVATED: " + active_name
2017-01-13 15:50:17 +01:00
deactivated_stream = get_stream ( deactivated_stream_name , realm )
2014-01-29 22:03:40 +01:00
self . assertTrue ( deactivated_stream . deactivated )
self . assertTrue ( deactivated_stream . invite_only )
self . assertEqual ( deactivated_stream . name , deactivated_stream_name )
subscribers = self . users_subscribed_to_stream (
2017-01-24 07:06:13 +01:00
deactivated_stream_name , realm )
2014-01-29 22:03:40 +01:00
self . assertEqual ( subscribers , [ ] )
# It doesn't show up in the list of public streams anymore.
2016-07-28 00:38:45 +02:00
result = self . client_get ( " /json/streams?include_subscribed=false " )
2017-08-17 08:45:20 +02:00
public_streams = [ s [ " name " ] for s in result . json ( ) [ " streams " ] ]
2014-01-29 22:03:40 +01:00
self . assertNotIn ( active_name , public_streams )
self . assertNotIn ( deactivated_stream_name , public_streams )
# Even if you could guess the new name, you can't subscribe to it.
2016-07-28 00:30:22 +02:00
result = self . client_post (
2015-11-30 21:39:40 +01:00
" /json/users/me/subscriptions " ,
2014-01-29 22:03:40 +01:00
{ " subscriptions " : ujson . dumps ( [ { " name " : deactivated_stream_name } ] ) } )
self . assert_json_error (
result , " Unable to access stream ( %s ). " % ( deactivated_stream_name , ) )
2017-11-05 10:51:25 +01:00
def test_you_must_be_realm_admin ( self ) - > None :
2017-08-22 21:41:08 +02:00
"""
You must be on the realm to create a stream .
"""
user_profile = self . example_user ( ' hamlet ' )
self . login ( user_profile . email )
other_realm = Realm . objects . create ( string_id = ' other ' )
stream = self . make_stream ( ' other_realm_stream ' , realm = other_realm )
result = self . client_delete ( ' /json/streams/ ' + str ( stream . id ) )
2018-03-08 01:47:17 +01:00
self . assert_json_error ( result , ' Must be an organization administrator ' )
2017-08-22 21:41:08 +02:00
# Even becoming a realm admin doesn't help us for an out-of-realm
# stream.
do_change_is_admin ( user_profile , True )
result = self . client_delete ( ' /json/streams/ ' + str ( stream . id ) )
self . assert_json_error ( result , ' Invalid stream id ' )
2017-11-05 10:51:25 +01:00
def test_delete_public_stream ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
When an administrator deletes a public stream , that stream is not
visible to users at all anymore .
"""
stream = self . set_up_stream_for_deletion ( " newstream " )
self . delete_stream ( stream )
2017-11-05 10:51:25 +01:00
def test_delete_private_stream ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
Administrators can delete private streams they are on .
"""
stream = self . set_up_stream_for_deletion ( " newstream " , invite_only = True )
self . delete_stream ( stream )
2017-11-05 10:51:25 +01:00
def test_delete_streams_youre_not_on ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
2017-08-22 21:41:08 +02:00
Administrators can delete public streams they aren ' t on, including
private streams in their realm .
2014-01-29 22:03:40 +01:00
"""
pub_stream = self . set_up_stream_for_deletion (
" pubstream " , subscribed = False )
2017-02-15 17:38:44 +01:00
self . delete_stream ( pub_stream )
2014-01-29 22:03:40 +01:00
priv_stream = self . set_up_stream_for_deletion (
" privstream " , subscribed = False , invite_only = True )
2017-08-22 21:41:08 +02:00
self . delete_stream ( priv_stream )
2014-01-29 22:03:40 +01:00
2017-11-20 03:22:57 +01:00
def attempt_unsubscribe_of_principal ( self , query_count : int , is_admin : bool = False ,
is_subbed : bool = True , invite_only : bool = False ,
2018-02-20 18:56:01 +01:00
other_user_subbed : bool = True ,
2018-05-16 21:09:52 +02:00
other_sub_users : Optional [ List [ UserProfile ] ] = None ) - > HttpResponse :
2016-06-04 19:50:38 +02:00
2014-01-30 22:50:51 +01:00
# Set up the main user, who is in most cases an admin.
2018-03-14 02:20:31 +01:00
if is_admin :
user_profile = self . example_user ( ' iago ' )
else :
user_profile = self . example_user ( ' hamlet ' )
2017-05-07 19:39:30 +02:00
email = user_profile . email
2014-01-30 22:50:51 +01:00
self . login ( email )
# Set up the stream.
stream_name = u " hümbüǵ "
2016-10-21 23:22:25 +02:00
self . make_stream ( stream_name , invite_only = invite_only )
2014-01-30 22:50:51 +01:00
# Set up the principal to be unsubscribed.
2017-05-07 21:25:59 +02:00
other_user_profile = self . example_user ( ' cordelia ' )
other_email = other_user_profile . email
2014-01-30 22:50:51 +01:00
# Subscribe the admin and/or principal as specified in the flags.
if is_subbed :
2017-08-25 06:01:29 +02:00
self . subscribe ( user_profile , stream_name )
2014-01-30 22:50:51 +01:00
if other_user_subbed :
2017-08-25 06:01:29 +02:00
self . subscribe ( other_user_profile , stream_name )
2018-02-20 18:56:01 +01:00
if other_sub_users :
for user in other_sub_users :
self . subscribe ( user , stream_name )
2014-01-30 22:50:51 +01:00
2017-10-29 21:03:11 +01:00
with queries_captured ( ) as queries :
result = self . client_delete (
" /json/users/me/subscriptions " ,
{ " subscriptions " : ujson . dumps ( [ stream_name ] ) ,
" principals " : ujson . dumps ( [ other_email ] ) } )
self . assert_length ( queries , query_count )
2014-01-30 22:50:51 +01:00
2014-01-31 18:08:23 +01:00
# If the removal succeeded, then assert that Cordelia is no longer subscribed.
if result . status_code not in [ 400 ] :
2016-12-04 01:04:55 +01:00
subbed_users = self . users_subscribed_to_stream ( stream_name , other_user_profile . realm )
2014-01-31 18:08:23 +01:00
self . assertNotIn ( other_user_profile , subbed_users )
2014-01-30 22:50:51 +01:00
return result
2017-11-05 10:51:25 +01:00
def test_cant_remove_others_from_stream ( self ) - > None :
2014-01-30 22:50:51 +01:00
"""
If you ' re not an admin, you can ' t remove other people from streams .
"""
result = self . attempt_unsubscribe_of_principal (
2017-10-29 21:03:11 +01:00
query_count = 3 , is_admin = False , is_subbed = True , invite_only = False ,
2014-01-30 22:50:51 +01:00
other_user_subbed = True )
self . assert_json_error (
result , " This action requires administrative rights " )
2017-11-05 10:51:25 +01:00
def test_admin_remove_others_from_public_stream ( self ) - > None :
2014-01-30 22:50:51 +01:00
"""
If you ' re an admin, you can remove people from public streams, even
those you aren ' t on.
"""
result = self . attempt_unsubscribe_of_principal (
2018-03-14 00:13:21 +01:00
query_count = 22 , is_admin = True , is_subbed = True , invite_only = False ,
2014-01-30 22:50:51 +01:00
other_user_subbed = True )
json = self . assert_json_success ( result )
self . assertEqual ( len ( json [ " removed " ] ) , 1 )
self . assertEqual ( len ( json [ " not_subscribed " ] ) , 0 )
2017-11-05 10:51:25 +01:00
def test_admin_remove_others_from_subbed_private_stream ( self ) - > None :
2014-01-30 22:50:51 +01:00
"""
If you ' re an admin, you can remove other people from private streams you
are on .
"""
result = self . attempt_unsubscribe_of_principal (
2018-03-14 00:13:21 +01:00
query_count = 22 , is_admin = True , is_subbed = True , invite_only = True ,
2014-01-30 22:50:51 +01:00
other_user_subbed = True )
json = self . assert_json_success ( result )
self . assertEqual ( len ( json [ " removed " ] ) , 1 )
self . assertEqual ( len ( json [ " not_subscribed " ] ) , 0 )
2017-11-05 10:51:25 +01:00
def test_admin_remove_others_from_unsubbed_private_stream ( self ) - > None :
2014-01-30 22:50:51 +01:00
"""
2018-02-20 18:56:01 +01:00
If you ' re an admin, you can remove people from private
2014-01-30 22:50:51 +01:00
streams you aren ' t on.
"""
result = self . attempt_unsubscribe_of_principal (
2018-03-14 00:13:21 +01:00
query_count = 22 , is_admin = True , is_subbed = False , invite_only = True ,
2018-02-20 18:56:01 +01:00
other_user_subbed = True , other_sub_users = [ self . example_user ( " othello " ) ] )
json = self . assert_json_success ( result )
self . assertEqual ( len ( json [ " removed " ] ) , 1 )
self . assertEqual ( len ( json [ " not_subscribed " ] ) , 0 )
2014-01-30 22:50:51 +01:00
2017-11-05 10:51:25 +01:00
def test_create_stream_by_admins_only_setting ( self ) - > None :
2016-05-12 10:28:00 +02:00
"""
2016-11-29 08:57:35 +01:00
When realm . create_stream_by_admins_only setting is active and
the number of days since the user had joined is less than waiting period
threshold , non admin users shouldn ' t be able to create new streams.
2016-05-12 10:28:00 +02:00
"""
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' hamlet ' )
email = user_profile . email
2016-05-12 10:28:00 +02:00
self . login ( email )
2017-03-21 18:08:40 +01:00
do_set_realm_property ( user_profile . realm , ' create_stream_by_admins_only ' , True )
2016-11-29 08:57:35 +01:00
stream_name = [ ' adminsonlysetting ' ]
result = self . common_subscribe_to_streams (
email ,
stream_name
)
self . assert_json_error ( result , ' User cannot create streams. ' )
2017-11-05 10:51:25 +01:00
def test_create_stream_by_waiting_period_threshold ( self ) - > None :
2016-11-29 08:57:35 +01:00
"""
Non admin users with account age greater or equal to waiting period
threshold should be able to create new streams .
"""
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' hamlet ' )
2017-05-29 19:54:06 +02:00
user_profile . date_joined = timezone_now ( )
user_profile . save ( )
2017-05-07 19:39:30 +02:00
email = user_profile . email
2016-11-29 08:57:35 +01:00
self . login ( email )
2016-05-12 10:28:00 +02:00
do_change_is_admin ( user_profile , False )
2017-03-21 18:08:40 +01:00
do_set_realm_property ( user_profile . realm , ' waiting_period_threshold ' , 10 )
2016-11-29 08:57:35 +01:00
stream_name = [ ' waitingperiodtest ' ]
2016-05-12 10:28:00 +02:00
result = self . common_subscribe_to_streams (
email ,
stream_name
)
self . assert_json_error ( result , ' User cannot create streams. ' )
2017-03-21 18:08:40 +01:00
do_set_realm_property ( user_profile . realm , ' waiting_period_threshold ' , 0 )
2016-11-29 08:57:35 +01:00
result = self . common_subscribe_to_streams (
email ,
stream_name
)
self . assert_json_success ( result )
2016-05-12 10:28:00 +02:00
2017-11-05 10:51:25 +01:00
def test_remove_already_not_subbed ( self ) - > None :
2014-01-30 22:50:51 +01:00
"""
Trying to unsubscribe someone who already isn ' t subscribed to a stream
fails gracefully .
"""
result = self . attempt_unsubscribe_of_principal (
2017-10-29 20:19:57 +01:00
query_count = 11 , is_admin = True , is_subbed = False , invite_only = False ,
2014-01-30 22:50:51 +01:00
other_user_subbed = False )
json = self . assert_json_success ( result )
self . assertEqual ( len ( json [ " removed " ] ) , 0 )
self . assertEqual ( len ( json [ " not_subscribed " ] ) , 1 )
2017-11-05 10:51:25 +01:00
def test_remove_invalid_user ( self ) - > None :
2014-01-30 22:50:51 +01:00
"""
Trying to unsubscribe an invalid user from a stream fails gracefully .
"""
2017-05-07 21:25:59 +02:00
user_profile = self . example_user ( ' hamlet ' )
admin_email = user_profile . email
2014-01-30 22:50:51 +01:00
self . login ( admin_email )
do_change_is_admin ( user_profile , True )
stream_name = u " hümbüǵ "
2016-10-21 23:22:25 +02:00
self . make_stream ( stream_name )
2014-01-30 22:50:51 +01:00
2016-12-23 02:37:10 +01:00
result = self . client_delete ( " /json/users/me/subscriptions " ,
{ " subscriptions " : ujson . dumps ( [ stream_name ] ) ,
" principals " : ujson . dumps ( [ " baduser@zulip.com " ] ) } )
2014-01-30 22:50:51 +01:00
self . assert_json_error (
result ,
2016-04-28 01:23:45 +02:00
" User not authorized to execute queries on behalf of ' baduser@zulip.com ' " ,
status_code = 403 )
2014-01-30 22:50:51 +01:00
2016-08-23 02:08:42 +02:00
class DefaultStreamTest ( ZulipTestCase ) :
2018-05-11 01:39:38 +02:00
def get_default_stream_names ( self , realm : Realm ) - > Set [ str ] :
2017-09-17 00:34:13 +02:00
streams = get_default_streams_for_realm ( realm . id )
2014-01-29 22:03:40 +01:00
stream_names = [ s . name for s in streams ]
return set ( stream_names )
2018-05-11 01:39:38 +02:00
def get_default_stream_descriptions ( self , realm : Realm ) - > Set [ str ] :
2017-09-17 00:34:13 +02:00
streams = get_default_streams_for_realm ( realm . id )
2016-12-08 01:43:15 +01:00
stream_descriptions = [ s . description for s in streams ]
return set ( stream_descriptions )
2017-11-05 10:51:25 +01:00
def test_set_default_streams ( self ) - > None :
2017-08-24 04:52:34 +02:00
realm = do_create_realm ( " testrealm " , " Test Realm " )
2016-12-08 01:43:15 +01:00
stream_dict = {
" apple " : { " description " : " A red fruit " , " invite_only " : False } ,
" banana " : { " description " : " A yellow fruit " , " invite_only " : False } ,
" Carrot Cake " : { " description " : " A delicious treat " , " invite_only " : False }
2018-05-11 01:39:38 +02:00
} # type: Dict[str, Dict[str, Any]]
2016-12-08 01:43:15 +01:00
expected_names = list ( stream_dict . keys ( ) )
expected_names . append ( " announce " )
expected_descriptions = [ i [ " description " ] for i in stream_dict . values ( ) ] + [ " " ]
set_default_streams ( realm , stream_dict )
2016-06-04 19:50:38 +02:00
stream_names_set = self . get_default_stream_names ( realm )
2016-12-08 01:43:15 +01:00
stream_descriptions_set = self . get_default_stream_descriptions ( realm )
2016-06-04 19:50:38 +02:00
self . assertEqual ( stream_names_set , set ( expected_names ) )
2016-12-08 01:43:15 +01:00
self . assertEqual ( stream_descriptions_set , set ( expected_descriptions ) )
2015-11-30 18:15:16 +01:00
2017-11-05 10:51:25 +01:00
def test_set_default_streams_no_notifications_stream ( self ) - > None :
2017-08-24 04:52:34 +02:00
realm = do_create_realm ( " testrealm " , " Test Realm " )
2015-11-30 18:15:16 +01:00
realm . notifications_stream = None
realm . save ( update_fields = [ " notifications_stream " ] )
2016-12-08 01:43:15 +01:00
stream_dict = {
" apple " : { " description " : " A red fruit " , " invite_only " : False } ,
" banana " : { " description " : " A yellow fruit " , " invite_only " : False } ,
" Carrot Cake " : { " description " : " A delicious treat " , " invite_only " : False }
2018-05-11 01:39:38 +02:00
} # type: Dict[str, Dict[str, Any]]
2016-12-08 01:43:15 +01:00
expected_names = list ( stream_dict . keys ( ) )
expected_descriptions = [ i [ " description " ] for i in stream_dict . values ( ) ]
set_default_streams ( realm , stream_dict )
2016-06-04 19:50:38 +02:00
stream_names_set = self . get_default_stream_names ( realm )
2016-12-08 01:43:15 +01:00
stream_descriptions_set = self . get_default_stream_descriptions ( realm )
2016-06-04 19:50:38 +02:00
self . assertEqual ( stream_names_set , set ( expected_names ) )
2016-12-08 01:43:15 +01:00
self . assertEqual ( stream_descriptions_set , set ( expected_descriptions ) )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_add_and_remove_default_stream ( self ) - > None :
2017-01-04 05:30:48 +01:00
realm = get_realm ( " zulip " )
2018-03-21 22:05:21 +01:00
stream = ensure_stream ( realm , " Added Stream " )
2014-01-29 22:03:40 +01:00
orig_stream_names = self . get_default_stream_names ( realm )
2017-01-30 04:23:08 +01:00
do_add_default_stream ( stream )
2014-01-29 22:03:40 +01:00
new_stream_names = self . get_default_stream_names ( realm )
added_stream_names = new_stream_names - orig_stream_names
self . assertEqual ( added_stream_names , set ( [ ' Added Stream ' ] ) )
# idempotentcy--2nd call to add_default_stream should be a noop
2017-01-30 04:23:08 +01:00
do_add_default_stream ( stream )
2014-01-29 22:03:40 +01:00
self . assertEqual ( self . get_default_stream_names ( realm ) , new_stream_names )
# start removing
2017-01-30 04:25:40 +01:00
do_remove_default_stream ( stream )
2014-01-29 22:03:40 +01:00
self . assertEqual ( self . get_default_stream_names ( realm ) , orig_stream_names )
# idempotentcy--2nd call to remove_default_stream should be a noop
2017-01-30 04:25:40 +01:00
do_remove_default_stream ( stream )
2014-01-29 22:03:40 +01:00
self . assertEqual ( self . get_default_stream_names ( realm ) , orig_stream_names )
2017-11-05 10:51:25 +01:00
def test_api_calls ( self ) - > None :
2017-05-07 17:21:26 +02:00
user_profile = self . example_user ( ' hamlet ' )
2014-01-29 22:03:40 +01:00
do_change_is_admin ( user_profile , True )
2018-08-15 20:45:55 +02:00
self . login ( user_profile . email )
2014-01-29 22:03:40 +01:00
stream_name = ' stream ADDED via api '
2018-03-21 23:51:41 +01:00
ensure_stream ( user_profile . realm , stream_name )
2016-12-31 08:31:34 +01:00
result = self . client_post ( ' /json/default_streams ' , dict ( stream_name = stream_name ) )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
self . assertTrue ( stream_name in self . get_default_stream_names ( user_profile . realm ) )
2018-08-15 20:45:55 +02:00
# look for it
self . subscribe ( user_profile , stream_name )
payload = dict (
include_public = ' true ' ,
include_default = ' true ' ,
)
result = self . client_get ( ' /json/streams ' , payload )
self . assert_json_success ( result )
streams = result . json ( ) [ ' streams ' ]
default_streams = {
stream [ ' name ' ]
for stream in streams
if stream [ ' is_default ' ]
}
self . assertEqual ( default_streams , { stream_name } )
other_streams = {
stream [ ' name ' ]
for stream in streams
if not stream [ ' is_default ' ]
}
self . assertTrue ( len ( other_streams ) > 0 )
2014-01-29 22:03:40 +01:00
# and remove it
result = self . client_delete ( ' /json/default_streams ' , dict ( stream_name = stream_name ) )
self . assert_json_success ( result )
self . assertFalse ( stream_name in self . get_default_stream_names ( user_profile . realm ) )
2018-08-07 14:13:58 +02:00
# Test admin can't add unsubscribed private stream
stream_name = " private_stream "
self . make_stream ( stream_name , invite_only = True )
self . subscribe ( self . example_user ( ' iago ' ) , stream_name )
result = self . client_post ( ' /json/default_streams ' , dict ( stream_name = stream_name ) )
self . assert_json_error ( result , " Invalid stream name ' %s ' " % ( stream_name ) )
self . subscribe ( user_profile , stream_name )
result = self . client_post ( ' /json/default_streams ' , dict ( stream_name = stream_name ) )
self . assert_json_success ( result )
self . assertTrue ( stream_name in self . get_default_stream_names ( user_profile . realm ) )
# Test admin can remove unsubscribed private stream
self . unsubscribe ( user_profile , stream_name )
result = self . client_delete ( ' /json/default_streams ' , dict ( stream_name = stream_name ) )
self . assert_json_success ( result )
self . assertFalse ( stream_name in self . get_default_stream_names ( user_profile . realm ) )
2014-01-29 22:03:40 +01:00
2017-11-01 18:20:34 +01:00
class DefaultStreamGroupTest ( ZulipTestCase ) :
def test_create_update_and_remove_default_stream_group ( self ) - > None :
realm = get_realm ( " zulip " )
# Test creating new default stream group
default_stream_groups = get_default_stream_groups ( realm )
self . assert_length ( default_stream_groups , 0 )
streams = [ ]
for stream_name in [ " stream1 " , " stream2 " , " stream3 " ] :
2018-03-21 22:05:21 +01:00
stream = ensure_stream ( realm , stream_name )
2017-11-01 18:20:34 +01:00
streams . append ( stream )
2017-12-01 07:57:54 +01:00
def get_streams ( group : DefaultStreamGroup ) - > List [ Stream ] :
return list ( group . streams . all ( ) . order_by ( ' name ' ) )
2017-11-01 18:20:34 +01:00
group_name = " group1 "
2017-11-14 20:51:34 +01:00
description = " This is group1 "
do_create_default_stream_group ( realm , group_name , description , streams )
2017-11-01 18:20:34 +01:00
default_stream_groups = get_default_stream_groups ( realm )
self . assert_length ( default_stream_groups , 1 )
self . assertEqual ( default_stream_groups [ 0 ] . name , group_name )
2017-11-14 20:51:34 +01:00
self . assertEqual ( default_stream_groups [ 0 ] . description , description )
2017-12-01 07:57:54 +01:00
self . assertEqual ( get_streams ( default_stream_groups [ 0 ] ) , streams )
2017-11-01 18:20:34 +01:00
# Test adding streams to existing default stream group
2017-11-14 20:33:09 +01:00
group = lookup_default_stream_groups ( [ " group1 " ] , realm ) [ 0 ]
2017-11-01 18:20:34 +01:00
new_stream_names = [ " stream4 " , " stream5 " ]
new_streams = [ ]
for new_stream_name in new_stream_names :
2018-03-21 22:05:21 +01:00
new_stream = ensure_stream ( realm , new_stream_name )
2017-11-01 18:20:34 +01:00
new_streams . append ( new_stream )
streams . append ( new_stream )
2017-11-14 20:33:09 +01:00
do_add_streams_to_default_stream_group ( realm , group , new_streams )
2017-11-01 18:20:34 +01:00
default_stream_groups = get_default_stream_groups ( realm )
self . assert_length ( default_stream_groups , 1 )
self . assertEqual ( default_stream_groups [ 0 ] . name , group_name )
2017-12-01 07:57:54 +01:00
self . assertEqual ( get_streams ( default_stream_groups [ 0 ] ) , streams )
2017-11-01 18:20:34 +01:00
# Test removing streams from existing default stream group
2017-11-14 20:33:09 +01:00
do_remove_streams_from_default_stream_group ( realm , group , new_streams )
2017-11-01 18:20:34 +01:00
remaining_streams = streams [ 0 : 3 ]
default_stream_groups = get_default_stream_groups ( realm )
self . assert_length ( default_stream_groups , 1 )
self . assertEqual ( default_stream_groups [ 0 ] . name , group_name )
2017-12-01 07:57:54 +01:00
self . assertEqual ( get_streams ( default_stream_groups [ 0 ] ) , remaining_streams )
2017-11-01 18:20:34 +01:00
2017-11-14 20:51:34 +01:00
# Test changing default stream group description
new_description = " group1 new description "
do_change_default_stream_group_description ( realm , group , new_description )
default_stream_groups = get_default_stream_groups ( realm )
self . assertEqual ( default_stream_groups [ 0 ] . description , new_description )
self . assert_length ( default_stream_groups , 1 )
2017-11-14 21:06:02 +01:00
# Test changing default stream group name
new_group_name = " new group1 "
do_change_default_stream_group_name ( realm , group , new_group_name )
default_stream_groups = get_default_stream_groups ( realm )
self . assert_length ( default_stream_groups , 1 )
self . assertEqual ( default_stream_groups [ 0 ] . name , new_group_name )
2017-12-01 07:57:54 +01:00
self . assertEqual ( get_streams ( default_stream_groups [ 0 ] ) , remaining_streams )
2017-11-14 21:06:02 +01:00
2017-11-01 18:20:34 +01:00
# Test removing default stream group
2017-11-14 20:33:09 +01:00
do_remove_default_stream_group ( realm , group )
2017-11-01 18:20:34 +01:00
default_stream_groups = get_default_stream_groups ( realm )
self . assert_length ( default_stream_groups , 0 )
# Test creating a default stream group which contains a default stream
do_add_default_stream ( remaining_streams [ 0 ] )
2017-11-17 07:00:53 +01:00
with self . assertRaisesRegex (
JsonableError , " ' stream1 ' is a default stream and cannot be added to ' new group1 ' " ) :
2017-11-14 21:06:02 +01:00
do_create_default_stream_group ( realm , new_group_name , " This is group1 " , remaining_streams )
2017-11-01 18:20:34 +01:00
def test_api_calls ( self ) - > None :
self . login ( self . example_email ( " hamlet " ) )
user_profile = self . example_user ( ' hamlet ' )
realm = user_profile . realm
do_change_is_admin ( user_profile , True )
# Test creating new default stream group
stream_names = [ " stream1 " , " stream2 " , " stream3 " ]
group_name = " group1 "
2017-11-14 20:51:34 +01:00
description = " This is group1 "
2017-11-01 18:20:34 +01:00
streams = [ ]
default_stream_groups = get_default_stream_groups ( realm )
self . assert_length ( default_stream_groups , 0 )
for stream_name in stream_names :
2018-03-21 22:05:21 +01:00
stream = ensure_stream ( realm , stream_name )
2017-11-01 18:20:34 +01:00
streams . append ( stream )
2017-11-14 20:33:09 +01:00
result = self . client_post ( ' /json/default_stream_groups/create ' ,
2017-11-14 20:51:34 +01:00
{ " group_name " : group_name , " description " : description ,
" stream_names " : ujson . dumps ( stream_names ) } )
2017-11-01 18:20:34 +01:00
self . assert_json_success ( result )
default_stream_groups = get_default_stream_groups ( realm )
self . assert_length ( default_stream_groups , 1 )
self . assertEqual ( default_stream_groups [ 0 ] . name , group_name )
2017-11-14 20:51:34 +01:00
self . assertEqual ( default_stream_groups [ 0 ] . description , description )
2017-11-18 00:31:54 +01:00
self . assertEqual ( list ( default_stream_groups [ 0 ] . streams . all ( ) . order_by ( " id " ) ) , streams )
2017-11-01 18:20:34 +01:00
2018-08-22 16:54:28 +02:00
# Try adding the same streams to the group.
result = self . client_post ( ' /json/default_stream_groups/create ' ,
{ " group_name " : group_name , " description " : description ,
" stream_names " : ujson . dumps ( stream_names ) } )
self . assert_json_error ( result , " Default stream group ' group1 ' already exists " )
2017-11-01 18:20:34 +01:00
# Test adding streams to existing default stream group
2017-11-14 20:33:09 +01:00
group_id = default_stream_groups [ 0 ] . id
2017-11-01 18:20:34 +01:00
new_stream_names = [ " stream4 " , " stream5 " ]
new_streams = [ ]
for new_stream_name in new_stream_names :
2018-03-21 22:05:21 +01:00
new_stream = ensure_stream ( realm , new_stream_name )
2017-11-01 18:20:34 +01:00
new_streams . append ( new_stream )
streams . append ( new_stream )
2017-11-14 20:33:09 +01:00
result = self . client_patch ( " /json/default_stream_groups/ {} /streams " . format ( group_id ) ,
{ " stream_names " : ujson . dumps ( new_stream_names ) } )
2017-11-01 18:20:34 +01:00
self . assert_json_error ( result , " Missing ' op ' argument " )
2017-11-14 20:33:09 +01:00
result = self . client_patch ( " /json/default_stream_groups/ {} /streams " . format ( group_id ) ,
{ " op " : " invalid " , " stream_names " : ujson . dumps ( new_stream_names ) } )
self . assert_json_error ( result , ' Invalid value for " op " . Specify one of " add " or " remove " . ' )
result = self . client_patch ( " /json/default_stream_groups/12345/streams " ,
{ " op " : " add " , " stream_names " : ujson . dumps ( new_stream_names ) } )
self . assert_json_error ( result , " Default stream group with id ' 12345 ' does not exist. " )
2017-11-01 18:20:34 +01:00
2017-11-14 20:33:09 +01:00
result = self . client_patch ( " /json/default_stream_groups/ {} /streams " . format ( group_id ) , { " op " : " add " } )
self . assert_json_error ( result , " Missing ' stream_names ' argument " )
2017-11-01 18:20:34 +01:00
do_add_default_stream ( new_streams [ 0 ] )
2017-11-14 20:33:09 +01:00
result = self . client_patch ( " /json/default_stream_groups/ {} /streams " . format ( group_id ) ,
{ " op " : " add " , " stream_names " : ujson . dumps ( new_stream_names ) } )
2017-11-01 18:20:34 +01:00
self . assert_json_error ( result , " ' stream4 ' is a default stream and cannot be added to ' group1 ' " )
do_remove_default_stream ( new_streams [ 0 ] )
2017-11-14 20:33:09 +01:00
result = self . client_patch ( " /json/default_stream_groups/ {} /streams " . format ( group_id ) ,
{ " op " : " add " , " stream_names " : ujson . dumps ( new_stream_names ) } )
self . assert_json_success ( result )
2017-11-01 18:20:34 +01:00
default_stream_groups = get_default_stream_groups ( realm )
self . assert_length ( default_stream_groups , 1 )
self . assertEqual ( default_stream_groups [ 0 ] . name , group_name )
2018-01-31 08:49:53 +01:00
self . assertEqual ( list ( default_stream_groups [ 0 ] . streams . all ( ) . order_by ( ' name ' ) ) , streams )
2017-11-01 18:20:34 +01:00
2017-11-14 20:33:09 +01:00
result = self . client_patch ( " /json/default_stream_groups/ {} /streams " . format ( group_id ) ,
{ " op " : " add " , " stream_names " : ujson . dumps ( new_stream_names ) } )
2017-11-17 07:00:53 +01:00
self . assert_json_error ( result ,
" Stream ' stream4 ' is already present in default stream group ' group1 ' " )
2017-11-01 18:20:34 +01:00
# Test removing streams from default stream group
2017-11-14 20:33:09 +01:00
result = self . client_patch ( " /json/default_stream_groups/12345/streams " ,
{ " op " : " remove " , " stream_names " : ujson . dumps ( new_stream_names ) } )
self . assert_json_error ( result , " Default stream group with id ' 12345 ' does not exist. " )
result = self . client_patch ( " /json/default_stream_groups/ {} /streams " . format ( group_id ) ,
{ " op " : " remove " , " stream_names " : ujson . dumps ( [ " random stream name " ] ) } )
2017-11-01 18:20:34 +01:00
self . assert_json_error ( result , " Invalid stream name ' random stream name ' " )
streams . remove ( new_streams [ 0 ] )
2017-11-14 20:33:09 +01:00
result = self . client_patch ( " /json/default_stream_groups/ {} /streams " . format ( group_id ) ,
{ " op " : " remove " , " stream_names " : ujson . dumps ( [ new_stream_names [ 0 ] ] ) } )
2017-11-01 18:20:34 +01:00
self . assert_json_success ( result )
default_stream_groups = get_default_stream_groups ( realm )
self . assert_length ( default_stream_groups , 1 )
self . assertEqual ( default_stream_groups [ 0 ] . name , group_name )
2018-01-31 08:49:53 +01:00
self . assertEqual ( list ( default_stream_groups [ 0 ] . streams . all ( ) . order_by ( ' name ' ) ) , streams )
2017-11-01 18:20:34 +01:00
2017-11-14 20:33:09 +01:00
result = self . client_patch ( " /json/default_stream_groups/ {} /streams " . format ( group_id ) ,
{ " op " : " remove " , " stream_names " : ujson . dumps ( new_stream_names ) } )
2017-11-01 18:20:34 +01:00
self . assert_json_error ( result , " Stream ' stream4 ' is not present in default stream group ' group1 ' " )
2017-11-14 20:51:34 +01:00
# Test changing description of default stream group
new_description = " new group1 description "
result = self . client_patch ( " /json/default_stream_groups/ {} " . format ( group_id ) ,
{ " group_name " : group_name , " op " : " change " } )
2017-11-14 21:06:02 +01:00
self . assert_json_error ( result , ' You must pass " new_description " or " new_group_name " . ' )
2017-11-14 20:51:34 +01:00
result = self . client_patch ( " /json/default_stream_groups/12345 " ,
{ " op " : " change " , " new_description " : ujson . dumps ( new_description ) } )
self . assert_json_error ( result , " Default stream group with id ' 12345 ' does not exist. " )
result = self . client_patch ( " /json/default_stream_groups/ {} " . format ( group_id ) ,
{ " group_name " : group_name ,
" op " : " change " ,
" new_description " : ujson . dumps ( new_description ) } )
self . assert_json_success ( result )
default_stream_groups = get_default_stream_groups ( realm )
self . assert_length ( default_stream_groups , 1 )
self . assertEqual ( default_stream_groups [ 0 ] . name , group_name )
self . assertEqual ( default_stream_groups [ 0 ] . description , new_description )
2017-11-14 21:06:02 +01:00
# Test changing name of default stream group
new_group_name = " new group1 "
do_create_default_stream_group ( realm , " group2 " , " " , [ ] )
result = self . client_patch ( " /json/default_stream_groups/ {} " . format ( group_id ) ,
{ " op " : " change " , " new_group_name " : ujson . dumps ( " group2 " ) } )
self . assert_json_error ( result , " Default stream group ' group2 ' already exists " )
new_group = lookup_default_stream_groups ( [ " group2 " ] , realm ) [ 0 ]
do_remove_default_stream_group ( realm , new_group )
result = self . client_patch ( " /json/default_stream_groups/ {} " . format ( group_id ) ,
{ " op " : " change " , " new_group_name " : ujson . dumps ( group_name ) } )
self . assert_json_error ( result , " This default stream group is already named ' group1 ' " )
result = self . client_patch ( " /json/default_stream_groups/ {} " . format ( group_id ) ,
{ " op " : " change " , " new_group_name " : ujson . dumps ( new_group_name ) } )
self . assert_json_success ( result )
default_stream_groups = get_default_stream_groups ( realm )
self . assert_length ( default_stream_groups , 1 )
self . assertEqual ( default_stream_groups [ 0 ] . name , new_group_name )
self . assertEqual ( default_stream_groups [ 0 ] . description , new_description )
2017-11-01 18:20:34 +01:00
# Test deleting a default stream group
2017-11-14 20:33:09 +01:00
result = self . client_delete ( ' /json/default_stream_groups/ {} ' . format ( group_id ) )
2017-11-01 18:20:34 +01:00
self . assert_json_success ( result )
default_stream_groups = get_default_stream_groups ( realm )
self . assert_length ( default_stream_groups , 0 )
2017-11-14 20:33:09 +01:00
result = self . client_delete ( ' /json/default_stream_groups/ {} ' . format ( group_id ) )
self . assert_json_error ( result , " Default stream group with id ' {} ' does not exist. " . format ( group_id ) )
2017-11-01 18:20:34 +01:00
2018-02-04 19:50:47 +01:00
def test_invalid_default_stream_group_name ( self ) - > None :
self . login ( self . example_email ( " iago " ) )
user_profile = self . example_user ( ' iago ' )
realm = user_profile . realm
stream_names = [ " stream1 " , " stream2 " , " stream3 " ]
description = " This is group1 "
streams = [ ]
for stream_name in stream_names :
2018-03-21 22:05:21 +01:00
stream = ensure_stream ( realm , stream_name )
2018-02-04 19:50:47 +01:00
streams . append ( stream )
result = self . client_post ( ' /json/default_stream_groups/create ' ,
{ " group_name " : " " , " description " : description ,
" stream_names " : ujson . dumps ( stream_names ) } )
self . assert_json_error ( result , " Invalid default stream group name ' ' " )
result = self . client_post ( ' /json/default_stream_groups/create ' ,
{ " group_name " : ' x ' * 100 , " description " : description ,
" stream_names " : ujson . dumps ( stream_names ) } )
self . assert_json_error ( result , " Default stream group name too long (limit: {} characters) "
. format ( ( DefaultStreamGroup . MAX_NAME_LENGTH ) ) )
result = self . client_post ( ' /json/default_stream_groups/create ' ,
{ " group_name " : " abc \000 " , " description " : description ,
" stream_names " : ujson . dumps ( stream_names ) } )
self . assert_json_error ( result , " Default stream group name ' abc \000 ' contains NULL (0x00) characters. " )
2018-08-16 16:17:20 +02:00
# Also test that lookup_default_stream_groups raises an
# error if we pass it a bad name. This function is used
# during registration, but it's a bit heavy to do a full
# test of that.
with self . assertRaisesRegex ( JsonableError , ' Invalid default stream group invalid-name ' ) :
lookup_default_stream_groups ( [ ' invalid-name ' ] , realm )
2016-08-23 02:08:42 +02:00
class SubscriptionPropertiesTest ( ZulipTestCase ) :
2017-11-05 10:51:25 +01:00
def test_set_stream_color ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
2017-05-09 07:01:42 +02:00
A POST request to / api / v1 / users / me / subscriptions / properties with stream_id and
2019-01-14 07:50:23 +01:00
color data sets the stream color , and for that stream only . Also , make sure that
any invalid hex color codes are bounced .
2014-01-29 22:03:40 +01:00
"""
2017-05-08 16:23:43 +02:00
test_user = self . example_user ( ' hamlet ' )
test_email = test_user . email
2017-05-23 20:57:59 +02:00
test_realm = test_user . realm
2014-01-29 22:03:40 +01:00
self . login ( test_email )
2017-05-08 16:23:43 +02:00
old_subs , _ = gather_subscriptions ( test_user )
2014-01-29 22:03:40 +01:00
sub = old_subs [ 0 ]
2017-05-09 07:01:42 +02:00
stream_id = sub [ ' stream_id ' ]
2017-07-11 21:51:31 +02:00
new_color = " #ffffff " # TODO: ensure that this is different from old_color
2017-12-14 19:02:31 +01:00
result = self . api_post ( test_email , " /api/v1/users/me/subscriptions/properties " ,
{ " subscription_data " : ujson . dumps ( [ { " property " : " color " ,
" stream_id " : stream_id ,
" value " : " #ffffff " } ] ) } )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2017-05-23 20:57:59 +02:00
new_subs = gather_subscriptions ( get_user ( test_email , test_realm ) ) [ 0 ]
2014-01-29 22:03:40 +01:00
found_sub = None
for sub in new_subs :
2017-05-09 07:01:42 +02:00
if sub [ ' stream_id ' ] == stream_id :
2014-01-29 22:03:40 +01:00
found_sub = sub
break
2017-05-24 04:21:29 +02:00
assert ( found_sub is not None )
2014-01-29 22:03:40 +01:00
self . assertEqual ( found_sub [ ' color ' ] , new_color )
new_subs . remove ( found_sub )
for sub in old_subs :
2017-05-09 07:01:42 +02:00
if sub [ ' stream_id ' ] == stream_id :
2014-01-29 22:03:40 +01:00
found_sub = sub
break
old_subs . remove ( found_sub )
self . assertEqual ( old_subs , new_subs )
2019-01-14 07:50:23 +01:00
invalid_color = " 3ffrff "
result = self . api_post ( test_email , " /api/v1/users/me/subscriptions/properties " ,
{ " subscription_data " : ujson . dumps ( [ { " property " : " color " ,
" stream_id " : stream_id ,
" value " : invalid_color } ] ) } )
self . assert_json_error ( result , " color is not a valid hex color code " )
2017-11-05 10:51:25 +01:00
def test_set_color_missing_stream_id ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
2017-05-09 07:01:42 +02:00
Updating the color property requires a ` stream_id ` key .
2014-01-29 22:03:40 +01:00
"""
2017-05-09 07:01:42 +02:00
test_user = self . example_user ( ' hamlet ' )
test_email = test_user . email
2014-01-29 22:03:40 +01:00
self . login ( test_email )
2017-12-14 19:02:31 +01:00
result = self . api_post ( test_email , " /api/v1/users/me/subscriptions/properties " ,
{ " subscription_data " : ujson . dumps ( [ { " property " : " color " ,
" value " : " #ffffff " } ] ) } )
2014-02-14 21:55:20 +01:00
self . assert_json_error (
2017-05-09 07:01:42 +02:00
result , " stream_id key is missing from subscription_data[0] " )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_set_color_unsubscribed_stream_id ( self ) - > None :
2016-08-18 12:33:06 +02:00
"""
Updating the color property requires a subscribed stream .
"""
2017-05-23 20:57:59 +02:00
test_email = self . example_email ( " hamlet " )
2016-08-18 12:33:06 +02:00
self . login ( test_email )
2017-05-23 20:57:59 +02:00
test_realm = get_realm ( " zulip " )
2016-08-18 12:33:06 +02:00
2017-05-09 07:01:42 +02:00
subscribed , unsubscribed , never_subscribed = gather_subscriptions_helper (
2017-05-23 20:57:59 +02:00
get_user ( test_email , test_realm ) )
2017-05-09 07:01:42 +02:00
not_subbed = unsubscribed + never_subscribed
2017-12-14 19:02:31 +01:00
result = self . api_post ( test_email , " /api/v1/users/me/subscriptions/properties " ,
{ " subscription_data " : ujson . dumps ( [ { " property " : " color " ,
" stream_id " : not_subbed [ 0 ] [ " stream_id " ] ,
" value " : " #ffffff " } ] ) } )
2016-08-18 12:33:06 +02:00
self . assert_json_error (
2017-05-09 07:01:42 +02:00
result , " Not subscribed to stream id %d " % ( not_subbed [ 0 ] [ " stream_id " ] , ) )
2016-07-16 18:50:41 +02:00
2017-11-05 10:51:25 +01:00
def test_set_color_missing_color ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
Updating the color property requires a color .
"""
2017-05-08 16:23:43 +02:00
test_user = self . example_user ( ' hamlet ' )
test_email = test_user . email
2014-01-29 22:03:40 +01:00
self . login ( test_email )
2017-05-08 16:23:43 +02:00
subs = gather_subscriptions ( test_user ) [ 0 ]
2017-12-14 19:02:31 +01:00
result = self . api_post ( test_email , " /api/v1/users/me/subscriptions/properties " ,
{ " subscription_data " : ujson . dumps ( [ { " property " : " color " ,
" stream_id " : subs [ 0 ] [ " stream_id " ] } ] ) } )
2014-02-14 21:55:20 +01:00
self . assert_json_error (
result , " value key is missing from subscription_data[0] " )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_set_pin_to_top ( self ) - > None :
2016-07-01 07:26:09 +02:00
"""
2017-05-09 07:01:42 +02:00
A POST request to / api / v1 / users / me / subscriptions / properties with stream_id and
2016-07-01 07:26:09 +02:00
pin_to_top data pins the stream .
"""
2017-05-07 21:25:59 +02:00
user_profile = self . example_user ( ' hamlet ' )
test_email = user_profile . email
2016-07-01 07:26:09 +02:00
self . login ( test_email )
old_subs , _ = gather_subscriptions ( user_profile )
sub = old_subs [ 0 ]
2017-05-09 07:01:42 +02:00
stream_id = sub [ ' stream_id ' ]
2016-07-01 07:26:09 +02:00
new_pin_to_top = not sub [ ' pin_to_top ' ]
2017-12-14 19:02:31 +01:00
result = self . api_post ( test_email , " /api/v1/users/me/subscriptions/properties " ,
{ " subscription_data " : ujson . dumps ( [ { " property " : " pin_to_top " ,
" stream_id " : stream_id ,
" value " : new_pin_to_top } ] ) } )
2016-07-01 07:26:09 +02:00
self . assert_json_success ( result )
2017-05-09 07:01:42 +02:00
updated_sub = get_subscription ( sub [ ' name ' ] , user_profile )
2016-07-01 07:26:09 +02:00
self . assertIsNotNone ( updated_sub )
self . assertEqual ( updated_sub . pin_to_top , new_pin_to_top )
2017-11-05 10:51:25 +01:00
def test_set_subscription_property_incorrect ( self ) - > None :
2016-07-16 18:50:41 +02:00
"""
Trying to set a property incorrectly returns a JSON error .
"""
2017-05-08 16:23:43 +02:00
test_user = self . example_user ( ' hamlet ' )
test_email = test_user . email
2016-07-16 18:50:41 +02:00
self . login ( test_email )
2017-05-08 16:23:43 +02:00
subs = gather_subscriptions ( test_user ) [ 0 ]
2016-07-16 18:50:41 +02:00
property_name = " in_home_view "
2017-12-14 19:02:31 +01:00
result = self . api_post ( test_email , " /api/v1/users/me/subscriptions/properties " ,
{ " subscription_data " : ujson . dumps ( [ { " property " : property_name ,
" value " : " bad " ,
" stream_id " : subs [ 0 ] [ " stream_id " ] } ] ) } )
2016-07-16 18:50:41 +02:00
self . assert_json_error ( result ,
' %s is not a boolean ' % ( property_name , ) )
property_name = " desktop_notifications "
2017-12-14 19:02:31 +01:00
result = self . api_post ( test_email , " /api/v1/users/me/subscriptions/properties " ,
{ " subscription_data " : ujson . dumps ( [ { " property " : property_name ,
" value " : " bad " ,
" stream_id " : subs [ 0 ] [ " stream_id " ] } ] ) } )
2016-07-16 18:50:41 +02:00
self . assert_json_error ( result ,
' %s is not a boolean ' % ( property_name , ) )
property_name = " audible_notifications "
2017-12-14 19:02:31 +01:00
result = self . api_post ( test_email , " /api/v1/users/me/subscriptions/properties " ,
{ " subscription_data " : ujson . dumps ( [ { " property " : property_name ,
" value " : " bad " ,
" stream_id " : subs [ 0 ] [ " stream_id " ] } ] ) } )
2016-07-16 18:50:41 +02:00
self . assert_json_error ( result ,
' %s is not a boolean ' % ( property_name , ) )
2017-08-17 16:55:32 +02:00
property_name = " push_notifications "
2017-12-14 19:02:31 +01:00
result = self . api_post ( test_email , " /api/v1/users/me/subscriptions/properties " ,
{ " subscription_data " : ujson . dumps ( [ { " property " : property_name ,
" value " : " bad " ,
" stream_id " : subs [ 0 ] [ " stream_id " ] } ] ) } )
2017-08-17 16:55:32 +02:00
self . assert_json_error ( result ,
' %s is not a boolean ' % ( property_name , ) )
2017-11-21 04:35:26 +01:00
property_name = " email_notifications "
result = self . api_post ( test_email , " /api/v1/users/me/subscriptions/properties " ,
{ " subscription_data " : ujson . dumps ( [ { " property " : property_name ,
" value " : " bad " ,
" stream_id " : subs [ 0 ] [ " stream_id " ] } ] ) } )
self . assert_json_error ( result ,
' %s is not a boolean ' % ( property_name , ) )
2016-07-16 18:50:41 +02:00
property_name = " color "
2017-12-14 19:02:31 +01:00
result = self . api_post ( test_email , " /api/v1/users/me/subscriptions/properties " ,
{ " subscription_data " : ujson . dumps ( [ { " property " : property_name ,
" value " : False ,
" stream_id " : subs [ 0 ] [ " stream_id " ] } ] ) } )
2016-07-16 18:50:41 +02:00
self . assert_json_error ( result ,
' %s is not a string ' % ( property_name , ) )
2017-11-05 10:51:25 +01:00
def test_json_subscription_property_invalid_stream ( self ) - > None :
2017-07-12 12:44:55 +02:00
test_email = self . example_email ( " hamlet " )
2016-07-24 16:45:20 +02:00
self . login ( test_email )
2017-05-09 07:01:42 +02:00
stream_id = 1000
2017-12-14 19:02:31 +01:00
result = self . api_post ( test_email , " /api/v1/users/me/subscriptions/properties " ,
{ " subscription_data " : ujson . dumps ( [ { " property " : " in_home_view " ,
" stream_id " : stream_id ,
" value " : False } ] ) } )
2017-05-09 07:01:42 +02:00
self . assert_json_error ( result , " Invalid stream id " )
2016-07-24 16:45:20 +02:00
2017-11-05 10:51:25 +01:00
def test_set_invalid_property ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
Trying to set an invalid property returns a JSON error .
"""
2017-05-08 16:23:43 +02:00
test_user = self . example_user ( ' hamlet ' )
test_email = test_user . email
2014-01-29 22:03:40 +01:00
self . login ( test_email )
2017-05-08 16:23:43 +02:00
subs = gather_subscriptions ( test_user ) [ 0 ]
2017-12-14 19:02:31 +01:00
result = self . api_post ( test_email , " /api/v1/users/me/subscriptions/properties " ,
{ " subscription_data " : ujson . dumps ( [ { " property " : " bad " ,
" value " : " bad " ,
" stream_id " : subs [ 0 ] [ " stream_id " ] } ] ) } )
2014-01-29 22:03:40 +01:00
self . assert_json_error ( result ,
" Unknown subscription property: bad " )
2016-08-23 02:08:42 +02:00
class SubscriptionRestApiTest ( ZulipTestCase ) :
2017-11-05 10:51:25 +01:00
def test_basic_add_delete ( self ) - > None :
2017-07-12 12:44:55 +02:00
email = self . example_email ( ' hamlet ' )
2017-07-12 13:07:48 +02:00
realm = self . example_user ( ' hamlet ' ) . realm
2014-01-29 22:03:40 +01:00
self . login ( email )
# add
request = {
' add ' : ujson . dumps ( [ { ' name ' : ' my_test_stream_1 ' } ] )
}
2017-12-14 19:02:31 +01:00
result = self . api_patch ( email , " /api/v1/users/me/subscriptions " , request )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2017-07-12 13:07:48 +02:00
streams = self . get_streams ( email , realm )
2014-01-29 22:03:40 +01:00
self . assertTrue ( ' my_test_stream_1 ' in streams )
# now delete the same stream
request = {
' delete ' : ujson . dumps ( [ ' my_test_stream_1 ' ] )
}
2017-12-14 19:02:31 +01:00
result = self . api_patch ( email , " /api/v1/users/me/subscriptions " , request )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2017-07-12 13:07:48 +02:00
streams = self . get_streams ( email , realm )
2014-01-29 22:03:40 +01:00
self . assertTrue ( ' my_test_stream_1 ' not in streams )
2019-01-10 15:03:15 +01:00
def test_add_with_color ( self ) - > None :
email = self . example_email ( ' hamlet ' )
self . login ( email )
# add with color proposition
request = {
' add ' : ujson . dumps ( [ { ' name ' : ' my_test_stream_2 ' , ' color ' : ' #afafaf ' } ] )
}
result = self . api_patch ( email , " /api/v1/users/me/subscriptions " , request )
self . assert_json_success ( result )
# incorrect color format
request = {
' subscriptions ' : ujson . dumps ( [ { ' name ' : ' my_test_stream_3 ' , ' color ' : ' #0g0g0g ' } ] )
}
result = self . api_post ( email , " /api/v1/users/me/subscriptions " , request )
self . assert_json_error ( result , ' subscriptions[0][ " color " ] is not a valid hex color code ' )
2017-11-05 10:51:25 +01:00
def test_api_valid_property ( self ) - > None :
2017-05-09 22:29:59 +02:00
"""
Trying to set valid json returns success message .
"""
test_user = self . example_user ( ' hamlet ' )
test_email = test_user . email
self . login ( test_email )
subs = gather_subscriptions ( test_user ) [ 0 ]
2017-12-14 19:02:31 +01:00
result = self . api_patch ( test_email , " /api/v1/users/me/subscriptions/ %d " % subs [ 0 ] [ " stream_id " ] ,
{ ' property ' : ' color ' , ' value ' : ' #c2c2c2 ' } )
2017-05-09 22:29:59 +02:00
self . assert_json_success ( result )
2017-11-05 10:51:25 +01:00
def test_api_invalid_property ( self ) - > None :
2017-05-09 22:29:59 +02:00
"""
Trying to set an invalid property returns a JSON error .
"""
test_user = self . example_user ( ' hamlet ' )
test_email = test_user . email
self . login ( test_email )
subs = gather_subscriptions ( test_user ) [ 0 ]
2017-12-14 19:02:31 +01:00
result = self . api_patch ( test_email , " /api/v1/users/me/subscriptions/ %d " % subs [ 0 ] [ " stream_id " ] ,
{ ' property ' : ' invalid ' , ' value ' : ' somevalue ' } )
2017-05-09 22:29:59 +02:00
self . assert_json_error ( result ,
" Unknown subscription property: invalid " )
2017-11-05 10:51:25 +01:00
def test_api_invalid_stream_id ( self ) - > None :
2017-05-09 22:29:59 +02:00
"""
Trying to set an invalid stream id returns a JSON error .
"""
2017-07-12 12:44:55 +02:00
test_email = self . example_email ( " hamlet " )
2017-05-09 22:29:59 +02:00
self . login ( test_email )
2017-12-14 19:02:31 +01:00
result = self . api_patch ( test_email , " /api/v1/users/me/subscriptions/121 " ,
{ ' property ' : ' in_home_view ' , ' value ' : ' somevalue ' } )
2017-05-09 22:29:59 +02:00
self . assert_json_error ( result ,
" Invalid stream id " )
2017-11-05 10:51:25 +01:00
def test_bad_add_parameters ( self ) - > None :
2017-07-12 12:44:55 +02:00
email = self . example_email ( ' hamlet ' )
2014-01-29 22:03:40 +01:00
self . login ( email )
2017-11-05 10:51:25 +01:00
def check_for_error ( val : Any , expected_message : str ) - > None :
2014-01-29 22:03:40 +01:00
request = {
' add ' : ujson . dumps ( val )
}
2017-12-14 19:02:31 +01:00
result = self . api_patch ( email , " /api/v1/users/me/subscriptions " , request )
2014-01-29 22:03:40 +01:00
self . assert_json_error ( result , expected_message )
check_for_error ( [ ' foo ' ] , ' add[0] is not a dict ' )
check_for_error ( [ { ' bogus ' : ' foo ' } ] , ' name key is missing from add[0] ' )
check_for_error ( [ { ' name ' : { } } ] , ' add[0][ " name " ] is not a string ' )
2017-11-05 10:51:25 +01:00
def test_bad_principals ( self ) - > None :
2017-07-12 12:44:55 +02:00
email = self . example_email ( ' hamlet ' )
2014-01-29 22:03:40 +01:00
self . login ( email )
request = {
' add ' : ujson . dumps ( [ { ' name ' : ' my_new_stream ' } ] ) ,
' principals ' : ujson . dumps ( [ { } ] ) ,
}
2017-12-14 19:02:31 +01:00
result = self . api_patch ( email , " /api/v1/users/me/subscriptions " , request )
2014-01-29 22:03:40 +01:00
self . assert_json_error ( result , ' principals[0] is not a string ' )
2017-11-05 10:51:25 +01:00
def test_bad_delete_parameters ( self ) - > None :
2017-07-12 12:44:55 +02:00
email = self . example_email ( ' hamlet ' )
2014-01-29 22:03:40 +01:00
self . login ( email )
request = {
' delete ' : ujson . dumps ( [ { ' name ' : ' my_test_stream_1 ' } ] )
}
2017-12-14 19:02:31 +01:00
result = self . api_patch ( email , " /api/v1/users/me/subscriptions " , request )
2014-01-29 22:03:40 +01:00
self . assert_json_error ( result , " delete[0] is not a string " )
2017-11-05 10:51:25 +01:00
def test_add_or_delete_not_specified ( self ) - > None :
2017-07-12 12:44:55 +02:00
email = self . example_email ( ' hamlet ' )
2016-07-16 18:50:41 +02:00
self . login ( email )
2017-12-14 19:02:31 +01:00
result = self . api_patch ( email , " /api/v1/users/me/subscriptions " , { } )
2016-07-16 18:50:41 +02:00
self . assert_json_error ( result ,
' Nothing to do. Specify at least one of " add " or " delete " . ' )
2017-11-05 10:51:25 +01:00
def test_patch_enforces_valid_stream_name_check ( self ) - > None :
2016-07-16 18:50:41 +02:00
"""
Only way to force an error is with a empty string .
"""
2017-07-12 12:44:55 +02:00
email = self . example_email ( ' hamlet ' )
2016-07-16 18:50:41 +02:00
self . login ( email )
invalid_stream_name = " "
request = {
' delete ' : ujson . dumps ( [ invalid_stream_name ] )
}
2017-12-14 19:02:31 +01:00
result = self . api_patch ( email , " /api/v1/users/me/subscriptions " , request )
2016-07-16 18:50:41 +02:00
self . assert_json_error ( result ,
2017-01-30 07:01:19 +01:00
" Invalid stream name ' %s ' " % ( invalid_stream_name , ) )
2016-07-16 18:50:41 +02:00
2017-11-05 10:51:25 +01:00
def test_stream_name_too_long ( self ) - > None :
2017-07-12 12:44:55 +02:00
email = self . example_email ( ' hamlet ' )
2016-07-16 18:50:41 +02:00
self . login ( email )
long_stream_name = " a " * 61
request = {
' delete ' : ujson . dumps ( [ long_stream_name ] )
}
2017-12-14 19:02:31 +01:00
result = self . api_patch ( email , " /api/v1/users/me/subscriptions " , request )
2016-07-16 18:50:41 +02:00
self . assert_json_error ( result ,
2018-01-08 19:54:19 +01:00
" Stream name too long (limit: 60 characters). " )
2016-07-16 18:50:41 +02:00
2017-11-05 10:51:25 +01:00
def test_stream_name_contains_null ( self ) - > None :
2017-07-12 12:44:55 +02:00
email = self . example_email ( ' hamlet ' )
2017-04-26 01:28:22 +02:00
self . login ( email )
stream_name = " abc \000 "
request = {
' delete ' : ujson . dumps ( [ stream_name ] )
}
2017-12-14 19:02:31 +01:00
result = self . api_patch ( email , " /api/v1/users/me/subscriptions " , request )
2017-04-26 01:28:22 +02:00
self . assert_json_error ( result ,
" Stream name ' %s ' contains NULL (0x00) characters. " % ( stream_name ) )
2017-11-05 10:51:25 +01:00
def test_compose_views_rollback ( self ) - > None :
2016-09-12 17:21:49 +02:00
'''
The compose_views function ( ) is used under the hood by
update_subscriptions_backend . It ' s a pretty simple method in terms of
control flow , but it uses a Django rollback , which may make it brittle
code when we upgrade Django . We test the functions ' s rollback logic
here with a simple scenario to avoid false positives related to
subscription complications .
'''
2017-05-07 17:21:26 +02:00
user_profile = self . example_user ( ' hamlet ' )
2016-09-12 17:21:49 +02:00
user_profile . full_name = ' Hamlet '
user_profile . save ( )
2017-11-05 10:51:25 +01:00
def method1 ( req : HttpRequest , user_profile : UserProfile ) - > HttpResponse :
2016-09-12 17:21:49 +02:00
user_profile . full_name = ' Should not be committed '
user_profile . save ( )
2016-10-21 07:34:04 +02:00
return json_success ( )
2016-09-12 17:21:49 +02:00
2017-11-05 10:51:25 +01:00
def method2 ( req : HttpRequest , user_profile : UserProfile ) - > HttpResponse :
2017-03-09 09:03:21 +01:00
return json_error ( ' random failure ' )
2016-09-12 17:21:49 +02:00
with self . assertRaises ( JsonableError ) :
compose_views ( None , user_profile , [ ( method1 , { } ) , ( method2 , { } ) ] )
2017-05-07 17:21:26 +02:00
user_profile = self . example_user ( ' hamlet ' )
2016-09-12 17:21:49 +02:00
self . assertEqual ( user_profile . full_name , ' Hamlet ' )
2016-08-23 02:08:42 +02:00
class SubscriptionAPITest ( ZulipTestCase ) :
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def setUp ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
All tests will be logged in as hamlet . Also save various useful values
as attributes that tests can access .
"""
2017-05-07 21:25:59 +02:00
self . user_profile = self . example_user ( ' hamlet ' )
self . test_email = self . user_profile . email
2017-10-07 16:00:39 +02:00
self . test_user = self . user_profile
2014-01-29 22:03:40 +01:00
self . login ( self . test_email )
2017-07-12 12:32:14 +02:00
self . test_realm = self . user_profile . realm
2017-07-12 13:07:48 +02:00
self . streams = self . get_streams ( self . test_email , self . test_realm )
2014-01-29 22:03:40 +01:00
2018-05-11 01:39:38 +02:00
def make_random_stream_names ( self , existing_stream_names : List [ str ] ) - > List [ str ] :
2014-01-29 22:03:40 +01:00
"""
Helper function to make up random stream names . It takes
existing_stream_names and randomly appends a digit to the end of each ,
but avoids names that appear in the list names_to_avoid .
"""
random_streams = [ ]
2017-07-12 12:32:14 +02:00
all_stream_names = [ stream . name for stream in Stream . objects . filter ( realm = self . test_realm ) ]
2014-01-29 22:03:40 +01:00
for stream in existing_stream_names :
random_stream = stream + str ( random . randint ( 0 , 9 ) )
2016-05-10 01:55:43 +02:00
if random_stream not in all_stream_names :
2014-01-29 22:03:40 +01:00
random_streams . append ( random_stream )
return random_streams
2017-11-05 10:51:25 +01:00
def test_successful_subscriptions_list ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
Calling / api / v1 / users / me / subscriptions should successfully return your subscriptions .
"""
email = self . test_email
2017-12-14 19:02:31 +01:00
result = self . api_get ( email , " /api/v1/users/me/subscriptions " )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2017-08-17 08:45:20 +02:00
json = result . json ( )
2014-01-29 22:03:40 +01:00
self . assertIn ( " subscriptions " , json )
for stream in json [ ' subscriptions ' ] :
2017-09-27 10:11:59 +02:00
self . assertIsInstance ( stream [ ' name ' ] , str )
self . assertIsInstance ( stream [ ' color ' ] , str )
2014-01-29 22:03:40 +01:00
self . assertIsInstance ( stream [ ' invite_only ' ] , bool )
2017-03-23 07:22:28 +01:00
# check that the stream name corresponds to an actual
# stream; will throw Stream.DoesNotExist if it doesn't
2017-07-12 12:32:14 +02:00
get_stream ( stream [ ' name ' ] , self . test_realm )
2014-01-29 22:03:40 +01:00
list_streams = [ stream [ ' name ' ] for stream in json [ " subscriptions " ] ]
# also check that this matches the list of your subscriptions
2016-07-10 20:43:58 +02:00
self . assertEqual ( sorted ( list_streams ) , sorted ( self . streams ) )
2014-01-29 22:03:40 +01:00
2018-05-11 01:39:38 +02:00
def helper_check_subs_before_and_after_add ( self , subscriptions : List [ str ] ,
2017-11-20 03:22:57 +01:00
other_params : Dict [ str , Any ] ,
2018-05-11 01:39:38 +02:00
subscribed : List [ str ] ,
already_subscribed : List [ str ] ,
email : str , new_subs : List [ str ] ,
2017-11-20 03:22:57 +01:00
realm : Realm ,
invite_only : bool = False ) - > None :
2014-01-29 22:03:40 +01:00
"""
Check result of adding subscriptions .
You can add subscriptions for yourself or possibly many
principals , which is why e - mails map to subscriptions in the
result .
The result json is of the form
{ " msg " : " " ,
" result " : " success " ,
2017-05-25 01:44:04 +02:00
" already_subscribed " : { self . example_email ( " iago " ) : [ " Venice " , " Verona " ] } ,
" subscribed " : { self . example_email ( " iago " ) : [ " Venice8 " ] } }
2014-01-29 22:03:40 +01:00
"""
result = self . common_subscribe_to_streams ( self . test_email , subscriptions ,
other_params , invite_only = invite_only )
self . assert_json_success ( result )
2017-08-17 08:45:20 +02:00
json = result . json ( )
2016-07-10 20:43:58 +02:00
self . assertEqual ( sorted ( subscribed ) , sorted ( json [ " subscribed " ] [ email ] ) )
self . assertEqual ( sorted ( already_subscribed ) , sorted ( json [ " already_subscribed " ] [ email ] ) )
2017-07-12 13:07:48 +02:00
new_streams = self . get_streams ( email , realm )
2016-07-10 20:43:58 +02:00
self . assertEqual ( sorted ( new_streams ) , sorted ( new_subs ) )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_successful_subscriptions_add ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
2016-04-13 02:05:48 +02:00
Calling POST / json / users / me / subscriptions should successfully add
streams , and should determine which are new subscriptions vs
which were already subscribed . We add 2 new streams to the
list of subscriptions and confirm the right number of events
are generated .
2014-01-29 22:03:40 +01:00
"""
self . assertNotEqual ( len ( self . streams ) , 0 ) # necessary for full test coverage
2016-06-04 19:50:38 +02:00
add_streams = [ u " Verona2 " , u " Denmark5 " ]
2014-01-29 22:03:40 +01:00
self . assertNotEqual ( len ( add_streams ) , 0 ) # necessary for full test coverage
2017-08-04 02:25:38 +02:00
events = [ ] # type: List[Mapping[str, Any]]
2014-01-29 22:03:40 +01:00
with tornado_redirected_to_list ( events ) :
self . helper_check_subs_before_and_after_add ( self . streams + add_streams , { } ,
2017-07-12 13:07:48 +02:00
add_streams , self . streams , self . test_email ,
self . streams + add_streams , self . test_realm )
2017-04-27 00:03:21 +02:00
self . assert_length ( events , 8 )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_successful_subscriptions_add_with_announce ( self ) - > None :
2016-06-24 20:10:27 +02:00
"""
Calling POST / json / users / me / subscriptions should successfully add
streams , and should determine which are new subscriptions vs
which were already subscribed . We add 2 new streams to the
list of subscriptions and confirm the right number of events
are generated .
"""
self . assertNotEqual ( len ( self . streams ) , 0 )
add_streams = [ u " Verona2 " , u " Denmark5 " ]
self . assertNotEqual ( len ( add_streams ) , 0 )
2017-08-04 02:25:38 +02:00
events = [ ] # type: List[Mapping[str, Any]]
2016-06-24 20:10:27 +02:00
other_params = {
' announce ' : ' true ' ,
}
2017-07-12 22:17:24 +02:00
notifications_stream = get_stream ( self . streams [ 0 ] , self . test_realm )
2017-09-17 19:53:38 +02:00
self . test_realm . notifications_stream_id = notifications_stream . id
2017-07-12 22:17:24 +02:00
self . test_realm . save ( )
2016-06-24 20:10:27 +02:00
# Delete the UserProfile from the cache so the realm change will be
# picked up
cache . cache_delete ( cache . user_profile_by_email_cache_key ( self . test_email ) )
with tornado_redirected_to_list ( events ) :
self . helper_check_subs_before_and_after_add ( self . streams + add_streams , other_params ,
2017-07-12 13:07:48 +02:00
add_streams , self . streams , self . test_email ,
self . streams + add_streams , self . test_realm )
2017-04-27 00:03:21 +02:00
self . assertEqual ( len ( events ) , 9 )
2016-06-24 20:10:27 +02:00
2017-11-05 10:51:25 +01:00
def test_successful_subscriptions_notifies_pm ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
2015-11-30 21:39:40 +01:00
Calling POST / json / users / me / subscriptions should notify when a new stream is created .
2014-01-29 22:03:40 +01:00
"""
2017-05-25 01:44:04 +02:00
invitee = self . example_email ( " iago " )
2014-01-29 22:03:40 +01:00
2017-07-12 13:07:48 +02:00
current_stream = self . get_streams ( invitee , self . test_realm ) [ 0 ]
2016-06-04 19:50:38 +02:00
invite_streams = self . make_random_stream_names ( [ current_stream ] ) [ : 1 ]
2014-01-29 22:03:40 +01:00
result = self . common_subscribe_to_streams (
invitee ,
invite_streams ,
extra_post_data = {
' announce ' : ' true ' ,
' principals ' : ' [ " %s " ] ' % ( self . user_profile . email , )
} ,
)
self . assert_json_success ( result )
2017-11-05 10:51:25 +01:00
def test_successful_subscriptions_notifies_stream ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
2015-11-30 21:39:40 +01:00
Calling POST / json / users / me / subscriptions should notify when a new stream is created .
2014-01-29 22:03:40 +01:00
"""
2017-05-25 01:44:04 +02:00
invitee = self . example_email ( " iago " )
2014-01-29 22:03:40 +01:00
invitee_full_name = ' Iago '
2019-01-08 18:24:22 +01:00
invitee_user = self . example_user ( ' iago ' )
2014-01-29 22:03:40 +01:00
2017-07-12 13:07:48 +02:00
current_stream = self . get_streams ( invitee , self . test_realm ) [ 0 ]
2016-06-04 19:50:38 +02:00
invite_streams = self . make_random_stream_names ( [ current_stream ] ) [ : 1 ]
2014-01-29 22:03:40 +01:00
2017-07-12 12:32:14 +02:00
notifications_stream = get_stream ( current_stream , self . test_realm )
2017-09-17 19:53:38 +02:00
self . test_realm . notifications_stream_id = notifications_stream . id
2017-07-12 12:32:14 +02:00
self . test_realm . save ( )
2014-01-29 22:03:40 +01:00
# Delete the UserProfile from the cache so the realm change will be
# picked up
cache . cache_delete ( cache . user_profile_by_email_cache_key ( invitee ) )
result = self . common_subscribe_to_streams (
invitee ,
invite_streams ,
extra_post_data = dict (
announce = ' true ' ,
principals = ' [ " %s " ] ' % ( self . user_profile . email , )
) ,
)
self . assert_json_success ( result )
2017-04-27 00:03:21 +02:00
msg = self . get_second_to_last_message ( )
2014-01-29 22:03:40 +01:00
self . assertEqual ( msg . recipient . type , Recipient . STREAM )
2017-05-08 17:42:50 +02:00
self . assertEqual ( msg . sender_id , self . notification_bot ( ) . id )
2019-02-20 10:15:33 +01:00
expected_msg = " @_** %s | %d ** just created a new stream #** %s **. " % ( invitee_full_name , invitee_user . id , invite_streams [ 0 ] )
2014-01-29 22:03:40 +01:00
self . assertEqual ( msg . content , expected_msg )
2017-11-05 10:51:25 +01:00
def test_successful_cross_realm_notification ( self ) - > None :
2017-01-18 23:19:18 +01:00
"""
Calling POST / json / users / me / subscriptions in a new realm
should notify with a proper new stream link
"""
2017-08-24 04:52:34 +02:00
realm = do_create_realm ( " testrealm " , " Test Realm " )
2017-01-18 23:19:18 +01:00
notifications_stream = Stream . objects . get ( name = ' announce ' , realm = realm )
realm . notifications_stream = notifications_stream
realm . save ( )
invite_streams = [ " cross_stream " ]
2017-05-07 17:21:26 +02:00
user = self . example_user ( ' AARON ' )
2017-01-18 23:19:18 +01:00
user . realm = realm
user . save ( )
# Delete the UserProfile from the cache so the realm change will be
# picked up
cache . cache_delete ( cache . user_profile_by_email_cache_key ( user . email ) )
result = self . common_subscribe_to_streams (
user . email ,
invite_streams ,
extra_post_data = dict (
announce = ' true '
) ,
2017-08-26 00:58:13 +02:00
subdomain = " testrealm " ,
2017-01-18 23:19:18 +01:00
)
self . assert_json_success ( result )
2017-04-27 00:03:21 +02:00
msg = self . get_second_to_last_message ( )
2017-01-18 23:19:18 +01:00
self . assertEqual ( msg . recipient . type , Recipient . STREAM )
2017-05-08 17:42:50 +02:00
self . assertEqual ( msg . sender_id , self . notification_bot ( ) . id )
2017-01-18 23:19:18 +01:00
stream_id = Stream . objects . latest ( ' id ' ) . id
2019-02-15 20:58:54 +01:00
expected_rendered_msg = ' <p><span class= " user-mention silent " data-user-id= " %d " > %s </span> just created a new stream <a class= " stream " data-stream-id= " %d " href= " /#narrow/stream/ %s - %s " ># %s </a>.</p> ' % (
2019-01-08 18:24:22 +01:00
user . id , user . full_name , stream_id , stream_id , invite_streams [ 0 ] , invite_streams [ 0 ] )
2017-01-18 23:19:18 +01:00
self . assertEqual ( msg . rendered_content , expected_rendered_msg )
2017-11-05 10:51:25 +01:00
def test_successful_subscriptions_notifies_with_escaping ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
2015-11-30 21:39:40 +01:00
Calling POST / json / users / me / subscriptions should notify when a new stream is created .
2014-01-29 22:03:40 +01:00
"""
2017-05-25 01:44:04 +02:00
invitee = self . example_email ( " iago " )
2014-01-29 22:03:40 +01:00
invitee_full_name = ' Iago '
2019-01-08 18:24:22 +01:00
invitee_user = self . example_user ( ' iago ' )
2014-01-29 22:03:40 +01:00
2017-07-12 13:07:48 +02:00
current_stream = self . get_streams ( invitee , self . test_realm ) [ 0 ]
2017-07-12 12:32:14 +02:00
notifications_stream = get_stream ( current_stream , self . test_realm )
2017-09-17 19:53:38 +02:00
self . test_realm . notifications_stream_id = notifications_stream . id
2017-07-12 12:32:14 +02:00
self . test_realm . save ( )
2016-01-24 03:39:44 +01:00
2014-01-29 22:03:40 +01:00
invite_streams = [ ' strange ) \\ test ' ]
result = self . common_subscribe_to_streams (
invitee ,
invite_streams ,
extra_post_data = {
' announce ' : ' true ' ,
' principals ' : ' [ " %s " ] ' % ( self . user_profile . email , )
} ,
)
self . assert_json_success ( result )
2017-04-27 00:03:21 +02:00
msg = self . get_second_to_last_message ( )
2017-05-08 17:42:50 +02:00
self . assertEqual ( msg . sender_id , self . notification_bot ( ) . id )
2019-02-20 10:15:33 +01:00
expected_msg = " @_** %s | %d ** just created a new stream #** %s **. " % ( invitee_full_name , invitee_user . id , invite_streams [ 0 ] )
2014-01-29 22:03:40 +01:00
self . assertEqual ( msg . content , expected_msg )
2017-11-05 10:51:25 +01:00
def test_non_ascii_stream_subscription ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
Subscribing to a stream name with non - ASCII characters succeeds .
"""
self . helper_check_subs_before_and_after_add ( self . streams + [ u " hümbüǵ " ] , { } ,
2017-07-12 13:07:48 +02:00
[ u " hümbüǵ " ] , self . streams , self . test_email ,
self . streams + [ u " hümbüǵ " ] , self . test_realm )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_subscriptions_add_too_long ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
2015-11-30 21:39:40 +01:00
Calling POST / json / users / me / subscriptions on a stream whose name is > 60
2014-01-29 22:03:40 +01:00
characters should return a JSON error .
"""
# character limit is 60 characters
long_stream_name = " a " * 61
result = self . common_subscribe_to_streams ( self . test_email , [ long_stream_name ] )
self . assert_json_error ( result ,
2018-01-08 19:54:19 +01:00
" Stream name too long (limit: 60 characters). " )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_subscriptions_add_stream_with_null ( self ) - > None :
2017-04-26 01:28:22 +02:00
"""
Calling POST / json / users / me / subscriptions on a stream whose name contains
null characters should return a JSON error .
"""
stream_name = " abc \000 "
result = self . common_subscribe_to_streams ( self . test_email , [ stream_name ] )
self . assert_json_error ( result ,
" Stream name ' %s ' contains NULL (0x00) characters. " % ( stream_name ) )
2017-11-05 10:51:25 +01:00
def test_user_settings_for_adding_streams ( self ) - > None :
2016-07-27 22:09:33 +02:00
with mock . patch ( ' zerver.models.UserProfile.can_create_streams ' , return_value = False ) :
2014-01-29 22:03:40 +01:00
result = self . common_subscribe_to_streams ( self . test_email , [ ' stream1 ' ] )
2016-05-19 03:46:33 +02:00
self . assert_json_error ( result , ' User cannot create streams. ' )
2016-07-27 22:09:33 +02:00
with mock . patch ( ' zerver.models.UserProfile.can_create_streams ' , return_value = True ) :
2016-05-19 03:46:33 +02:00
result = self . common_subscribe_to_streams ( self . test_email , [ ' stream2 ' ] )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2016-05-19 03:46:33 +02:00
# User should still be able to subscribe to an existing stream
2016-07-27 22:09:33 +02:00
with mock . patch ( ' zerver.models.UserProfile.can_create_streams ' , return_value = False ) :
2016-05-19 03:46:33 +02:00
result = self . common_subscribe_to_streams ( self . test_email , [ ' stream2 ' ] )
self . assert_json_success ( result )
2014-01-29 22:03:40 +01:00
2018-07-30 00:59:45 +02:00
def test_can_create_streams ( self ) - > None :
othello = self . example_user ( ' othello ' )
othello . is_realm_admin = True
self . assertTrue ( othello . can_create_streams ( ) )
othello . is_realm_admin = False
othello . realm . create_stream_by_admins_only = True
self . assertFalse ( othello . can_create_streams ( ) )
othello . realm . create_stream_by_admins_only = False
othello . is_guest = True
self . assertFalse ( othello . can_create_streams ( ) )
othello . is_guest = False
othello . realm . waiting_period_threshold = 1000
othello . date_joined = timezone_now ( ) - timedelta ( days = ( othello . realm . waiting_period_threshold - 1 ) )
self . assertFalse ( othello . can_create_streams ( ) )
othello . date_joined = timezone_now ( ) - timedelta ( days = ( othello . realm . waiting_period_threshold + 1 ) )
self . assertTrue ( othello . can_create_streams ( ) )
2018-07-30 01:25:13 +02:00
def test_user_settings_for_subscribing_other_users ( self ) - > None :
"""
You can ' t subscribe other people to streams if you are a guest or your waiting period is not over.
"""
invitee_email = self . example_email ( " cordelia " )
with mock . patch ( ' zerver.models.UserProfile.can_subscribe_other_users ' , return_value = False ) :
result = self . common_subscribe_to_streams ( self . test_email , [ ' stream1 ' ] , { " principals " : ujson . dumps ( [ invitee_email ] ) } )
self . assert_json_error ( result , " Your account is too new to modify other users ' subscriptions. " )
with mock . patch ( ' zerver.models.UserProfile.can_subscribe_other_users ' , return_value = True ) :
result = self . common_subscribe_to_streams ( self . test_email , [ ' stream2 ' ] , { " principals " : ujson . dumps ( [ invitee_email ] ) } )
self . assert_json_success ( result )
def test_can_subscribe_other_users ( self ) - > None :
"""
You can ' t subscribe other people to streams if you are a guest or your waiting period is not over.
"""
othello = self . example_user ( ' othello ' )
othello . is_realm_admin = True
self . assertTrue ( othello . can_subscribe_other_users ( ) )
othello . is_realm_admin = False
othello . is_guest = True
self . assertFalse ( othello . can_subscribe_other_users ( ) )
othello . is_guest = False
othello . realm . waiting_period_threshold = 1000
othello . date_joined = timezone_now ( ) - timedelta ( days = ( othello . realm . waiting_period_threshold - 1 ) )
self . assertFalse ( othello . can_subscribe_other_users ( ) )
othello . date_joined = timezone_now ( ) - timedelta ( days = ( othello . realm . waiting_period_threshold + 1 ) )
self . assertTrue ( othello . can_subscribe_other_users ( ) )
2017-11-05 10:51:25 +01:00
def test_subscriptions_add_invalid_stream ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
2015-11-30 21:39:40 +01:00
Calling POST / json / users / me / subscriptions on a stream whose name is invalid ( as
2014-01-29 22:03:40 +01:00
defined by valid_stream_name in zerver / views . py ) should return a JSON
error .
"""
# currently, the only invalid name is the empty string
invalid_stream_name = " "
result = self . common_subscribe_to_streams ( self . test_email , [ invalid_stream_name ] )
self . assert_json_error ( result ,
2017-01-30 07:01:19 +01:00
" Invalid stream name ' %s ' " % ( invalid_stream_name , ) )
2014-01-29 22:03:40 +01:00
2018-05-11 01:39:38 +02:00
def assert_adding_subscriptions_for_principal ( self , invitee_email : str , invitee_realm : Realm ,
streams : List [ str ] , invite_only : bool = False ) - > None :
2014-01-29 22:03:40 +01:00
"""
2015-11-30 21:39:40 +01:00
Calling POST / json / users / me / subscriptions on behalf of another principal ( for
2014-01-29 22:03:40 +01:00
whom you have permission to add subscriptions ) should successfully add
those subscriptions and send a message to the subscribee notifying
them .
"""
2017-05-23 20:57:59 +02:00
other_profile = get_user ( invitee_email , invitee_realm )
2017-07-12 13:07:48 +02:00
current_streams = self . get_streams ( invitee_email , invitee_realm )
2014-01-29 22:03:40 +01:00
self . assertIsInstance ( other_profile , UserProfile )
self . assertNotEqual ( len ( current_streams ) , 0 ) # necessary for full test coverage
self . assertNotEqual ( len ( streams ) , 0 ) # necessary for full test coverage
streams_to_sub = streams [ : 1 ] # just add one, to make the message easier to check
streams_to_sub . extend ( current_streams )
self . helper_check_subs_before_and_after_add ( streams_to_sub ,
2017-05-23 20:57:59 +02:00
{ " principals " : ujson . dumps ( [ invitee_email ] ) } , streams [ : 1 ] ,
current_streams , invitee_email , streams_to_sub ,
2017-07-12 13:07:48 +02:00
invitee_realm , invite_only = invite_only )
2017-04-27 00:03:21 +02:00
# verify that a welcome message was sent to the stream
2016-04-13 23:59:08 +02:00
msg = self . get_last_message ( )
2017-04-27 00:03:21 +02:00
self . assertEqual ( msg . recipient . type , msg . recipient . STREAM )
2018-11-10 16:11:12 +01:00
self . assertEqual ( msg . topic_name ( ) , u ' hello ' )
2017-04-27 00:03:21 +02:00
self . assertEqual ( msg . sender . email , settings . WELCOME_BOT )
self . assertIn ( ' Welcome to #** ' , msg . content )
2017-11-05 10:51:25 +01:00
def test_multi_user_subscription ( self ) - > None :
2017-10-07 16:00:39 +02:00
user1 = self . example_user ( " cordelia " )
user2 = self . example_user ( " iago " )
2017-01-04 05:30:48 +01:00
realm = get_realm ( " zulip " )
2014-01-29 22:03:40 +01:00
streams_to_sub = [ ' multi_user_stream ' ]
2017-08-04 02:25:38 +02:00
events = [ ] # type: List[Mapping[str, Any]]
2017-11-30 08:43:12 +01:00
flush_per_request_caches ( )
2014-01-29 22:03:40 +01:00
with tornado_redirected_to_list ( events ) :
with queries_captured ( ) as queries :
self . common_subscribe_to_streams (
self . test_email ,
streams_to_sub ,
2017-10-07 16:00:39 +02:00
dict ( principals = ujson . dumps ( [ user1 . email , user2 . email ] ) ) ,
2017-01-24 06:34:26 +01:00
)
2019-02-07 02:05:34 +01:00
self . assert_length ( queries , 43 )
2014-01-29 22:03:40 +01:00
2017-05-16 01:32:50 +02:00
self . assert_length ( events , 7 )
2015-11-01 17:14:31 +01:00
for ev in [ x for x in events if x [ ' event ' ] [ ' type ' ] not in ( ' message ' , ' stream ' ) ] :
2016-07-12 23:57:16 +02:00
if isinstance ( ev [ ' event ' ] [ ' subscriptions ' ] [ 0 ] , dict ) :
self . assertEqual ( ev [ ' event ' ] [ ' op ' ] , ' add ' )
self . assertEqual (
2017-01-24 07:06:13 +01:00
set ( ev [ ' event ' ] [ ' subscriptions ' ] [ 0 ] [ ' subscribers ' ] ) ,
2017-10-07 16:00:39 +02:00
set ( [ user1 . id , user2 . id ] )
2016-07-12 23:57:16 +02:00
)
else :
# Check "peer_add" events for streams users were
# never subscribed to, in order for the neversubscribed
# structure to stay up-to-date.
self . assertEqual ( ev [ ' event ' ] [ ' op ' ] , ' peer_add ' )
2014-01-29 22:03:40 +01:00
stream = get_stream ( ' multi_user_stream ' , realm )
2017-10-29 15:40:07 +01:00
self . assertEqual ( num_subscribers_for_stream_id ( stream . id ) , 2 )
2014-01-29 22:03:40 +01:00
# Now add ourselves
events = [ ]
with tornado_redirected_to_list ( events ) :
with queries_captured ( ) as queries :
self . common_subscribe_to_streams (
2017-01-24 07:06:13 +01:00
self . test_email ,
streams_to_sub ,
dict ( principals = ujson . dumps ( [ self . test_email ] ) ) ,
2014-01-29 22:03:40 +01:00
)
2017-04-03 17:13:42 +02:00
self . assert_length ( queries , 16 )
2014-01-29 22:03:40 +01:00
2016-09-25 21:30:10 +02:00
self . assert_length ( events , 2 )
2014-01-29 22:03:40 +01:00
add_event , add_peer_event = events
2014-02-06 21:21:21 +01:00
self . assertEqual ( add_event [ ' event ' ] [ ' type ' ] , ' subscription ' )
2014-01-29 22:03:40 +01:00
self . assertEqual ( add_event [ ' event ' ] [ ' op ' ] , ' add ' )
2017-05-23 20:57:59 +02:00
self . assertEqual ( add_event [ ' users ' ] , [ get_user ( self . test_email , self . test_realm ) . id ] )
2014-01-29 22:03:40 +01:00
self . assertEqual (
2017-01-24 07:06:13 +01:00
set ( add_event [ ' event ' ] [ ' subscriptions ' ] [ 0 ] [ ' subscribers ' ] ) ,
2017-10-07 16:00:39 +02:00
set ( [ user1 . id , user2 . id , self . test_user . id ] )
2014-01-29 22:03:40 +01:00
)
2018-06-03 19:11:52 +02:00
self . assertNotIn ( self . example_user ( ' polonius ' ) . id , add_peer_event [ ' users ' ] )
2018-09-24 11:47:47 +02:00
self . assertEqual ( len ( add_peer_event [ ' users ' ] ) , 17 )
2014-02-06 21:21:21 +01:00
self . assertEqual ( add_peer_event [ ' event ' ] [ ' type ' ] , ' subscription ' )
2014-01-29 22:03:40 +01:00
self . assertEqual ( add_peer_event [ ' event ' ] [ ' op ' ] , ' peer_add ' )
2016-10-31 20:18:32 +01:00
self . assertEqual ( add_peer_event [ ' event ' ] [ ' user_id ' ] , self . user_profile . id )
2014-01-29 22:03:40 +01:00
stream = get_stream ( ' multi_user_stream ' , realm )
2017-10-29 15:40:07 +01:00
self . assertEqual ( num_subscribers_for_stream_id ( stream . id ) , 3 )
2014-01-29 22:03:40 +01:00
2016-10-20 00:50:09 +02:00
# Finally, add othello.
2014-01-29 22:03:40 +01:00
events = [ ]
2017-05-07 21:25:59 +02:00
user_profile = self . example_user ( ' othello ' )
email3 = user_profile . email
2017-10-07 16:00:39 +02:00
user3 = user_profile
2017-05-23 20:57:59 +02:00
realm3 = user_profile . realm
2014-01-29 22:03:40 +01:00
stream = get_stream ( ' multi_user_stream ' , realm )
with tornado_redirected_to_list ( events ) :
2016-10-20 00:50:09 +02:00
bulk_add_subscriptions ( [ stream ] , [ user_profile ] )
2014-01-29 22:03:40 +01:00
2016-09-25 21:30:10 +02:00
self . assert_length ( events , 2 )
2014-01-29 22:03:40 +01:00
add_event , add_peer_event = events
2014-02-06 21:21:21 +01:00
self . assertEqual ( add_event [ ' event ' ] [ ' type ' ] , ' subscription ' )
2014-01-29 22:03:40 +01:00
self . assertEqual ( add_event [ ' event ' ] [ ' op ' ] , ' add ' )
2017-05-23 20:57:59 +02:00
self . assertEqual ( add_event [ ' users ' ] , [ get_user ( email3 , realm3 ) . id ] )
2014-01-29 22:03:40 +01:00
self . assertEqual (
2017-01-24 07:06:13 +01:00
set ( add_event [ ' event ' ] [ ' subscriptions ' ] [ 0 ] [ ' subscribers ' ] ) ,
2017-10-07 16:00:39 +02:00
set ( [ user1 . id , user2 . id , user3 . id , self . test_user . id ] )
2014-01-29 22:03:40 +01:00
)
2016-10-20 00:50:09 +02:00
# We don't send a peer_add event to othello
self . assertNotIn ( user_profile . id , add_peer_event [ ' users ' ] )
2018-06-03 19:11:52 +02:00
self . assertNotIn ( self . example_user ( ' polonius ' ) . id , add_peer_event [ ' users ' ] )
2018-09-24 11:47:47 +02:00
self . assertEqual ( len ( add_peer_event [ ' users ' ] ) , 17 )
2014-02-06 21:21:21 +01:00
self . assertEqual ( add_peer_event [ ' event ' ] [ ' type ' ] , ' subscription ' )
2014-01-29 22:03:40 +01:00
self . assertEqual ( add_peer_event [ ' event ' ] [ ' op ' ] , ' peer_add ' )
2016-10-31 20:18:32 +01:00
self . assertEqual ( add_peer_event [ ' event ' ] [ ' user_id ' ] , user_profile . id )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_private_stream_subscription ( self ) - > None :
2017-01-29 01:21:31 +01:00
realm = get_realm ( " zulip " )
# Create a private stream with Hamlet subscribed
stream_name = " private "
2018-03-21 22:05:21 +01:00
stream = ensure_stream ( realm , stream_name , invite_only = True )
2017-01-29 01:21:31 +01:00
2017-05-07 21:25:59 +02:00
existing_user_profile = self . example_user ( ' hamlet ' )
2017-01-29 01:21:31 +01:00
bulk_add_subscriptions ( [ stream ] , [ existing_user_profile ] )
# Now subscribe Cordelia to the stream, capturing events
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' cordelia ' )
2017-01-29 01:21:31 +01:00
2017-08-04 02:25:38 +02:00
events = [ ] # type: List[Mapping[str, Any]]
2017-01-29 01:21:31 +01:00
with tornado_redirected_to_list ( events ) :
bulk_add_subscriptions ( [ stream ] , [ user_profile ] )
self . assert_length ( events , 3 )
create_event , add_event , add_peer_event = events
self . assertEqual ( create_event [ ' event ' ] [ ' type ' ] , ' stream ' )
self . assertEqual ( create_event [ ' event ' ] [ ' op ' ] , ' create ' )
2018-03-16 10:57:17 +01:00
self . assertEqual ( create_event [ ' users ' ] , [ user_profile . id ] )
2017-01-29 01:21:31 +01:00
self . assertEqual ( create_event [ ' event ' ] [ ' streams ' ] [ 0 ] [ ' name ' ] , stream_name )
self . assertEqual ( add_event [ ' event ' ] [ ' type ' ] , ' subscription ' )
self . assertEqual ( add_event [ ' event ' ] [ ' op ' ] , ' add ' )
self . assertEqual ( add_event [ ' users ' ] , [ user_profile . id ] )
self . assertEqual (
set ( add_event [ ' event ' ] [ ' subscriptions ' ] [ 0 ] [ ' subscribers ' ] ) ,
2017-10-07 16:00:39 +02:00
set ( [ user_profile . id , existing_user_profile . id ] )
2017-01-29 01:21:31 +01:00
)
2018-02-14 17:59:01 +01:00
# We don't send a peer_add event to othello, but we do send peer_add event to
# all realm admins.
2017-01-29 01:21:31 +01:00
self . assertNotIn ( user_profile . id , add_peer_event [ ' users ' ] )
2018-02-14 17:59:01 +01:00
self . assertEqual ( len ( add_peer_event [ ' users ' ] ) , 2 )
2017-01-29 01:21:31 +01:00
self . assertEqual ( add_peer_event [ ' event ' ] [ ' type ' ] , ' subscription ' )
self . assertEqual ( add_peer_event [ ' event ' ] [ ' op ' ] , ' peer_add ' )
self . assertEqual ( add_peer_event [ ' event ' ] [ ' user_id ' ] , user_profile . id )
2018-03-16 10:57:17 +01:00
# Do not send stream creation event to realm admin users
# even if realm admin is subscribed to stream cause realm admin already get
# private stream creation event on stream creation.
2018-03-21 22:05:21 +01:00
new_stream = ensure_stream ( realm , " private stream " , invite_only = True )
2018-03-16 10:57:17 +01:00
events = [ ]
with tornado_redirected_to_list ( events ) :
bulk_add_subscriptions ( [ new_stream ] , [ self . example_user ( " iago " ) ] )
self . assert_length ( events , 2 )
create_event , add_event = events
self . assertEqual ( create_event [ ' event ' ] [ ' type ' ] , ' stream ' )
self . assertEqual ( create_event [ ' event ' ] [ ' op ' ] , ' create ' )
self . assertEqual ( create_event [ ' users ' ] , [ ] )
self . assertEqual ( add_event [ ' event ' ] [ ' type ' ] , ' subscription ' )
self . assertEqual ( add_event [ ' event ' ] [ ' op ' ] , ' add ' )
self . assertEqual ( add_event [ ' users ' ] , [ self . example_user ( " iago " ) . id ] )
2019-01-24 09:16:35 +01:00
def test_subscibe_to_announce_only_stream ( self ) - > None :
"""
Members can subscribe to streams where only admins can post
but not create those streams , only realm admins can
"""
member = self . example_user ( " AARON " )
result = self . common_subscribe_to_streams ( member . email , [ " announce " ] )
self . assert_json_success ( result )
streams_raw = [ {
' name ' : ' new_stream ' ,
' is_announcement_only ' : True ,
} ]
with self . assertRaisesRegex (
JsonableError , " User cannot create a stream with these settings. " ) :
list_to_streams ( streams_raw , member , autocreate = True )
admin = self . example_user ( " iago " )
result = list_to_streams ( streams_raw , admin , autocreate = True )
self . assert_length ( result [ 0 ] , 0 )
self . assert_length ( result [ 1 ] , 1 )
self . assertEqual ( result [ 1 ] [ 0 ] . name , ' new_stream ' )
self . assertEqual ( result [ 1 ] [ 0 ] . is_announcement_only , True )
2018-05-04 19:14:29 +02:00
def test_guest_user_subscribe ( self ) - > None :
2018-05-02 17:00:06 +02:00
""" Guest users cannot subscribe themselves to anything """
guest_user = self . example_user ( " polonius " )
guest_email = guest_user . email
result = self . common_subscribe_to_streams ( guest_email , [ " Denmark " ] )
2018-05-04 19:14:29 +02:00
self . assert_json_error ( result , " Not allowed for guest users " )
2018-05-02 17:00:06 +02:00
2018-05-04 19:14:29 +02:00
# Verify the internal checks also block guest users.
stream = get_stream ( " Denmark " , guest_user . realm )
self . assertEqual ( filter_stream_authorization ( guest_user , [ stream ] ) ,
( [ ] , [ stream ] ) )
2018-06-12 17:34:59 +02:00
# Test UserProfile.can_create_streams for guest users.
streams_raw = [ {
' invite_only ' : False ,
' history_public_to_subscribers ' : None ,
' name ' : ' new_stream ' ,
' is_announcement_only ' : False
} ]
with self . assertRaisesRegex ( JsonableError , " User cannot create streams. " ) :
list_to_streams ( streams_raw , guest_user )
2018-05-04 19:14:29 +02:00
stream = self . make_stream ( ' private_stream ' , invite_only = True )
2018-05-02 17:00:06 +02:00
result = self . common_subscribe_to_streams ( guest_email , [ " private_stream " ] )
2018-05-04 19:14:29 +02:00
self . assert_json_error ( result , " Not allowed for guest users " )
self . assertEqual ( filter_stream_authorization ( guest_user , [ stream ] ) ,
( [ ] , [ stream ] ) )
2018-05-02 17:00:06 +02:00
2017-11-05 10:51:25 +01:00
def test_users_getting_add_peer_event ( self ) - > None :
2016-07-22 23:30:47 +02:00
"""
Check users getting add_peer_event is correct
"""
streams_to_sub = [ ' multi_user_stream ' ]
2017-06-10 14:17:51 +02:00
orig_emails_to_subscribe = [ self . test_email , self . example_email ( " othello " ) ]
2016-07-22 23:30:47 +02:00
self . common_subscribe_to_streams (
self . test_email ,
streams_to_sub ,
2017-06-10 14:17:51 +02:00
dict ( principals = ujson . dumps ( orig_emails_to_subscribe ) ) )
2016-07-22 23:30:47 +02:00
2017-06-10 14:17:51 +02:00
new_emails_to_subscribe = [ self . example_email ( " iago " ) , self . example_email ( " cordelia " ) ]
2017-08-04 02:25:38 +02:00
events = [ ] # type: List[Mapping[str, Any]]
2016-07-22 23:30:47 +02:00
with tornado_redirected_to_list ( events ) :
self . common_subscribe_to_streams (
2017-01-24 07:06:13 +01:00
self . test_email ,
streams_to_sub ,
2017-06-10 14:17:51 +02:00
dict ( principals = ujson . dumps ( new_emails_to_subscribe ) ) ,
2016-07-22 23:30:47 +02:00
)
add_peer_events = [ events [ 2 ] , events [ 3 ] ]
for add_peer_event in add_peer_events :
self . assertEqual ( add_peer_event [ ' event ' ] [ ' type ' ] , ' subscription ' )
self . assertEqual ( add_peer_event [ ' event ' ] [ ' op ' ] , ' peer_add ' )
event_sent_to_ids = add_peer_event [ ' users ' ]
2017-06-10 14:17:51 +02:00
sent_emails = [
get_user_profile_by_id ( user_id ) . email
for user_id in event_sent_to_ids ]
for email in new_emails_to_subscribe :
2016-07-22 23:30:47 +02:00
# Make sure new users subscribed to stream is not in
# peer_add event recipient list
2017-06-10 14:17:51 +02:00
self . assertNotIn ( email , sent_emails )
for old_user in orig_emails_to_subscribe :
2016-07-22 23:30:47 +02:00
# Check non new users are in peer_add event recipient list.
2017-06-10 14:17:51 +02:00
self . assertIn ( old_user , sent_emails )
2016-07-22 23:30:47 +02:00
2017-11-05 10:51:25 +01:00
def test_users_getting_remove_peer_event ( self ) - > None :
2016-10-20 20:12:39 +02:00
"""
Check users getting add_peer_event is correct
"""
2017-08-25 06:01:29 +02:00
user1 = self . example_user ( " othello " )
user2 = self . example_user ( " cordelia " )
user3 = self . example_user ( " hamlet " )
user4 = self . example_user ( " iago " )
2018-02-14 17:59:01 +01:00
user5 = self . example_user ( " AARON " )
2016-10-20 20:12:39 +02:00
2016-10-21 23:22:25 +02:00
stream1 = self . make_stream ( ' stream1 ' )
stream2 = self . make_stream ( ' stream2 ' )
private = self . make_stream ( ' private_stream ' , invite_only = True )
2016-10-20 20:12:39 +02:00
2017-08-25 06:01:29 +02:00
self . subscribe ( user1 , ' stream1 ' )
self . subscribe ( user2 , ' stream1 ' )
self . subscribe ( user3 , ' stream1 ' )
2016-10-20 20:12:39 +02:00
2017-08-25 06:01:29 +02:00
self . subscribe ( user2 , ' stream2 ' )
2016-10-20 20:12:39 +02:00
2017-08-25 06:01:29 +02:00
self . subscribe ( user1 , ' private_stream ' )
self . subscribe ( user2 , ' private_stream ' )
self . subscribe ( user3 , ' private_stream ' )
2016-10-20 20:12:39 +02:00
2017-08-04 02:25:38 +02:00
events = [ ] # type: List[Mapping[str, Any]]
2016-10-20 20:12:39 +02:00
with tornado_redirected_to_list ( events ) :
bulk_remove_subscriptions (
2018-03-14 00:13:21 +01:00
[ user1 , user2 ] ,
[ stream1 , stream2 , private ] ,
get_client ( " website " )
2016-10-20 20:12:39 +02:00
)
peer_events = [ e for e in events
2016-12-03 00:04:17 +01:00
if e [ ' event ' ] . get ( ' op ' ) == ' peer_remove ' ]
2016-10-20 20:12:39 +02:00
notifications = set ( )
for event in peer_events :
for user_id in event [ ' users ' ] :
for stream_name in event [ ' event ' ] [ ' subscriptions ' ] :
2016-11-08 15:04:18 +01:00
removed_user_id = event [ ' event ' ] [ ' user_id ' ]
notifications . add ( ( user_id , removed_user_id , stream_name ) )
2016-10-20 20:12:39 +02:00
# POSITIVE CASES FIRST
2016-11-08 15:04:18 +01:00
self . assertIn ( ( user3 . id , user1 . id , ' stream1 ' ) , notifications )
self . assertIn ( ( user4 . id , user1 . id , ' stream1 ' ) , notifications )
2016-10-20 20:12:39 +02:00
2016-11-08 15:04:18 +01:00
self . assertIn ( ( user3 . id , user2 . id , ' stream1 ' ) , notifications )
self . assertIn ( ( user4 . id , user2 . id , ' stream1 ' ) , notifications )
2016-10-20 20:12:39 +02:00
2016-11-08 15:04:18 +01:00
self . assertIn ( ( user1 . id , user2 . id , ' stream2 ' ) , notifications )
self . assertIn ( ( user3 . id , user2 . id , ' stream2 ' ) , notifications )
self . assertIn ( ( user4 . id , user2 . id , ' stream2 ' ) , notifications )
2016-10-20 20:12:39 +02:00
2016-11-08 15:04:18 +01:00
self . assertIn ( ( user3 . id , user1 . id , ' private_stream ' ) , notifications )
self . assertIn ( ( user3 . id , user2 . id , ' private_stream ' ) , notifications )
2016-10-20 20:12:39 +02:00
2018-02-14 17:59:01 +01:00
self . assertIn ( ( user4 . id , user1 . id , ' private_stream ' ) , notifications )
self . assertIn ( ( user4 . id , user2 . id , ' private_stream ' ) , notifications )
2016-10-20 20:12:39 +02:00
# NEGATIVE
# don't be notified if you are being removed yourself
2016-11-08 15:04:18 +01:00
self . assertNotIn ( ( user1 . id , user1 . id , ' stream1 ' ) , notifications )
2016-10-20 20:12:39 +02:00
# don't send false notifications for folks that weren't actually
# subscribed int he first place
2016-11-08 15:04:18 +01:00
self . assertNotIn ( ( user3 . id , user1 . id , ' stream2 ' ) , notifications )
2016-10-20 20:12:39 +02:00
# don't send notifications for random people
2016-11-08 15:04:18 +01:00
self . assertNotIn ( ( user3 . id , user4 . id , ' stream2 ' ) , notifications )
2016-10-20 20:12:39 +02:00
2018-02-14 17:59:01 +01:00
# don't send notifications to unsubscribed non realm admin users for private streams
self . assertNotIn ( ( user5 . id , user1 . id , ' private_stream ' ) , notifications )
2016-10-20 20:12:39 +02:00
2017-11-05 10:51:25 +01:00
def test_bulk_subscribe_MIT ( self ) - > None :
2018-08-21 19:20:31 +02:00
mit_user = self . mit_user ( ' starnine ' )
2017-03-04 09:19:37 +01:00
realm = get_realm ( " zephyr " )
2018-08-21 19:20:31 +02:00
stream_names = [ " stream_ %s " % i for i in range ( 40 ) ]
streams = [
2016-10-21 23:22:25 +02:00
self . make_stream ( stream_name , realm = realm )
2018-08-21 19:20:31 +02:00
for stream_name in stream_names ]
for stream in streams :
stream . is_in_zephyr_realm = True
stream . save ( )
2014-01-29 22:03:40 +01:00
2017-08-04 02:25:38 +02:00
events = [ ] # type: List[Mapping[str, Any]]
2014-01-29 22:03:40 +01:00
with tornado_redirected_to_list ( events ) :
with queries_captured ( ) as queries :
self . common_subscribe_to_streams (
2018-08-21 19:20:31 +02:00
mit_user . email ,
stream_names ,
dict ( principals = ujson . dumps ( [ mit_user . email ] ) ) ,
2017-08-26 00:58:13 +02:00
subdomain = " zephyr " ,
2014-01-29 22:03:40 +01:00
)
2016-07-27 01:45:29 +02:00
# Make sure Zephyr mirroring realms such as MIT do not get
# any tornado subscription events
2016-09-25 21:30:10 +02:00
self . assert_length ( events , 0 )
2017-11-26 01:45:15 +01:00
self . assert_length ( queries , 9 )
2014-01-29 22:03:40 +01:00
2018-08-21 19:20:54 +02:00
events = [ ]
with tornado_redirected_to_list ( events ) :
bulk_remove_subscriptions (
users = [ mit_user ] ,
streams = streams ,
acting_client = get_client ( ' website ' ) ,
)
self . assert_length ( events , 0 )
2017-11-05 10:51:25 +01:00
def test_bulk_subscribe_many ( self ) - > None :
2016-06-04 19:50:38 +02:00
2014-01-29 22:03:40 +01:00
# Create a whole bunch of streams
2015-11-01 17:15:05 +01:00
streams = [ " stream_ %s " % i for i in range ( 20 ) ]
2016-10-21 23:22:25 +02:00
for stream_name in streams :
self . make_stream ( stream_name )
2014-01-29 22:03:40 +01:00
with queries_captured ( ) as queries :
2019-01-31 14:32:37 +01:00
self . common_subscribe_to_streams (
self . test_email ,
streams ,
dict ( principals = ujson . dumps ( [ self . test_email ] ) ) ,
)
2014-01-29 22:03:40 +01:00
# Make sure we don't make O(streams) queries
2017-04-03 17:13:42 +02:00
self . assert_length ( queries , 21 )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_subscriptions_add_for_principal ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
You can subscribe other people to streams .
"""
2017-05-23 20:57:59 +02:00
invitee_email = self . example_email ( " iago " )
invitee_realm = get_realm ( ' zulip ' )
2017-07-12 13:07:48 +02:00
current_streams = self . get_streams ( invitee_email , invitee_realm )
2014-01-29 22:03:40 +01:00
invite_streams = self . make_random_stream_names ( current_streams )
2017-05-23 20:57:59 +02:00
self . assert_adding_subscriptions_for_principal ( invitee_email , invitee_realm , invite_streams )
2014-01-29 22:03:40 +01:00
2018-05-21 03:54:42 +02:00
def test_subscriptions_add_for_principal_deactivated ( self ) - > None :
"""
You can ' t subscribe deactivated people to streams.
"""
target_profile = self . example_user ( " cordelia " )
result = self . common_subscribe_to_streams ( self . test_email , " Verona " ,
{ " principals " : ujson . dumps ( [ target_profile . email ] ) } )
self . assert_json_success ( result )
do_deactivate_user ( target_profile )
result = self . common_subscribe_to_streams ( self . test_email , " Denmark " ,
{ " principals " : ujson . dumps ( [ target_profile . email ] ) } )
self . assert_json_error ( result , " User not authorized to execute queries on behalf of ' cordelia@zulip.com ' " ,
status_code = 403 )
2017-11-05 10:51:25 +01:00
def test_subscriptions_add_for_principal_invite_only ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
You can subscribe other people to invite only streams .
"""
2017-05-23 20:57:59 +02:00
invitee_email = self . example_email ( " iago " )
invitee_realm = get_realm ( ' zulip ' )
2017-07-12 13:07:48 +02:00
current_streams = self . get_streams ( invitee_email , invitee_realm )
2014-01-29 22:03:40 +01:00
invite_streams = self . make_random_stream_names ( current_streams )
2017-05-23 20:57:59 +02:00
self . assert_adding_subscriptions_for_principal ( invitee_email , invitee_realm , invite_streams ,
2014-01-29 22:03:40 +01:00
invite_only = True )
2017-11-05 10:51:25 +01:00
def test_non_ascii_subscription_for_principal ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
You can subscribe other people to streams even if they containing
non - ASCII characters .
"""
2017-05-23 20:57:59 +02:00
self . assert_adding_subscriptions_for_principal ( self . example_email ( " iago " ) , get_realm ( ' zulip ' ) , [ u " hümbüǵ " ] )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_subscription_add_invalid_principal ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
Calling subscribe on behalf of a principal that does not exist
should return a JSON error .
"""
invalid_principal = " rosencrantz-and-guildenstern@zulip.com "
2017-05-23 20:57:59 +02:00
invalid_principal_realm = get_realm ( " zulip " )
2014-01-29 22:03:40 +01:00
# verify that invalid_principal actually doesn't exist
with self . assertRaises ( UserProfile . DoesNotExist ) :
2017-05-23 20:57:59 +02:00
get_user ( invalid_principal , invalid_principal_realm )
2014-01-29 22:03:40 +01:00
result = self . common_subscribe_to_streams ( self . test_email , self . streams ,
{ " principals " : ujson . dumps ( [ invalid_principal ] ) } )
self . assert_json_error ( result , " User not authorized to execute queries on behalf of ' %s ' "
2016-04-28 01:23:45 +02:00
% ( invalid_principal , ) , status_code = 403 )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_subscription_add_principal_other_realm ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
Calling subscribe on behalf of a principal in another realm
should return a JSON error .
"""
2017-05-23 02:33:53 +02:00
profile = self . mit_user ( ' starnine ' )
principal = profile . email
2014-01-29 22:03:40 +01:00
# verify that principal exists (thus, the reason for the error is the cross-realming)
self . assertIsInstance ( profile , UserProfile )
result = self . common_subscribe_to_streams ( self . test_email , self . streams ,
{ " principals " : ujson . dumps ( [ principal ] ) } )
self . assert_json_error ( result , " User not authorized to execute queries on behalf of ' %s ' "
2016-04-28 01:23:45 +02:00
% ( principal , ) , status_code = 403 )
2014-01-29 22:03:40 +01:00
2018-05-11 01:39:38 +02:00
def helper_check_subs_before_and_after_remove ( self , subscriptions : List [ str ] ,
2017-11-20 03:22:57 +01:00
json_dict : Dict [ str , Any ] ,
2018-05-11 01:39:38 +02:00
email : str , new_subs : List [ str ] ,
2017-11-20 03:22:57 +01:00
realm : Realm ) - > None :
2014-01-29 22:03:40 +01:00
"""
Check result of removing subscriptions .
Unlike adding subscriptions , you can only remove subscriptions
for yourself , so the result format is different .
{ " msg " : " " ,
" removed " : [ " Denmark " , " Scotland " , " Verona " ] ,
" not_subscribed " : [ " Rome " ] , " result " : " success " }
"""
2016-12-23 02:37:10 +01:00
result = self . client_delete ( " /json/users/me/subscriptions " ,
{ " subscriptions " : ujson . dumps ( subscriptions ) } )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2017-08-17 08:45:20 +02:00
json = result . json ( )
2017-09-27 10:11:59 +02:00
for key , val in json_dict . items ( ) :
2016-07-10 20:43:58 +02:00
self . assertEqual ( sorted ( val ) , sorted ( json [ key ] ) ) # we don't care about the order of the items
2017-07-12 13:07:48 +02:00
new_streams = self . get_streams ( email , realm )
2016-07-10 20:43:58 +02:00
self . assertEqual ( sorted ( new_streams ) , sorted ( new_subs ) )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_successful_subscriptions_remove ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
2016-12-23 02:37:10 +01:00
Calling DELETE / json / users / me / subscriptions should successfully remove streams ,
2014-01-29 22:03:40 +01:00
and should determine which were removed vs which weren ' t subscribed to.
We cannot randomly generate stream names because the remove code
verifies whether streams exist .
"""
2017-03-05 08:57:51 +01:00
self . assertGreaterEqual ( len ( self . streams ) , 2 )
2014-01-29 22:03:40 +01:00
streams_to_remove = self . streams [ 1 : ]
not_subbed = [ ]
for stream in Stream . objects . all ( ) :
2016-05-10 01:55:43 +02:00
if stream . name not in self . streams :
2014-01-29 22:03:40 +01:00
not_subbed . append ( stream . name )
random . shuffle ( not_subbed )
self . assertNotEqual ( len ( not_subbed ) , 0 ) # necessary for full test coverage
try_to_remove = not_subbed [ : 3 ] # attempt to remove up to 3 streams not already subbed to
streams_to_remove . extend ( try_to_remove )
self . helper_check_subs_before_and_after_remove ( streams_to_remove ,
2016-12-03 00:04:17 +01:00
{ " removed " : self . streams [ 1 : ] , " not_subscribed " : try_to_remove } ,
2017-07-12 13:07:48 +02:00
self . test_email , [ self . streams [ 0 ] ] , self . test_realm )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_subscriptions_remove_fake_stream ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
2016-12-23 02:37:10 +01:00
Calling DELETE / json / users / me / subscriptions on a stream that doesn ' t exist
2014-01-29 22:03:40 +01:00
should return a JSON error .
"""
random_streams = self . make_random_stream_names ( self . streams )
self . assertNotEqual ( len ( random_streams ) , 0 ) # necessary for full test coverage
streams_to_remove = random_streams [ : 1 ] # pick only one fake stream, to make checking the error message easy
2016-12-23 02:37:10 +01:00
result = self . client_delete ( " /json/users/me/subscriptions " ,
{ " subscriptions " : ujson . dumps ( streams_to_remove ) } )
2014-01-29 22:03:40 +01:00
self . assert_json_error ( result , " Stream(s) ( %s ) do not exist " % ( random_streams [ 0 ] , ) )
2018-05-11 01:39:38 +02:00
def helper_subscriptions_exists ( self , stream : str , expect_success : bool , subscribed : bool ) - > None :
2014-01-29 22:03:40 +01:00
"""
2017-07-25 02:15:40 +02:00
Call / json / subscriptions / exists on a stream and expect a certain result .
2014-01-29 22:03:40 +01:00
"""
2016-07-28 00:30:22 +02:00
result = self . client_post ( " /json/subscriptions/exists " ,
2014-01-29 22:03:40 +01:00
{ " stream " : stream } )
2017-08-17 08:45:20 +02:00
json = result . json ( )
2017-07-25 02:15:40 +02:00
if expect_success :
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
else :
2016-12-16 02:01:34 +01:00
self . assertEqual ( result . status_code , 404 )
2016-06-04 19:50:38 +02:00
if subscribed :
2014-01-29 22:03:40 +01:00
self . assertIn ( " subscribed " , json )
self . assertEqual ( json [ " subscribed " ] , subscribed )
2017-11-05 10:51:25 +01:00
def test_successful_subscriptions_exists_subbed ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
Calling / json / subscriptions / exist on a stream to which you are subbed
should return that it exists and that you are subbed .
"""
self . assertNotEqual ( len ( self . streams ) , 0 ) # necessary for full test coverage
self . helper_subscriptions_exists ( self . streams [ 0 ] , True , True )
2017-11-05 10:51:25 +01:00
def test_successful_subscriptions_exists_not_subbed ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
Calling / json / subscriptions / exist on a stream to which you are not
subbed should return that it exists and that you are not subbed .
"""
2017-07-12 12:32:14 +02:00
all_stream_names = [ stream . name for stream in Stream . objects . filter ( realm = self . test_realm ) ]
2014-01-29 22:03:40 +01:00
streams_not_subbed = list ( set ( all_stream_names ) - set ( self . streams ) )
self . assertNotEqual ( len ( streams_not_subbed ) , 0 ) # necessary for full test coverage
self . helper_subscriptions_exists ( streams_not_subbed [ 0 ] , True , False )
2017-11-05 10:51:25 +01:00
def test_subscriptions_does_not_exist ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
Calling / json / subscriptions / exist on a stream that doesn ' t exist should
return that it doesn ' t exist.
"""
random_streams = self . make_random_stream_names ( self . streams )
self . assertNotEqual ( len ( random_streams ) , 0 ) # necessary for full test coverage
2016-06-04 19:50:38 +02:00
self . helper_subscriptions_exists ( random_streams [ 0 ] , False , False )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_subscriptions_exist_invalid_name ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
Calling / json / subscriptions / exist on a stream whose name is invalid ( as
defined by valid_stream_name in zerver / views . py ) should return a JSON
error .
"""
# currently, the only invalid stream name is the empty string
invalid_stream_name = " "
2016-07-28 00:30:22 +02:00
result = self . client_post ( " /json/subscriptions/exists " ,
2014-01-29 22:03:40 +01:00
{ " stream " : invalid_stream_name } )
2017-01-30 07:01:19 +01:00
self . assert_json_error ( result , " Invalid stream name ' ' " )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_existing_subscriptions_autosubscription ( self ) - > None :
2016-06-21 15:54:18 +02:00
"""
Call / json / subscriptions / exist on an existing stream and autosubscribe to it .
"""
2017-01-12 01:41:16 +01:00
stream_name = " new_public_stream "
2017-05-25 01:50:35 +02:00
result = self . common_subscribe_to_streams ( self . example_email ( " cordelia " ) , [ stream_name ] ,
2017-01-12 01:41:16 +01:00
invite_only = False )
2016-07-28 00:30:22 +02:00
result = self . client_post ( " /json/subscriptions/exists " ,
2017-01-12 01:41:16 +01:00
{ " stream " : stream_name , " autosubscribe " : " false " } )
2016-06-21 15:54:18 +02:00
self . assert_json_success ( result )
2017-08-16 09:52:04 +02:00
self . assertIn ( " subscribed " , result . json ( ) )
self . assertFalse ( result . json ( ) [ " subscribed " ] )
2017-01-12 01:41:16 +01:00
result = self . client_post ( " /json/subscriptions/exists " ,
{ " stream " : stream_name , " autosubscribe " : " true " } )
self . assert_json_success ( result )
2017-08-16 09:52:04 +02:00
self . assertIn ( " subscribed " , result . json ( ) )
self . assertTrue ( result . json ( ) [ " subscribed " ] )
2016-06-21 15:54:18 +02:00
2017-11-05 10:51:25 +01:00
def test_existing_subscriptions_autosubscription_private_stream ( self ) - > None :
2017-01-23 05:22:40 +01:00
""" Call /json/subscriptions/exist on an existing private stream with
autosubscribe should fail .
"""
stream_name = " Saxony "
2017-05-25 01:50:35 +02:00
result = self . common_subscribe_to_streams ( self . example_email ( " cordelia " ) , [ stream_name ] ,
2017-01-23 05:22:40 +01:00
invite_only = True )
2017-07-12 12:32:14 +02:00
stream = get_stream ( stream_name , self . test_realm )
2017-01-23 05:22:40 +01:00
result = self . client_post ( " /json/subscriptions/exists " ,
2017-01-12 01:41:16 +01:00
{ " stream " : stream_name , " autosubscribe " : " true " } )
# We can't see invite-only streams here
self . assert_json_error ( result , " Invalid stream name ' Saxony ' " , status_code = 404 )
# Importantly, we are not now subscribed
2017-10-29 15:40:07 +01:00
self . assertEqual ( num_subscribers_for_stream_id ( stream . id ) , 1 )
2017-01-12 01:41:16 +01:00
# A user who is subscribed still sees the stream exists
2017-05-25 01:50:35 +02:00
self . login ( self . example_email ( " cordelia " ) )
2017-01-12 01:41:16 +01:00
result = self . client_post ( " /json/subscriptions/exists " ,
{ " stream " : stream_name , " autosubscribe " : " false " } )
2017-01-23 05:22:40 +01:00
self . assert_json_success ( result )
2017-08-16 09:52:04 +02:00
self . assertIn ( " subscribed " , result . json ( ) )
self . assertTrue ( result . json ( ) [ " subscribed " ] )
2017-01-23 05:22:40 +01:00
2018-05-11 01:39:38 +02:00
def get_subscription ( self , user_profile : UserProfile , stream_name : str ) - > Subscription :
2017-07-12 12:32:14 +02:00
stream = get_stream ( stream_name , self . test_realm )
2014-01-29 22:03:40 +01:00
return Subscription . objects . get (
user_profile = user_profile ,
recipient__type = Recipient . STREAM ,
recipient__type_id = stream . id ,
)
2017-11-05 10:51:25 +01:00
def test_subscriptions_add_notification_default_true ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
2017-08-17 16:55:32 +02:00
When creating a subscription , the desktop , push , and audible notification
2014-02-05 22:56:30 +01:00
settings for that stream are derived from the global notification
settings .
2014-01-29 22:03:40 +01:00
"""
2017-05-07 21:25:59 +02:00
user_profile = self . example_user ( ' iago ' )
2017-05-23 20:57:59 +02:00
invitee_email = user_profile . email
invitee_realm = user_profile . realm
2014-02-05 22:56:30 +01:00
user_profile . enable_stream_desktop_notifications = True
2017-08-17 16:55:32 +02:00
user_profile . enable_stream_push_notifications = True
2014-02-05 22:56:30 +01:00
user_profile . enable_stream_sounds = True
2017-11-21 04:35:26 +01:00
user_profile . enable_stream_email_notifications = True
2014-01-29 22:03:40 +01:00
user_profile . save ( )
2017-07-12 13:07:48 +02:00
current_stream = self . get_streams ( invitee_email , invitee_realm ) [ 0 ]
2016-06-04 19:50:38 +02:00
invite_streams = self . make_random_stream_names ( [ current_stream ] )
2017-05-23 20:57:59 +02:00
self . assert_adding_subscriptions_for_principal ( invitee_email , invitee_realm , invite_streams )
2014-01-29 22:03:40 +01:00
subscription = self . get_subscription ( user_profile , invite_streams [ 0 ] )
2016-10-04 01:05:44 +02:00
2017-10-27 09:06:40 +02:00
with mock . patch ( ' zerver.models.Recipient.__str__ ' , return_value = ' recip ' ) :
2016-10-04 01:05:44 +02:00
self . assertEqual ( str ( subscription ) ,
2016-12-03 00:04:17 +01:00
u ' <Subscription: '
2017-07-12 13:00:36 +02:00
' <UserProfile: %s <Realm: zulip 1>> -> recip> ' % ( self . example_email ( ' iago ' ) , ) )
2016-10-04 01:05:44 +02:00
2014-02-05 22:56:30 +01:00
self . assertTrue ( subscription . desktop_notifications )
2017-08-17 16:55:32 +02:00
self . assertTrue ( subscription . push_notifications )
2014-02-05 22:56:30 +01:00
self . assertTrue ( subscription . audible_notifications )
2017-11-21 04:35:26 +01:00
self . assertTrue ( subscription . email_notifications )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_subscriptions_add_notification_default_false ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
2017-08-17 16:55:32 +02:00
When creating a subscription , the desktop , push , and audible notification
2014-02-05 22:56:30 +01:00
settings for that stream are derived from the global notification
settings .
2014-01-29 22:03:40 +01:00
"""
2017-05-07 21:25:59 +02:00
user_profile = self . example_user ( ' iago ' )
2017-05-23 20:57:59 +02:00
invitee_email = user_profile . email
invitee_realm = user_profile . realm
2014-02-05 22:56:30 +01:00
user_profile . enable_stream_desktop_notifications = False
2017-08-17 16:55:32 +02:00
user_profile . enable_stream_push_notifications = False
2014-02-05 22:56:30 +01:00
user_profile . enable_stream_sounds = False
2014-01-29 22:03:40 +01:00
user_profile . save ( )
2017-07-12 13:07:48 +02:00
current_stream = self . get_streams ( invitee_email , invitee_realm ) [ 0 ]
2016-06-04 19:50:38 +02:00
invite_streams = self . make_random_stream_names ( [ current_stream ] )
2017-05-23 20:57:59 +02:00
self . assert_adding_subscriptions_for_principal ( invitee_email , invitee_realm , invite_streams )
2014-01-29 22:03:40 +01:00
subscription = self . get_subscription ( user_profile , invite_streams [ 0 ] )
2014-02-05 22:56:30 +01:00
self . assertFalse ( subscription . desktop_notifications )
2017-08-17 16:55:32 +02:00
self . assertFalse ( subscription . push_notifications )
2014-02-05 22:56:30 +01:00
self . assertFalse ( subscription . audible_notifications )
2014-01-29 22:03:40 +01:00
2017-11-13 21:24:51 +01:00
def test_mark_messages_as_unread_on_unsubscribe ( self ) - > None :
realm = get_realm ( " zulip " )
user = self . example_user ( " iago " )
random_user = self . example_user ( " hamlet " )
2018-03-21 22:05:21 +01:00
stream1 = ensure_stream ( realm , " stream1 " , invite_only = False )
stream2 = ensure_stream ( realm , " stream2 " , invite_only = False )
private = ensure_stream ( realm , " private_stream " , invite_only = True )
2017-11-13 21:24:51 +01:00
self . subscribe ( user , " stream1 " )
self . subscribe ( user , " stream2 " )
2017-11-29 23:35:33 +01:00
self . subscribe ( user , " private_stream " )
2017-11-13 21:24:51 +01:00
self . subscribe ( random_user , " stream1 " )
self . subscribe ( random_user , " stream2 " )
2017-11-29 23:35:33 +01:00
self . subscribe ( random_user , " private_stream " )
2017-11-13 21:24:51 +01:00
self . send_stream_message ( random_user . email , " stream1 " , " test " , " test " )
self . send_stream_message ( random_user . email , " stream2 " , " test " , " test " )
2017-11-29 23:35:33 +01:00
self . send_stream_message ( random_user . email , " private_stream " , " test " , " test " )
2017-11-13 21:24:51 +01:00
def get_unread_stream_data ( ) - > List [ Dict [ str , Any ] ] :
raw_unread_data = get_raw_unread_data ( user )
aggregated_data = aggregate_unread_data ( raw_unread_data )
return aggregated_data [ ' streams ' ]
result = get_unread_stream_data ( )
2017-11-29 23:35:33 +01:00
self . assert_length ( result , 3 )
2017-11-13 21:24:51 +01:00
self . assertEqual ( result [ 0 ] [ ' stream_id ' ] , stream1 . id )
self . assertEqual ( result [ 1 ] [ ' stream_id ' ] , stream2 . id )
2017-11-29 23:35:33 +01:00
self . assertEqual ( result [ 2 ] [ ' stream_id ' ] , private . id )
2017-11-13 21:24:51 +01:00
# Unsubscribing should mark all the messages in stream2 as read
self . unsubscribe ( user , " stream2 " )
2017-11-29 23:35:33 +01:00
self . unsubscribe ( user , " private_stream " )
2017-11-13 21:24:51 +01:00
self . subscribe ( user , " stream2 " )
2017-11-29 23:35:33 +01:00
self . subscribe ( user , " private_stream " )
2017-11-13 21:24:51 +01:00
result = get_unread_stream_data ( )
self . assert_length ( result , 1 )
self . assertEqual ( result [ 0 ] [ ' stream_id ' ] , stream1 . id )
2014-01-29 22:03:40 +01:00
2018-05-15 17:33:16 +02:00
def test_gather_subscriptions_excludes_deactivated_streams ( self ) - > None :
"""
Check that gather_subscriptions_helper does not include deactivated streams in its
results .
"""
realm = get_realm ( " zulip " )
admin_user = self . example_user ( " iago " )
non_admin_user = self . example_user ( " cordelia " )
self . login ( admin_user . email )
for stream_name in [ " stream1 " , " stream2 " , " stream3 " , ] :
self . make_stream ( stream_name , realm = realm , invite_only = False )
self . subscribe ( admin_user , stream_name )
self . subscribe ( non_admin_user , stream_name )
self . subscribe ( self . example_user ( " othello " ) , stream_name )
def delete_stream ( stream_name : str ) - > None :
stream_id = get_stream ( stream_name , realm ) . id
result = self . client_delete ( ' /json/streams/ %d ' % ( stream_id , ) )
self . assert_json_success ( result )
# Deleted/deactivated stream should not be returned in the helper results
admin_before_delete = gather_subscriptions_helper ( admin_user )
non_admin_before_delete = gather_subscriptions_helper ( non_admin_user )
# Delete our stream
delete_stream ( " stream1 " )
# Get subs after delete
admin_after_delete = gather_subscriptions_helper ( admin_user )
non_admin_after_delete = gather_subscriptions_helper ( non_admin_user )
# Compare results - should be 1 stream less
self . assertTrue (
len ( admin_before_delete [ 0 ] ) == len ( admin_after_delete [ 0 ] ) + 1 ,
' Expected exactly 1 less stream from gather_subscriptions_helper ' )
self . assertTrue (
len ( non_admin_before_delete [ 0 ] ) == len ( non_admin_after_delete [ 0 ] ) + 1 ,
' Expected exactly 1 less stream from gather_subscriptions_helper ' )
2018-05-16 03:36:18 +02:00
def test_validate_user_access_to_subscribers_helper ( self ) - > None :
"""
Ensure the validate_user_access_to_subscribers_helper is properly raising
ValidationError on missing user , user not - in - realm .
"""
user_profile = self . example_user ( ' othello ' )
realm_name = ' no_othello_allowed '
realm = do_create_realm ( realm_name , ' Everyone but Othello is allowed ' )
stream_dict = {
' name ' : ' publicstream ' ,
' description ' : ' Public stream with public history ' ,
' realm_id ' : realm . id
}
# For this test to work, othello can't be in the no_othello_here realm
self . assertNotEqual ( user_profile . realm . id , realm . id , ' Expected othello user to not be in this realm. ' )
# This should result in missing user
with self . assertRaises ( ValidationError ) :
2018-05-16 21:09:52 +02:00
validate_user_access_to_subscribers_helper ( None , stream_dict , lambda : True )
2018-05-16 03:36:18 +02:00
# This should result in user not in realm
with self . assertRaises ( ValidationError ) :
2018-05-16 21:09:52 +02:00
validate_user_access_to_subscribers_helper ( user_profile , stream_dict , lambda : True )
2018-05-15 17:33:16 +02:00
2018-08-17 03:33:16 +02:00
def test_subscriptions_query_count ( self ) - > None :
"""
Test database query count when creating stream with api / v1 / users / me / subscriptions .
"""
user1 = self . example_user ( " cordelia " )
user2 = self . example_user ( " iago " )
new_streams = [
' query_count_stream_1 ' ,
' query_count_stream_2 ' ,
' query_count_stream_3 '
]
# Test creating a public stream when realm does not have a notification stream.
with queries_captured ( ) as queries :
self . common_subscribe_to_streams (
self . test_email ,
[ new_streams [ 0 ] ] ,
dict ( principals = ujson . dumps ( [ user1 . email , user2 . email ] ) ) ,
)
2019-02-07 02:05:34 +01:00
self . assert_length ( queries , 43 )
2018-08-17 03:33:16 +02:00
# Test creating private stream.
with queries_captured ( ) as queries :
self . common_subscribe_to_streams (
self . test_email ,
[ new_streams [ 1 ] ] ,
dict ( principals = ujson . dumps ( [ user1 . email , user2 . email ] ) ) ,
invite_only = True ,
)
2019-02-07 02:05:34 +01:00
self . assert_length ( queries , 38 )
2018-08-17 03:33:16 +02:00
# Test creating a public stream with announce when realm has a notification stream.
notifications_stream = get_stream ( self . streams [ 0 ] , self . test_realm )
self . test_realm . notifications_stream_id = notifications_stream . id
self . test_realm . save ( )
with queries_captured ( ) as queries :
self . common_subscribe_to_streams (
self . test_email ,
[ new_streams [ 2 ] ] ,
dict (
announce = ' true ' ,
principals = ujson . dumps ( [ user1 . email , user2 . email ] )
)
)
2019-02-07 02:05:34 +01:00
self . assert_length ( queries , 51 )
2018-08-17 03:33:16 +02:00
2016-08-23 02:08:42 +02:00
class GetPublicStreamsTest ( ZulipTestCase ) :
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_public_streams_api ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
2016-04-17 14:47:43 +02:00
Ensure that the query we use to get public streams successfully returns
a list of streams
2014-01-29 22:03:40 +01:00
"""
2017-07-12 12:44:55 +02:00
email = self . example_email ( ' hamlet ' )
2017-05-23 20:57:59 +02:00
realm = get_realm ( ' zulip ' )
2014-01-29 22:03:40 +01:00
self . login ( email )
# Check it correctly lists the user's subs with include_public=false
2017-12-14 19:02:31 +01:00
result = self . api_get ( email , " /api/v1/streams?include_public=false " )
result2 = self . api_get ( email , " /api/v1/users/me/subscriptions " )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2017-08-17 08:45:20 +02:00
json = result . json ( )
2014-01-29 22:03:40 +01:00
self . assertIn ( " streams " , json )
self . assertIsInstance ( json [ " streams " ] , list )
self . assert_json_success ( result2 )
json2 = ujson . loads ( result2 . content )
self . assertEqual ( sorted ( [ s [ " name " ] for s in json [ " streams " ] ] ) ,
sorted ( [ s [ " name " ] for s in json2 [ " subscriptions " ] ] ) )
# Check it correctly lists all public streams with include_subscribed=false
2017-12-14 19:02:31 +01:00
result = self . api_get ( email , " /api/v1/streams?include_public=true&include_subscribed=false " )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2017-08-17 08:45:20 +02:00
json = result . json ( )
2014-01-29 22:03:40 +01:00
all_streams = [ stream . name for stream in
2017-05-23 20:57:59 +02:00
Stream . objects . filter ( realm = realm ) ]
2014-01-29 22:03:40 +01:00
self . assertEqual ( sorted ( s [ " name " ] for s in json [ " streams " ] ) ,
sorted ( all_streams ) )
# Check non-superuser can't use include_all_active
2017-12-14 19:02:31 +01:00
result = self . api_get ( email , " /api/v1/streams?include_all_active=true " )
2014-01-29 22:03:40 +01:00
self . assertEqual ( result . status_code , 400 )
2017-01-03 18:31:43 +01:00
class StreamIdTest ( ZulipTestCase ) :
2017-11-05 10:51:25 +01:00
def setUp ( self ) - > None :
2017-05-07 21:25:59 +02:00
self . user_profile = self . example_user ( ' hamlet ' )
self . email = self . user_profile . email
2017-01-03 18:31:43 +01:00
self . login ( self . email )
2017-11-05 10:51:25 +01:00
def test_get_stream_id ( self ) - > None :
2017-01-03 18:31:43 +01:00
stream = gather_subscriptions ( self . user_profile ) [ 0 ] [ 0 ]
result = self . client_get ( " /json/get_stream_id?stream= %s " % ( stream [ ' name ' ] , ) )
self . assert_json_success ( result )
self . assertEqual ( result . json ( ) [ ' stream_id ' ] , stream [ ' stream_id ' ] )
2017-11-05 10:51:25 +01:00
def test_get_stream_id_wrong_name ( self ) - > None :
2017-01-03 18:31:43 +01:00
result = self . client_get ( " /json/get_stream_id?stream=wrongname " )
2017-01-30 01:57:25 +01:00
self . assert_json_error ( result , u " Invalid stream name ' wrongname ' " )
2017-01-03 18:31:43 +01:00
2016-08-23 02:08:42 +02:00
class InviteOnlyStreamTest ( ZulipTestCase ) :
2017-11-05 10:51:25 +01:00
def test_must_be_subbed_to_send ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
If you try to send a message to an invite - only stream to which
you aren ' t subscribed, you ' ll get a 400.
"""
2017-07-12 12:44:55 +02:00
self . login ( self . example_email ( " hamlet " ) )
2014-01-29 22:03:40 +01:00
# Create Saxony as an invite-only stream.
self . assert_json_success (
2017-07-12 12:44:55 +02:00
self . common_subscribe_to_streams ( self . example_email ( " hamlet " ) , [ " Saxony " ] ,
2014-01-29 22:03:40 +01:00
invite_only = True ) )
2017-05-25 01:50:35 +02:00
email = self . example_email ( " cordelia " )
2014-01-29 22:03:40 +01:00
with self . assertRaises ( JsonableError ) :
2017-10-28 18:13:37 +02:00
self . send_stream_message ( email , " Saxony " )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_list_respects_invite_only_bit ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
Make sure that / api / v1 / users / me / subscriptions properly returns
the invite - only bit for streams that are invite - only
"""
2017-07-12 12:44:55 +02:00
email = self . example_email ( ' hamlet ' )
2014-01-29 22:03:40 +01:00
self . login ( email )
result1 = self . common_subscribe_to_streams ( email , [ " Saxony " ] , invite_only = True )
self . assert_json_success ( result1 )
result2 = self . common_subscribe_to_streams ( email , [ " Normandy " ] , invite_only = False )
self . assert_json_success ( result2 )
2017-12-14 19:02:31 +01:00
result = self . api_get ( email , " /api/v1/users/me/subscriptions " )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2017-08-16 09:52:04 +02:00
self . assertIn ( " subscriptions " , result . json ( ) )
for sub in result . json ( ) [ " subscriptions " ] :
2014-01-29 22:03:40 +01:00
if sub [ ' name ' ] == " Normandy " :
2018-06-27 00:04:03 +02:00
self . assertEqual ( sub [ ' invite_only ' ] , False , " Normandy was mistakenly marked private " )
2014-01-29 22:03:40 +01:00
if sub [ ' name ' ] == " Saxony " :
2018-06-27 00:04:03 +02:00
self . assertEqual ( sub [ ' invite_only ' ] , True , " Saxony was not properly marked private " )
2014-01-29 22:03:40 +01:00
2016-07-29 21:06:22 +02:00
@slow ( " lots of queries " )
2017-11-05 10:51:25 +01:00
def test_inviteonly ( self ) - > None :
2014-01-29 22:03:40 +01:00
# Creating an invite-only stream is allowed
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' hamlet ' )
email = user_profile . email
2014-01-29 22:03:40 +01:00
stream_name = " Saxony "
result = self . common_subscribe_to_streams ( email , [ stream_name ] , invite_only = True )
self . assert_json_success ( result )
2017-08-17 08:45:20 +02:00
json = result . json ( )
2014-01-29 22:03:40 +01:00
self . assertEqual ( json [ " subscribed " ] , { email : [ stream_name ] } )
self . assertEqual ( json [ " already_subscribed " ] , { } )
# Subscribing oneself to an invite-only stream is not allowed
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' othello ' )
email = user_profile . email
2014-01-29 22:03:40 +01:00
self . login ( email )
result = self . common_subscribe_to_streams ( email , [ stream_name ] )
self . assert_json_error ( result , ' Unable to access stream (Saxony). ' )
# authorization_errors_fatal=False works
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' othello ' )
email = user_profile . email
2014-01-29 22:03:40 +01:00
self . login ( email )
result = self . common_subscribe_to_streams ( email , [ stream_name ] ,
extra_post_data = { ' authorization_errors_fatal ' : ujson . dumps ( False ) } )
self . assert_json_success ( result )
2017-08-17 08:45:20 +02:00
json = result . json ( )
2014-01-29 22:03:40 +01:00
self . assertEqual ( json [ " unauthorized " ] , [ stream_name ] )
self . assertEqual ( json [ " subscribed " ] , { } )
self . assertEqual ( json [ " already_subscribed " ] , { } )
# Inviting another user to an invite-only stream is allowed
2017-05-07 19:39:30 +02:00
user_profile = self . example_user ( ' hamlet ' )
email = user_profile . email
2014-01-29 22:03:40 +01:00
self . login ( email )
result = self . common_subscribe_to_streams (
email , [ stream_name ] ,
2017-05-25 02:08:35 +02:00
extra_post_data = { ' principals ' : ujson . dumps ( [ self . example_email ( " othello " ) ] ) } )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2017-08-17 08:45:20 +02:00
json = result . json ( )
2017-05-25 02:08:35 +02:00
self . assertEqual ( json [ " subscribed " ] , { self . example_email ( " othello " ) : [ stream_name ] } )
2014-01-29 22:03:40 +01:00
self . assertEqual ( json [ " already_subscribed " ] , { } )
# Make sure both users are subscribed to this stream
2017-01-13 15:50:17 +01:00
stream_id = get_stream ( stream_name , user_profile . realm ) . id
2017-12-14 19:02:31 +01:00
result = self . api_get ( email , " /api/v1/streams/ %d /members " % ( stream_id , ) )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2017-08-17 08:45:20 +02:00
json = result . json ( )
2014-01-29 22:03:40 +01:00
2017-05-25 02:08:35 +02:00
self . assertTrue ( self . example_email ( " othello " ) in json [ ' subscribers ' ] )
2017-07-12 12:44:55 +02:00
self . assertTrue ( self . example_email ( ' hamlet ' ) in json [ ' subscribers ' ] )
2014-01-29 22:03:40 +01:00
2016-08-23 02:08:42 +02:00
class GetSubscribersTest ( ZulipTestCase ) :
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def setUp ( self ) - > None :
2017-05-07 21:25:59 +02:00
self . user_profile = self . example_user ( ' hamlet ' )
self . email = self . user_profile . email
2014-01-29 22:03:40 +01:00
self . login ( self . email )
2018-05-11 01:39:38 +02:00
def assert_user_got_subscription_notification ( self , expected_msg : str ) - > None :
2017-05-16 01:32:50 +02:00
# verify that the user was sent a message informing them about the subscription
msg = self . get_last_message ( )
self . assertEqual ( msg . recipient . type , msg . recipient . PERSONAL )
self . assertEqual ( msg . sender_id , self . notification_bot ( ) . id )
2018-05-11 01:39:38 +02:00
def non_ws ( s : str ) - > str :
2017-05-16 01:32:50 +02:00
return s . replace ( ' \n ' , ' ' ) . replace ( ' ' , ' ' )
self . assertEqual ( non_ws ( msg . content ) , non_ws ( expected_msg ) )
2018-05-11 01:39:38 +02:00
def check_well_formed_result ( self , result : Dict [ str , Any ] , stream_name : str , realm : Realm ) - > None :
2014-01-29 22:03:40 +01:00
"""
A successful call to get_subscribers returns the list of subscribers in
the form :
{ " msg " : " " ,
" result " : " success " ,
2017-07-12 12:44:55 +02:00
" subscribers " : [ self . example_email ( " hamlet " ) , self . example_email ( " prospero " ) ] }
2014-01-29 22:03:40 +01:00
"""
self . assertIn ( " subscribers " , result )
self . assertIsInstance ( result [ " subscribers " ] , list )
true_subscribers = [ user_profile . email for user_profile in self . users_subscribed_to_stream (
2017-01-24 07:06:13 +01:00
stream_name , realm ) ]
2016-07-10 20:43:58 +02:00
self . assertEqual ( sorted ( result [ " subscribers " ] ) , sorted ( true_subscribers ) )
2014-01-29 22:03:40 +01:00
2018-05-11 01:39:38 +02:00
def make_subscriber_request ( self , stream_id : int , email : Optional [ str ] = None ) - > HttpResponse :
2014-01-29 22:03:40 +01:00
if email is None :
email = self . email
2017-12-14 19:02:31 +01:00
return self . api_get ( email , " /api/v1/streams/ %d /members " % ( stream_id , ) )
2014-01-29 22:03:40 +01:00
2018-05-11 01:39:38 +02:00
def make_successful_subscriber_request ( self , stream_name : str ) - > None :
2017-01-13 15:50:17 +01:00
stream_id = get_stream ( stream_name , self . user_profile . realm ) . id
2016-12-30 11:42:59 +01:00
result = self . make_subscriber_request ( stream_id )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( result )
2017-08-17 08:45:20 +02:00
self . check_well_formed_result ( result . json ( ) ,
2016-12-24 08:00:19 +01:00
stream_name , self . user_profile . realm )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_subscriber ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
get_subscribers returns the list of subscribers .
"""
stream_name = gather_subscriptions ( self . user_profile ) [ 0 ] [ 0 ] [ ' name ' ]
self . make_successful_subscriber_request ( stream_name )
2016-07-29 21:06:22 +02:00
@slow ( " common_subscribe_to_streams is slow " )
2017-11-05 10:51:25 +01:00
def test_gather_subscriptions ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
gather_subscriptions returns correct results with only 3 queries
2017-05-16 01:32:50 +02:00
( We also use this test to verify subscription notifications to
folks who get subscribed to streams . )
2014-01-29 22:03:40 +01:00
"""
2015-11-01 17:15:05 +01:00
streams = [ " stream_ %s " % i for i in range ( 10 ) ]
2016-10-21 23:22:25 +02:00
for stream_name in streams :
self . make_stream ( stream_name )
2017-05-25 02:08:35 +02:00
users_to_subscribe = [ self . email , self . example_email ( " othello " ) , self . example_email ( " cordelia " ) ]
2014-01-29 22:03:40 +01:00
ret = self . common_subscribe_to_streams (
self . email ,
streams ,
dict ( principals = ujson . dumps ( users_to_subscribe ) ) )
2017-05-16 01:32:50 +02:00
self . assert_json_success ( ret )
msg = '''
2018-07-30 08:06:37 +02:00
Hi there ! @ * * King Hamlet * * just subscribed you to the following streams :
2017-05-16 01:32:50 +02:00
* #**stream_0**
* #**stream_1**
* #**stream_2**
* #**stream_3**
* #**stream_4**
* #**stream_5**
* #**stream_6**
* #**stream_7**
* #**stream_8**
* #**stream_9**
'''
self . assert_user_got_subscription_notification ( msg )
# Subscribe ourself first.
ret = self . common_subscribe_to_streams (
self . email ,
[ " stream_invite_only_1 " ] ,
dict ( principals = ujson . dumps ( [ self . email ] ) ) ,
invite_only = True )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( ret )
2017-05-16 01:32:50 +02:00
# Now add in other users, and this should trigger messages
# to notify the user.
2014-01-29 22:03:40 +01:00
ret = self . common_subscribe_to_streams (
self . email ,
[ " stream_invite_only_1 " ] ,
dict ( principals = ujson . dumps ( users_to_subscribe ) ) ,
invite_only = True )
self . assert_json_success ( ret )
2017-05-16 01:32:50 +02:00
msg = '''
2018-07-30 08:06:37 +02:00
Hi there ! @ * * King Hamlet * * just subscribed you to the stream #**stream_invite_only_1**.
2017-05-16 01:32:50 +02:00
'''
self . assert_user_got_subscription_notification ( msg )
2014-01-29 22:03:40 +01:00
with queries_captured ( ) as queries :
subscriptions = gather_subscriptions ( self . user_profile )
self . assertTrue ( len ( subscriptions [ 0 ] ) > = 11 )
for sub in subscriptions [ 0 ] :
if not sub [ " name " ] . startswith ( " stream_ " ) :
continue
self . assertTrue ( len ( sub [ " subscribers " ] ) == len ( users_to_subscribe ) )
2017-04-03 17:13:42 +02:00
self . assert_length ( queries , 7 )
2014-01-29 22:03:40 +01:00
2016-07-29 21:06:22 +02:00
@slow ( " common_subscribe_to_streams is slow " )
2017-11-05 10:51:25 +01:00
def test_never_subscribed_streams ( self ) - > None :
2016-07-12 23:57:16 +02:00
"""
Check never_subscribed streams are fetched correctly and not include invite_only streams .
"""
2017-01-04 05:30:48 +01:00
realm = get_realm ( " zulip " )
2017-08-22 16:51:07 +02:00
users_to_subscribe = [
self . example_email ( " othello " ) ,
self . example_email ( " cordelia " ) ,
]
public_streams = [
' test_stream_public_1 ' ,
' test_stream_public_2 ' ,
' test_stream_public_3 ' ,
' test_stream_public_4 ' ,
' test_stream_public_5 ' ,
]
private_streams = [
' test_stream_invite_only_1 ' ,
' test_stream_invite_only_2 ' ,
]
2017-11-05 10:51:25 +01:00
def create_public_streams ( ) - > None :
2017-08-22 16:51:07 +02:00
for stream_name in public_streams :
self . make_stream ( stream_name , realm = realm )
ret = self . common_subscribe_to_streams (
self . email ,
public_streams ,
dict ( principals = ujson . dumps ( users_to_subscribe ) )
)
self . assert_json_success ( ret )
create_public_streams ( )
2017-11-05 10:51:25 +01:00
def create_private_streams ( ) - > None :
2017-08-22 16:51:07 +02:00
ret = self . common_subscribe_to_streams (
self . email ,
private_streams ,
dict ( principals = ujson . dumps ( users_to_subscribe ) ) ,
invite_only = True
)
self . assert_json_success ( ret )
create_private_streams ( )
2017-11-05 10:51:25 +01:00
def get_never_subscribed ( ) - > List [ Dict [ str , Any ] ] :
2017-08-22 16:51:07 +02:00
with queries_captured ( ) as queries :
sub_data = gather_subscriptions_helper ( self . user_profile )
never_subscribed = sub_data [ 2 ]
2017-04-03 17:13:42 +02:00
self . assert_length ( queries , 6 )
2017-08-22 16:51:07 +02:00
# Ignore old streams.
never_subscribed = [
dct for dct in never_subscribed
if dct [ ' name ' ] . startswith ( ' test_ ' )
]
return never_subscribed
never_subscribed = get_never_subscribed ( )
2016-07-12 23:57:16 +02:00
# Invite only stream should not be there in never_subscribed streams
2017-08-22 16:51:07 +02:00
self . assertEqual ( len ( never_subscribed ) , len ( public_streams ) )
2016-07-12 23:57:16 +02:00
for stream_dict in never_subscribed :
2017-08-22 16:51:07 +02:00
name = stream_dict [ ' name ' ]
self . assertFalse ( ' invite_only ' in name )
self . assertTrue ( len ( stream_dict [ " subscribers " ] ) == len ( users_to_subscribe ) )
2016-07-12 23:57:16 +02:00
2018-03-16 12:28:19 +01:00
# Send private stream subscribers to all realm admins.
2017-11-05 10:51:25 +01:00
def test_admin_case ( ) - > None :
2017-08-22 16:18:35 +02:00
self . user_profile . is_realm_admin = True
2018-03-16 12:28:19 +01:00
# Test realm admins can get never subscribed private stream's subscribers.
2017-08-22 16:18:35 +02:00
never_subscribed = get_never_subscribed ( )
self . assertEqual (
len ( never_subscribed ) ,
len ( public_streams ) + len ( private_streams )
)
for stream_dict in never_subscribed :
2018-03-16 12:28:19 +01:00
self . assertTrue ( len ( stream_dict [ " subscribers " ] ) == len ( users_to_subscribe ) )
2017-08-22 16:18:35 +02:00
test_admin_case ( )
2018-06-02 09:25:39 +02:00
def test_gather_subscribed_streams_for_guest_user ( self ) - > None :
guest_user = self . example_user ( " polonius " )
stream_name_sub = " public_stream_1 "
self . make_stream ( stream_name_sub , realm = get_realm ( " zulip " ) )
self . subscribe ( guest_user , stream_name_sub )
stream_name_unsub = " public_stream_2 "
self . make_stream ( stream_name_unsub , realm = get_realm ( " zulip " ) )
self . subscribe ( guest_user , stream_name_unsub )
self . unsubscribe ( guest_user , stream_name_unsub )
stream_name_never_sub = " public_stream_3 "
self . make_stream ( stream_name_never_sub , realm = get_realm ( " zulip " ) )
normal_user = self . example_user ( " aaron " )
self . subscribe ( normal_user , stream_name_sub )
self . subscribe ( normal_user , stream_name_unsub )
self . subscribe ( normal_user , stream_name_unsub )
subs , unsubs , neversubs = gather_subscriptions_helper ( guest_user )
# Guest users get info about subscribed public stream's subscribers
expected_stream_exists = False
for sub in subs :
if sub [ " name " ] == stream_name_sub :
expected_stream_exists = True
self . assertEqual ( len ( sub [ " subscribers " ] ) , 2 )
self . assertTrue ( expected_stream_exists )
# Guest users don't get info about unsubscribed public stream's subscribers
expected_stream_exists = False
for unsub in unsubs :
if unsub [ " name " ] == stream_name_unsub :
expected_stream_exists = True
self . assertNotIn ( " subscribers " , unsub )
self . assertTrue ( expected_stream_exists )
# Guest user don't get data about never subscribed public stream's data
self . assertEqual ( len ( neversubs ) , 0 )
2018-03-16 12:28:19 +01:00
def test_previously_subscribed_private_streams ( self ) - > None :
admin_user = self . example_user ( " iago " )
non_admin_user = self . example_user ( " cordelia " )
stream_name = " private_stream "
self . make_stream ( stream_name , realm = get_realm ( " zulip " ) , invite_only = True )
self . subscribe ( admin_user , stream_name )
self . subscribe ( non_admin_user , stream_name )
self . subscribe ( self . example_user ( " othello " ) , stream_name )
self . unsubscribe ( admin_user , stream_name )
self . unsubscribe ( non_admin_user , stream_name )
2018-06-01 22:17:47 +02:00
# Test admin user gets previously subscribed private stream's subscribers.
2018-03-16 12:28:19 +01:00
sub_data = gather_subscriptions_helper ( admin_user )
unsubscribed_streams = sub_data [ 1 ]
self . assertEqual ( len ( unsubscribed_streams ) , 1 )
self . assertEqual ( len ( unsubscribed_streams [ 0 ] [ " subscribers " ] ) , 1 )
2018-06-01 22:17:47 +02:00
# Test non admin users cannot get previously subscribed private stream's subscribers.
2018-03-16 12:28:19 +01:00
sub_data = gather_subscriptions_helper ( non_admin_user )
unsubscribed_streams = sub_data [ 1 ]
self . assertEqual ( len ( unsubscribed_streams ) , 1 )
2018-06-01 22:17:47 +02:00
self . assertFalse ( ' subscribers ' in unsubscribed_streams [ 0 ] )
2018-03-16 12:28:19 +01:00
2017-11-05 10:51:25 +01:00
def test_gather_subscriptions_mit ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
gather_subscriptions returns correct results with only 3 queries
"""
# Subscribe only ourself because invites are disabled on mit.edu
2017-05-23 02:33:53 +02:00
mit_user_profile = self . mit_user ( ' starnine ' )
email = mit_user_profile . email
2017-05-24 21:21:35 +02:00
users_to_subscribe = [ email , self . mit_email ( " espuser " ) ]
2014-01-29 22:03:40 +01:00
for email in users_to_subscribe :
2017-10-08 21:16:51 +02:00
stream = self . subscribe ( get_user ( email , mit_user_profile . realm ) , " mit_stream " )
self . assertTrue ( stream . is_in_zephyr_realm )
2014-01-29 22:03:40 +01:00
ret = self . common_subscribe_to_streams (
2017-05-23 02:33:53 +02:00
email ,
2014-01-29 22:03:40 +01:00
[ " mit_invite_only " ] ,
dict ( principals = ujson . dumps ( users_to_subscribe ) ) ,
2017-08-26 00:58:13 +02:00
invite_only = True ,
subdomain = " zephyr " )
2014-01-29 22:03:40 +01:00
self . assert_json_success ( ret )
with queries_captured ( ) as queries :
2017-05-23 02:33:53 +02:00
subscriptions = gather_subscriptions ( mit_user_profile )
2014-01-29 22:03:40 +01:00
self . assertTrue ( len ( subscriptions [ 0 ] ) > = 2 )
for sub in subscriptions [ 0 ] :
if not sub [ " name " ] . startswith ( " mit_ " ) :
2017-03-05 08:07:56 +01:00
raise AssertionError ( " Unexpected stream! " )
2014-01-29 22:03:40 +01:00
if sub [ " name " ] == " mit_invite_only " :
self . assertTrue ( len ( sub [ " subscribers " ] ) == len ( users_to_subscribe ) )
else :
self . assertTrue ( len ( sub [ " subscribers " ] ) == 0 )
2017-04-03 17:13:42 +02:00
self . assert_length ( queries , 6 )
2014-01-29 22:03:40 +01:00
2017-11-05 10:51:25 +01:00
def test_nonsubscriber ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
Even a non - subscriber to a public stream can query a stream ' s membership
with get_subscribers .
"""
# Create a stream for which Hamlet is the only subscriber.
stream_name = " Saxony "
self . common_subscribe_to_streams ( self . email , [ stream_name ] )
2017-05-25 02:08:35 +02:00
other_email = self . example_email ( " othello " )
2014-01-29 22:03:40 +01:00
# Fetch the subscriber list as a non-member.
self . login ( other_email )
self . make_successful_subscriber_request ( stream_name )
2017-11-05 10:51:25 +01:00
def test_subscriber_private_stream ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
A subscriber to a private stream can query that stream ' s membership.
"""
stream_name = " Saxony "
self . common_subscribe_to_streams ( self . email , [ stream_name ] ,
invite_only = True )
self . make_successful_subscriber_request ( stream_name )
2018-02-14 17:59:01 +01:00
stream_id = get_stream ( stream_name , self . user_profile . realm ) . id
# Verify another user can't get the data.
self . login ( self . example_email ( " cordelia " ) )
result = self . client_get ( " /json/streams/ %d /members " % ( stream_id , ) )
self . assert_json_error ( result , u ' Invalid stream id ' )
# But an organization administrator can
self . login ( self . example_email ( " iago " ) )
result = self . client_get ( " /json/streams/ %d /members " % ( stream_id , ) )
self . assert_json_success ( result )
2017-11-05 10:51:25 +01:00
def test_json_get_subscribers_stream_not_exist ( self ) - > None :
2016-07-16 18:50:41 +02:00
"""
json_get_subscribers also returns the list of subscribers for a stream .
"""
2016-12-30 11:42:59 +01:00
stream_id = 99999999
result = self . client_get ( " /json/streams/ %d /members " % ( stream_id , ) )
self . assert_json_error ( result , u ' Invalid stream id ' )
2016-07-16 18:50:41 +02:00
2017-11-05 10:51:25 +01:00
def test_json_get_subscribers ( self ) - > None :
2016-06-21 18:20:15 +02:00
"""
json_get_subscribers in zerver / views / streams . py
also returns the list of subscribers for a stream .
"""
stream_name = gather_subscriptions ( self . user_profile ) [ 0 ] [ 0 ] [ ' name ' ]
2017-01-13 15:50:17 +01:00
stream_id = get_stream ( stream_name , self . user_profile . realm ) . id
2016-06-21 18:20:15 +02:00
expected_subscribers = gather_subscriptions ( self . user_profile ) [ 0 ] [ 0 ] [ ' subscribers ' ]
2016-12-30 11:42:59 +01:00
result = self . client_get ( " /json/streams/ %d /members " % ( stream_id , ) )
2016-06-21 18:20:15 +02:00
self . assert_json_success ( result )
2017-08-17 08:45:20 +02:00
result_dict = result . json ( )
2016-06-21 18:20:15 +02:00
self . assertIn ( ' subscribers ' , result_dict )
self . assertIsInstance ( result_dict [ ' subscribers ' ] , list )
2018-05-11 01:39:38 +02:00
subscribers = [ ] # type: List[str]
2016-06-21 18:20:15 +02:00
for subscriber in result_dict [ ' subscribers ' ] :
2017-09-27 10:11:59 +02:00
self . assertIsInstance ( subscriber , str )
2016-06-21 18:20:15 +02:00
subscribers . append ( subscriber )
self . assertEqual ( set ( subscribers ) , set ( expected_subscribers ) )
2017-11-05 10:51:25 +01:00
def test_nonsubscriber_private_stream ( self ) - > None :
2014-01-29 22:03:40 +01:00
"""
2018-02-14 17:59:01 +01:00
A non - subscriber non realm admin user to a private stream can ' t query that stream ' s membership .
But unsubscribed realm admin users can query private stream ' s membership.
2014-01-29 22:03:40 +01:00
"""
# Create a private stream for which Hamlet is the only subscriber.
stream_name = " NewStream "
self . common_subscribe_to_streams ( self . email , [ stream_name ] ,
invite_only = True )
2017-05-07 21:25:59 +02:00
user_profile = self . example_user ( ' othello ' )
other_email = user_profile . email
2014-01-29 22:03:40 +01:00
2018-02-14 17:59:01 +01:00
# Try to fetch the subscriber list as a non-member & non-realm-admin-user.
2017-01-13 15:50:17 +01:00
stream_id = get_stream ( stream_name , user_profile . realm ) . id
2016-12-30 11:42:59 +01:00
result = self . make_subscriber_request ( stream_id , email = other_email )
2017-01-30 02:01:53 +01:00
self . assert_json_error ( result , " Invalid stream id " )
2017-01-30 00:48:45 +01:00
2018-02-14 17:59:01 +01:00
# Try to fetch the subscriber list as a non-member & realm-admin-user.
self . login ( self . example_email ( " iago " ) )
self . make_successful_subscriber_request ( stream_name )
2017-01-30 00:48:45 +01:00
class AccessStreamTest ( ZulipTestCase ) :
2017-11-05 10:51:25 +01:00
def test_access_stream ( self ) - > None :
2017-01-30 00:48:45 +01:00
"""
A comprehensive security test for the access_stream_by_ * API functions .
"""
# Create a private stream for which Hamlet is the only subscriber.
2017-05-07 21:25:59 +02:00
hamlet = self . example_user ( ' hamlet ' )
hamlet_email = hamlet . email
2017-01-30 00:48:45 +01:00
stream_name = " new_private_stream "
self . login ( hamlet_email )
self . common_subscribe_to_streams ( hamlet_email , [ stream_name ] ,
invite_only = True )
stream = get_stream ( stream_name , hamlet . realm )
2017-05-07 21:25:59 +02:00
othello = self . example_user ( ' othello ' )
2017-01-30 00:48:45 +01:00
# Nobody can access a stream that doesn't exist
with self . assertRaisesRegex ( JsonableError , " Invalid stream id " ) :
access_stream_by_id ( hamlet , 501232 )
with self . assertRaisesRegex ( JsonableError , " Invalid stream name ' invalid stream ' " ) :
access_stream_by_name ( hamlet , " invalid stream " )
# Hamlet can access the private stream
( stream_ret , rec_ret , sub_ret ) = access_stream_by_id ( hamlet , stream . id )
2017-09-17 19:53:38 +02:00
self . assertEqual ( stream . id , stream_ret . id )
2018-05-16 21:09:52 +02:00
assert sub_ret is not None
2017-01-30 00:48:45 +01:00
self . assertEqual ( sub_ret . recipient , rec_ret )
self . assertEqual ( sub_ret . recipient . type_id , stream . id )
( stream_ret2 , rec_ret2 , sub_ret2 ) = access_stream_by_name ( hamlet , stream . name )
2017-09-17 19:53:38 +02:00
self . assertEqual ( stream_ret . id , stream_ret2 . id )
2017-01-30 00:48:45 +01:00
self . assertEqual ( sub_ret , sub_ret2 )
self . assertEqual ( rec_ret , rec_ret2 )
# Othello cannot access the private stream
with self . assertRaisesRegex ( JsonableError , " Invalid stream id " ) :
access_stream_by_id ( othello , stream . id )
with self . assertRaisesRegex ( JsonableError , " Invalid stream name ' new_private_stream ' " ) :
access_stream_by_name ( othello , stream . name )
# Both Othello and Hamlet can access a public stream that only
# Hamlet is subscribed to in this realm
public_stream_name = " public_stream "
self . common_subscribe_to_streams ( hamlet_email , [ public_stream_name ] ,
invite_only = False )
public_stream = get_stream ( public_stream_name , hamlet . realm )
access_stream_by_id ( othello , public_stream . id )
access_stream_by_name ( othello , public_stream . name )
access_stream_by_id ( hamlet , public_stream . id )
access_stream_by_name ( hamlet , public_stream . name )
# Nobody can access a public stream in another realm
2017-03-04 09:19:37 +01:00
mit_realm = get_realm ( " zephyr " )
2018-03-21 22:05:21 +01:00
mit_stream = ensure_stream ( mit_realm , " mit_stream " , invite_only = False )
2017-05-23 01:27:31 +02:00
sipbtest = self . mit_user ( " sipbtest " )
2017-01-30 00:48:45 +01:00
with self . assertRaisesRegex ( JsonableError , " Invalid stream id " ) :
access_stream_by_id ( hamlet , mit_stream . id )
with self . assertRaisesRegex ( JsonableError , " Invalid stream name ' mit_stream ' " ) :
access_stream_by_name ( hamlet , mit_stream . name )
with self . assertRaisesRegex ( JsonableError , " Invalid stream id " ) :
access_stream_by_id ( sipbtest , stream . id )
with self . assertRaisesRegex ( JsonableError , " Invalid stream name ' new_private_stream ' " ) :
access_stream_by_name ( sipbtest , stream . name )
# MIT realm users cannot access even public streams in their realm
with self . assertRaisesRegex ( JsonableError , " Invalid stream id " ) :
access_stream_by_id ( sipbtest , mit_stream . id )
with self . assertRaisesRegex ( JsonableError , " Invalid stream name ' mit_stream ' " ) :
access_stream_by_name ( sipbtest , mit_stream . name )
# But they can access streams they are subscribed to
2017-08-26 00:58:13 +02:00
self . common_subscribe_to_streams ( sipbtest . email , [ mit_stream . name ] , subdomain = " zephyr " )
2017-01-30 00:48:45 +01:00
access_stream_by_id ( sipbtest , mit_stream . id )
access_stream_by_name ( sipbtest , mit_stream . name )
2018-05-02 17:00:06 +02:00
def test_stream_access_by_guest ( self ) - > None :
guest_user_profile = self . example_user ( ' polonius ' )
self . login ( guest_user_profile . email )
stream_name = " public_stream_1 "
stream = self . make_stream ( stream_name , guest_user_profile . realm , invite_only = False )
# Guest user don't have access to unsubscribed public streams
with self . assertRaisesRegex ( JsonableError , " Invalid stream id " ) :
access_stream_by_id ( guest_user_profile , stream . id )
# Guest user have access to subscribed public streams
self . subscribe ( guest_user_profile , stream_name )
( stream_ret , rec_ret , sub_ret ) = access_stream_by_id ( guest_user_profile , stream . id )
2018-05-16 21:09:52 +02:00
assert sub_ret is not None
2018-05-02 17:00:06 +02:00
self . assertEqual ( stream . id , stream_ret . id )
self . assertEqual ( sub_ret . recipient , rec_ret )
self . assertEqual ( sub_ret . recipient . type_id , stream . id )
stream_name = " private_stream_1 "
stream = self . make_stream ( stream_name , guest_user_profile . realm , invite_only = True )
# Obviously, a guest user doesn't have access to unsubscribed private streams either
with self . assertRaisesRegex ( JsonableError , " Invalid stream id " ) :
access_stream_by_id ( guest_user_profile , stream . id )
# Guest user have access to subscribed private streams
self . subscribe ( guest_user_profile , stream_name )
( stream_ret , rec_ret , sub_ret ) = access_stream_by_id ( guest_user_profile , stream . id )
2018-05-16 21:09:52 +02:00
assert sub_ret is not None
2018-05-02 17:00:06 +02:00
self . assertEqual ( stream . id , stream_ret . id )
self . assertEqual ( sub_ret . recipient , rec_ret )
self . assertEqual ( sub_ret . recipient . type_id , stream . id )
2018-06-20 23:03:03 +02:00
class StreamTrafficTest ( ZulipTestCase ) :
def test_average_weekly_stream_traffic_calculation ( self ) - > None :
# No traffic data for the stream
self . assertEqual (
get_average_weekly_stream_traffic ( 42 , timezone_now ( ) - timedelta ( days = 300 ) , { 1 : 4003 } ) , 0 )
# using high numbers here to make it more likely to catch small errors in the denominators
# of the calculations. That being said we don't want to go over 100, since then the 2
# significant digits calculation gets applied
# old stream
self . assertEqual (
get_average_weekly_stream_traffic ( 42 , timezone_now ( ) - timedelta ( days = 300 ) , { 42 : 98 * 4 + 3 } ) , 98 )
# stream between 7 and 27 days old
self . assertEqual (
get_average_weekly_stream_traffic ( 42 , timezone_now ( ) - timedelta ( days = 10 ) , { 42 : ( 98 * 10 + 9 ) / / 7 } ) , 98 )
# stream less than 7 days old
self . assertEqual (
2018-07-23 23:05:32 +02:00
get_average_weekly_stream_traffic ( 42 , timezone_now ( ) - timedelta ( days = 5 ) , { 42 : 100 } ) , None )
2018-06-20 23:03:03 +02:00
# average traffic between 0 and 1
self . assertEqual (
get_average_weekly_stream_traffic ( 42 , timezone_now ( ) - timedelta ( days = 300 ) , { 42 : 1 } ) , 1 )
def test_round_to_2_significant_digits ( self ) - > None :
self . assertEqual ( 120 , round_to_2_significant_digits ( 116 ) )