markdown: Fix stream description with topic permalink not rendered.

Previously, when description for a channel -- either during its
creating or when we change its description contained a topic
permalink (through #-mention), then it was not rendered. This
is because of lack of authorization to access the channel.

This is fixed by passing the acting_user through the methods
which update or add the description, so that permissions
of the acting_user could be used to determine whether to
render the #-mention in stream description or not.
This commit is contained in:
roanster007
2025-02-13 00:38:12 +05:30
committed by Tim Abbott
parent 4789de2e96
commit c562503089
3 changed files with 81 additions and 4 deletions

View File

@@ -1495,7 +1495,9 @@ def do_change_stream_description(
) -> None:
old_description = stream.description
stream.description = new_description
stream.rendered_description = render_stream_description(new_description, stream.realm)
stream.rendered_description = render_stream_description(
new_description, stream.realm, acting_user=acting_user
)
stream.save(update_fields=["description", "rendered_description"])
RealmAuditLog.objects.create(
realm=stream.realm,

View File

@@ -128,10 +128,14 @@ def get_default_value_for_history_public_to_subscribers(
return history_public_to_subscribers
def render_stream_description(text: str, realm: Realm) -> str:
def render_stream_description(
text: str, realm: Realm, *, acting_user: UserProfile | None = None
) -> str:
from zerver.lib.markdown import markdown_convert
return markdown_convert(text, message_realm=realm, no_previews=True).rendered_content
return markdown_convert(
text, message_realm=realm, no_previews=True, acting_user=acting_user
).rendered_content
def send_stream_creation_event(
@@ -258,7 +262,9 @@ def create_stream_if_needed(
recipient = Recipient.objects.create(type_id=stream.id, type=Recipient.STREAM)
stream.recipient = recipient
stream.rendered_description = render_stream_description(stream_description, realm)
stream.rendered_description = render_stream_description(
stream_description, realm, acting_user=acting_user
)
stream.save(update_fields=["recipient", "rendered_description"])
event_time = timezone_now()

View File

@@ -395,6 +395,39 @@ class TestCreateStreams(ZulipTestCase):
stream = get_stream("new_stream", realm)
self.assertEqual(stream.description, "multi line description")
def test_create_api_topic_permalink_description(self) -> None:
user = self.example_user("iago")
realm = user.realm
self.login_user(user)
hamlet = self.example_user("hamlet")
core_stream = self.make_stream("core", realm, True, history_public_to_subscribers=True)
self.subscribe(hamlet, "core")
msg_id = self.send_stream_message(hamlet, "core", topic_name="testing")
# Test permalink not generated for description since user has no access to
# the channel.
subscriptions = [{"name": "stream1", "description": "#**core>testing**"}]
result = self.subscribe_via_post(user, subscriptions, subdomain="zulip")
self.assert_json_success(result)
stream = get_stream("stream1", realm)
self.assertEqual(stream.rendered_description, "<p>#<strong>core&gt;testing</strong></p>")
self.subscribe(user, "core")
# Test permalink generated for the description since user now has access
# to the channel.
subscriptions = [{"name": "stream2", "description": "#**core>testing**"}]
result = self.subscribe_via_post(user, subscriptions, subdomain="zulip")
self.assert_json_success(result)
stream = get_stream("stream2", realm)
self.assertEqual(
stream.rendered_description,
f'<p><a class="stream-topic" data-stream-id="{core_stream.id}" href="/#narrow/channel/{core_stream.id}-core/topic/testing/with/{msg_id}">#{core_stream.name} &gt; testing</a></p>',
)
def test_history_public_to_subscribers_on_stream_creation(self) -> None:
realm = get_realm("zulip")
stream_dicts: list[StreamDict] = [
@@ -2434,6 +2467,42 @@ class StreamAdminTest(ZulipTestCase):
)
self.assert_json_success(result)
# Verify that we render topic permalinks in the description depending
# on whether the acting_user has access to that channel.
hamlet = self.example_user("hamlet")
core_stream = self.make_stream("core", realm, True, history_public_to_subscribers=True)
self.subscribe(hamlet, "core")
msg_id = self.send_stream_message(hamlet, "core", topic_name="testing")
result = self.client_patch(
f"/json/streams/{stream_id}",
{"description": "#**core>testing**"},
)
stream = get_stream("stream_name1", realm)
# permalink is not rendered since acting_user has no access to channel.
self.assertEqual(
stream.rendered_description,
"<p>#<strong>core&gt;testing</strong></p>",
)
self.subscribe(user_profile, "core")
result = self.client_patch(
f"/json/streams/{stream_id}",
{"description": "#**core>testing**"},
)
stream = get_stream("stream_name1", realm)
# permalink is rendered since acting_user now has access to channel.
self.assertEqual(
stream.rendered_description,
f'<p><a class="stream-topic" data-stream-id="{core_stream.id}" href="/#narrow/channel/{core_stream.id}-core/topic/testing/with/{msg_id}">#{core_stream.name} &gt; testing</a></p>',
)
def test_change_stream_description_requires_administer_channel_permissions(self) -> None:
user_profile = self.example_user("hamlet")
self.login_user(user_profile)