Skip to content

Commit 745f372

Browse files
committed
widget: Add process_poll_widget function.
Added process_poll_widget function to process submessages containing a poll widget. Returns the question of the poll along with options and their voters in a dict.
1 parent d6f0cbf commit 745f372

File tree

2 files changed

+349
-3
lines changed

2 files changed

+349
-3
lines changed

tests/widget/test_widget.py

Lines changed: 303 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
from typing import Any
1+
from typing import Any, Dict, List
22

33
import pytest
44
from pytest import param as case
55

6-
from zulipterminal.widget import find_widget_type
6+
from zulipterminal.widget import find_widget_type, process_poll_widget
77

88

99
@pytest.mark.parametrize(
@@ -58,3 +58,304 @@ def test_find_widget_type(submessage: Any, expected_widget_type: str) -> None:
5858
widget_type = find_widget_type(submessage)
5959

6060
assert widget_type == expected_widget_type
61+
62+
63+
@pytest.mark.parametrize(
64+
"submessage, expected_poll_question, expected_options",
65+
[
66+
case(
67+
[
68+
{
69+
"id": 12082,
70+
"message_id": 1957499,
71+
"sender_id": 27294,
72+
"msg_type": "widget",
73+
"content": '{"widget_type": "poll", "extra_data": '
74+
'{"question": "Do polls work on ZT?", "options": ["Yes", "No"]}}',
75+
},
76+
{
77+
"id": 12083,
78+
"message_id": 1957499,
79+
"sender_id": 27294,
80+
"msg_type": "widget",
81+
"content": '{"type":"vote","key":"canned,0","vote":1}',
82+
},
83+
{
84+
"id": 12084,
85+
"message_id": 1957499,
86+
"sender_id": 27294,
87+
"msg_type": "widget",
88+
"content": '{"type":"vote","key":"canned,0","vote":-1}',
89+
},
90+
{
91+
"id": 12085,
92+
"message_id": 1957499,
93+
"sender_id": 27294,
94+
"msg_type": "widget",
95+
"content": '{"type":"vote","key":"canned,1","vote":1}',
96+
},
97+
{
98+
"id": 12086,
99+
"message_id": 1957499,
100+
"sender_id": 27294,
101+
"msg_type": "widget",
102+
"content": '{"type":"vote","key":"canned,0","vote":1}',
103+
},
104+
{
105+
"id": 12087,
106+
"message_id": 1957499,
107+
"sender_id": 27294,
108+
"msg_type": "widget",
109+
"content": '{"type":"vote","key":"canned,1","vote":-1}',
110+
},
111+
],
112+
"Do polls work on ZT?",
113+
{
114+
"canned,0": {"option": "Yes", "votes": [27294]},
115+
"canned,1": {"option": "No", "votes": []},
116+
},
117+
id="poll_widget_with_votes",
118+
),
119+
case(
120+
[
121+
{
122+
"id": 12089,
123+
"message_id": 1957662,
124+
"sender_id": 27294,
125+
"msg_type": "widget",
126+
"content": '{"widget_type": "poll", "extra_data": {"question": "Is '
127+
'this a poll with options added later?", '
128+
'"options": ["Yes", "No"]}}',
129+
},
130+
{
131+
"id": 12090,
132+
"message_id": 1957662,
133+
"sender_id": 27294,
134+
"msg_type": "widget",
135+
"content": '{"type":"new_option","idx":1,"option":"Maybe"}',
136+
},
137+
{
138+
"id": 12091,
139+
"message_id": 1957662,
140+
"sender_id": 27294,
141+
"msg_type": "widget",
142+
"content": '{"type":"vote","key":"canned,1","vote":1}',
143+
},
144+
{
145+
"id": 12092,
146+
"message_id": 1957662,
147+
"sender_id": 27294,
148+
"msg_type": "widget",
149+
"content": '{"type":"vote","key":"canned,1","vote":-1}',
150+
},
151+
{
152+
"id": 12093,
153+
"message_id": 1957662,
154+
"sender_id": 27294,
155+
"msg_type": "widget",
156+
"content": '{"type":"vote","key":"27294,1","vote":1}',
157+
},
158+
{
159+
"id": 12094,
160+
"message_id": 1957662,
161+
"sender_id": 27294,
162+
"msg_type": "widget",
163+
"content": '{"type":"vote","key":"canned,0","vote":1}',
164+
},
165+
],
166+
"Is this a poll with options added later?",
167+
{
168+
"canned,0": {"option": "Yes", "votes": [27294]},
169+
"canned,1": {"option": "No", "votes": []},
170+
"27294,1": {"option": "Maybe", "votes": [27294]},
171+
},
172+
id="poll_widget_with_new_option_and_votes",
173+
),
174+
case(
175+
[
176+
{
177+
"id": 12095,
178+
"message_id": 1957682,
179+
"sender_id": 27294,
180+
"msg_type": "widget",
181+
"content": '{"widget_type": "poll", "extra_data": {"question": '
182+
'"Let\'s change this question later?", "options": ["Yes"]}}',
183+
},
184+
{
185+
"id": 12096,
186+
"message_id": 1957682,
187+
"sender_id": 27294,
188+
"msg_type": "widget",
189+
"content": '{"type":"vote","key":"canned,0","vote":1}',
190+
},
191+
{
192+
"id": 12097,
193+
"message_id": 1957682,
194+
"sender_id": 27294,
195+
"msg_type": "widget",
196+
"content": '{"type":"new_option","idx":1,"option":"No"}',
197+
},
198+
{
199+
"id": 12098,
200+
"message_id": 1957682,
201+
"sender_id": 27294,
202+
"msg_type": "widget",
203+
"content": '{"type":"vote","key":"canned,0","vote":-1}',
204+
},
205+
{
206+
"id": 12099,
207+
"message_id": 1957682,
208+
"sender_id": 27294,
209+
"msg_type": "widget",
210+
"content": '{"type":"question",'
211+
'"question":"Has this question stayed the same?"}',
212+
},
213+
{
214+
"id": 12100,
215+
"message_id": 1957682,
216+
"sender_id": 27294,
217+
"msg_type": "widget",
218+
"content": '{"type":"vote","key":"27294,1","vote":1}',
219+
},
220+
],
221+
"Has this question stayed the same?",
222+
{
223+
"canned,0": {"option": "Yes", "votes": []},
224+
"27294,1": {"option": "No", "votes": [27294]},
225+
},
226+
id="poll_widget_with_new_question_and_votes",
227+
),
228+
case(
229+
[
230+
{
231+
"id": 12101,
232+
"message_id": 1957693,
233+
"sender_id": 27294,
234+
"msg_type": "widget",
235+
"content": '{"widget_type": "poll", "extra_data": {"question": "",'
236+
' "options": ["Yes", "No"]}}',
237+
}
238+
],
239+
"",
240+
{
241+
"canned,0": {"option": "Yes", "votes": []},
242+
"canned,1": {"option": "No", "votes": []},
243+
},
244+
id="poll_widget_with_empty_question",
245+
),
246+
case(
247+
[
248+
{
249+
"id": 12102,
250+
"message_id": 1957700,
251+
"sender_id": 27294,
252+
"msg_type": "widget",
253+
"content": '{"widget_type": "poll", "extra_data": {'
254+
'"question": "Does this poll have options?", "options": []}}',
255+
}
256+
],
257+
"Does this poll have options?",
258+
{},
259+
id="poll_widget_with_empty_options",
260+
),
261+
case(
262+
[
263+
{
264+
"id": 12112,
265+
"message_id": 1957722,
266+
"sender_id": 27294,
267+
"msg_type": "widget",
268+
"content": '{"widget_type": "poll", "extra_data": {"question": "",'
269+
' "options": []}}',
270+
}
271+
],
272+
"",
273+
{},
274+
id="poll_widget_with_empty_question_and_options",
275+
),
276+
case(
277+
[
278+
{
279+
"id": 12103,
280+
"message_id": 1957719,
281+
"sender_id": 27294,
282+
"msg_type": "widget",
283+
"content": '{"widget_type": "poll", "extra_data": {"question": "'
284+
'Does this poll have multiple voters?", "options": ["Yes", "No"]}}',
285+
},
286+
{
287+
"id": 12104,
288+
"message_id": 1957719,
289+
"sender_id": 27294,
290+
"msg_type": "widget",
291+
"content": '{"type":"vote","key":"canned,0","vote":1}',
292+
},
293+
{
294+
"id": 12105,
295+
"message_id": 1957719,
296+
"sender_id": 27294,
297+
"msg_type": "widget",
298+
"content": '{"type":"vote","key":"canned,1","vote":1}',
299+
},
300+
{
301+
"id": 12106,
302+
"message_id": 1957719,
303+
"sender_id": 27294,
304+
"msg_type": "widget",
305+
"content": '{"type":"vote","key":"canned,0","vote":-1}',
306+
},
307+
{
308+
"id": 12107,
309+
"message_id": 1957719,
310+
"sender_id": 32159,
311+
"msg_type": "widget",
312+
"content": '{"type":"new_option","idx":1,"option":"Maybe"}',
313+
},
314+
{
315+
"id": 12108,
316+
"message_id": 1957719,
317+
"sender_id": 32159,
318+
"msg_type": "widget",
319+
"content": '{"type":"vote","key":"32159,1","vote":1}',
320+
},
321+
{
322+
"id": 12109,
323+
"message_id": 1957719,
324+
"sender_id": 32159,
325+
"msg_type": "widget",
326+
"content": '{"type":"vote","key":"canned,0","vote":1}',
327+
},
328+
{
329+
"id": 12110,
330+
"message_id": 1957719,
331+
"sender_id": 27294,
332+
"msg_type": "widget",
333+
"content": '{"type":"vote","key":"canned,1","vote":-1}',
334+
},
335+
{
336+
"id": 12111,
337+
"message_id": 1957719,
338+
"sender_id": 27294,
339+
"msg_type": "widget",
340+
"content": '{"type":"vote","key":"canned,0","vote":1}',
341+
},
342+
],
343+
"Does this poll have multiple voters?",
344+
{
345+
"canned,0": {"option": "Yes", "votes": [32159, 27294]},
346+
"canned,1": {"option": "No", "votes": []},
347+
"32159,1": {"option": "Maybe", "votes": [32159]},
348+
},
349+
id="poll_widget_with_multiple_voters",
350+
),
351+
],
352+
)
353+
def test_process_poll_widget(
354+
submessage: List[Dict[str, Any]],
355+
expected_poll_question: str,
356+
expected_options: Dict[str, Dict[str, Any]],
357+
) -> None:
358+
poll_question, options = process_poll_widget(submessage)
359+
360+
assert poll_question == expected_poll_question
361+
assert options == expected_options

zulipterminal/widget.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"""
44

55
import json
6-
from typing import Any
6+
from typing import Any, Dict, List, Optional, Tuple
77

88

99
def find_widget_type(submessage: Any) -> str:
@@ -15,3 +15,48 @@ def find_widget_type(submessage: Any) -> str:
1515
return "unknown"
1616
else:
1717
return "unknown"
18+
19+
20+
def process_poll_widget(
21+
poll_content: Optional[List[Dict[str, Any]]]
22+
) -> Tuple[str, Dict[str, Dict[str, Any]]]:
23+
if poll_content is None:
24+
return "", {}
25+
26+
poll_question = ""
27+
options = {}
28+
29+
for entry in poll_content:
30+
content = entry["content"]
31+
sender_id = entry["sender_id"]
32+
msg_type = entry["msg_type"]
33+
34+
if msg_type == "widget":
35+
widget = json.loads(content)
36+
37+
if widget.get("widget_type") == "poll":
38+
poll_question = widget["extra_data"]["question"]
39+
for i, option in enumerate(widget["extra_data"]["options"]):
40+
option_id = f"canned,{i}"
41+
options[option_id] = {"option": option, "votes": []}
42+
43+
elif widget.get("type") == "question":
44+
poll_question = widget["question"]
45+
46+
elif widget.get("type") == "vote":
47+
option_id = widget["key"]
48+
vote_type = widget["vote"]
49+
50+
if option_id in options:
51+
if vote_type == 1 and sender_id not in options[option_id]["votes"]:
52+
options[option_id]["votes"].append(sender_id)
53+
elif vote_type == -1 and sender_id in options[option_id]["votes"]:
54+
options[option_id]["votes"].remove(sender_id)
55+
56+
elif widget.get("type") == "new_option":
57+
idx = widget["idx"]
58+
new_option = widget["option"]
59+
option_id = f"{sender_id},{idx}"
60+
options[option_id] = {"option": new_option, "votes": []}
61+
62+
return poll_question, options

0 commit comments

Comments
 (0)