Explorar o código

Version 5.5.2 (#3005)

Marino Faggiana hai 9 meses
pai
achega
9e4e7af280

+ 21 - 0
File Provider Extension/FileProviderData.swift

@@ -58,6 +58,14 @@ class fileProviderData: NSObject {
         case workingSet
     }
 
+    struct UploadMetadata {
+        var id: String
+        var metadata: tableMetadata
+        var task: URLSessionUploadTask?
+    }
+
+    var uploadMetadata: [UploadMetadata] = []
+
     // MARK: - 
 
     func setupAccount(domain: NSFileProviderDomain?, providerExtension: NSFileProviderExtension) -> tableAccount? {
@@ -140,4 +148,17 @@ class fileProviderData: NSObject {
         fileProviderManager.signalEnumerator(for: .workingSet) { _ in }
         return item
     }
+
+    // MARK: -
+
+    func appendUploadMetadata(id: String, metadata: tableMetadata, task: URLSessionUploadTask?) {
+        if let index = uploadMetadata.firstIndex(where: { $0.id == id }) {
+            uploadMetadata.remove(at: index)
+        }
+        uploadMetadata.append(UploadMetadata(id: id, metadata: metadata, task: task))
+    }
+
+    func getUploadMetadata(id: String) -> UploadMetadata? {
+        return uploadMetadata.filter({ $0.id == id }).first
+    }
 }

+ 36 - 28
File Provider Extension/FileProviderExtension+NetworkingDelegate.swift

@@ -36,37 +36,45 @@ extension FileProviderExtension: NCNetworkingDelegate {
     func uploadComplete(fileName: String, serverUrl: String, ocId: String?, etag: String?, date: Date?, size: Int64, task: URLSessionTask, error: NKError) {
         guard let url = task.currentRequest?.url,
               let metadata = NCManageDatabase.shared.getMetadata(from: url, sessionTaskIdentifier: task.taskIdentifier) else { return }
-        if error == .success, let ocId {
-            /// SIGNAL
-            fileProviderData.shared.signalEnumerator(ocId: metadata.ocIdTemp, type: .delete)
-            metadata.fileName = fileName
-            metadata.serverUrl = serverUrl
-            metadata.uploadDate = (date as? NSDate) ?? NSDate()
-            metadata.etag = etag ?? ""
-            metadata.ocId = ocId
-            metadata.size = size
-            if let fileId = NCUtility().ocIdToFileId(ocId: ocId) {
-                metadata.fileId = fileId
-            }
-            metadata.session = ""
-            metadata.sessionError = ""
-            metadata.status = NCGlobal.shared.metadataStatusNormal
 
-            NCManageDatabase.shared.addMetadata(metadata)
-            NCManageDatabase.shared.addLocalFile(metadata: metadata)
-            /// NEW File
-            if ocId != metadata.ocIdTemp {
-                let atPath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocIdTemp)
-                let toPath = utilityFileSystem.getDirectoryProviderStorageOcId(ocId)
-                utilityFileSystem.copyFile(atPath: atPath, toPath: toPath)
+        DispatchQueue.global(qos: .userInteractive).async {
+            if error == .success, let ocId {
+                /// SIGNAL
+                fileProviderData.shared.signalEnumerator(ocId: metadata.ocIdTemp, type: .delete)
+                metadata.fileName = fileName
+                metadata.serverUrl = serverUrl
+                metadata.uploadDate = (date as? NSDate) ?? NSDate()
+                metadata.etag = etag ?? ""
+                metadata.ocId = ocId
+                metadata.size = size
+                if let fileId = NCUtility().ocIdToFileId(ocId: ocId) {
+                    metadata.fileId = fileId
+                }
+
+                metadata.sceneIdentifier = nil
+                metadata.session = ""
+                metadata.sessionError = ""
+                metadata.sessionSelector = ""
+                metadata.sessionDate = nil
+                metadata.sessionTaskIdentifier = 0
+                metadata.status = NCGlobal.shared.metadataStatusNormal
+
+                NCManageDatabase.shared.addMetadata(metadata)
+                NCManageDatabase.shared.addLocalFile(metadata: metadata)
+                /// NEW File
+                if !metadata.ocIdTemp.isEmpty, ocId != metadata.ocIdTemp {
+                    let atPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocIdTemp)
+                    let toPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(ocId)
+                    self.utilityFileSystem.copyFile(atPath: atPath, toPath: toPath)
+                    NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocIdTemp))
+                }
+                /// SIGNAL
+                fileProviderData.shared.signalEnumerator(ocId: metadata.ocId, type: .update)
+            } else {
                 NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocIdTemp))
+                /// SIGNAL
+                fileProviderData.shared.signalEnumerator(ocId: metadata.ocIdTemp, type: .delete)
             }
