Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix - handle unencoded urls coming from API #612

Merged
merged 4 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions Mlem.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
503422582AAB798600EFE88D /* AppFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503422572AAB798600EFE88D /* AppFlow.swift */; };
503BA26F2A2C94540052516C /* URL+Identifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503BA26E2A2C94540052516C /* URL+Identifiable.swift */; };
504106CD2A744D7F000AAEF8 /* CommentRepository+Dependency.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504106CC2A744D7F000AAEF8 /* CommentRepository+Dependency.swift */; };
504ECBAE2AB45B2A006C0B96 /* LemmyURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504ECBAD2AB45B2A006C0B96 /* LemmyURL.swift */; };
504ECBB12AB4B101006C0B96 /* LemmyURLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504ECBB02AB4B101006C0B96 /* LemmyURLTests.swift */; };
505240E32A86916500EA4558 /* FavoriteCommunitiesTracker+Dependency.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505240E22A86916500EA4558 /* FavoriteCommunitiesTracker+Dependency.swift */; };
505240E52A86E32700EA4558 /* CommunityListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505240E42A86E32700EA4558 /* CommunityListModel.swift */; };
505240E72A88D36D00EA4558 /* SectionIndexTitles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505240E62A88D36D00EA4558 /* SectionIndexTitles.swift */; };
Expand Down Expand Up @@ -94,7 +96,6 @@
50D61E5B2AA32B9400A926EC /* APISession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50D61E5A2AA32B9400A926EC /* APISession.swift */; };
50D61E5D2AA4904F00A926EC /* FeedTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50D61E5C2AA4904F00A926EC /* FeedTracking.swift */; };
50DBB8E02A805836002870B1 /* MockErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50DBB8DF2A805836002870B1 /* MockErrorHandler.swift */; };
50DBB8E22A80F9E4002870B1 /* APICommunity+Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50DBB8E12A80F9E4002870B1 /* APICommunity+Mock.swift */; };
50EC39B22A346DDC00E014C2 /* URLHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50EC39B12A346DDC00E014C2 /* URLHandler.swift */; };
50F2851C2A5C5C1500CF8865 /* TokenRefreshView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50F2851B2A5C5C1500CF8865 /* TokenRefreshView.swift */; };
50F830F82A4C92BF00D67099 /* FeedTrackerItemProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50F830F72A4C92BF00D67099 /* FeedTrackerItemProviding.swift */; };
Expand Down Expand Up @@ -477,6 +478,8 @@
503422572AAB798600EFE88D /* AppFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppFlow.swift; sourceTree = "<group>"; };
503BA26E2A2C94540052516C /* URL+Identifiable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Identifiable.swift"; sourceTree = "<group>"; };
504106CC2A744D7F000AAEF8 /* CommentRepository+Dependency.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CommentRepository+Dependency.swift"; sourceTree = "<group>"; };
504ECBAD2AB45B2A006C0B96 /* LemmyURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LemmyURL.swift; sourceTree = "<group>"; };
504ECBB02AB4B101006C0B96 /* LemmyURLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LemmyURLTests.swift; sourceTree = "<group>"; };
505240E22A86916500EA4558 /* FavoriteCommunitiesTracker+Dependency.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FavoriteCommunitiesTracker+Dependency.swift"; sourceTree = "<group>"; };
505240E42A86E32700EA4558 /* CommunityListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommunityListModel.swift; sourceTree = "<group>"; };
505240E62A88D36D00EA4558 /* SectionIndexTitles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionIndexTitles.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -530,7 +533,6 @@
50D61E5A2AA32B9400A926EC /* APISession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APISession.swift; sourceTree = "<group>"; };
50D61E5C2AA4904F00A926EC /* FeedTracking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedTracking.swift; sourceTree = "<group>"; };
50DBB8DF2A805836002870B1 /* MockErrorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockErrorHandler.swift; sourceTree = "<group>"; };
50DBB8E12A80F9E4002870B1 /* APICommunity+Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APICommunity+Mock.swift"; sourceTree = "<group>"; };
50EC39B12A346DDC00E014C2 /* URLHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLHandler.swift; sourceTree = "<group>"; };
50F2851B2A5C5C1500CF8865 /* TokenRefreshView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenRefreshView.swift; sourceTree = "<group>"; };
50F830F72A4C92BF00D67099 /* FeedTrackerItemProviding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedTrackerItemProviding.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1046,6 +1048,14 @@
path = TabBar;
sourceTree = "<group>";
};
504ECBAF2AB4B0DF006C0B96 /* Model */ = {
isa = PBXGroup;
children = (
504ECBB02AB4B101006C0B96 /* LemmyURLTests.swift */,
);
path = Model;
sourceTree = "<group>";
};
5064D03B2A6DE05000B22EE3 /* Notifications */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1163,7 +1173,6 @@
isa = PBXGroup;
children = (
50DBB8DF2A805836002870B1 /* MockErrorHandler.swift */,
50DBB8E12A80F9E4002870B1 /* APICommunity+Mock.swift */,
);
path = Mocks;
sourceTree = "<group>";
Expand Down Expand Up @@ -1460,6 +1469,7 @@
6363D5D927EE196A00E34822 /* MlemTests */ = {
isa = PBXGroup;
children = (
504ECBAF2AB4B0DF006C0B96 /* Model */,
50CC4A802AA0D5F90074C845 /* Parsers */,
50CC4A7B2A9CFF840074C845 /* Supporting Files */,
50BC1AB72A89741000E3C48B /* Community List */,
Expand Down Expand Up @@ -1526,6 +1536,7 @@
isa = PBXGroup;
children = (
637218032A3A2AAD008C4816 /* HierarchicalComment.swift */,
504ECBAD2AB45B2A006C0B96 /* LemmyURL.swift */,
);
path = Internal;
sourceTree = "<group>";
Expand Down Expand Up @@ -2534,6 +2545,7 @@
6D405B032A43E7DB00C65F9C /* Sidebar Header Label.swift in Sources */,
50785F762A9A684300117245 /* SavedAccountTracker+Dependency.swift in Sources */,
632578182A29F83C00446A66 /* PostSortMenu.swift in Sources */,
504ECBAE2AB45B2A006C0B96 /* LemmyURL.swift in Sources */,
CDA217EA2A63093E00BDA173 /* ReportComment.swift in Sources */,
CDA217E82A63029B00BDA173 /* ReportMention.swift in Sources */,
508845CF2A3641160088E483 /* JSONDecoder+Default.swift in Sources */,
Expand Down Expand Up @@ -2808,11 +2820,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
504ECBB12AB4B101006C0B96 /* LemmyURLTests.swift in Sources */,
50DBB8E02A805836002870B1 /* MockErrorHandler.swift in Sources */,
6363D5DB27EE196A00E34822 /* MlemTests.swift in Sources */,
50BC1AB92A89744200E3C48B /* CommunityListModelTests.swift in Sources */,
50CC4A782A9CBDF70074C845 /* TimestampedValueTests.swift in Sources */,
50DBB8E22A80F9E4002870B1 /* APICommunity+Mock.swift in Sources */,
50CC4A822AA0D61F0074C845 /* InstanceMetadataParserTests.swift in Sources */,
50C86ABC2A7E50E200277519 /* PersistenceRepositoryTests.swift in Sources */,
);
Expand Down
27 changes: 27 additions & 0 deletions Mlem/API/Internal/LemmyURL.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// LemmyURL.swift
// Mlem
//
// Created by mormaer on 15/09/2023.
//
//

import Foundation

struct LemmyURL {
let url: URL

init?(string: String?) {
guard let string else {
return nil
}

if let url = URL(string: string) {
self.url = url
} else if let encoded = string.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed), let url = URL(string: encoded) {
self.url = url
} else {
return nil
}
}
}
9 changes: 7 additions & 2 deletions Mlem/API/Models/Community/APICommunity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ struct APICommunity: Codable, Identifiable {
let nsfw: Bool
let actorId: URL
let local: Bool
let icon: URL?
let banner: URL?
let icon: String?
let banner: String?
let hidden: Bool
let postingRestrictedToMods: Bool
let instanceId: Int
Expand All @@ -44,3 +44,8 @@ extension APICommunity: Comparable {
return lhsFullCommunity < rhsFullCommunity
}
}

