Skip to content

Commit b860aa3

Browse files
Merge branch 'zulip:main' into stream-channel
2 parents c652751 + fa3c6e1 commit b860aa3

File tree

4 files changed

+402
-3
lines changed

4 files changed

+402
-3
lines changed

.github/workflows/lint-and-test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ jobs:
170170
gitlint --commits FETCH_HEAD..${{ github.event.pull_request.head.sha }}
171171

172172
base_pytest:
173-
runs-on: ubuntu-latest
173+
runs-on: ubuntu-22.04
174174
name: Install & test - CPython 3.7 (ubuntu), codecov
175175
steps:
176176
- uses: actions/checkout@v4

tests/widget/test_widget.py

+321-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
import pytest
44
from pytest import param as case
55

6-
from zulipterminal.widget import Submessage, find_widget_type, process_todo_widget
6+
from zulipterminal.widget import (
7+
Submessage,
8+
find_widget_type,
9+
process_poll_widget,
10+
process_todo_widget,
11+
)
712

813

914
@pytest.mark.parametrize(
@@ -343,3 +348,318 @@ def test_process_todo_widget(
343348

344349
assert title == expected_title
345350
assert tasks == expected_tasks
351+
352+
353+
@pytest.mark.parametrize(
354+
"submessages, expected_poll_question, expected_options",
355+
[
356+
case(
357+
[
358+
{
359+
"id": 12082,
360+
"message_id": 1957499,
361+
"sender_id": 27294,
362+
"msg_type": "widget",
363+
"content": (
364+
'{"widget_type": "poll", "extra_data": {'
365+
'"question": "Do polls work on ZT?", "options": ["Yes", "No"]}}'
366+
),
367+
},
368+
{
369+
"id": 12083,
370+
"message_id": 1957499,
371+
"sender_id": 27294,
372+
"msg_type": "widget",
373+
"content": '{"type":"vote","key":"canned,0","vote":1}',
374+
},
375+
{
376+
"id": 12084,
377+
"message_id": 1957499,
378+
"sender_id": 27294,
379+
"msg_type": "widget",
380+
"content": '{"type":"vote","key":"canned,0","vote":-1}',
381+
},
382+
{
383+
"id": 12085,
384+
"message_id": 1957499,
385+
"sender_id": 27294,
386+
"msg_type": "widget",
387+
"content": '{"type":"vote","key":"canned,1","vote":1}',
388+
},
389+
{
390+
"id": 12086,
391+
"message_id": 1957499,
392+
"sender_id": 27294,
393+
"msg_type": "widget",
394+
"content": '{"type":"vote","key":"canned,0","vote":1}',
395+
},
396+
{
397+
"id": 12087,
398+
"message_id": 1957499,
399+
"sender_id": 27294,
400+
"msg_type": "widget",
401+
"content": '{"type":"vote","key":"canned,1","vote":-1}',
402+
},
403+
],
404+
"Do polls work on ZT?",
405+
{
406+
"canned,0": {"option": "Yes", "votes": [27294]},
407+
"canned,1": {"option": "No", "votes": []},
408+
},
409+
id="multiple_vote_events",
410+
),
411+
case(
412+
[
413+
{
414+
"id": 12089,
415+
"message_id": 1957662,
416+
"sender_id": 27294,
417+
"msg_type": "widget",
418+
"content": (
419+
'{"widget_type": "poll", "extra_data": {"question": "Is '
420+
'this a poll with options added later?", '
421+
'"options": ["Yes", "No"]}}'
422+
),
423+
},
424+
{
425+
"id": 12090,
426+
"message_id": 1957662,
427+
"sender_id": 27294,
428+
"msg_type": "widget",
429+
"content": '{"type":"new_option","idx":1,"option":"Maybe"}',
430+
},
431+
{
432+
"id": 12091,
433+
"message_id": 1957662,
434+
"sender_id": 27294,
435+
"msg_type": "widget",
436+
"content": '{"type":"vote","key":"canned,1","vote":1}',
437+
},
438+
{
439+
"id": 12092,
440+
"message_id": 1957662,
441+
"sender_id": 27294,
442+
"msg_type": "widget",
443+
"content": '{"type":"vote","key":"canned,1","vote":-1}',
444+
},
445+
{
446+
"id": 12093,
447+
"message_id": 1957662,
448+
"sender_id": 27294,
449+
"msg_type": "widget",
450+
"content": '{"type":"vote","key":"27294,1","vote":1}',
451+
},
452+
{
453+
"id": 12094,
454+
"message_id": 1957662,
455+
"sender_id": 27294,
456+
"msg_type": "widget",
457+
"content": '{"type":"vote","key":"canned,0","vote":1}',
458+
},
459+
],
460+
"Is this a poll with options added later?",
461+
{
462+
"canned,0": {"option": "Yes", "votes": [27294]},
463+
"canned,1": {"option": "No", "votes": []},
464+
"27294,1": {"option": "Maybe", "votes": [27294]},
465+
},
466+
id="new_option_and_votes",
467+
),
468+
case(
469+
[
470+
{
471+
"id": 12095,
472+
"message_id": 1957682,
473+
"sender_id": 27294,
474+
"msg_type": "widget",
475+
"content": (
476+
'{"widget_type": "poll", "extra_data": {"question": '
477+
'"Let\'s change this question later?", "options": ["Yes"]}}'
478+
),
479+
},
480+
{
481+
"id": 12096,
482+
"message_id": 1957682,
483+
"sender_id": 27294,
484+
"msg_type": "widget",
485+
"content": '{"type":"vote","key":"canned,0","vote":1}',
486+
},
487+
{
488+
"id": 12097,
489+
"message_id": 1957682,
490+
"sender_id": 27294,
491+
"msg_type": "widget",
492+
"content": '{"type":"new_option","idx":1,"option":"No"}',
493+
},
494+
{
495+
"id": 12098,
496+
"message_id": 1957682,
497+
"sender_id": 27294,
498+
"msg_type": "widget",
499+
"content": '{"type":"vote","key":"canned,0","vote":-1}',
500+
},
501+
{
502+
"id": 12099,
503+
"message_id": 1957682,
504+
"sender_id": 27294,
505+
"msg_type": "widget",
506+
"content": '{"type":"question",'
507+
'"question":"Has this question stayed the same?"}',
508+
},
509+
{
510+
"id": 12100,
511+
"message_id": 1957682,
512+
"sender_id": 27294,
513+
"msg_type": "widget",
514+
"content": '{"type":"vote","key":"27294,1","vote":1}',
515+
},
516+
],
517+
"Has this question stayed the same?",
518+
{
519+
"canned,0": {"option": "Yes", "votes": []},
520+
"27294,1": {"option": "No", "votes": [27294]},
521+
},
522+
id="new_question_and_votes",
523+
),
524+
case(
525+
[
526+
{
527+
"id": 12101,
528+
"message_id": 1957693,
529+
"sender_id": 27294,
530+
"msg_type": "widget",
531+
"content": (
532+
'{"widget_type": "poll", "extra_data": {"question": "",'
533+
' "options": ["Yes", "No"]}}'
534+
),
535+
}
536+
],
537+
"",
538+
{
539+
"canned,0": {"option": "Yes", "votes": []},
540+
"canned,1": {"option": "No", "votes": []},
541+
},
542+
id="empty_question",
543+
),
544+
case(
545+
[
546+
{
547+
"id": 12102,
548+
"message_id": 1957700,
549+
"sender_id": 27294,
550+
"msg_type": "widget",
551+
"content": (
552+
'{"widget_type": "poll", "extra_data": {'
553+
'"question": "Does this poll have options?", "options": []}}'
554+
),
555+
}
556+
],
557+
"Does this poll have options?",
558+
{},
559+
id="empty_options",
560+
),
561+
case(
562+
[
563+
{
564+
"id": 12112,
565+
"message_id": 1957722,
566+
"sender_id": 27294,
567+
"msg_type": "widget",
568+
"content": (
569+
'{"widget_type": "poll", "extra_data": {"question": "",'
570+
' "options": []}}'
571+
),
572+
}
573+
],
574+
"",
575+
{},
576+
id="empty_question_and_options",
577+
),
578+
case(
579+
[
580+
{
581+
"id": 12103,
582+
"message_id": 1957719,
583+
"sender_id": 27294,
584+
"msg_type": "widget",
585+
"content": (
586+
'{"widget_type": "poll", "extra_data": {"question": "Does'
587+
' this poll have multiple voters?", "options": ["Yes", "No"]}}'
588+
),
589+
},
590+
{
591+
"id": 12104,
592+
"message_id": 1957719,
593+
"sender_id": 27294,
594+
"msg_type": "widget",
595+
"content": '{"type":"vote","key":"canned,0","vote":1}',
596+
},
597+
{
598+
"id": 12105,
599+
"message_id": 1957719,
600+
"sender_id": 27294,
601+
"msg_type": "widget",
602+
"content": '{"type":"vote","key":"canned,1","vote":1}',
603+
},
604+
{
605+
"id": 12106,
606+
"message_id": 1957719,
607+
"sender_id": 27294,
608+
"msg_type": "widget",
609+
"content": '{"type":"vote","key":"canned,0","vote":-1}',
610+
},
611+
{
612+
"id": 12107,
613+
"message_id": 1957719,
614+
"sender_id": 32159,
615+
"msg_type": "widget",
616+
"content": '{"type":"new_option","idx":1,"option":"Maybe"}',
617+
},
618+
{
619+
"id": 12108,
620+
"message_id": 1957719,
621+
"sender_id": 32159,
622+
"msg_type": "widget",
623+
"content": '{"type":"vote","key":"32159,1","vote":1}',
624+
},
625+
{
626+
"id": 12109,
627+
"message_id": 1957719,
628+
"sender_id": 32159,
629+
"msg_type": "widget",
630+
"content": '{"type":"vote","key":"canned,0","vote":1}',
631+
},
632+
{
633+
"id": 12110,
634+
"message_id": 1957719,
635+
"sender_id": 27294,
636+
"msg_type": "widget",
637+
"content": '{"type":"vote","key":"canned,1","vote":-1}',
638+
},
639+
{
640+
"id": 12111,
641+
"message_id": 1957719,
642+
"sender_id": 27294,
643+
"msg_type": "widget",
644+
"content": '{"type":"vote","key":"canned,0","vote":1}',
645+
},
646+
],
647+
"Does this poll have multiple voters?",
648+
{
649+
"canned,0": {"option": "Yes", "votes": [32159, 27294]},
650+
"canned,1": {"option": "No", "votes": []},
651+
"32159,1": {"option": "Maybe", "votes": [32159]},
652+
},
653+
id="multiple_voters",
654+
),
655+
],
656+
)
657+
def test_process_poll_widget(
658+
submessages: List[Submessage],
659+
expected_poll_question: str,
660+
expected_options: Dict[str, Dict[str, Union[str, List[str]]]],
661+
) -> None:
662+
poll_question, options = process_poll_widget(submessages)
663+
664+
assert poll_question == expected_poll_question
665+
assert options == expected_options

zulipterminal/ui_tools/messages.py

+38-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@
3333
from zulipterminal.server_url import near_message_url
3434
from zulipterminal.ui_tools.tables import render_table
3535
from zulipterminal.urwid_types import urwid_MarkupTuple, urwid_Size
36-
from zulipterminal.widget import find_widget_type, process_todo_widget
36+
from zulipterminal.widget import (
37+
find_widget_type,
38+
process_poll_widget,
39+
process_todo_widget,
40+
)
3741

3842

3943
if typing.TYPE_CHECKING:
@@ -753,6 +757,39 @@ def main_view(self) -> List[Any]:
753757
# though it's not very useful.
754758
self.message["content"] = todo_widget
755759

760+
elif widget_type == "poll":
761+
poll_question, poll_options = process_poll_widget(
762+
self.message.get("submessages", [])
763+
)
764+
765+
# TODO: ZT doesn't yet support adding poll questions after the
766+
# creation of the poll. So, if the poll question is not provided,
767+
# we show a message to add one via the web app.
768+
if not poll_question:
769+
poll_question = (
770+
"No poll question is provided. Please add one via the web app."
771+
)
772+
773+
poll_widget = f"<strong>Poll\n{poll_question}</strong>"
774+
775+
if poll_options:
776+
max_votes_len = max(
777+
len(str(len(option["votes"])))
778+
for option in poll_options.values()
779+
)
780+
781+
for option_info in poll_options.values():
782+
padded_votes = f"{len(option_info['votes']):>{max_votes_len}}"
783+
poll_widget += f"\n[ {padded_votes} ] {option_info['option']}"
784+
else:
785+
poll_widget += (
786+
"\nNo options provided. Please add them via the web app."
787+
)
788+
789+
# Update the message content with the latest poll_widget,
790+
# similar to the todo_widget above.
791+
self.message["content"] = poll_widget
792+
756793
# Transform raw message content into markup (As needed by urwid.Text)
757794
content, self.message_links, self.time_mentions = self.transform_content(
758795
self.message["content"], self.model.server_url

0 commit comments

Comments
 (0)