-            /// SIGNAL
-            fileProviderData.shared.signalEnumerator(ocId: metadata.ocId, type: .update)
-        } else {
-            NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocIdTemp))
-            /// SIGNAL
-            fileProviderData.shared.signalEnumerator(ocId: metadata.ocIdTemp, type: .delete)
         }
     }
 }

+ 25 - 5
File Provider Extension/FileProviderExtension.swift

@@ -166,7 +166,13 @@ class FileProviderExtension: NSFileProviderExtension {
     override func startProvidingItem(at url: URL, completionHandler: @escaping ((_ error: Error?) -> Void)) {
         let pathComponents = url.pathComponents
         let itemIdentifier = NSFileProviderItemIdentifier(pathComponents[pathComponents.count - 2])
-        guard let metadata = providerUtility.getTableMetadataFromItemIdentifier(itemIdentifier) else {
+        var metadata: tableMetadata?
+        if let result = fileProviderData.shared.getUploadMetadata(id: itemIdentifier.rawValue) {
+            metadata = result.metadata
+        } else {
+            metadata = NCManageDatabase.shared.getMetadataFromOcIdAndOcIdTemp(itemIdentifier.rawValue)
+        }
+        guard let metadata else {
             return completionHandler(NSFileProviderError(.noSuchItem))
         }
         if metadata.session == NCNetworking.shared.sessionUploadBackgroundExtension {
@@ -200,6 +206,12 @@ class FileProviderExtension: NSFileProviderExtension {
                 return completionHandler(NSFileProviderError(.noSuchItem))
             }
             if error == .success {
+                metadata.sceneIdentifier = nil
+                metadata.session = ""
+                metadata.sessionError = ""
+                metadata.sessionSelector = ""
+                metadata.sessionDate = nil
+                metadata.sessionTaskIdentifier = 0
                 metadata.status = NCGlobal.shared.metadataStatusNormal
                 metadata.date = (date as? NSDate) ?? NSDate()
                 metadata.etag = etag ?? ""
@@ -226,16 +238,23 @@ class FileProviderExtension: NSFileProviderExtension {
         assert(pathComponents.count > 2)
         let itemIdentifier = NSFileProviderItemIdentifier(pathComponents[pathComponents.count - 2])
         let fileName = pathComponents[pathComponents.count - 1]
-        guard let metadata = NCManageDatabase.shared.getMetadataFromOcIdAndOcIdTemp(itemIdentifier.rawValue) else { return }
+        var metadata: tableMetadata?
+        if let result = fileProviderData.shared.getUploadMetadata(id: itemIdentifier.rawValue) {
+            metadata = result.metadata
+        } else {
+            metadata = NCManageDatabase.shared.getMetadataFromOcIdAndOcIdTemp(itemIdentifier.rawValue)
+        }
+        guard let metadata else {
+            return
+        }
         let serverUrlFileName = metadata.serverUrl + "/" + fileName
-        let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: fileName)
-        utilityFileSystem.copyFile(atPath: url.path, toPath: fileNameLocalPath)
+
         NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
                                                    session: NCNetworking.shared.sessionUploadBackgroundExtension,
                                                    sessionError: "",
                                                    selector: "",
                                                    status: NCGlobal.shared.metadataStatusUploading)
-        if let task = NKBackground(nkCommonInstance: NextcloudKit.shared.nkCommonInstance).upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, dateCreationFile: nil, dateModificationFile: nil, session: NCNetworking.shared.sessionManagerUploadBackgroundExtension) {
+        if let task = NKBackground(nkCommonInstance: NextcloudKit.shared.nkCommonInstance).upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: url.path, dateCreationFile: nil, dateModificationFile: nil, session: NCNetworking.shared.sessionManagerUploadBackgroundExtension) {
             NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
                                                        status: NCGlobal.shared.metadataStatusUploading,
                                                        taskIdentifier: task.taskIdentifier)
@@ -304,6 +323,7 @@ class FileProviderExtension: NSFileProviderExtension {
                                                                status: NCGlobal.shared.metadataStatusUploading,
                                                                taskIdentifier: task.taskIdentifier)
                     fileProviderData.shared.fileProviderManager.register(task, forItemWithIdentifier: NSFileProviderItemIdentifier(ocIdTemp)) { _ in }
+                    fileProviderData.shared.appendUploadMetadata(id: ocIdTemp, metadata: metadata, task: task)
                 }
 
                 let item = FileProviderItem(metadata: tableMetadata.init(value: metadata), parentItemIdentifier: parentItemIdentifier)

+ 20 - 4
File Provider Extension/FileProviderUtility.swift

@@ -75,12 +75,12 @@ class fileProviderUtility: NSObject {
         do {
             try fileManager.removeItem(atPath: toPath)
         } catch let error {
-            print("error: \(error)")
+            print("Error: \(error.localizedDescription)")
         }
         do {
             try fileManager.copyItem(atPath: atPath, toPath: toPath)
         } catch let error {
-            print("error: \(error)")
+            print("Error: \(error.localizedDescription)")
         }
     }
 
@@ -90,12 +90,28 @@ class fileProviderUtility: NSObject {
         do {
             try fileManager.removeItem(atPath: toPath)
         } catch let error {
-            print("error: \(error)")
+            print("Error: \(error.localizedDescription)")
         }
         do {
             try fileManager.moveItem(atPath: atPath, toPath: toPath)
         } catch let error {
-            print("error: \(error)")
+            print("Error: \(error.localizedDescription)")
+        }
+    }
+
+    func getFileSize(from url: URL) -> Int64? {
+        do {
+            let attributes = try fileManager.attributesOfItem(atPath: url.path)
+
+            if let fileSize = attributes[FileAttributeKey.size] as? Int64 {
+                return fileSize
+            } else {
+                print("Failed to retrieve file size.")
+                return nil
+            }
+        } catch {
+            print("Error: \(error.localizedDescription)")
+            return nil
         }
     }
 }

+ 4 - 4
Nextcloud.xcodeproj/project.pbxproj

@@ -5414,7 +5414,7 @@
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 11;
+				CURRENT_PROJECT_VERSION = 2;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DEVELOPMENT_TEAM = NKUJUXUJ3B;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -5441,7 +5441,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 5.5.0;
+				MARKETING_VERSION = 5.5.2;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_CFLAGS = "-v";
 				OTHER_LDFLAGS = "";
@@ -5480,7 +5480,7 @@
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 11;
+				CURRENT_PROJECT_VERSION = 2;
 				DEVELOPMENT_TEAM = NKUJUXUJ3B;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
@@ -5504,7 +5504,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 5.5.0;
+				MARKETING_VERSION = 5.5.2;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_CFLAGS = "-v";
 				OTHER_LDFLAGS = "";

+ 6 - 6
Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme

@@ -15,9 +15,9 @@
             buildForAnalyzing = "YES">
             <BuildableReference
                BuildableIdentifier = "primary"
-               BlueprintIdentifier = "F771E3CF20E2392D00AFB62D"
-               BuildableName = "File Provider Extension.appex"
-               BlueprintName = "File Provider Extension"
+               BlueprintIdentifier = "F77B0DEB1D118A16002130FE"
+               BuildableName = "Nextcloud.app"
+               BlueprintName = "Nextcloud"
                ReferencedContainer = "container:Nextcloud.xcodeproj">
             </BuildableReference>
          </BuildActionEntry>
@@ -29,9 +29,9 @@
             buildForAnalyzing = "YES">
             <BuildableReference
                BuildableIdentifier = "primary"
-               BlueprintIdentifier = "F77B0DEB1D118A16002130FE"
-               BuildableName = "Nextcloud.app"
-               BlueprintName = "Nextcloud"
+               BlueprintIdentifier = "F771E3CF20E2392D00AFB62D"
+               BuildableName = "File Provider Extension.appex"
+               BlueprintName = "File Provider Extension"
                ReferencedContainer = "container:Nextcloud.xcodeproj">
             </BuildableReference>
          </BuildActionEntry>

+ 7 - 0
iOSClient/Account Settings/NCAccountSettingsModel.swift

@@ -140,6 +140,13 @@ class NCAccountSettingsModel: ObservableObject, ViewOnAppearHandling {
         return (nil, "", "")
     }
 
+    /// Is the user an Admin
+    func isAdminGroup() -> Bool {
+        guard let activeAccount else { return false }
+        let groups = NCManageDatabase.shared.getAccountGroups(account: activeAccount.account)
+        return groups.contains(NCGlobal.shared.groupAdmin)
+    }
+
     /// Function to know the height of "account" data
     func getTableViewHeight() -> CGFloat {
         guard let activeAccount else { return 0 }

+ 47 - 45
iOSClient/Account Settings/NCAccountSettingsView.swift

@@ -181,52 +181,54 @@ struct NCAccountSettingsView: View {
                     }
                     ///
                     /// Certificate server
-                    Button(action: {
-                        showServerCertificate.toggle()
-                    }, label: {
-                        HStack {
-                            Image(systemName: "lock")
-                                .resizable()
-                                .scaledToFit()
-                                .font(Font.system(.body).weight(.light))
-                                .frame(width: 20, height: 20)
-                                .foregroundStyle(Color(NCBrandColor.shared.iconImageColor))
-                            Text(NSLocalizedString("_certificate_details_", comment: ""))
-                                .lineLimit(1)
-                                .truncationMode(.middle)
-                                .foregroundStyle(Color(NCBrandColor.shared.textColor))
-                                .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20))
-                        }
-                        .font(.system(size: 14))
-                    })
-                    .sheet(isPresented: $showServerCertificate) {
-                        if let url = URL(string: model.activeAccount?.urlBase), let host = url.host {
-                            certificateDetailsView(host: host, title: NSLocalizedString("_certificate_view_", comment: ""))
-                        }
-                    }
-                    ///
-                    /// Certificate push
-                    Button(action: {
-                        showPushCertificate.toggle()
-                    }, label: {
-                        HStack {
-                            Image(systemName: "lock")
-                                .resizable()
-                                .scaledToFit()
-                                .font(Font.system(.body).weight(.light))
-                                .frame(width: 20, height: 20)
-                                .foregroundStyle(Color(NCBrandColor.shared.iconImageColor))
-                            Text(NSLocalizedString("_certificate_pn_details_", comment: ""))
-                                .lineLimit(1)
-                                .truncationMode(.middle)
-                                .foregroundStyle(Color(NCBrandColor.shared.textColor))
-                                .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20))
+                    if model.isAdminGroup() {
+                        Button(action: {
+                            showServerCertificate.toggle()
+                        }, label: {
+                            HStack {
+                                Image(systemName: "lock")
+                                    .resizable()
+                                    .scaledToFit()
+                                    .font(Font.system(.body).weight(.light))
+                                    .frame(width: 20, height: 20)
+                                    .foregroundStyle(Color(NCBrandColor.shared.iconImageColor))
+                                Text(NSLocalizedString("_certificate_details_", comment: ""))
+                                    .lineLimit(1)
+                                    .truncationMode(.middle)
+                                    .foregroundStyle(Color(NCBrandColor.shared.textColor))
+                                    .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20))
+                            }
+                            .font(.system(size: 14))
+                        })
+                        .sheet(isPresented: $showServerCertificate) {
+                            if let url = URL(string: model.activeAccount?.urlBase), let host = url.host {
+                                certificateDetailsView(host: host, title: NSLocalizedString("_certificate_view_", comment: ""))
+                            }
                         }
