Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -136,34 +136,42 @@ public final class FilesDatabaseManager: Sendable {
/// - Returns: Metadata related to the item found by the parameters.
///
public func itemMetadata(account: String, locatedAtRemoteUrl rawRemoteURL: String) -> SendableItemMetadata? {
guard let remoteURLComponents = URLComponents(string: rawRemoteURL) else {
guard var urlComponents = URLComponents(string: rawRemoteURL) else {
logger.error("Failed to create URL components from raw remote URL.", [.account: account, .url: rawRemoteURL])
return nil
}

guard let remoteURL = remoteURLComponents.url else {
// Clear everything which is not part of the path to be able to derive a prefix which is then removed from the original raw remote URL.
urlComponents.fragment = nil
urlComponents.query = nil
urlComponents.path = ""

guard let baseURL = urlComponents.url else {
logger.error("Failed to derive base URL from components.", [.account: account, .url: rawRemoteURL])
return nil
}

// Get the file name but also take the possible fragment into consideration which is not part of a URL path but a file name.
var fileName = remoteURL.lastPathComponent

if let fragment = remoteURL.fragment {
fileName = "\(fileName)#\(fragment)"
guard let basePrefix = baseURL.absoluteString.removingPercentEncoding else {
logger.error("Failed to derive absolute string from base URL.", [.account: account, .url: rawRemoteURL])
return nil
}

// Derive the parent address by removing the last path component and discarding the fragment which may actually be part of the file name and not a URL fragment.
var parentURLComponents = remoteURLComponents
parentURLComponents.path = remoteURL.deletingLastPathComponent().path
parentURLComponents.fragment = nil
let index = rawRemoteURL.index(rawRemoteURL.startIndex, offsetBy: basePrefix.count)
let rawRemotePath = rawRemoteURL.suffix(from: index)
let pathComponents = rawRemotePath.split(separator: "/")

guard var rawParentURL = parentURLComponents.url?.absoluteString.removingPercentEncoding else {
// Get the file name but also take the possible fragment into consideration which is not part of a URL path but a file name.
// Hence a .lastPathComponent does not work and the path must be split by its slashes.
guard let fileNameSubstring = pathComponents.last else {
return nil
}

// Remove any trailing slash.
if rawParentURL.hasSuffix("/") {
rawParentURL.removeLast()
}
let fileName = String(fileNameSubstring)

// Derive the parent address by removing the last path component and discarding the fragment which may actually be part of the file name and not a URL fragment.
let parentPathComponents = pathComponents.dropLast()
Comment thread
i2h3 marked this conversation as resolved.
let parentPath = "/\(parentPathComponents.joined(separator: "/"))"
let rawParentURL = baseURL.absoluteString + parentPath

if let metadata = itemMetadatas.where({
$0.account == account && $0.serverUrl == rawParentURL && $0.fileName == fileName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,44 @@ final class FilesDatabaseManagerTests: NextcloudFileProviderKitTestCase {
XCTAssertNotNil(Self.dbManager.itemMetadata(account: account, locatedAtRemoteUrl: fullUrl))
}

func testFindingItemBasedOnRemotePathInDirectoryWithHashtagInName() throws {
let account = "TestAccount"
let filename = "super duper new file"
let parentUrl = "https://cloud.example.com/files/my great and # dir/dir-2"
let fullUrl = parentUrl + "/" + filename

let deepNestedDirectoryMetadata = RealmItemMetadata()
deepNestedDirectoryMetadata.ocId = filename
deepNestedDirectoryMetadata.account = account
deepNestedDirectoryMetadata.serverUrl = parentUrl
deepNestedDirectoryMetadata.fileName = filename
deepNestedDirectoryMetadata.directory = true

let realm = Self.dbManager.ncDatabase()
try realm.write { realm.add(deepNestedDirectoryMetadata) }

XCTAssertNotNil(Self.dbManager.itemMetadata(account: account, locatedAtRemoteUrl: fullUrl))
}

func testFindingItemBasedOnRemotePathInDirectoryWithQuestionMarkInName() throws {
let account = "TestAccount"
let filename = "super duper new file"
let parentUrl = "https://cloud.example.com/files/my great and incredible dir ?/dir-2"
let fullUrl = parentUrl + "/" + filename

let deepNestedDirectoryMetadata = RealmItemMetadata()
deepNestedDirectoryMetadata.ocId = filename
deepNestedDirectoryMetadata.account = account
deepNestedDirectoryMetadata.serverUrl = parentUrl
deepNestedDirectoryMetadata.fileName = filename
deepNestedDirectoryMetadata.directory = true

let realm = Self.dbManager.ncDatabase()
try realm.write { realm.add(deepNestedDirectoryMetadata) }

XCTAssertNotNil(Self.dbManager.itemMetadata(account: account, locatedAtRemoteUrl: fullUrl))
}

func testKeepDownloadedSetting() throws {
let existingMetadata = RealmItemMetadata()
existingMetadata.ocId = "id-1"
Expand Down
Loading