Skip to content

Commit ccfbbbe

Browse files
committed
streams: Handle adding/removing stream events.
1 parent db88a08 commit ccfbbbe

File tree

2 files changed

+287
-2
lines changed

2 files changed

+287
-2
lines changed

tests/model/test_model.py

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,48 @@ def model(self, mocker, initial_data, user_profile,
4646
model = Model(self.controller)
4747
return model
4848

49+
@pytest.fixture
50+
def initial_pinned_streams(self):
51+
return [{
52+
'name': 'test1',
53+
'id': 101,
54+
'color': '#9af',
55+
'invite_only': False,
56+
'description': 'lets test',
57+
'in_home_view': False
58+
}]
59+
60+
@pytest.fixture
61+
def initial_unpinned_streams(self):
62+
return [{
63+
'name': 'test2',
64+
'id': 100,
65+
'color': '#9af',
66+
'invite_only': False,
67+
'description': 'lets test'
68+
}]
69+
70+
@pytest.fixture
71+
def initial_stream_dict(self):
72+
return {
73+
101: {
74+
'name': 'test1',
75+
'id': 101,
76+
'color': '#9af',
77+
'invite_only': False,
78+
'description': 'lets test',
79+
'in_home_view': False
80+
},
81+
100: {
82+
'name': 'test2',
83+
'id': 100,
84+
'color': '#9af',
85+
'invite_only': False,
86+
'description': 'lets test',
87+
'in_home_view': False
88+
}
89+
}
90+
4991
def test_init(self, model, initial_data, user_profile,
5092
unicode_emojis, custom_emojis, stream_dict):
5193
assert hasattr(model, 'controller')
@@ -2100,6 +2142,213 @@ def test_fetch_custom_emojis(self, mocker, model, custom_emojis,
21002142

21012143
assert fetched_custom_emojis == custom_emojis
21022144

2145+
@pytest.mark.parametrize(['event', 'expected_pinned_streams',
2146+
'expected_unpinned_streams'], [
2147+
(
2148+
{
2149+
'op': 'add',
2150+
'type': 'subscription',
2151+
'subscriptions': [
2152+
{
2153+
'name': 'all',
2154+
'stream_id': 1,
2155+
'description': '',
2156+
'color': '#95a5fd',
2157+
'pin_to_top': False,
2158+
'invite_only': False,
2159+
'in_home_view': True
2160+
}
2161+
]
2162+
},
2163+
[{
2164+
'name': 'test1',
2165+
'id': 101,
2166+
'color': '#9af',
2167+
'invite_only': False,
2168+
'description': 'lets test',
2169+
'in_home_view': False
2170+
}],
2171+
[{
2172+
'name': 'all',
2173+
'id': 1,
2174+
'color': '#9af',
2175+
'invite_only': False,
2176+
'description': ''
2177+
},
2178+
{
2179+
'name': 'test2',
2180+
'id': 100,
2181+
'color': '#9af',
2182+
'invite_only': False,
2183+
'description': 'lets test'
2184+
}]
2185+
),
2186+
(
2187+
{
2188+
'op': 'add',
2189+
'type': 'subscription',
2190+
'subscriptions': [
2191+
{
2192+
'name': 'design',
2193+
'stream_id': 2,
2194+
'description': '',
2195+
'color': '#95a5fd',
2196+
'pin_to_top': True,
2197+
'invite_only': False,
2198+
'in_home_view': True
2199+
}
2200+
]
2201+
},
2202+
[{
2203+
'name': 'design',
2204+
'id': 2,
2205+
'color': '#9af',
2206+
'invite_only': False,
2207+
'description': ''
2208+
},
2209+
{
2210+
'name': 'test1',
2211+
'id': 101,
2212+
'color': '#9af',
2213+
'invite_only': False,
2214+
'description': 'lets test',
2215+
'in_home_view': False,
2216+
'invite_only': False
2217+
}],
2218+
[{
2219+
'name': 'test2',
2220+
'id': 100,
2221+
'color': '#9af',
2222+
'invite_only': False,
2223+
'description': 'lets test'
2224+
}]
2225+
),
2226+
(
2227+
{
2228+
'op': 'add',
2229+
'type': 'subscription',
2230+
'subscriptions': [
2231+
{
2232+
'name': 'all',
2233+
'stream_id': 3,
2234+
'description': '',
2235+
'color': '#95a5fd',
2236+
'pin_to_top': True,
2237+
'invite_only': False,
2238+
'in_home_view': False
2239+
}
2240+
]
2241+
},
2242+
[{
2243+
'name': 'all',
2244+
'id': 3,
2245+
'color': '#9af',
2246+
'invite_only': False,
2247+
'description': ''
2248+
},
2249+
{
2250+
'name': 'test1',
2251+
'id': 101,
2252+
'color': '#9af',
2253+
'invite_only': False,
2254+
'description': 'lets test',
2255+
'in_home_view': False
2256+
}],
2257+
[{
2258+
'name': 'test2',
2259+
'id': 100,
2260+
'color': '#9af',
2261+
'invite_only': False,
2262+
'description': 'lets test'
2263+
}]
2264+
)], ids=[
2265+
'add_1',
2266+
'add_and_pin_2',
2267+
'add_and_mute_3'
2268+
]
2269+
)
2270+
def test__handle_subscription_event_add_stream(
2271+
self, model, mocker,
2272+
event,
2273+
expected_pinned_streams,
2274+
expected_unpinned_streams,
2275+
initial_pinned_streams,
2276+
initial_unpinned_streams
2277+
):
2278+
2279+
model.pinned_streams = deepcopy(initial_pinned_streams)
2280+
model.unpinned_streams = deepcopy(initial_unpinned_streams)
2281+
model._handle_subscription_event(event)
2282+
2283+
assert model.pinned_streams == expected_pinned_streams
2284+
assert model.unpinned_streams == expected_unpinned_streams
2285+
2286+
(model.controller.view.left_panel.update_stream_view
2287+
.assert_called_once_with())
2288+
model.controller.update_screen.assert_called_once_with()
2289+
2290+
@pytest.mark.parametrize(['event', 'expected_pinned_streams',
2291+
'expected_unpinned_streams'], [
2292+
(
2293+
{
2294+
'op': 'remove',
2295+
'type': 'subscription',
2296+
'subscriptions': [{
2297+
'name': 'test1',
2298+
'stream_id': 101
2299+
}]
2300+
},
2301+
[],
2302+
[{
2303+
'name': 'test2',
2304+
'id': 100,
2305+
'color': '#9af',
2306+
'invite_only': False,
2307+
'description': 'lets test'
2308+
}]
2309+
),
2310+
(
2311+
{
2312+
'op': 'remove',
2313+
'type': 'subscription',
2314+
'subscriptions': [{
2315+
'name': 'test2',
2316+
'stream_id': 100
2317+
}]
2318+
},
2319+
[{
2320+
'name': 'test1',
2321+
'id': 101,
2322+
'color': '#9af',
2323+
'invite_only': False,
2324+
'description': 'lets test',
2325+
'in_home_view': False
2326+
}],
2327+
[]
2328+
)], ids=[
2329+
'remove_2',
2330+
'remove_4'
2331+
]
2332+
)
2333+
def test__handle_subscription_event_remove_stream(
2334+
self, model, mocker,
2335+
event,
2336+
expected_pinned_streams,
2337+
expected_unpinned_streams,
2338+
initial_pinned_streams,
2339+
initial_unpinned_streams,
2340+
initial_stream_dict
2341+
):
2342+
model.pinned_streams = deepcopy(initial_pinned_streams)
2343+
model.unpinned_streams = deepcopy(initial_unpinned_streams)
2344+
model.stream_dict = initial_stream_dict
2345+
model._handle_subscription_event(event)
2346+
assert model.pinned_streams == expected_pinned_streams
2347+
assert model.unpinned_streams == expected_unpinned_streams
2348+
update_left_panel = model.controller.view.left_panel.update_stream_view
2349+
update_left_panel.assert_called_once_with()
2350+
model.controller.update_screen.assert_called_once_with()
2351+
21032352
# Use LoopEnder with raising_event to cause the event loop to end without
21042353
# processing the event
21052354
class LoopEnder(Exception):

zulipterminal/model.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -824,13 +824,41 @@ def _get_stream_by_id(self, streams: List[StreamData], stream_id: int
824824
return stream
825825
raise RuntimeError("Invalid stream id.")
826826

827+
def _unsubscribe_to_streams(self,
828+
stream_info_list: List[Subscription]) -> None:
829+
is_pinned_stream_removed = False
830+
is_unpinned_stream_removed = False
831+
for stream_info in stream_info_list:
832+
stream_id = stream_info['stream_id']
833+
if self.is_stream_in_list(stream_id, self.pinned_streams):
834+
stream = self._get_stream_by_id(self.pinned_streams,
835+
stream_id)
836+
self.pinned_streams.remove(stream)
837+
is_pinned_stream_removed = True
838+
else:
839+
stream = self._get_stream_by_id(self.unpinned_streams,
840+
stream_id)
841+
self.unpinned_streams.remove(stream)
842+
is_unpinned_stream_removed = True
843+
if stream_id in self.muted_streams:
844+
self.muted_streams.remove(stream_id)
845+
846+
if is_pinned_stream_removed:
847+
sort_streams(self.pinned_streams)
848+
if is_unpinned_stream_removed:
849+
sort_streams(self.unpinned_streams)
850+
827851
def _handle_subscription_event(self, event: Event) -> None:
828852
"""
829853
Handle changes in subscription (eg. muting/unmuting,
830854
pinning/unpinning streams)
831855
"""
832856
assert event['type'] == "subscription"
833857

858+
def _update_sidebar() -> None:
859+
self.controller.view.left_panel.update_stream_view()
860+
self.controller.update_screen()
861+
834862
if event['op'] == 'update':
835863
if hasattr(self.controller, 'view'):
836864
if event.get('property', None) == 'in_home_view':
@@ -873,8 +901,16 @@ def _handle_subscription_event(self, event: Event) -> None:
873901
self.unpinned_streams.append(stream)
874902
sort_streams(self.unpinned_streams)
875903
sort_streams(self.pinned_streams)
876-
self.controller.view.left_panel.update_stream_view()
877-
self.controller.update_screen()
904+
_update_sidebar()
905+
906+
elif event['op'] == 'add':
907+
self._subscribe_to_streams(event['subscriptions'])
908+
_update_sidebar()
909+
910+
elif event['op'] == 'remove':
911+
self._unsubscribe_to_streams(event['subscriptions'])
912+
_update_sidebar()
913+
878914
elif event['op'] in ('peer_add', 'peer_remove'):
879915
# NOTE: ZFL 35 commit was not atomic with API change
880916
# (ZFL >=35 can use new plural style)

0 commit comments

Comments
 (0)