-                        .font(.system(size: 14))
-                    })
-                    .sheet(isPresented: $showPushCertificate) {
-                        if let url = URL(string: NCBrandOptions.shared.pushNotificationServerProxy), let host = url.host {
-                            certificateDetailsView(host: host, title: NSLocalizedString("_certificate_pn_view_", comment: ""))
+                        ///
+                        /// Certificate push
+                        Button(action: {
+                            showPushCertificate.toggle()
+                        }, label: {
+                            HStack {
+                                Image(systemName: "lock")
+                                    .resizable()
+                                    .scaledToFit()
+                                    .font(Font.system(.body).weight(.light))
+                                    .frame(width: 20, height: 20)
+                                    .foregroundStyle(Color(NCBrandColor.shared.iconImageColor))
+                                Text(NSLocalizedString("_certificate_pn_details_", comment: ""))
+                                    .lineLimit(1)
+                                    .truncationMode(.middle)
+                                    .foregroundStyle(Color(NCBrandColor.shared.textColor))
+                                    .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20))
+                            }
+                            .font(.system(size: 14))
+                        })
+                        .sheet(isPresented: $showPushCertificate) {
+                            if let url = URL(string: NCBrandOptions.shared.pushNotificationServerProxy), let host = url.host {
+                                certificateDetailsView(host: host, title: NSLocalizedString("_certificate_pn_view_", comment: ""))
+                            }
                         }
                     }
                 })

