Skip to content

Commit fdadfa0

Browse files
committed
widget: Add process_todo_widget function.
Added process_todo_widget function to process submessages containing a todo widget. Returns the title of the widget along with tasks and their state (completed/uncompleted) as a dict. Tests added.
1 parent 6bd973b commit fdadfa0

File tree

2 files changed

+259
-3
lines changed

2 files changed

+259
-3
lines changed

tests/widget/test_widget.py

Lines changed: 212 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
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_todo_widget
77

88

99
@pytest.mark.parametrize(
@@ -58,3 +58,213 @@ 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_title, expected_tasks",
65+
[
66+
case(
67+
[
68+
{
69+
"id": 11899,
70+
"message_id": 1954463,
71+
"sender_id": 27294,
72+
"msg_type": "widget",
73+
"content": '{"widget_type": "todo", "extra_data": '
74+
'{"task_list_title": "Today\'s Tasks", "tasks": [{"task": '
75+
'"Write code", "desc": ""}, {"task": "Sleep", "desc": ""}]}}',
76+
},
77+
{
78+
"id": 11900,
79+
"message_id": 1954463,
80+
"sender_id": 27294,
81+
"msg_type": "widget",
82+
"content": '{"type":"new_task","key":2,"task":"Eat","desc":"",'
83+
'"completed":false}',
84+
},
85+
],
86+
"Today's Tasks",
87+
{
88+
"0,canned": {"task": "Write code", "desc": "", "completed": False},
89+
"1,canned": {"task": "Sleep", "desc": "", "completed": False},
90+
"2,27294": {"task": "Eat", "desc": "", "completed": False},
91+
},
92+
id="todo_with_title_and_unfinished_tasks",
93+
),
94+
case(
95+
[
96+
{
97+
"id": 11912,
98+
"message_id": 1954626,
99+
"sender_id": 27294,
100+
"msg_type": "widget",
101+
"content": '{"widget_type": "todo", "extra_data": '
102+
'{"task_list_title": "", "tasks": [{"task": "Hey", "desc": ""}, '
103+
'{"task": "Hi", "desc": ""}]}}',
104+
}
105+
],
106+
"Task list",
107+
{
108+
"0,canned": {"task": "Hey", "desc": "", "completed": False},
109+
"1,canned": {"task": "Hi", "desc": "", "completed": False},
110+
},
111+
id="todo_without_title_and_unfinished_tasks",
112+
),
113+
case(
114+
[
115+
{
116+
"id": 11919,
117+
"message_id": 1954843,
118+
"sender_id": 27294,
119+
"msg_type": "widget",
120+
"content": '{"widget_type": "todo", "extra_data": '
121+
'{"task_list_title": "", "tasks": []}}',
122+
}
123+
],
124+
"Task list",
125+
{},
126+
id="todo_without_title_or_tasks",
127+
),
128+
case(
129+
[
130+
{
131+
"id": 11932,
132+
"message_id": 1954847,
133+
"sender_id": 27294,
134+
"msg_type": "widget",
135+
"content": '{"widget_type": "todo", "extra_data": '
136+
'{"task_list_title": "", "tasks": []}}',
137+
},
138+
{
139+
"id": 11933,
140+
"message_id": 1954847,
141+
"sender_id": 27294,
142+
"msg_type": "widget",
143+
"content": '{"type":"new_task","key":2,"task":"Write code",'
144+
'"desc":"Make the todo ZT PR!","completed":false}',
145+
},
146+
{
147+
"id": 11934,
148+
"message_id": 1954847,
149+
"sender_id": 27294,
150+
"msg_type": "widget",
151+
"content": '{"type":"new_task","key":4,"task":"Sleep",'
152+
'"desc":"at least 8 hours a day","completed":false}',
153+
},
154+
{
155+
"id": 11935,
156+
"message_id": 1954847,
157+
"sender_id": 27294,
158+
"msg_type": "widget",
159+
"content": '{"type":"new_task","key":6,"task":"Eat",'
160+
'"desc":"3 meals a day","completed":false}',
161+
},
162+
{
163+
"id": 11936,
164+
"message_id": 1954847,
165+
"sender_id": 27294,
166+
"msg_type": "widget",
167+
"content": '{"type":"new_task","key":8,"task":"Exercise",'
168+
'"desc":"an hour a day","completed":false}',
169+
},
170+
{
171+
"id": 11937,
172+
"message_id": 1954847,
173+
"sender_id": 27294,
174+
"msg_type": "widget",
175+
"content": '{"type":"strike","key":"2,27294"}',
176+
},
177+
{
178+
"id": 11938,
179+
"message_id": 1954847,
180+
"sender_id": 27294,
181+
"msg_type": "widget",
182+
"content": '{"type":"strike","key":"2,27294"}',
183+
},
184+
{
185+
"id": 11939,
186+
"message_id": 1954847,
187+
"sender_id": 27294,
188+
"msg_type": "widget",
189+
"content": '{"type":"strike","key":"4,27294"}',
190+
},
191+
{
192+
"id": 11940,
193+
"message_id": 1954847,
194+
"sender_id": 27294,
195+
"msg_type": "widget",
196+
"content": '{"type":"strike","key":"6,27294"}',
197+
},
198+
{
199+
"id": 11941,
200+
"message_id": 1954847,
201+
"sender_id": 27294,
202+
"msg_type": "widget",
203+
"content": '{"type":"strike","key":"8,27294"}',
204+
},
205+
{
206+
"id": 11942,
207+
"message_id": 1954847,
208+
"sender_id": 27294,
209+
"msg_type": "widget",
210+
"content": '{"type":"strike","key":"2,27294"}',
211+
},
212+
{
213+
"id": 11943,
214+
"message_id": 1954847,
215+
"sender_id": 27294,
216+
"msg_type": "widget",
217+
"content": '{"type":"strike","key":"4,27294"}',
218+
},
219+
{
220+
"id": 11944,
221+
"message_id": 1954847,
222+
"sender_id": 27294,
223+
"msg_type": "widget",
224+
"content": '{"type":"strike","key":"6,27294"}',
225+
},
226+
{
227+
"id": 11945,
228+
"message_id": 1954847,
229+
"sender_id": 27294,
230+
"msg_type": "widget",
231+
"content": '{"type":"strike","key":"4,27294"}',
232+
},
233+
{
234+
"id": 11946,
235+
"message_id": 1954847,
236+
"sender_id": 27294,
237+
"msg_type": "widget",
238+
"content": '{"type":"strike","key":"8,27294"}',
239+
},
240+
],
241+
"Task list",
242+
{
243+
"2,27294": {
244+
"task": "Write code",
245+
"desc": "Make the todo ZT PR!",
246+
"completed": True,
247+
},
248+
"4,27294": {
249+
"task": "Sleep",
250+
"desc": "at least 8 hours a day",
251+
"completed": True,
252+
},
253+
"6,27294": {"task": "Eat", "desc": "3 meals a day", "completed": False},
254+
"8,27294": {
255+
"task": "Exercise",
256+
"desc": "an hour a day",
257+
"completed": False,
258+
},
259+
},
260+
id="todo_with_title_and_description_and_some_tasks_completed",
261+
),
262+
],
263+
)
264+
def test_process_todo_widget(
265+
submessage: Any, expected_title: str, expected_tasks: Dict[str, Dict[str, Any]]
266+
) -> None:
267+
title, tasks = process_todo_widget(submessage)
268+
269+
assert title == expected_title
270+
assert tasks == expected_tasks

