def _parse_narrow_link(cls, link: str) -> ParsedNarrowLink: """ Returns either a dict with narrow parameters for supported links or an empty dict. """ # NOTE: The optional stream_id link version is deprecated. The extended # support is for old messages. # We expect the fragment to be one of the following types: # a. narrow/stream/[{stream_id}-]{stream-name} # b. narrow/stream/[{stream_id}-]{stream-name}/near/{message_id} # c. narrow/stream/[{stream_id}-]{stream-name}/topic/ # {encoded.20topic.20name} # d. narrow/stream/[{stream_id}-]{stream-name}/topic/ # {encoded.20topic.20name}/near/{message_id} fragments = urlparse(link.rstrip("/")).fragment.split("/") len_fragments = len(fragments) parsed_link = ParsedNarrowLink() if len_fragments == 3 and fragments[1] == "stream": stream_data = cls._decode_stream_data(fragments[2]) parsed_link = dict(narrow="stream", stream=stream_data) elif (len_fragments == 5 and fragments[1] == "stream" and fragments[3] == "topic"): stream_data = cls._decode_stream_data(fragments[2]) topic_name = hash_util_decode(fragments[4]) parsed_link = dict(narrow="stream:topic", stream=stream_data, topic_name=topic_name) elif len_fragments == 5 and fragments[1] == "stream" and fragments[ 3] == "near": stream_data = cls._decode_stream_data(fragments[2]) message_id = cls._decode_message_id(fragments[4]) parsed_link = dict(narrow="stream:near", stream=stream_data, message_id=message_id) elif (len_fragments == 7 and fragments[1] == "stream" and fragments[3] == "topic" and fragments[5] == "near"): stream_data = cls._decode_stream_data(fragments[2]) topic_name = hash_util_decode(fragments[4]) message_id = cls._decode_message_id(fragments[6]) parsed_link = dict( narrow="stream:topic:near", stream=stream_data, topic_name=topic_name, message_id=message_id, ) return parsed_link
def _decode_stream_data(encoded_stream_data: str) -> DecodedStream: """ Returns a dict with optional stream ID and stream name. """ # Modern links come patched with the stream ID and '-' as delimiters. if re.match('^[0-9]+-', encoded_stream_data): stream_id, *_ = encoded_stream_data.split('-') # Given how encode_stream() in zerver/lib/url_encoding.py # replaces ' ' with '-' in the stream name, skip extracting the # stream name to avoid any ambiguity. return DecodedStream(stream_id=int(stream_id), stream_name=None) else: # Deprecated links did not start with the stream ID. stream_name = hash_util_decode(encoded_stream_data) return DecodedStream(stream_id=None, stream_name=stream_name)
def test_hash_util_decode(quoted_string: str, expected_unquoted_string: str) -> None: return_value = hash_util_decode(quoted_string) assert return_value == expected_unquoted_string