+ 1 - 1
iOSClient/AppDelegate.swift

@@ -458,7 +458,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         let account: String = "\(user) \(urlBase)"
 
         NextcloudKit.shared.setup(account: account, user: user, userId: user, password: password, urlBase: urlBase, groupIdentifier: NCBrandOptions.shared.capabilitiesGroup)
-        NextcloudKit.shared.getUserProfile { _, userProfile, _, error in
+        NextcloudKit.shared.getUserProfile { account, userProfile, _, error in
             if error == .success, let userProfile {
                 NCManageDatabase.shared.deleteAccount(account)
                 NCManageDatabase.shared.addAccount(account, urlBase: urlBase, user: user, userId: userProfile.userId, password: password)

+ 12 - 0
iOSClient/Data/NCManageDatabase+Account.swift

@@ -407,4 +407,16 @@ extension NCManageDatabase {
             NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Could not write to database: \(error)")
         }
     }
+
+    func getAccountGroups(account: String) -> [String] {
+        do {
+            let realm = try Realm()
+            if let result = realm.objects(tableAccount.self).filter("account == %@", account).first {
+                return result.groups.components(separatedBy: ",")
+            }
+        } catch let error as NSError {
+            NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Could not access database: \(error)")
+        }
+        return []
+    }
 }

+ 77 - 77
iOSClient/Data/NCManageDatabase.swift

@@ -40,17 +40,47 @@ class NCManageDatabase: NSObject {
     let utilityFileSystem = NCUtilityFileSystem()
 
     override init() {
-        let dirGroup = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroup)
-        let databaseFileUrlPath = dirGroup?.appendingPathComponent(NCGlobal.shared.appDatabaseNextcloud + "/" + databaseName)
-
-        if let databaseFilePath = databaseFileUrlPath?.path {
-            if FileManager.default.fileExists(atPath: databaseFilePath) {
-                NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] DATABASE FOUND in " + databaseFilePath)
-            } else {
-                NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] DATABASE NOT FOUND in " + databaseFilePath)
+        func migrationSchema(_ migration: Migration, _ oldSchemaVersion: UInt64) {
+            if oldSchemaVersion < 354 {
+                migration.deleteData(forType: NCDBLayoutForView.className())
             }
         }
 
+        func compactDB(_ totalBytes: Int, _ usedBytes: Int) -> Bool {
+            // totalBytes refers to the size of the file on disk in bytes (data + free space)
+            // usedBytes refers to the number of bytes used by data in the file
+            // Compact if the file is over 100MB in size and less than 50% 'used'
+            let oneHundredMB = 100 * 1024 * 1024
+            return (totalBytes > oneHundredMB) && (Double(usedBytes) / Double(totalBytes)) < 0.5
+        }
+        var realm: Realm?
+        let dirGroup = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroup)
+        let databaseFileUrlPath = dirGroup?.appendingPathComponent(NCGlobal.shared.appDatabaseNextcloud + "/" + databaseName)
+        let bundleUrl: URL = Bundle.main.bundleURL
+        let bundlePathExtension: String = bundleUrl.pathExtension
+        let bundleFileName: String = (bundleUrl.path as NSString).lastPathComponent
+        let isAppex: Bool = bundlePathExtension == "appex"
+        var objectTypesAppex = [tableMetadata.self,
+                                tableLocalFile.self,
+                                tableDirectory.self,
+                                tableTag.self,
+                                tableAccount.self,
+                                tableCapabilities.self,
+                                tablePhotoLibrary.self,
+                                tableE2eEncryption.self,
+                                tableE2eEncryptionLock.self,
+                                tableE2eMetadata12.self,
+                                tableE2eMetadata.self,
+                                tableE2eUsers.self,
+                                tableE2eCounter.self,
+                                tableShare.self,
+                                tableChunk.self,
+                                tableAvatar.self,
+                                tableDashboardWidget.self,
+                                tableDashboardWidgetButton.self,
+                                NCDBLayoutForView.self,
+                                TableSecurityGuardDiagnostics.self]
+
         // Disable file protection for directory DB
         // https://docs.mongodb.com/realm/sdk/ios/examples/configure-and-open-a-realm/#std-label-ios-open-a-local-realm
         if let folderPathURL = dirGroup?.appendingPathComponent(NCGlobal.shared.appDatabaseNextcloud) {
@@ -62,61 +92,49 @@ class NCManageDatabase: NSObject {
             }
         }
 
-        do {
-            _ = try Realm(configuration: Realm.Configuration(
-                fileURL: databaseFileUrlPath,
-                schemaVersion: databaseSchemaVersion,
-                migrationBlock: { migration, oldSchemaVersion in
-                    if oldSchemaVersion < 354 {
-                        migration.deleteData(forType: NCDBLayoutForView.className())
-                    }
-                }, shouldCompactOnLaunch: { totalBytes, usedBytes in
-                    // totalBytes refers to the size of the file on disk in bytes (data + free space)
-                    // usedBytes refers to the number of bytes used by data in the file
-                    // Compact if the file is over 100MB in size and less than 50% 'used'
-                    let oneHundredMB = 100 * 1024 * 1024
-                    return (totalBytes > oneHundredMB) && (Double(usedBytes) / Double(totalBytes)) < 0.5
+        if isAppex {
+            if bundleFileName == "File Provider Extension.appex" {
+                objectTypesAppex = [tableMetadata.self,
+                                    tableLocalFile.self,
+                                    tableDirectory.self,
+                                    tableTag.self,
+                                    tableAccount.self,
+                                    tableCapabilities.self]
+            }
+            do {
+                Realm.Configuration.defaultConfiguration =
+                Realm.Configuration(fileURL: databaseFileUrlPath,
+                                    schemaVersion: databaseSchemaVersion,
+                                    migrationBlock: { migration, oldSchemaVersion in
+                                        migrationSchema(migration, oldSchemaVersion)
+                                    }, shouldCompactOnLaunch: { totalBytes, usedBytes in
+                                        compactDB(totalBytes, usedBytes)
+                                    }, objectTypes: objectTypesAppex)
+                realm = try Realm()
+                if let realm, let url = realm.configuration.fileURL {
+                    print("Realm is located at: \(url)")
                 }
-            ))
-        } catch let error {
-            if let databaseFileUrlPath = databaseFileUrlPath {
-                do {
-#if !EXTENSION
-                    let nkError = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: error.localizedDescription)
-                    NCContentPresenter().showError(error: nkError, priority: .max)
-#endif
-                    NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] DATABASE ERROR: \(error.localizedDescription)")
-                    try FileManager.default.removeItem(at: databaseFileUrlPath)
-                } catch {}
+            } catch let error {
+                NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] DATABASE ERROR: \(error.localizedDescription)")
             }
-        }
-
-        Realm.Configuration.defaultConfiguration = Realm.Configuration(
-            fileURL: dirGroup?.appendingPathComponent(NCGlobal.shared.appDatabaseNextcloud + "/" + databaseName),
-            schemaVersion: databaseSchemaVersion
-        )
-
-        // Verify Database, if corrupt remove it
-        do {
-            _ = try Realm()
-        } catch let error {
-            if let databaseFileUrlPath = databaseFileUrlPath {
-                do {
-#if !EXTENSION
-                    let nkError = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: error.localizedDescription)
-                    NCContentPresenter().showError(error: nkError, priority: .max)
-#endif
-                    NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] DATABASE ERROR: \(error.localizedDescription)")
-                    try FileManager.default.removeItem(at: databaseFileUrlPath)
-                } catch { }
+        } else {
+            do {
+                Realm.Configuration.defaultConfiguration =
+                Realm.Configuration(fileURL: databaseFileUrlPath,
+                                    schemaVersion: databaseSchemaVersion,
+                                    migrationBlock: { migration, oldSchemaVersion in
+                                        migrationSchema(migration, oldSchemaVersion)
+                                    }, shouldCompactOnLaunch: { totalBytes, usedBytes in
+                                        compactDB(totalBytes, usedBytes)
+                                    })
+                realm = try Realm()
+                if let realm, let url = realm.configuration.fileURL {
+                    print("Realm is located at: \(url)")
+                }
+            } catch let error {
+                NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] DATABASE ERROR: \(error.localizedDescription)")
             }
         }
