From fd91f726293d94718247832139ebdd6ea08f9110 Mon Sep 17 00:00:00 2001 From: Zixuan James Li Date: Tue, 12 Nov 2024 21:30:16 -0500 Subject: [PATCH] internal_link: Always include a "/" after hostname Fixes: #845 Signed-off-by: Zixuan James Li --- lib/model/internal_link.dart | 9 ++++++++- test/model/internal_link_test.dart | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/model/internal_link.dart b/lib/model/internal_link.dart index c132eb0b66..a5dd23c2a2 100644 --- a/lib/model/internal_link.dart +++ b/lib/model/internal_link.dart @@ -96,7 +96,14 @@ Uri narrowLink(PerAccountStore store, Narrow narrow, {int? nearMessageId}) { fragment.write('/near/$nearMessageId'); } - return store.realmUrl.replace(fragment: fragment.toString()); + Uri result = store.realmUrl.replace(fragment: fragment.toString()); + if (result.path.isEmpty) { + // Always ensure that there is a '/' right after the hostname. + // A generated URL without '/' looks odd, + // and if used in a Zulip message does not get automatically linkified. + result = result.replace(path: '/'); + } + return result; } /// A [Narrow] from a given URL, on `store`'s realm. diff --git a/test/model/internal_link_test.dart b/test/model/internal_link_test.dart index 1f53fd11ac..3949339321 100644 --- a/test/model/internal_link_test.dart +++ b/test/model/internal_link_test.dart @@ -127,6 +127,23 @@ void main() { '#narrow/dm/1,2-dm/near/12345', '#narrow/pm-with/1,2-pm/near/12345'); }); + + test('normalize links to always include a "/" after hostname', () { + String narrowLinkFor({required String realmUrl}) { + final store = eg.store( + account: eg.account(user: eg.selfUser, realmUrl: Uri.parse(realmUrl))); + return narrowLink(store, const CombinedFeedNarrow()).toString(); + } + + check(narrowLinkFor(realmUrl: 'http://chat.example.com')) + .equals( 'http://chat.example.com/#narrow'); + check(narrowLinkFor(realmUrl: 'http://chat.example.com/')) + .equals( 'http://chat.example.com/#narrow'); + check(narrowLinkFor(realmUrl: 'http://chat.example.com/path')) + .equals( 'http://chat.example.com/path#narrow'); + check(narrowLinkFor(realmUrl: 'http://chat.example.com/path/')) + .equals( 'http://chat.example.com/path/#narrow'); + }); }); final realmUrl = Uri.parse('https://example.com/');