diff --git a/Brand/NCBrand.swift b/Brand/NCBrand.swift index 0fd9b5b6a7..00550b2a58 100755 --- a/Brand/NCBrand.swift +++ b/Brand/NCBrand.swift @@ -20,6 +20,43 @@ let userAgent: String = { The codename embodies the concept of dynamic, living matter — reflecting our vision of a platform that is not only powerful and reliable, but also capable of continuous transformation and intelligent adaptation. */ +struct NextcloudVersion: Comparable { + let major: Int + let minor: Int + let micro: Int + + init(_ major: Int, _ minor: Int = 0, _ micro: Int = 0) { + self.major = major + self.minor = minor + self.micro = micro + } + + init(_ capabilities: NKCapabilities.Capabilities) { + self.major = capabilities.serverVersionMajor + self.minor = capabilities.serverVersionMinor + self.micro = capabilities.serverVersionMicro + } + + static let v18 = NextcloudVersion(18) + static let v20 = NextcloudVersion(20) + static let v23 = NextcloudVersion(23) + static let v24 = NextcloudVersion(24) + static let v25 = NextcloudVersion(25) + static let v26 = NextcloudVersion(26) + static let v27 = NextcloudVersion(27) + static let v28 = NextcloudVersion(28) + static let v30 = NextcloudVersion(30) + static let v31 = NextcloudVersion(31) + static let v32 = NextcloudVersion(32) + static let v32_0_2 = NextcloudVersion(32, 0, 2) + static let v33 = NextcloudVersion(33) + static let v34 = NextcloudVersion(34) + + static func < (lhs: NextcloudVersion, rhs: NextcloudVersion) -> Bool { + (lhs.major, lhs.minor, lhs.micro) < (rhs.major, rhs.minor, rhs.micro) + } +} + final class NCBrandOptions: @unchecked Sendable { static let shared = NCBrandOptions() @@ -129,19 +166,8 @@ final class NCBrandOptions: @unchecked Sendable { } func isServerVersion(_ capabilities: NKCapabilities.Capabilities, - greaterOrEqualTo major: Int, - _ minor: Int, - _ micro: Int) -> Bool { - - let server = ( - capabilities.serverVersionMajor, - capabilities.serverVersionMinor, - capabilities.serverVersionMicro - ) - - let required = (major, minor, micro) - - return server >= required + greaterOrEqualTo version: NextcloudVersion) -> Bool { + return NextcloudVersion(capabilities) >= version } } diff --git a/File Provider Extension/FileProviderData.swift b/File Provider Extension/FileProviderData.swift index 9c36bb5bf0..a7913a77f2 100644 --- a/File Provider Extension/FileProviderData.swift +++ b/File Provider Extension/FileProviderData.swift @@ -90,7 +90,7 @@ class FileProviderData: NSObject { return isPaginated } else if serverUrl == NCUtilityFileSystem().getHomeServer(session: session), let capabilities = await NextcloudKit.shared.getCapabilitiesAsync(account: session.account).capabilities, - NCBrandOptions.shared.isServerVersion(capabilities, greaterOrEqualTo: 32, 0, 2) { + NCBrandOptions.shared.isServerVersion(capabilities, greaterOrEqualTo: .v32_0_2) { isPaginated = true return true } @@ -197,6 +197,8 @@ class FileProviderData: NSObject { etag: String?, date: Date?, size: Int64, + ownerId: String?, + permissions: String?, task: URLSessionTask, error: NKError) async { guard let metadata = await NCManageDatabase.shared.getMetadataAsync(predicate: NSPredicate(format: "serverUrl == %@ AND fileName == %@ AND sessionTaskIdentifier == %d", serverUrl, fileName, task.taskIdentifier)) else { @@ -229,6 +231,7 @@ class FileProviderData: NSObject { if let fileId = fileProviderUtility().ocIdToFileId(ocId: ocId) { metadata.fileId = fileId } + await NCNetworking.shared.applyUploadResponse(to: metadata, ownerId: ownerId, permissions: permissions) metadata.sceneIdentifier = nil metadata.session = "" diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index de48cf1181..b942a859d3 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -181,6 +181,10 @@ F3F442F02DDE2A7700FD701F /* NCMetadataPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F442ED2DDE292600FD701F /* NCMetadataPermissions.swift */; }; F3F442F12DDE2A7700FD701F /* NCMetadataPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F442ED2DDE292600FD701F /* NCMetadataPermissions.swift */; }; F3F442F42DDE2A7700FD701F /* NCMetadataPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F442ED2DDE292600FD701F /* NCMetadataPermissions.swift */; }; + F6E0A1012FAD000100000001 /* NCNetworking+UploadResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6E0A1002FAD000100000001 /* NCNetworking+UploadResponse.swift */; }; + F6E0A1022FAD000100000001 /* NCNetworking+UploadResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6E0A1002FAD000100000001 /* NCNetworking+UploadResponse.swift */; }; + F6E0A1032FAD000100000001 /* NCNetworking+UploadResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6E0A1002FAD000100000001 /* NCNetworking+UploadResponse.swift */; }; + F6E0A1042FAD000100000001 /* NCNetworking+UploadResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6E0A1002FAD000100000001 /* NCNetworking+UploadResponse.swift */; }; F700222C1EC479840080073F /* Custom.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F700222B1EC479840080073F /* Custom.xcassets */; }; F700222D1EC479840080073F /* Custom.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F700222B1EC479840080073F /* Custom.xcassets */; }; F700510122DF63AC003A3356 /* NCShare.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F700510022DF63AC003A3356 /* NCShare.storyboard */; }; @@ -1313,6 +1317,7 @@ F3E173AF2C9AF637006D177A /* ScreenAwakeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenAwakeManager.swift; sourceTree = ""; }; F3E173BF2C9B1067006D177A /* AwakeMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AwakeMode.swift; sourceTree = ""; }; F3F442ED2DDE292600FD701F /* NCMetadataPermissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMetadataPermissions.swift; sourceTree = ""; }; + F6E0A1002FAD000100000001 /* NCNetworking+UploadResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCNetworking+UploadResponse.swift"; sourceTree = ""; }; F700222B1EC479840080073F /* Custom.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Custom.xcassets; sourceTree = ""; }; F700510022DF63AC003A3356 /* NCShare.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCShare.storyboard; sourceTree = ""; }; F700510422DF6A89003A3356 /* NCShare.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShare.swift; sourceTree = ""; }; @@ -2492,6 +2497,7 @@ F74230F22C79B57200CA1ACA /* NCNetworking+Task.swift */, F785129A2D79899E0087DDD0 /* NCNetworking+TermsOfService.swift */, F71916102E2901E800E13E96 /* NCNetworking+Upload.swift */, + F6E0A1002FAD000100000001 /* NCNetworking+UploadResponse.swift */, F7327E2F2B73A86700A462C7 /* NCNetworking+WebDAV.swift */, F70D8D8024A4A9BF000A5756 /* NCNetworkingProcess.swift */, F755BD9A20594AC7008C5FBB /* NCService.swift */, @@ -4279,6 +4285,7 @@ F763413E2EBE5DC00056F538 /* FileProviderItem.swift in Sources */, F7490E8729882CA8009DCE94 /* ThreadSafeDictionary.swift in Sources */, F7E742FA2EC0A5BC00E2362A /* NCManageDatabase+Metadata.swift in Sources */, + F6E0A1032FAD000100000001 /* NCNetworking+UploadResponse.swift in Sources */, F7E742FC2EC0A5FD00E2362A /* NCManageDatabase+Metadata+Session.swift in Sources */, F3E173C52C9B1067006D177A /* AwakeMode.swift in Sources */, F76341392EBE5CF80056F538 /* FileProviderData.swift in Sources */, @@ -4328,6 +4335,7 @@ F740BEF02A35C2AD00E9B6D5 /* UILabel+Extension.swift in Sources */, F7C30E01291BD2610017149B /* NCNetworkingE2EERename.swift in Sources */, AF4BF61A27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */, + F6E0A1022FAD000100000001 /* NCNetworking+UploadResponse.swift in Sources */, AF4BF615275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */, F798F0E225880608000DAFFD /* UIColor+Extension.swift in Sources */, F7C9B9202B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */, @@ -4520,6 +4528,7 @@ F7E742F72EC0A4CD00E2362A /* NCManageDatabase+LocalFile.swift in Sources */, F7E742F52EC0A3DD00E2362A /* NCManageDatabase+Directory.swift in Sources */, F7E742F92EC0A5BC00E2362A /* NCManageDatabase+Metadata.swift in Sources */, + F6E0A1042FAD000100000001 /* NCNetworking+UploadResponse.swift in Sources */, F763412E2EBE255B0056F538 /* NCNetworking+NextcloudKitDelegate.swift in Sources */, F78E2D6929AF02DB0024D4F3 /* Database.swift in Sources */, F771E3F320E239A600AFB62D /* FileProviderData.swift in Sources */, @@ -4610,6 +4619,7 @@ F755CB402B8CB13C00CE27E9 /* NCMediaLayout.swift in Sources */, F73EF7B72B0224AB0087E6E9 /* NCManageDatabase+ExternalSites.swift in Sources */, AF4BF61927562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */, + F6E0A1012FAD000100000001 /* NCNetworking+UploadResponse.swift in Sources */, F78A18B623CDD07D00F681F3 /* NCViewerRichWorkspaceWebView.swift in Sources */, AFA2AC8527849604008E1EA7 /* NCActivityCommentView.swift in Sources */, AFCE353727E4ED7B00FEA6C2 /* NCShareCells.swift in Sources */, diff --git a/iOSClient/Assistant/NCAssistantModel.swift b/iOSClient/Assistant/NCAssistantModel.swift index 7b796643ca..02dbc8c11f 100644 --- a/iOSClient/Assistant/NCAssistantModel.swift +++ b/iOSClient/Assistant/NCAssistantModel.swift @@ -43,7 +43,7 @@ class NCAssistantModel { self.session = NCSession.shared.getSession(controller: controller) let capabilities = NCNetworking.shared.capabilities[session.account] ?? NKCapabilities.Capabilities() - useV2 = capabilities.serverVersionMajor >= NCGlobal.shared.nextcloudVersion30 + useV2 = NCBrandOptions.shared.isServerVersion(capabilities, greaterOrEqualTo: .v30) loadAllTypes() } diff --git a/iOSClient/Data/NCMetadataTranfersSuccess.swift b/iOSClient/Data/NCMetadataTranfersSuccess.swift index 6f115ae4a8..abfe48133f 100644 --- a/iOSClient/Data/NCMetadataTranfersSuccess.swift +++ b/iOSClient/Data/NCMetadataTranfersSuccess.swift @@ -25,7 +25,12 @@ actor NCMetadataTranfersSuccess { delegates.removeAll { $0 as AnyObject === delegate as AnyObject } } - func append(metadata: tableMetadata, ocId: String, date: Date?, etag: String?) async { + func append(metadata: tableMetadata, + ocId: String, + date: Date?, + etag: String?, + ownerId: String? = nil, + permissions: String? = nil) async { metadata.ocId = ocId metadata.uploadDate = (date as? NSDate) ?? NSDate() metadata.etag = etag ?? "" @@ -34,6 +39,7 @@ actor NCMetadataTranfersSuccess { if let fileId = self.utility.ocIdToFileId(ocId: ocId) { metadata.fileId = fileId } + await NCNetworking.shared.applyUploadResponse(to: metadata, ownerId: ownerId, permissions: permissions) metadata.session = "" metadata.sessionError = "" diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon+Search.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon+Search.swift index 4a836e1c82..d748b07ac6 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon+Search.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon+Search.swift @@ -29,7 +29,7 @@ extension NCCollectionViewCommon { setSearchBarLoading(true) networkSearchInProgress = true - if capabilities.serverVersionMajor >= global.nextcloudVersion20 { + if NCBrandOptions.shared.isServerVersion(capabilities, greaterOrEqualTo: .v20) { await unifiedSearch(text: text) } else { await searchLiteral(text: text) diff --git a/iOSClient/Main/Create/Upload Assets/NCUploadAssetsModel.swift b/iOSClient/Main/Create/Upload Assets/NCUploadAssetsModel.swift index 04f9521bd1..2172b5c7dc 100644 --- a/iOSClient/Main/Create/Upload Assets/NCUploadAssetsModel.swift +++ b/iOSClient/Main/Create/Upload Assets/NCUploadAssetsModel.swift @@ -172,7 +172,7 @@ class NCUploadAssetsModel: ObservableObject, NCCreateFormUploadConflictDelegate self.uploadInProgress.toggle() return } - let autoMkcol = capabilities.serverVersionMajor >= NCGlobal.shared.nextcloudVersion33 + let autoMkcol = NCBrandOptions.shared.isServerVersion(capabilities, greaterOrEqualTo: .v33) func createProcessUploads() { if !self.dismissView { diff --git a/iOSClient/Media/NCMedia+Netwoking.swift b/iOSClient/Media/NCMedia+Netwoking.swift index f64ad08fd5..e00c439176 100644 --- a/iOSClient/Media/NCMedia+Netwoking.swift +++ b/iOSClient/Media/NCMedia+Netwoking.swift @@ -18,23 +18,12 @@ extension NCMedia { guard let nkSession = NextcloudKit.shared.nkCommonInstance.nksessions.session(forAccount: account) else { return (account, nil, .urlError) } - let capabilities = await NKCapabilities.shared.getCapabilities(for: account) let files: [NKFile] = [] let href = "/files/" + nkSession.userId + path - let elementDate: String - var lessDateString: String - var greaterDateString: String - - if capabilities.serverVersionMajor >= self.global.nextcloudVersionFuture { - elementDate = "nc:metadata-photos-original_date_time" - lessDateString = String(lessDate.timeIntervalSince1970) - greaterDateString = String(greaterDate.timeIntervalSince1970) - } else { - elementDate = "d:getlastmodified" - lessDateString = lessDate.formatted(using: "yyyy-MM-dd'T'HH:mm:ssZZZZZ") - greaterDateString = greaterDate.formatted(using: "yyyy-MM-dd'T'HH:mm:ssZZZZZ") - } + let elementDate = "d:getlastmodified" + let lessDateString = lessDate.formatted(using: "yyyy-MM-dd'T'HH:mm:ssZZZZZ") + let greaterDateString = greaterDate.formatted(using: "yyyy-MM-dd'T'HH:mm:ssZZZZZ") let httpBodyString = String(format: getRequestBodySearchMedia( createProperties: options.createProperties, diff --git a/iOSClient/Media/NCMediaDataSource.swift b/iOSClient/Media/NCMediaDataSource.swift index ecbc2a9d6c..adde0f44f3 100644 --- a/iOSClient/Media/NCMediaDataSource.swift +++ b/iOSClient/Media/NCMediaDataSource.swift @@ -11,17 +11,11 @@ extension NCMedia { guard let tblAccount = await self.database.getTableAccountAsync(predicate: NSPredicate(format: "account == %@", self.session.account)) else { return } - let capabilities = await NKCapabilities.shared.getCapabilities(for: self.session.account) let mediaPredicate = self.imageCache.getMediaPredicate(session: self.session, mediaPath: tblAccount.mediaPath, showOnlyImages: self.showOnlyImages, showOnlyVideos: self.showOnlyVideos) - var sortedByKeyPath: String - if capabilities.serverVersionMajor >= self.global.nextcloudVersionFuture { - sortedByKeyPath = "datePhotosOriginal" - } else { - sortedByKeyPath = "date" - } + let sortedByKeyPath = "date" if let metadatas = await self.database.getMetadatasAsync(predicate: mediaPredicate, sortedByKeyPath: sortedByKeyPath, ascending: false) { self.database.filterAndNormalizeLivePhotos(from: metadatas) { metadatas in @@ -180,13 +174,6 @@ extension NCMedia { mediaPredicate ]) - if capabilities.serverVersionMajor >= self.global.nextcloudVersionFuture { - predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [ - NSPredicate(format: "datePhotosOriginal >= %@ AND datePhotosOriginal <= %@ AND mediaSearch == true", greaterDate as NSDate, lessDate as NSDate), - mediaPredicate - ]) - } - let localMetadatas = await self.database.getMetadatasAsync(predicate: predicate) await MainActor.run { @@ -258,12 +245,7 @@ public class NCMediaDataSource: NSObject { private func getMetadataFromTableMetadata(_ metadata: tableMetadata) -> Metadata { let capabilities = NCNetworking.shared.capabilities[metadata.account] ?? NKCapabilities.Capabilities() - let date: Date - if capabilities.serverVersionMajor >= self.global.nextcloudVersionFuture { - date = metadata.datePhotosOriginal as Date - } else { - date = metadata.date as Date - } + let date = metadata.date as Date return Metadata(date: date, etag: metadata.etag, imageSize: CGSize(width: metadata.width, height: metadata.height), diff --git a/iOSClient/Menu/NCContextMenuPlus.swift b/iOSClient/Menu/NCContextMenuPlus.swift index 0782aed87d..19d41fd1d3 100644 --- a/iOSClient/Menu/NCContextMenuPlus.swift +++ b/iOSClient/Menu/NCContextMenuPlus.swift @@ -153,7 +153,7 @@ class NCContextMenuPlus: NSObject { // ------------------------------- RICHDOCUMENT TEXT - if capabilities.serverVersionMajor >= NCGlobal.shared.nextcloudVersion18, + if NCBrandOptions.shared.isServerVersion(capabilities, greaterOrEqualTo: .v18), directory?.richWorkspace == nil, !isDirectoryE2EE, isNetworkReachable { diff --git a/iOSClient/Menu/NCContextMenuProfile.swift b/iOSClient/Menu/NCContextMenuProfile.swift index bc4b64ab47..615b895fff 100644 --- a/iOSClient/Menu/NCContextMenuProfile.swift +++ b/iOSClient/Menu/NCContextMenuProfile.swift @@ -36,7 +36,7 @@ class NCContextMenuProfile: NSObject { func viewMenu() -> UIMenu { let capabilities = NCNetworking.shared.capabilities[session.account] ?? NKCapabilities.Capabilities() - guard capabilities.serverVersionMajor >= NCGlobal.shared.nextcloudVersion23 else { + guard NCBrandOptions.shared.isServerVersion(capabilities, greaterOrEqualTo: .v23) else { return UIMenu() } diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift index cd2eee1ef7..3afbac7c84 100644 --- a/iOSClient/NCGlobal.swift +++ b/iOSClient/NCGlobal.swift @@ -40,27 +40,6 @@ final class NCGlobal: Sendable { let twoFactorNotificatioName = "twofactor_nextcloud_notification" let termsOfServiceName = "terms_of_service" - // Nextcloud version - // - let nextcloudVersion18: Int = 18 - let nextcloudVersion20: Int = 20 - let nextcloudVersion23: Int = 23 - let nextcloudVersion24: Int = 24 - let nextcloudVersion25: Int = 25 - let nextcloudVersion26: Int = 26 - let nextcloudVersion27: Int = 27 - let nextcloudVersion28: Int = 28 - let nextcloudVersion30: Int = 30 - let nextcloudVersion31: Int = 31 - let nextcloudVersion32: Int = 32 - let nextcloudVersion33: Int = 33 - let nextcloudVersionFuture: Int = 99999 - - - // Nextcloud unsupported - // - let nextcloud_unsupported_version: Int = 20 - // Intro selector // let introLogin: Int = 0 diff --git a/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift b/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift index aa64cea15a..7fe696cca4 100644 --- a/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift +++ b/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift @@ -195,6 +195,9 @@ class NCNetworkingE2EEUpload: NSObject { if let fileId = self.utility.ocIdToFileId(ocId: ocId) { metadata.fileId = fileId } + await NCNetworking.shared.applyUploadResponse(to: metadata, + ownerId: resultsSendFile.ownerId, + permissions: resultsSendFile.permissions) metadata.chunk = 0 metadata.session = "" @@ -238,7 +241,7 @@ class NCNetworkingE2EEUpload: NSObject { tokenBanner: Int?, requestHandle: @escaping (_ request: UploadRequest) -> Void = { _ in }, currentUploadTask: @escaping (_ task: Task<(account: String, file: NKFile?, error: NKError), Never>?) -> Void = { _ in }) - async -> (ocId: String?, etag: String?, date: Date?, error: NKError) { + async -> (ocId: String?, etag: String?, date: Date?, ownerId: String?, permissions: String?, error: NKError) { if metadata.chunk > 0 { let payload = LucidBannerPayload.Update( title: NSLocalizedString("_wait_file_preparation_", comment: ""), @@ -289,7 +292,12 @@ class NCNetworkingE2EEUpload: NSObject { currentUploadTask(task) let results = await task.value - return (results.file?.ocId, results.file?.etag, results.file?.date, results.error) + return (results.file?.ocId, + results.file?.etag, + results.file?.date, + results.file?.ownerId, + results.file?.permissions, + results.error) } else { let payload = LucidBannerPayload.Update( title: NSLocalizedString("_keep_active_for_upload_", comment: ""), @@ -320,7 +328,12 @@ class NCNetworkingE2EEUpload: NSObject { } } - return (results.ocId, results.etag, results.date, results.error) + return (results.ocId, + results.etag, + results.date, + results.ownerId, + results.permissions, + results.error) } } } diff --git a/iOSClient/Networking/NCAutoUpload.swift b/iOSClient/Networking/NCAutoUpload.swift index c99d1085e9..4e4fbe34c1 100644 --- a/iOSClient/Networking/NCAutoUpload.swift +++ b/iOSClient/Networking/NCAutoUpload.swift @@ -87,7 +87,7 @@ class NCAutoUpload: NSObject { assets: [PHAsset], fileNames: [String]) async -> Int { let capabilities = await NKCapabilities.shared.getCapabilities(for: tblAccount.account) - let autoMkcol = capabilities.serverVersionMajor >= NCGlobal.shared.nextcloudVersion33 + let autoMkcol = NCBrandOptions.shared.isServerVersion(capabilities, greaterOrEqualTo: .v33) let session = NCSession.shared.getSession(account: tblAccount.account) let autoUploadServerUrlBase = await self.database.getAccountAutoUploadServerUrlBaseAsync(account: tblAccount.account, urlBase: tblAccount.urlBase, userId: tblAccount.userId) var metadatas: [tableMetadata] = [] @@ -306,7 +306,7 @@ class NCAutoUpload: NSObject { // If server supports auto MKCOL (Nextcloud >= 33), skip manual folder creation. if let capabilities = capabilitiesByAccount[metadata.account] { - let autoMkcol = capabilities.serverVersionMajor >= NCGlobal.shared.nextcloudVersion33 + let autoMkcol = NCBrandOptions.shared.isServerVersion(capabilities, greaterOrEqualTo: .v33) if autoMkcol { continue } diff --git a/iOSClient/Networking/NCNetworking+NextcloudKitDelegate.swift b/iOSClient/Networking/NCNetworking+NextcloudKitDelegate.swift index 3b84a934eb..116d4c52c8 100644 --- a/iOSClient/Networking/NCNetworking+NextcloudKitDelegate.swift +++ b/iOSClient/Networking/NCNetworking+NextcloudKitDelegate.swift @@ -9,7 +9,6 @@ import Alamofire import LucidBanner extension NCNetworking { - #if !EXTENSION func networkReachabilityObserver(_ typeReachability: NKTypeReachability) { if typeReachability == NKTypeReachability.reachableCellular || typeReachability == NKTypeReachability.reachableEthernetOrWiFi { @@ -125,6 +124,8 @@ extension NCNetworking { etag: String?, date: Date?, size: Int64, + ownerId: String?, + permissions: String?, task: URLSessionTask, error: NKError) { Task { @@ -137,6 +138,8 @@ extension NCNetworking { etag: etag, date: date, size: size, + ownerId: ownerId, + permissions: permissions, task: task, error: error) @@ -152,14 +155,18 @@ extension NCNetworking { await self.uploadSuccess(withMetadata: metadata, ocId: ocId, etag: etag, - date: date) + date: date, + ownerId: ownerId, + permissions: permissions) } else { #if !EXTENSION await NCManageDatabase.shared.deleteMetadataAsync(ocId: metadata.ocId) await NCNetworking.shared.metadataTranfersSuccess.append(metadata: metadata, ocId: ocId, date: date, - etag: etag) + etag: etag, + ownerId: ownerId, + permissions: permissions) #endif } } else { diff --git a/iOSClient/Networking/NCNetworking+Upload.swift b/iOSClient/Networking/NCNetworking+Upload.swift index 50ba5fb80a..8df6f1621d 100644 --- a/iOSClient/Networking/NCNetworking+Upload.swift +++ b/iOSClient/Networking/NCNetworking+Upload.swift @@ -25,7 +25,8 @@ extension NCNetworking { etag: String?, date: Date?, size: Int64, - response: AFDataResponse?, + ownerId: String?, + permissions: String?, error: NKError) { let options = NKRequestOptions(customHeader: customHeaders, queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue) let results = await NextcloudKit.shared.uploadAsync(serverUrlFileName: serverUrlFileName, @@ -47,8 +48,14 @@ extension NCNetworking { } progressHandler: { progress in progressHandler(progress.completedUnitCount, progress.totalUnitCount, progress.fractionCompleted) } - - return results + return (results.account, + results.ocId, + results.etag, + results.date, + results.size, + results.ownerId, + results.permissions, + results.error) } // MARK: - Upload chunk file in foreground @@ -148,7 +155,12 @@ extension NCNetworking { directory: directory) if performPostProcessing, let file { - await uploadSuccess(withMetadata: metadata, ocId: file.ocId, etag: file.etag, date: file.date) + await uploadSuccess(withMetadata: metadata, + ocId: file.ocId, + etag: file.etag, + date: file.date, + ownerId: file.ownerId, + permissions: file.permissions) } backupFile = file @@ -232,7 +244,9 @@ extension NCNetworking { func uploadSuccess(withMetadata metadata: tableMetadata, ocId: String, etag: String?, - date: Date?) async { + date: Date?, + ownerId: String? = nil, + permissions: String? = nil) async { nkLog(success: "Uploaded file: " + metadata.serverUrlFileName) metadata.uploadDate = (date as? NSDate) ?? NSDate() @@ -243,6 +257,7 @@ extension NCNetworking { if let fileId = NCUtility().ocIdToFileId(ocId: ocId) { metadata.fileId = fileId } + await applyUploadResponse(to: metadata, ownerId: ownerId, permissions: permissions) metadata.session = "" metadata.sessionError = "" @@ -504,4 +519,5 @@ extension NCNetworking { return (localFile: localFile, livePhoto: livePhoto, autoUpload: autoUpload) } + } diff --git a/iOSClient/Networking/NCNetworking+UploadResponse.swift b/iOSClient/Networking/NCNetworking+UploadResponse.swift new file mode 100644 index 0000000000..c1aa7d4d50 --- /dev/null +++ b/iOSClient/Networking/NCNetworking+UploadResponse.swift @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: Nextcloud GmbH +// SPDX-FileCopyrightText: 2026 Milen Pivchev +// SPDX-License-Identifier: GPL-3.0-or-later + +import NextcloudKit + +extension NCNetworking { + /// Applies per-file metadata returned by Nextcloud 34+ upload responses. + /// + /// Older servers do not return `X-NC-OwnerId` or `X-NC-Permissions` on upload responses, so this method keeps the + /// existing locally-created metadata unchanged unless the connected server is new enough and the response values are non-empty. + /// + /// - Parameters: + /// - metadata: Local metadata row for the uploaded file. + /// - ownerId: Owner id parsed from the upload response. + /// - permissions: DAV permissions parsed from the upload response. + func applyUploadResponse(to metadata: tableMetadata, ownerId: String?, permissions: String?) async { + let capabilities: NKCapabilities.Capabilities + if let cachedCapabilities = self.capabilities[metadata.account] { + capabilities = cachedCapabilities + } else { + capabilities = await NKCapabilities.shared.getCapabilities(for: metadata.account) + } + guard NCBrandOptions.shared.isServerVersion(capabilities, greaterOrEqualTo: .v34) else { + return + } + + if let ownerId, !ownerId.isEmpty { + metadata.ownerId = ownerId + if metadata.ownerDisplayName.isEmpty { + metadata.ownerDisplayName = ownerId + } + } + + if let permissions, !permissions.isEmpty { + metadata.permissions = permissions + } + } +} diff --git a/iOSClient/Networking/NCService.swift b/iOSClient/Networking/NCService.swift index 9c79b399d4..f6715693d3 100644 --- a/iOSClient/Networking/NCService.swift +++ b/iOSClient/Networking/NCService.swift @@ -69,7 +69,7 @@ class NCService: NSObject { systemImage: "xmark.icloud.fill", imageAnimation: .none) return false - } else if serverInfo.versionMajor <= NCGlobal.shared.nextcloud_unsupported_version { + } else if NextcloudVersion(serverInfo.versionMajor) <= .v20 { await showWarningBanner(windowScene: windowScene, subtitle: "_warning_unsupported_", systemImage: "xmark.icloud.fill", diff --git a/iOSClient/Utility/NCLivePhoto.swift b/iOSClient/Utility/NCLivePhoto.swift index b53706a253..6849887f53 100644 --- a/iOSClient/Utility/NCLivePhoto.swift +++ b/iOSClient/Utility/NCLivePhoto.swift @@ -723,7 +723,7 @@ extension NCLivePhoto { Task { let capabilities = await NKCapabilities.shared.getCapabilities(for: metadata1.account) - guard capabilities.serverVersionMajor >= NCGlobal.shared.nextcloudVersion28 else { + guard NCBrandOptions.shared.isServerVersion(capabilities, greaterOrEqualTo: .v28) else { return }