-
-        do {
-            _ = try Realm()
-        } catch let error as NSError {
-            NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Could not open database: \(error)")
-        }
     }
 
     // MARK: -
@@ -184,24 +202,6 @@ class NCManageDatabase: NSObject {
         self.clearTable(tableE2eCounter.self, account: account)
     }
 
-    @objc func removeDB() {
-        let realmURL = Realm.Configuration.defaultConfiguration.fileURL!
-        let realmURLs = [
-            realmURL,
-            realmURL.appendingPathExtension("lock"),
-            realmURL.appendingPathExtension("note"),
-            realmURL.appendingPathExtension("management")
-        ]
-
-        for URL in realmURLs {
-            do {
-                try FileManager.default.removeItem(at: URL)
-            } catch let error {
-                NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Could not write to database: \(error)")
-            }
-        }
-    }
-
     func getThreadConfined(_ object: Object) -> Any {
         return ThreadSafeReference(to: object)
     }

+ 7 - 2
iOSClient/Main/Collection Common/NCCollectionViewCommon.swift

@@ -596,13 +596,14 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
         let image = utility.loadUserImage(for: appDelegate.user, displayName: activeAccount?.displayName, userBaseUrl: appDelegate)
         let accountButton = AccountSwitcherButton(type: .custom)
         let accounts = NCManageDatabase.shared.getAllAccountOrderAlias()