zulipterminal/widget.py

Lines changed: 47 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, Tuple
77

88

99
def find_widget_type(submessage: Any) -> str:
@@ -15,3 +15,49 @@ def find_widget_type(submessage: Any) -> str:
1515
return "unknown"
1616
else:
1717
return "unknown"
18+
19+
20+
def process_todo_widget(todo_list: Any) -> Tuple[str, Dict[str, Dict[str, Any]]]:
21+
title = ""
22+
tasks = {}
23+
24+
for entry in todo_list:
25+
content = entry.get("content")
26+
sender_id = entry.get("sender_id")
27+
msg_type = entry.get("msg_type")
28+
29+
if msg_type == "widget" and content:
30+
widget = json.loads(content)
31+
32+
if widget.get("widget_type") == "todo":
33+
if "extra_data" in widget and widget["extra_data"] is not None:
34+
title = widget["extra_data"].get("task_list_title", "")
35+
if title == "":
36+
# Webapp uses "Task list" as default title
37+
title = "Task list"
38+
# Process initial tasks
39+
for i, task in enumerate(widget["extra_data"].get("tasks", [])):
40+
# Initial tasks get ID as "index,canned"
41+
task_id = f"{i},canned"
42+
tasks[task_id] = {
43+
"task": task["task"],
44+
"desc": task.get("desc", ""),
45+
"completed": False,
46+
}
47+
48+
elif widget.get("type") == "new_task":
49+
# New tasks get ID as "key,sender_id"
50+
task_id = f"{widget['key']},{sender_id}"
51+
tasks[task_id] = {
52+
"task": widget["task"],
53+
"desc": widget.get("desc", ""),
54+
"completed": False,
55+
}
56+
57+
elif widget.get("type") == "strike":
58+
# Strike event - toggle task completion state
59+
task_id = widget["key"]
60+
if task_id in tasks:
61+
tasks[task_id]["completed"] = not tasks[task_id]["completed"]
62+
63+
return title, tasks

0 commit comments

Comments
 (0)