extension APICommunity {
var iconUrl: URL? { LemmyURL(string: icon)?.url }
var bannerUrl: URL? { LemmyURL(string: banner)?.url }
}
12 changes: 9 additions & 3 deletions Mlem/API/Models/Person/APIPerson.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ struct APIPerson: Decodable, Identifiable, Hashable {
let id: Int
let name: String
let displayName: String?
let avatar: URL?
let avatar: String?
let banned: Bool
let published: Date
let updated: Date?
let actorId: URL
let bio: String?
let local: Bool
let banner: URL?
let banner: String?
let deleted: Bool
let sharedInboxUrl: URL?
let sharedInboxUrl: String?
let matrixUserId: String?
let admin: Bool? // this is no longer returned on beehaw...
let botAccount: Bool
Expand All @@ -34,3 +34,9 @@ extension APIPerson: Equatable {
lhs.actorId == rhs.actorId
}
}

extension APIPerson {
var avatarUrl: URL? { LemmyURL(string: avatar)?.url }
var bannerUrl: URL? { LemmyURL(string: banner)?.url }
var sharedInboxLink: URL? { LemmyURL(string: sharedInboxUrl)?.url }
}
9 changes: 7 additions & 2 deletions Mlem/API/Models/Posts/APIPost.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Foundation
struct APIPost: Decodable {
let id: Int
let name: String
let url: URL?
let url: String?
let body: String?
let creatorId: Int
let communityId: Int
Expand All @@ -28,10 +28,15 @@ struct APIPost: Decodable {
let nsfw: Bool
let published: Date
let removed: Bool
let thumbnailUrl: URL?
let thumbnailUrl: String?
let updated: Date?
}

extension APIPost {
var linkUrl: URL? { LemmyURL(string: url)?.url }
mormaer marked this conversation as resolved.
Show resolved Hide resolved
var thumbnailImageUrl: URL? { LemmyURL(string: thumbnailUrl)?.url }
}

extension APIPost: Equatable {
static func == (lhs: APIPost, rhs: APIPost) -> Bool {
lhs.id == rhs.id
Expand Down
6 changes: 5 additions & 1 deletion Mlem/API/Models/Posts/APIPostReport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ struct APIPostReport: Decodable {
let creatorId: Int
let postId: Int
let originalPostName: String
let originalPostUrl: URL?
let originalPostUrl: String?
let originalPostBody: String?
let reason: String
let resolved: Bool
let resolverId: Int?
let published: Date
let updated: Date?
}

extension APIPostReport {
var originalUrl: URL? { LemmyURL(string: originalPostUrl)?.url }
}
9 changes: 7 additions & 2 deletions Mlem/API/Models/Site/APISite.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,17 @@ struct APISite: Decodable {
let name: String
let sidebar: String?
let published: Date
let icon: URL?
let banner: URL?
let icon: String?
let banner: String?
let description: String?
let actorId: String?
let lastRefreshedAt: Date
let inboxUrl: String
let publicKey: String
let instanceId: Int
}

extension APISite {
var iconUrl: URL? { LemmyURL(string: icon)?.url }
var bannerUrl: URL? { LemmyURL(string: banner)?.url }
}
4 changes: 2 additions & 2 deletions Mlem/Extensions/Mocks/APICommunity+Mock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ extension APICommunity {
nsfw: Bool = false,
actorId: URL = .mock,
local: Bool = false,
icon: URL? = nil,
banner: URL? = nil,
icon: String? = nil,
banner: String? = nil,
hidden: Bool = false,
postingRestrictedToMods: Bool = false,
instanceId: Int = 0
Expand Down
6 changes: 3 additions & 3 deletions Mlem/Extensions/Mocks/APIPerson+Mock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ extension APIPerson {
id: Int = 0,
name: String = "Mock Person",
displayName: String? = nil,
avatar: URL? = nil,
avatar: String? = nil,
banned: Bool = false,
published: Date = .mock,
updated: Date? = nil,
actorId: URL = .mock,
bio: String? = nil,
local: Bool = false,
banner: URL? = nil,
banner: String? = nil,
deleted: Bool = false,
sharedInboxUrl: URL? = nil,
sharedInboxUrl: String? = nil,
matrixUserId: String? = nil,
admin: Bool = false,
botAccount: Bool = false,
Expand Down
4 changes: 2 additions & 2 deletions Mlem/Extensions/Mocks/APIPost+Mock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ extension APIPost {
static func mock(
id: Int = 0,
name: String = "Mock Post",
url: URL? = nil,
url: String? = nil,
body: String? = nil,
creatorId: Int = 0,
communityId: Int = 0,
Expand All @@ -29,7 +29,7 @@ extension APIPost {
nsfw: Bool = false,
published: Date = .mock,
removed: Bool = false,
thumbnailUrl: URL? = nil,
thumbnailUrl: String? = nil,
updated: Date? = nil
) -> APIPost {
.init(
Expand Down
4 changes: 2 additions & 2 deletions Mlem/Extensions/Mocks/APISite+Mock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ extension APISite {
name: String = "Mock Site",
sidebar: String? = nil,
published: Date = .mock,
icon: URL? = nil,
banner: URL? = nil,
icon: String? = nil,
banner: String? = nil,
description: String? = nil,
actorId: String? = nil,
lastRefreshedAt: Date = .mock,
Expand Down
4 changes: 2 additions & 2 deletions Mlem/Models/Content/Post Model.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ struct PostModel {

var postType: PostType {
// post with URL: either image or link
if let postUrl = post.url {
if let postUrl = post.linkUrl {
// if image, return image link, otherwise return thumbnail
return postUrl.isImage ? .image(postUrl) : .link(post.thumbnailUrl)
return postUrl.isImage ? .image(postUrl) : .link(post.thumbnailImageUrl)
}

// otherwise text, but post.body needs to be present, even if it's an empty string
Expand Down
6 changes: 3 additions & 3 deletions Mlem/Models/Trackers/Post Tracker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -416,11 +416,11 @@ class PostTracker: ObservableObject {
for post in newPosts {
// preload user and community avatars--fetching both because we don't know which we'll need, but these are super tiny
// so it's probably not an API crime, right?
if let communityAvatarLink = post.community.icon {
if let communityAvatarLink = post.community.iconUrl {
imageRequests.append(ImageRequest(url: communityAvatarLink.withIcon64Parameters))
}

if let userAvatarLink = post.creator.avatar {
if let userAvatarLink = post.creator.avatarUrl {
imageRequests.append(ImageRequest(url: userAvatarLink.withIcon64Parameters))
}

Expand All @@ -430,7 +430,7 @@ class PostTracker: ObservableObject {
imageRequests.append(ImageRequest(url: url, priority: .high))
case let .link(url):
// websites: load image and favicon
if let baseURL = post.post.url?.host,
if let baseURL = post.post.linkUrl?.host,
let favIconURL = URL(string: "https://www.google.com/s2/favicons?sz=64&domain=\(baseURL)") {
imageRequests.append(ImageRequest(url: favIconURL))
}
Expand Down
2 changes: 1 addition & 1 deletion Mlem/Views/Shared/Accounts/Add Account View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ struct AddSavedInstanceView: View {
instanceLink: instanceURL,
accessToken: response.jwt,
username: username,
avatarUrl: user.avatar
avatarUrl: user.avatarUrl
)

// MARK: - Save the account's credentials into the keychain
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ struct InstanceSummary: View {
if let siteData {
VStack(spacing: AppConstants.postAndCommentSpacing) {
HStack(alignment: .top, spacing: AppConstants.postAndCommentSpacing) {
instanceIcon(url: siteData.site.icon)
instanceIcon(url: siteData.site.iconUrl)
.padding(.leading, 1)

Spacer()
Expand Down
2 changes: 1 addition & 1 deletion Mlem/Views/Shared/Components/Thumbnail Image View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ struct ThumbnailImageView: View {
contentMode: .fill
)
.onTapGesture {
if let url = post.post.url {
if let url = post.post.linkUrl {
openURL(url)
markPostAsRead()
}
Expand Down
2 changes: 1 addition & 1 deletion Mlem/Views/Shared/Composer/PostComposerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct PostComposerView: View {
self.editModel = editModel

self._postTitle = State(initialValue: editModel.editPost?.post.name ?? "")
self._postURL = State(initialValue: editModel.editPost?.post.url?.description ?? "")
self._postURL = State(initialValue: editModel.editPost?.post.linkUrl?.description ?? "")
self._postBody = State(initialValue: editModel.editPost?.post.body ?? "")
self._isNSFW = State(initialValue: editModel.editPost?.post.nsfw ?? false)
}
Expand Down
Loading