+        var childrenAccountSubmenu: [UIMenuElement] = []
 
         accountButton.setImage(image, for: .normal)
         accountButton.setImage(image, for: .highlighted)
         accountButton.semanticContentAttribute = .forceLeftToRight
         accountButton.sizeToFit()
 
-        if !accounts.isEmpty, !NCBrandOptions.shared.disable_multiaccount {
+        if !accounts.isEmpty {
             let accountActions: [UIAction] = accounts.map { account in
                 let image = utility.loadUserImage(for: account.user, displayName: account.displayName, userBaseUrl: account)
                 var name: String = ""
@@ -637,8 +638,12 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
                 self.present(accountSettingsController, animated: true, completion: nil)
             }
 
-            let addAccountSubmenu = UIMenu(title: "", options: .displayInline, children: [addAccountAction, settingsAccountAction])
+            if !NCBrandOptions.shared.disable_multiaccount {
+                childrenAccountSubmenu.append(addAccountAction)
+            }
+            childrenAccountSubmenu.append(settingsAccountAction)
 
+            let addAccountSubmenu = UIMenu(title: "", options: .displayInline, children: childrenAccountSubmenu)
             let menu = UIMenu(children: accountActions + [addAccountSubmenu])
 
             accountButton.menu = menu

+ 4 - 0
iOSClient/NCGlobal.swift

@@ -485,4 +485,8 @@ class NCGlobal: NSObject {
     // DRAG & DROP
     //
     let metadataOcIdDataRepresentation      = "text/com.nextcloud.ocId"
+
+    // GROUP AMIN
+    //
+    let groupAdmin                          = "admin"
 }

+ 5 - 0
iOSClient/Settings/Advanced/NCSettingsAdvancedModel.swift

@@ -33,6 +33,8 @@ class NCSettingsAdvancedModel: ObservableObject, ViewOnAppearHandling {
     let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
     /// Keychain access
     var keychain = NCKeychain()
+    /// State variable for indicating if the user is in Admin group
+    @Published var isAdminGroup: Bool = false
     /// State variable for indicating whether hidden files are shown.
     @Published var showHiddenFiles: Bool = false
     /// State variable for indicating the most compatible format.
@@ -65,6 +67,8 @@ class NCSettingsAdvancedModel: ObservableObject, ViewOnAppearHandling {
 
     /// Triggered when the view appears.
     func onViewAppear() {
+        let groups = NCManageDatabase.shared.getAccountGroups(account: appDelegate.account)
+        isAdminGroup = groups.contains(NCGlobal.shared.groupAdmin)
         showHiddenFiles = keychain.showHiddenFiles
         mostCompatible = keychain.formatCompatibility
         livePhoto = keychain.livePhoto
@@ -73,6 +77,7 @@ class NCSettingsAdvancedModel: ObservableObject, ViewOnAppearHandling {
         crashReporter = keychain.disableCrashservice
         selectedLogLevel = LogLevel(rawValue: keychain.logLevel) ?? .standard
         selectedInterval = CacheDeletionInterval(rawValue: keychain.cleanUpDay) ?? .never
+
         DispatchQueue.global().async {
             self.calculateSize()
         }

+ 21 - 19
iOSClient/Settings/Advanced/NCSettingsAdvancedView.swift

@@ -182,26 +182,28 @@ struct NCSettingsAdvancedView: View {
                     Text(NSLocalizedString("_diagnostics_", comment: ""))
                 }, footer: { })
                 /// Set Log Level() & Capabilities
-                Section(content: {
-                    NavigationLink(destination: LazyView {
-                        NCCapabilitiesView(model: NCCapabilitiesModel())
-                    }) {
-                        HStack {
-                            Image(systemName: "list.bullet")
-                                .resizable()
-                                .scaledToFit()
-                                .font(Font.system(.body).weight(.light))
-                                .frame(width: 25, height: 25)
-                                .foregroundColor(Color(NCBrandColor.shared.iconImageColor))
-                            Text(NSLocalizedString("_capabilities_", comment: ""))
+                if model.isAdminGroup {
+                    Section(content: {
+                        NavigationLink(destination: LazyView {
+                            NCCapabilitiesView(model: NCCapabilitiesModel())
+                        }) {
+                            HStack {
+                                Image(systemName: "list.bullet")
+                                    .resizable()
+                                    .scaledToFit()
+                                    .font(Font.system(.body).weight(.light))
+                                    .frame(width: 25, height: 25)
+                                    .foregroundColor(Color(NCBrandColor.shared.iconImageColor))
+                                Text(NSLocalizedString("_capabilities_", comment: ""))
+                            }
+                            .font(.system(size: 16))
                         }
-                        .font(.system(size: 16))
-                    }
-                }, header: {
-                    Text(NSLocalizedString("_capabilities_", comment: ""))
-                }, footer: {
-                    Text(NSLocalizedString("_capabilities_footer_", comment: ""))
-                })
+                    }, header: {
+                        Text(NSLocalizedString("_capabilities_", comment: ""))
+                    }, footer: {
+                        Text(NSLocalizedString("_capabilities_footer_", comment: ""))
+                    })
+                }
             }
             /// Delete in Cache & Clear Cache
             Section(content: {

BIN=BIN
iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings


BIN=BIN
iOSClient/Supporting Files/fr.lproj/Localizable.strings


+ 1 - 1
iOSClient/Utility/NCContentPresenter.swift

@@ -108,7 +108,7 @@ class NCContentPresenter: NSObject {
         DispatchQueue.main.asyncAfter(deadline: .now() + afterDelay) {
             switch error.errorCode {
             case Int(CFNetworkErrors.cfurlErrorNotConnectedToInternet.rawValue):
-                let image = UIImage(named: "InfoNetwork")!.image(color: .white, size: 20)
+                let image = UIImage(named: "InfoNetwork")?.image(color: .white, size: 20)
                 self.noteTop(text: NSLocalizedString(title, comment: ""), image: image, color: .lightGray, delay: delay, priority: .max)
             default:
                 var responseMessage = ""