From 9b778999e5f914845a50986169204e60d364a740 Mon Sep 17 00:00:00 2001 From: Hank Grabowski Date: Wed, 29 Nov 2023 18:32:03 -0600 Subject: [PATCH 1/2] Add replacing tag links to the local server --- .../timeline_entry_mastodon_extensions.dart | 9 ++-- lib/utils/html_to_edit_text_helper.dart | 48 +++++++++++++++++++ lib/utils/network_utils.dart | 5 ++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/lib/serializers/mastodon/timeline_entry_mastodon_extensions.dart b/lib/serializers/mastodon/timeline_entry_mastodon_extensions.dart index 50efe9a..684f76c 100644 --- a/lib/serializers/mastodon/timeline_entry_mastodon_extensions.dart +++ b/lib/serializers/mastodon/timeline_entry_mastodon_extensions.dart @@ -1,6 +1,4 @@ import 'package:logging/logging.dart'; -import 'package:relatica/services/auth_service.dart'; -import 'package:relatica/services/reshared_via_service.dart'; import '../../globals.dart'; import '../../models/engagement_summary.dart'; @@ -8,10 +6,13 @@ import '../../models/link_data.dart'; import '../../models/location_data.dart'; import '../../models/timeline_entry.dart'; import '../../models/visibility.dart'; +import '../../services/auth_service.dart'; import '../../services/connections_manager.dart'; import '../../services/hashtag_service.dart'; +import '../../services/reshared_via_service.dart'; import '../../utils/active_profile_selector.dart'; import '../../utils/dateutils.dart'; +import '../../utils/html_to_edit_text_helper.dart'; import 'connection_mastodon_extensions.dart'; import 'hashtag_mastodon_extensions.dart'; import 'link_preview_mastodon_extensions.dart'; @@ -100,7 +101,6 @@ extension TimelineEntryMastodonExtensions on TimelineEntry { } const title = ''; - final body = json['content'] ?? ''; final spoilerText = json['spoiler_text'] ?? ''; final externalLink = json['uri'] ?? ''; const actualLocationData = LocationData(); @@ -137,6 +137,9 @@ extension TimelineEntryMastodonExtensions on TimelineEntry { } } + final rawBody = json['content'] ?? ''; + final body = htmlWithTagLinkSwap(rawBody, tags); + final connection = ConnectionMastodonExtensions.fromJson(json['account']); connectionManager?.upsertConnection(connection); diff --git a/lib/utils/html_to_edit_text_helper.dart b/lib/utils/html_to_edit_text_helper.dart index 19aed42..b2632bb 100644 --- a/lib/utils/html_to_edit_text_helper.dart +++ b/lib/utils/html_to_edit_text_helper.dart @@ -1,5 +1,10 @@ import 'package:html/dom.dart'; import 'package:html/parser.dart'; +import 'package:path/path.dart' as p; + +import '../globals.dart'; +import '../services/auth_service.dart'; +import 'network_utils.dart'; String htmlToSimpleText(String htmlContentFragment) { try { @@ -13,6 +18,49 @@ String htmlToSimpleText(String htmlContentFragment) { } } +void _updateSwapTagLinks(Node node, List tags) { + if (node is Element) { + if (node.attributes.containsKey('href') && + (node.attributes['class']?.contains('hashtag') ?? false) && + node.attributes['rel'] == 'tag') { + final url = Uri.parse(node.attributes['href'] ?? ''); + late final String tag; + final pathEnd = p.split(url.path).last; + if (pathEnd == 'search' && url.queryParameters.containsKey('tag')) { + tag = url.queryParameters['search']!; + } else { + tag = pathEnd; + } + // final tagLowercase = tag.toLowerCase(); + // final hasExpectedTag = tags + // .firstWhere((t) => t.toLowerCase() == tagLowercase, + // orElse: () => '') + // .isNotEmpty; + const hasExpectedTag = true; + if (hasExpectedTag) { + final profile = getIt().currentProfile; + final newTagUrl = generateTagUrlFromProfile(profile, tag); + print(node.attributes['href']); + node.attributes['href'] = newTagUrl.toString(); + print(node.attributes['href']); + } + } + node.nodes.forEach((n) => _updateSwapTagLinks(n, tags)); + } +} + +String htmlWithTagLinkSwap(String htmlContentFragment, List tags) { + try { + final dom = parseFragment(htmlContentFragment); + dom.nodes.forEach((n) => _updateSwapTagLinks(n, tags)); + + final result = dom.outerHtml; + return result; + } catch (e) { + return htmlContentFragment; + } +} + extension NodeTextConverter on Node { String nodeToEditText() { if (nodes.isEmpty) { diff --git a/lib/utils/network_utils.dart b/lib/utils/network_utils.dart index cf3d2a6..c6db2b4 100644 --- a/lib/utils/network_utils.dart +++ b/lib/utils/network_utils.dart @@ -6,6 +6,7 @@ import 'package:result_monad/result_monad.dart'; import '../friendica_client/paged_response.dart'; import '../globals.dart'; +import '../models/auth/profile.dart'; import '../models/exec_error.dart'; final _logger = Logger('NetworkUtils'); @@ -267,3 +268,7 @@ FutureResult deleteUrl( ExecError(type: ErrorType.localError, message: e.toString())); } } + +Uri generateTagUrlFromProfile(Profile profile, String tag) { + return Uri.https(profile.serverName, '/search', {'tag': tag}); +} From 6efc9ec1229d2bf614bbbb82c42790735bd1abdb Mon Sep 17 00:00:00 2001 From: Hank Grabowski Date: Wed, 29 Nov 2023 18:36:22 -0600 Subject: [PATCH 2/2] Add check that tag getting converted match expected tags from rest of status payload --- lib/utils/html_to_edit_text_helper.dart | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/utils/html_to_edit_text_helper.dart b/lib/utils/html_to_edit_text_helper.dart index b2632bb..20a5c76 100644 --- a/lib/utils/html_to_edit_text_helper.dart +++ b/lib/utils/html_to_edit_text_helper.dart @@ -31,12 +31,10 @@ void _updateSwapTagLinks(Node node, List tags) { } else { tag = pathEnd; } - // final tagLowercase = tag.toLowerCase(); - // final hasExpectedTag = tags - // .firstWhere((t) => t.toLowerCase() == tagLowercase, - // orElse: () => '') - // .isNotEmpty; - const hasExpectedTag = true; + final tagLowercase = tag.toLowerCase(); + final hasExpectedTag = tags + .firstWhere((t) => t.toLowerCase() == tagLowercase, orElse: () => '') + .isNotEmpty; if (hasExpectedTag) { final profile = getIt().currentProfile; final newTagUrl = generateTagUrlFromProfile(profile, tag);