Skip to content

Commit 7105240

Browse files
zee-bitneiljp
authored andcommitted
boxes/server_url/docs: Update to use new webapp quoting style.
This commit adds the same new quoting style as used in the webapp, ie. indicating the quoted author and location. The URL generation part of the code now has its own module named server_url.py, along with the tests for this module added as test_server_url.py. This will allow to track changes in the server and make constructing and deconstructing server URL's easier. This module can also be later integrated into the API package. Details of server_url.py are added to docs/developer-file-overview.md Tests added and amended. Fixes #514.
1 parent fde575a commit 7105240

File tree

4 files changed

+174
-1
lines changed

4 files changed

+174
-1
lines changed

docs/developer-file-overview.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Zulip Terminal uses [Zulip's API](https://zulip.com/api/) to store and retrieve
77
| zulipterminal/ | core.py | Defines the `Controller`, which sets up the `model`, `view`, and coordinates the application |
88
| | helper.py | Helper functions used in multiple places |
99
| | model.py | Defines the `Model`, fetching and storing data retrieved from the Zulip server |
10+
| | server_url.py | Constructs and encodes server_url of messages. |
1011
| | ui.py | Defines the `View`, and controls where each component is displayed |
1112
| | unicode_emojis.py | Stores valid unicode emoji data |
1213
| | urwid_types.py | Preliminary urwid types to improve type analysis |

tests/server_url/test_server_url.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import pytest
2+
3+
from zulipterminal.server_url import encode_stream, near_message_url
4+
5+
6+
@pytest.mark.parametrize('stream_id, stream_name, expected_encoded_string', [
7+
(10, 'zulip terminal', '10-zulip-terminal'),
8+
(12, '<strong>xss</strong>', '12-.3Cstrong.3Exss.3C.2Fstrong.3E'),
9+
(17, '#test-here #T1 #T2 #T3', '17-.23test-here-.23T1-.23T2-.23T3'),
10+
(27, ':party_parrot:', '27-.3Aparty_parrot.3A'),
11+
(44, '(ZT) % zulip ?/; &', '44-.28ZT.29-.25-zulip-.3F.2F.3B-.26'),
12+
(273, 'abc + de = abcde', '273-abc-.2B-de-.3D-abcde'),
13+
(374, '/ in a stream name ?', '374-.2F-in-a-stream-name-.3F'),
14+
])
15+
def test_encode_stream(stream_id, stream_name, expected_encoded_string):
16+
encoded_string = encode_stream(
17+
stream_id=stream_id, stream_name=stream_name
18+
)
19+
20+
assert encoded_string == expected_encoded_string
21+
22+
23+
@pytest.mark.parametrize(['server_url', 'msg', 'expected_message_url'], [
24+
(
25+
'https://chat.zulip.org',
26+
{
27+
'id': 17252,
28+
'type': 'stream',
29+
'stream_id': 23,
30+
'display_recipient': 'zulip terminal',
31+
'subject': '#test-here #T1 #T2 #T3',
32+
},
33+
('https://chat.zulip.org/#narrow/stream/23-zulip-terminal'
34+
'/topic/.23test-here.20.23T1.20.23T2.20.23T3/near/17252'),
35+
),
36+
(
37+
'https://foo-bar.co.in',
38+
{
39+
'id': 5412,
40+
'type': 'stream',
41+
'stream_id': 425,
42+
'display_recipient': '/ in a stream name ?',
43+
'subject': 'abc + de = abcde'
44+
},
45+
('https://foo-bar.co.in/#narrow/stream/425-.2F-in-a-stream-name-.3F'
46+
'/topic/abc.20.2B.20de.20.3D.20abcde/near/5412'),
47+
),
48+
(
49+
'https://foo.bar.com',
50+
{
51+
'id': 24284,
52+
'type': 'private',
53+
'display_recipient': [
54+
{
55+
'id': 12,
56+
},
57+
{
58+
'id': 144,
59+
},
60+
{
61+
'id': 249,
62+
}
63+
]
64+
},
65+
'https://foo.bar.com/#narrow/pm-with/12,144,249-pm/near/24284',
66+
),
67+
])
68+
def test_near_message_url(server_url, msg, expected_message_url):
69+
message_url = near_message_url(server_url=server_url, message=msg)
70+
71+
assert message_url == expected_message_url

zulipterminal/server_url.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import urllib.parse
2+
3+
from zulipterminal.helper import Message
4+
5+
6+
def hash_util_encode(string: str) -> str:
7+
"""
8+
Hide URI-encoding by replacing '%' with '.'
9+
urllib.quote is equivalent to encodeURIComponent in JavaScript.
10+
Referred from zerver/lib/url_encoding.py
11+
"""
12+
# `safe` has a default value of "/", but we want those encoded, too.
13+
return urllib.parse.quote(
14+
string, safe=b"").replace(".", "%2E").replace("%", ".")
15+
16+
17+
def encode_stream(stream_id: int, stream_name: str) -> str:
18+
"""
19+
Encodes stream_name with stream_id and replacing any occurence
20+
of whitespace to '-'. This is the format of message representation
21+
in webapp. Referred from zerver/lib/url_encoding.py.
22+
"""
23+
stream_name = stream_name.replace(' ', '-')
24+
return str(stream_id) + '-' + hash_util_encode(stream_name)
25+
26+
27+
def near_stream_message_url(server_url: str, message: Message) -> str:
28+
"""
29+
Returns the complete encoded URL of a message from #narrow/stream.
30+
Referred from zerver/lib/url_encoding.py.
31+
"""
32+
message_id = str(message['id'])
33+
stream_id = message['stream_id']
34+
stream_name = message['display_recipient']
35+
topic_name = message['subject']
36+
encoded_stream = encode_stream(stream_id, stream_name)
37+
encoded_topic = hash_util_encode(topic_name)
38+
39+
parts = [
40+
server_url,
41+
'#narrow',
42+
'stream',
43+
encoded_stream,
44+
'topic',
45+
encoded_topic,
46+
'near',
47+
message_id,
48+
]
49+
full_url = '/'.join(parts)
50+
return full_url
51+
52+
53+
def near_pm_message_url(server_url: str, message: Message) -> str:
54+
"""
55+
Returns the complete encoded URL of a message from #narrow/pm-with.
56+
Referred from zerver/lib/url_encoding.py.
57+
"""
58+
message_id = str(message['id'])
59+
str_user_ids = [
60+
str(recipient['id'])
61+
for recipient in message['display_recipient']
62+
]
63+
64+
pm_str = ','.join(str_user_ids) + '-pm'
65+
parts = [
66+
server_url,
67+
'#narrow',
68+
'pm-with',
69+
pm_str,
70+
'near',
71+
message_id,
72+
]
73+
full_url = '/'.join(parts)
74+
return full_url
75+
76+
77+
def near_message_url(server_url: str, message: Message) -> str:
78+
"""
79+
Returns the correct encoded URL of a message, if
80+
it is present in stream/pm-with accordingly.
81+
Referred from zerver/lib/url_encoding.py.
82+
"""
83+
if message['type'] == 'stream':
84+
url = near_stream_message_url(server_url, message)
85+
else:
86+
url = near_pm_message_url(server_url, message)
87+
return url

zulipterminal/ui_tools/boxes.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
Message, format_string, get_unused_fence, match_emoji, match_group,
2727
match_stream, match_topics, match_user,
2828
)
29+
from zulipterminal.server_url import near_message_url
2930
from zulipterminal.ui_tools.buttons import EditModeButton
3031
from zulipterminal.ui_tools.tables import render_table
3132
from zulipterminal.urwid_types import urwid_Size
@@ -1233,7 +1234,20 @@ def keypress(self, size: urwid_Size, key: str) -> Optional[str]:
12331234
self.message['id'])['raw_content']
12341235
fence = get_unused_fence(message_raw_content)
12351236

1236-
quote = '{0}quote\n{1}\n{0}\n'.format(fence, message_raw_content)
1237+
absolute_url = near_message_url(
1238+
self.model.server_url[:-1], self.message)
1239+
1240+
# Compose box should look something like this:
1241+
# @_**Zeeshan|514** [said](link to message):
1242+
# ```quote
1243+
# message_content
1244+
# ```
1245+
quote = '@_**{0}|{1}** [said]({2}):\n{3}quote\n{4}\n{3}\n'.format(
1246+
self.message['sender_full_name'],
1247+
self.message['sender_id'],
1248+
absolute_url,
1249+
fence,
1250+
message_raw_content)
12371251

12381252
self.model.controller.view.write_box.msg_write_box.set_edit_text(
12391253
quote)

0 commit comments

Comments
 (0)