Skip to content

Commit 0433e30

Browse files
committed
model: Add toggle_topic_resolve_status function to (un)resolve topics.
Fixes zulip#1075 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.
1 parent 2b30a1d commit 0433e30

File tree

2 files changed

+115
-0
lines changed

2 files changed

+115
-0
lines changed

tests/model/test_model.py

+82
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from pytest import param as case
88
from zulip import Client, ZulipError
99

10+
from zulipterminal.api_types import RESOLVED_TOPIC_PREFIX
1011
from zulipterminal.config.symbols import STREAM_TOPIC_SEPARATOR
1112
from zulipterminal.helper import initial_index, powerset
1213
from zulipterminal.model import (
@@ -1259,6 +1260,87 @@ def test_can_user_edit_topic(
12591260
else:
12601261
report_error.assert_called_once_with(expected_response[user_type][0])
12611262

1263+
@pytest.mark.parametrize(
1264+
"topic_name, msg_response, server_feature_level, topic_editing_limit_seconds,"
1265+
" expected_new_topic_name, expected_footer_error",
1266+
[
1267+
case(
1268+
"hi!",
1269+
{
1270+
"subject": "hi!",
1271+
"timestamp": 11662271397,
1272+
"id": 1,
1273+
},
1274+
12,
1275+
259200,
1276+
RESOLVED_TOPIC_PREFIX + "hi!",
1277+
None,
1278+
id="topic_resolved:Zulip2.1+:ZFL12",
1279+
),
1280+
case(
1281+
"hi!",
1282+
{
1283+
"subject": "hi!",
1284+
"timestamp": 0,
1285+
"id": 1,
1286+
},
1287+
None,
1288+
None,
1289+
RESOLVED_TOPIC_PREFIX + "hi!",
1290+
None,
1291+
id="no_time_limit:Zulip2.1+:None",
1292+
),
1293+
case(
1294+
RESOLVED_TOPIC_PREFIX + "hi!",
1295+
{
1296+
"subject": RESOLVED_TOPIC_PREFIX + "hi!",
1297+
"timestamp": 11662271397,
1298+
"id": 1,
1299+
},
1300+
10,
1301+
86400,
1302+
"hi!",
1303+
None,
1304+
id="topic_unresolved:Zulip2.1+:ZFL10",
1305+
),
1306+
],
1307+
)
1308+
def test_toggle_topic_resolve_status(
1309+
self,
1310+
mocker,
1311+
model,
1312+
initial_data,
1313+
topic_name,
1314+
msg_response,
1315+
server_feature_level,
1316+
topic_editing_limit_seconds,
1317+
expected_new_topic_name,
1318+
expected_footer_error,
1319+
stream_id=1,
1320+
):
1321+
model.initial_data = initial_data
1322+
model.server_feature_level = server_feature_level
1323+
initial_data[
1324+
"realm_community_topic_editing_limit_seconds"
1325+
] = topic_editing_limit_seconds
1326+
# If user can't edit topic, topic (un)resolve is disabled. Therefore,
1327+
# default return_value=True
1328+
model.can_user_edit_topic = mocker.Mock(return_value=True)
1329+
model.get_latest_message_in_topic = mocker.Mock(return_value=msg_response)
1330+
model.update_stream_message = mocker.Mock(return_value={"result": "success"})
1331+
report_error = model.controller.report_error
1332+
1333+
model.toggle_topic_resolve_status(stream_id, topic_name)
1334+
1335+
if not expected_footer_error:
1336+
model.update_stream_message.assert_called_once_with(
1337+
message_id=msg_response["id"],
1338+
topic=expected_new_topic_name,
1339+
propagate_mode="change_all",
1340+
)
1341+
else:
1342+
report_error.assert_called_once_with(expected_footer_error)
1343+
12621344
# NOTE: This tests only getting next-unread, not a fixed anchor
12631345
def test_success_get_messages(
12641346
self,

zulipterminal/model.py

+33
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
from zulipterminal import unicode_emojis
3232
from zulipterminal.api_types import (
33+
RESOLVED_TOPIC_PREFIX,
3334
Composition,
3435
EditPropagateMode,
3536
Event,
@@ -699,6 +700,38 @@ def can_user_edit_topic(self) -> bool:
699700
self.controller.report_error("User not found")
700701
return False
701702

703+
def toggle_topic_resolve_status(self, stream_id: int, topic_name: str) -> None:
704+
if self.can_user_edit_topic():
705+
latest_msg = self.get_latest_message_in_topic(stream_id, topic_name)
706+
if latest_msg:
707+
time_since_msg_sent = time.time() - latest_msg["timestamp"]
708+
# ZFL < 11, community_topic_editing_limit_seconds
709+
# was hardcoded as int value in secs eg. 86400s (1 day) or None
710+
if self.server_feature_level is None or self.server_feature_level >= 11:
711+
edit_time_limit = self.initial_data.get(
712+
"realm_community_topic_editing_limit_seconds", None
713+
)
714+
else:
715+
edit_time_limit = 86400
716+
# Don't allow editing topic if time-limit exceeded.
717+
if (
718+
edit_time_limit is not None
719+
and time_since_msg_sent >= edit_time_limit
720+
):
721+
self.controller.report_error(
722+
" Time limit for editing topic has been exceeded."
723+
)
724+
else:
725+
if topic_name.startswith(RESOLVED_TOPIC_PREFIX):
726+
topic_name = topic_name[2:]
727+
else:
728+
topic_name = RESOLVED_TOPIC_PREFIX + topic_name
729+
self.update_stream_message(
730+
message_id=latest_msg["id"],
731+
topic=topic_name,
732+
propagate_mode="change_all",
733+
)
734+
702735
def generate_all_emoji_data(
703736
self, custom_emoji: Dict[str, RealmEmojiData]
704737
) -> Tuple[NamedEmojiData, List[str]]:

0 commit comments

Comments
 (0)