diff --git a/File Provider Extension/FileProviderData.swift b/File Provider Extension/FileProviderData.swift index bc271a4649..bcff143cf2 100644 --- a/File Provider Extension/FileProviderData.swift +++ b/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 + } } diff --git a/File Provider Extension/FileProviderExtension+NetworkingDelegate.swift b/File Provider Extension/FileProviderExtension+NetworkingDelegate.swift index 5fbf694170..a5d7ec5f5d 100644 --- a/File Provider Extension/FileProviderExtension+NetworkingDelegate.swift +++ b/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) } } } diff --git a/File Provider Extension/FileProviderExtension.swift b/File Provider Extension/FileProviderExtension.swift index 276d010c09..799f42ec22 100644 --- a/File Provider Extension/FileProviderExtension.swift +++ b/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) diff --git a/File Provider Extension/FileProviderUtility.swift b/File Provider Extension/FileProviderUtility.swift index 68c05440bd..037dc21a08 100644 --- a/File Provider Extension/FileProviderUtility.swift +++ b/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 } } } diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index c563b89e3f..6c2c0ed949 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/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 = ""; diff --git a/Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme b/Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme index 82a2e51c2b..63a60a11ef 100755 --- a/Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme +++ b/Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme @@ -15,9 +15,9 @@ buildForAnalyzing = "YES"> @@ -29,9 +29,9 @@ buildForAnalyzing = "YES"> diff --git a/iOSClient/Account Settings/NCAccountSettingsModel.swift b/iOSClient/Account Settings/NCAccountSettingsModel.swift index 08fa601180..4cdc26f904 100644 --- a/iOSClient/Account Settings/NCAccountSettingsModel.swift +++ b/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 } diff --git a/iOSClient/Account Settings/NCAccountSettingsView.swift b/iOSClient/Account Settings/NCAccountSettingsView.swift index c8a9e500c7..74480985df 100644 --- a/iOSClient/Account Settings/NCAccountSettingsView.swift +++ b/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: "")) + } } } }) diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index 5d1afabd3d..3b6180bece 100644 --- a/iOSClient/AppDelegate.swift +++ b/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) diff --git a/iOSClient/Data/NCManageDatabase+Account.swift b/iOSClient/Data/NCManageDatabase+Account.swift index 567b60dfc0..91038bee94 100644 --- a/iOSClient/Data/NCManageDatabase+Account.swift +++ b/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 [] + } } diff --git a/iOSClient/Data/NCManageDatabase.swift b/iOSClient/Data/NCManageDatabase.swift index 44ce135ab7..466173bcc4 100644 --- a/iOSClient/Data/NCManageDatabase.swift +++ b/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) } diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 85dd37e79f..80cae01f9b 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/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 diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift index f5b8b12e32..f3b43df76e 100644 --- a/iOSClient/NCGlobal.swift +++ b/iOSClient/NCGlobal.swift @@ -485,4 +485,8 @@ class NCGlobal: NSObject { // DRAG & DROP // let metadataOcIdDataRepresentation = "text/com.nextcloud.ocId" + + // GROUP AMIN + // + let groupAdmin = "admin" } diff --git a/iOSClient/Settings/Advanced/NCSettingsAdvancedModel.swift b/iOSClient/Settings/Advanced/NCSettingsAdvancedModel.swift index 233cb1db94..8c8ca47fc6 100644 --- a/iOSClient/Settings/Advanced/NCSettingsAdvancedModel.swift +++ b/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() } diff --git a/iOSClient/Settings/Advanced/NCSettingsAdvancedView.swift b/iOSClient/Settings/Advanced/NCSettingsAdvancedView.swift index 45fcf06880..6dfc43b6f6 100644 --- a/iOSClient/Settings/Advanced/NCSettingsAdvancedView.swift +++ b/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: { diff --git a/iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings b/iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings index aa3a4c494a..a1bf61a889 100644 Binary files a/iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings and b/iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings differ diff --git a/iOSClient/Supporting Files/fr.lproj/Localizable.strings b/iOSClient/Supporting Files/fr.lproj/Localizable.strings index dd7cb11fcc..54351d3a7f 100644 Binary files a/iOSClient/Supporting Files/fr.lproj/Localizable.strings and b/iOSClient/Supporting Files/fr.lproj/Localizable.strings differ diff --git a/iOSClient/Utility/NCContentPresenter.swift b/iOSClient/Utility/NCContentPresenter.swift index 5cbfe1d1fa..0e8475034c 100644 --- a/iOSClient/Utility/NCContentPresenter.swift +++ b/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 = ""