From f106cc78bb25c71e97b78e7b4cad6482e5bcec80 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Tue, 17 May 2022 11:57:59 -0400 Subject: [PATCH] Fall back to Foundation URL if WebURL parsing fails WebURL doesn't support Unicode domains/IDNA --- .../Sources/Pachyderm/Model/Hashtag.swift | 3 +-- .../Sources/Pachyderm/Model/Mention.swift | 21 ++++++++++++++++++- Pachyderm/Tests/PachydermTests/URLTests.swift | 20 ++++++++++++++++++ Tusker/Views/ContentTextView.swift | 6 ++++-- Tusker/Views/StatusContentTextView.swift | 2 +- 5 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 Pachyderm/Tests/PachydermTests/URLTests.swift diff --git a/Pachyderm/Sources/Pachyderm/Model/Hashtag.swift b/Pachyderm/Sources/Pachyderm/Model/Hashtag.swift index 82ef7ffc..ad046701 100644 --- a/Pachyderm/Sources/Pachyderm/Model/Hashtag.swift +++ b/Pachyderm/Sources/Pachyderm/Model/Hashtag.swift @@ -35,8 +35,7 @@ public class Hashtag: Codable { throw DecodingError.dataCorruptedError(forKey: .url, in: container, debugDescription: "unable to convert WebURL \(s?.debugDescription ?? "nil") to URL") } } catch { - let s = try? container.decode(String.self, forKey: .url) - throw DecodingError.dataCorruptedError(forKey: .url, in: container, debugDescription: "unable to decode WebURL from \(s?.debugDescription ?? "nil")") + self.url = try container.decode(URL.self, forKey: .url) } self.history = try container.decodeIfPresent([History].self, forKey: .history) } diff --git a/Pachyderm/Sources/Pachyderm/Model/Mention.swift b/Pachyderm/Sources/Pachyderm/Model/Mention.swift index 601e386c..84f4ca3a 100644 --- a/Pachyderm/Sources/Pachyderm/Model/Mention.swift +++ b/Pachyderm/Sources/Pachyderm/Model/Mention.swift @@ -8,14 +8,33 @@ import Foundation import WebURL +import WebURLFoundationExtras public class Mention: Codable { - public let url: WebURL + public let url: URL public let username: String public let acct: String /// The instance-local ID of the user being mentioned. public let id: String + public required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.username = try container.decode(String.self, forKey: .username) + self.acct = try container.decode(String.self, forKey: .acct) + self.id = try container.decode(String.self, forKey: .id) + do { + let webURL = try container.decode(WebURL.self, forKey: .url) + if let url = URL(webURL) { + self.url = url + } else { + let s = try? container.decode(String.self, forKey: .url) + throw DecodingError.dataCorruptedError(forKey: .url, in: container, debugDescription: "unable to convert WebURL \(s?.debugDescription ?? "nil") to URL") + } + } catch { + self.url = try container.decode(URL.self, forKey: .url) + } + } + private enum CodingKeys: String, CodingKey { case url case username diff --git a/Pachyderm/Tests/PachydermTests/URLTests.swift b/Pachyderm/Tests/PachydermTests/URLTests.swift new file mode 100644 index 00000000..4ac4344a --- /dev/null +++ b/Pachyderm/Tests/PachydermTests/URLTests.swift @@ -0,0 +1,20 @@ +// +// URLTests.swift +// +// +// Created by Shadowfacts on 5/17/22. +// + +import XCTest +import WebURL +import WebURLFoundationExtras + +class URLTests: XCTestCase { + + func testDecodeURL() { + print(WebURL(URL(string: "https://xn--baw-joa.social/@unituebingen")!)) + let url = WebURL("https://xn--baw-joa.social/@unituebingen") + print(url) + } + +} diff --git a/Tusker/Views/ContentTextView.swift b/Tusker/Views/ContentTextView.swift index 69bc5c64..bfb6084f 100644 --- a/Tusker/Views/ContentTextView.swift +++ b/Tusker/Views/ContentTextView.swift @@ -108,10 +108,12 @@ class ContentTextView: LinkTextView, BaseEmojiLabel { // screws up its determination of the line height making multiple lines of emojis squash together attributed.append(NSAttributedString(string: "\n", attributes: [.font: defaultFont])) case "a": - if let link = try? node.attr("href"), - let webURL = WebURL(link), + let href = try! node.attr("href") + if let webURL = WebURL(href), let url = URL(webURL) { attributed.addAttribute(.link, value: url, range: attributed.fullRange) + } else if let url = URL(string: href) { + attributed.addAttribute(.link, value: url, range: attributed.fullRange) } case "p": attributed.append(NSAttributedString(string: "\n\n", attributes: [.font: defaultFont])) diff --git a/Tusker/Views/StatusContentTextView.swift b/Tusker/Views/StatusContentTextView.swift index f8fd23b6..33657f27 100644 --- a/Tusker/Views/StatusContentTextView.swift +++ b/Tusker/Views/StatusContentTextView.swift @@ -27,7 +27,7 @@ class StatusContentTextView: ContentTextView { let status = mastodonController.persistentContainer.status(for: statusID) { mention = status.mentions.first { (mention) in // Mastodon and Pleroma include the @ in the text, GNU Social does not - (text.dropFirst() == mention.username || text == mention.username) && url.host == mention.url.host!.serialized + (text.dropFirst() == mention.username || text == mention.username) && url.host == mention.url.host! } } else { mention = nil