Skip to content

Commit 6b7eb6b

Browse files
rsashanksrdeotarse
andcommitted
model: Add toggle_topic_resolve_status function to (un)resolve topics.
The function calls get_latest_message_in_topic to fetch recent message in topic to be (un)resolved. It verifies user and editing conditions using can_user_edit_topic function and finally add or remove RESOLVED_TOPIC_PREFIX from topic name. Co-authored-by: Shivam Deotarse <[email protected]>
1 parent 7116761 commit 6b7eb6b

File tree

2 files changed

+235
-0
lines changed

2 files changed

+235
-0
lines changed

tests/model/test_model.py

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from pytest_mock import MockerFixture
1010
from zulip import Client, ZulipError
1111

12+
from zulipterminal.api_types import RESOLVED_TOPIC_PREFIX
1213
from zulipterminal.config.symbols import STREAM_TOPIC_SEPARATOR
1314
from zulipterminal.helper import initial_index, powerset
1415
from zulipterminal.model import (
@@ -1360,6 +1361,200 @@ def test_can_user_edit_topic(
13601361
else:
13611362
report_error.assert_called_once_with(expected_response[user_type][0])
13621363

1364+
@pytest.mark.parametrize(
1365+
"topic_name, latest_message_timestamp, server_feature_level,"
1366+
" topic_editing_limit_seconds, move_messages_within_stream_limit_seconds,"
1367+
" expected_new_topic_name",
1368+
[
1369+
case(
1370+
"hi!",
1371+
11662271397,
1372+
0,
1373+
None,
1374+
None,
1375+
RESOLVED_TOPIC_PREFIX + "hi!",
1376+
id="topic_resolved:Zulip2.1+:ZFL0",
1377+
),
1378+
case(
1379+
RESOLVED_TOPIC_PREFIX + "hi!",
1380+
11662271397,
1381+
0,
1382+
None,
1383+
None,
1384+
"hi!",
1385+
id="topic_unresolved:Zulip2.1+:ZFL0",
1386+
),
1387+
case(
1388+
RESOLVED_TOPIC_PREFIX + "hi!",
1389+
11662271397,
1390+
10,
1391+
86400,
1392+
None,
1393+
"hi!",
1394+
id="topic_unresolved:Zulip2.1+:ZFL10",
1395+
),
1396+
case(
1397+
"hi!",
1398+
11662271397,
1399+
12,
1400+
259200,
1401+
None,
1402+
RESOLVED_TOPIC_PREFIX + "hi!",
1403+
id="topic_resolved:Zulip2.1+:ZFL12",
1404+
),
1405+
case(
1406+
"hi!",
1407+
11662271397,
1408+
162,
1409+
86400,
1410+
86400,
1411+
RESOLVED_TOPIC_PREFIX + "hi!",
1412+
id="topic_resolved:Zulip7.0+:ZFL162",
1413+
),
1414+
case(
1415+
RESOLVED_TOPIC_PREFIX + "hi!",
1416+
11662271397,
1417+
162,
1418+
259200,
1419+
259200,
1420+
"hi!",
1421+
id="topic_unresolved:Zulip7.0+:ZFL162",
1422+
),
1423+
case(
1424+
"hi!",
1425+
11662271397,
1426+
184,
1427+
259200,
1428+
259200,
1429+
RESOLVED_TOPIC_PREFIX + "hi!",
1430+
id="topic_unresolved:Zulip7.0+:ZFL184",
1431+
),
1432+
case(
1433+
RESOLVED_TOPIC_PREFIX + "hi!",
1434+
11662271397,
1435+
184,
1436+
259200,
1437+
259200,
1438+
"hi!",
1439+
id="topic_unresolved:Zulip7.0+:ZFL184",
1440+
),
1441+
],
1442+
)
1443+
def test_toggle_topic_resolve_status_no_footer_error(
1444+
self,
1445+
mocker,
1446+
model,
1447+
initial_data,
1448+
topic_name,
1449+
latest_message_timestamp,
1450+
server_feature_level,
1451+
topic_editing_limit_seconds,
1452+
move_messages_within_stream_limit_seconds,
1453+
expected_new_topic_name,
1454+
stream_id=1,
1455+
message_id=1,
1456+
):
1457+
model.initial_data = initial_data
1458+
model.server_feature_level = server_feature_level
1459+
initial_data[
1460+
"realm_community_topic_editing_limit_seconds"
1461+
] = topic_editing_limit_seconds
1462+
initial_data[
1463+
"realm_move_messages_within_stream_limit_seconds"
1464+
] = move_messages_within_stream_limit_seconds
1465+
# If user can't edit topic, topic (un)resolve is disabled. Therefore,
1466+
# default return_value=True
1467+
model.can_user_edit_topic = mocker.Mock(return_value=True)
1468+
model.get_latest_message_in_topic = mocker.Mock(
1469+
return_value={
1470+
"subject": topic_name,
1471+
"timestamp": latest_message_timestamp,
1472+
"id": message_id,
1473+
}
1474+
)
1475+
model.update_stream_message = mocker.Mock(return_value={"result": "success"})
1476+
1477+
model.toggle_topic_resolve_status(stream_id, topic_name)
1478+
1479+
model.update_stream_message.assert_called_once_with(
1480+
message_id=message_id,
1481+
topic=expected_new_topic_name,
1482+
propagate_mode="change_all",
1483+
)
1484+
1485+
@pytest.mark.parametrize(
1486+
"topic_name, latest_message_timestamp, server_feature_level,"
1487+
" topic_editing_limit_seconds, move_messages_within_stream_limit_seconds,"
1488+
" expected_footer_error,",
1489+
[
1490+
case(
1491+
"hi!",
1492+
0,
1493+
12,
1494+
86400,
1495+
None,
1496+
" Time limit for editing topic has been exceeded.",
1497+
id="time_limit_exceeded:Zulip2.1+:ZFL12",
1498+
),
1499+
case(
1500+
"hi!",
1501+
0,
1502+
162,
1503+
259200,
1504+
259200,
1505+
" Time limit for editing topic has been exceeded.",
1506+
id="time_limit_exceeded:Zulip7.0+:ZFL162",
1507+
),
1508+
case(
1509+
"hi!",
1510+
0,
1511+
184,
1512+
None,
1513+
86400,
1514+
" Time limit for editing topic has been exceeded.",
1515+
id="topic_resolved:Zulip2.1+:ZFL184",
1516+
),
1517+
],
1518+
)
1519+
def test_toggle_topic_resolve_status_footer_error(
1520+
self,
1521+
mocker,
1522+
model,
1523+
initial_data,
1524+
topic_name,
1525+
latest_message_timestamp,
1526+
server_feature_level,
1527+
topic_editing_limit_seconds,
1528+
move_messages_within_stream_limit_seconds,
1529+
expected_footer_error,
1530+
stream_id=1,
1531+
message_id=1,
1532+
):
1533+
model.initial_data = initial_data
1534+
model.server_feature_level = server_feature_level
1535+
initial_data[
1536+
"realm_community_topic_editing_limit_seconds"
1537+
] = topic_editing_limit_seconds
1538+
initial_data[
1539+
"realm_move_messages_within_stream_limit_seconds"
1540+
] = move_messages_within_stream_limit_seconds
1541+
# If user can't edit topic, topic (un)resolve is disabled. Therefore,
1542+
# default return_value=True
1543+
model.can_user_edit_topic = mocker.Mock(return_value=True)
1544+
model.get_latest_message_in_topic = mocker.Mock(
1545+
return_value={
1546+
"subject": topic_name,
1547+
"timestamp": latest_message_timestamp,
1548+
"id": message_id,
1549+
}
1550+
)
1551+
model.update_stream_message = mocker.Mock(return_value={"result": "success"})
1552+
report_error = model.controller.report_error
1553+
1554+
model.toggle_topic_resolve_status(stream_id, topic_name)
1555+
1556+
report_error.assert_called_once_with(expected_footer_error)
1557+
13631558
# NOTE: This tests only getting next-unread, not a fixed anchor
13641559
def test_success_get_messages(
13651560
self,

zulipterminal/model.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
MAX_TOPIC_NAME_LENGTH,
3737
PRESENCE_OFFLINE_THRESHOLD_SECS,
3838
PRESENCE_PING_INTERVAL_SECS,
39+
RESOLVED_TOPIC_PREFIX,
3940
TYPING_STARTED_EXPIRY_PERIOD,
4041
TYPING_STARTED_WAIT_PERIOD,
4142
TYPING_STOPPED_WAIT_PERIOD,
@@ -709,6 +710,45 @@ def can_user_edit_topic(self) -> bool:
709710
self.controller.report_error("User not found")
710711
return False
711712

713+
def toggle_topic_resolve_status(self, stream_id: int, topic_name: str) -> None:
714+
latest_msg = self.get_latest_message_in_topic(stream_id, topic_name)
715+
if not self.can_user_edit_topic() or not latest_msg:
716+
return
717+
718+
time_since_msg_sent = time.time() - latest_msg["timestamp"]
719+
720+
# ZFL >= 162, realm_move_messages_within_stream_limit_seconds was
721+
# introduced in place of realm_community_topic_editing_limit_seconds
722+
if self.server_feature_level >= 162:
723+
edit_time_limit = self.initial_data.get(
724+
"realm_move_messages_within_stream_limit_seconds", None
725+
)
726+
elif 11 <= self.server_feature_level < 162:
727+
edit_time_limit = self.initial_data.get(
728+
"realm_community_topic_editing_limit_seconds", None
729+
)
730+
# ZFL < 11, community_topic_editing_limit_seconds
731+
# was hardcoded as int value in secs eg. 86400s (1 day) or None
732+
else:
733+
edit_time_limit = 86400
734+
735+
# Don't allow editing topic if time-limit exceeded.
736+
if edit_time_limit is not None and time_since_msg_sent >= edit_time_limit:
737+
self.controller.report_error(
738+
" Time limit for editing topic has been exceeded."
739+
)
740+
return
741+
742+
if topic_name.startswith(RESOLVED_TOPIC_PREFIX):
743+
topic_name = topic_name[2:]
744+
else:
745+
topic_name = RESOLVED_TOPIC_PREFIX + topic_name
746+
self.update_stream_message(
747+
message_id=latest_msg["id"],
748+
topic=topic_name,
749+
propagate_mode="change_all",
750+
)
751+
712752
def generate_all_emoji_data(
713753
self, custom_emoji: Dict[str, RealmEmojiData]
714754
) -> Tuple[NamedEmojiData, List[str]]:

0 commit comments

Comments
 (0)