marinofaggiana 4 gadi atpakaļ
vecāks
revīzija
4aec62b0f4

+ 1 - 1
Cartfile

@@ -4,7 +4,7 @@ github "kishikawakatsumi/UICKeyChainStore" "v2.1.2"
 github "MortimerGoro/MGSwipeTableCell" "1.6.8"
 github "dzenbot/DZNEmptyDataSet" "v1.8.1"
 github "jdg/MBProgressHUD" "1.1.0"
-github "realm/realm-cocoa" "v5.0.3"
+github "realm/realm-cocoa" "v5.1.0"
 github "SVGKit/SVGKit" "3.x"
 github "WeTransfer/WeScan" "1.2.0"
 github "malcommac/SwiftRichString"

+ 1 - 1
Cartfile.resolved

@@ -20,7 +20,7 @@ github "marinofaggiana/KTVHTTPCache" "2.0.2"
 github "marinofaggiana/TOPasscodeViewController" "0.0.7"
 github "marinofaggiana/XLForm" "eb9381ad8129f60402bf412250fb31b95a628a08"
 github "nextcloud/ios-communication-library" "acfefcb525417e66cb38e8f29e68346b67418e42"
-github "realm/realm-cocoa" "v5.0.3"
+github "realm/realm-cocoa" "v5.1.0"
 github "rechsteiner/Parchment" "v1.7.0"
 github "scenee/FloatingPanel" "v1.7.5"
 github "tilltue/TLPhotoPicker" "2.0.11"

+ 28 - 0
Carthage/Checkouts/realm-cocoa/CHANGELOG.md

@@ -1,3 +1,31 @@
+5.1.0 Release notes (2020-06-22)
+=============================================================
+
+### Enhancements
+
+* Allow opening full-sync Realms in read-only mode. This disables local schema
+  initialization, which makes it possible to open a Realm which the user does
+  not have write access to without using asyncOpen. In addition, it will report
+  errors immediately when an operation would require writing to the Realm
+  rather than reporting it via the sync error handler only after the server
+  rejects the write.
+
+### Fixed
+
+* Opening a Realm using a configuration object read from an existing Realm
+  would incorrectly bind the new Realm to the original Realm's thread/queue,
+  resulting in "Realm accessed from incorrect thread." exceptions.
+  ([#6574](https://github.com/realm/realm-cocoa/issues/6574),
+  [#6559](https://github.com/realm/realm-cocoa/issues/6559), since 5.0.0).
+
+### Compatibility
+
+* File format: Generates Realms with format v10 (Reads and upgrades all previous formats)
+* Realm Object Server: 3.21.0 or later.
+* Realm Studio: 3.11 or later.
+* APIs are backwards compatible with all previous releases in the 5.x.y series.
+* Carthage release for Swift is built with Xcode 11.5.
+
 5.0.3 Release notes (2020-06-10)
 =============================================================
 

+ 97 - 0
Carthage/Checkouts/realm-cocoa/Realm/ObjectServerTests/RLMObjectServerTests.mm

@@ -21,12 +21,15 @@
 #import "RLMSyncSessionRefreshHandle+ObjectServerTests.h"
 #import "RLMSyncUser+ObjectServerTests.h"
 
+#import "RLMObjectSchema_Private.hpp"
 #import "RLMRealm+Sync.h"
 #import "RLMRealmConfiguration_Private.h"
 #import "RLMRealmUtil.hpp"
 #import "RLMRealm_Dynamic.h"
 #import "RLMRealm_Private.hpp"
+#import "RLMSchema_Private.h"
 #import "RLMSyncUtil_Private.h"
+
 #import "shared_realm.hpp"
 
 #pragma mark - Test objects
@@ -2351,4 +2354,98 @@ static NSURL *certificateURL(NSString *filename) {
     [self waitForExpectations:@[ex3, ex4] timeout:4.0];
 }
 
+#pragma mark - Read Only
+
+- (RLMSyncUser *)userForTest:(SEL)sel {
+    return [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(sel)
+                                                                               register:self.isParent]
+                                  server:[RLMObjectServerTests authServerURL]];
+}
+
+- (void)testPartialSyncCannotBeReadOnly {
+    RLMSyncUser *user = [self userForTest:_cmd];
+    RLMRealmConfiguration *config = [user configurationWithURL:nil fullSynchronization:NO];
+    RLMAssertThrowsWithReason(config.readOnly = true,
+                              @"Read-only mode is not supported for query-based sync.");
+}
+
+- (void)testOpenSynchronouslyInReadOnlyBeforeRemoteSchemaIsInitialized {
+    NSURL *url = REALM_URL();
+    RLMSyncUser *user = [self userForTest:_cmd];
+
+    if (self.isParent) {
+        RLMRealmConfiguration *config = [user configurationWithURL:url fullSynchronization:YES];
+        config.readOnly = true;
+        RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:nil];
+        CHECK_COUNT(0, SyncObject, realm);
+        RLMRunChildAndWait();
+        [self waitForDownloadsForUser:user realms:@[realm] realmURLs:@[url] expectedCounts:@[@3]];
+    } else {
+        RLMRealm *realm = [self openRealmForURL:url user:user];
+        [self addSyncObjectsToRealm:realm descriptions:@[@"child-1", @"child-2", @"child-3"]];
+        [self waitForUploadsForRealm:realm];
+        CHECK_COUNT(3, SyncObject, realm);
+    }
+}
+
+- (void)testAddPropertyToReadOnlyRealmWithExistingLocalCopy {
+    NSURL *url = REALM_URL();
+    RLMSyncUser *user = [self userForTest:_cmd];
+
+    if (!self.isParent) {
+        RLMRealm *realm = [self openRealmForURL:url user:user];
+        [self addSyncObjectsToRealm:realm descriptions:@[@"child-1", @"child-2", @"child-3"]];
+        [self waitForUploadsForRealm:realm];
+        return;
+    }
+    RLMRunChildAndWait();
+
+    RLMRealmConfiguration *config = [user configurationWithURL:url fullSynchronization:YES];
+    config.readOnly = true;
+    @autoreleasepool {
+        (void)[self asyncOpenRealmWithConfiguration:config];
+    }
+
+    RLMObjectSchema *objectSchema = [RLMObjectSchema schemaForObjectClass:SyncObject.class];
+    objectSchema.properties = [RLMObjectSchema schemaForObjectClass:HugeSyncObject.class].properties;
+    config.customSchema = [[RLMSchema alloc] init];
+    config.customSchema.objectSchema = @[objectSchema];
+
+    RLMAssertThrowsWithReason([RLMRealm realmWithConfiguration:config error:nil],
+                              @"Property 'SyncObject.dataProp' has been added.");
+
+    @autoreleasepool {
+        NSError *error = [self asyncOpenErrorWithConfiguration:config];
+        XCTAssertNotEqual([error.localizedDescription rangeOfString:@"Property 'SyncObject.dataProp' has been added."].location,
+                          NSNotFound);
+    }
+}
+
+- (void)testAddPropertyToReadOnlyRealmWithAsyncOpen {
+    NSURL *url = REALM_URL();
+    RLMSyncUser *user = [self userForTest:_cmd];
+
+    if (!self.isParent) {
+        RLMRealm *realm = [self openRealmForURL:url user:user];
+        [self addSyncObjectsToRealm:realm descriptions:@[@"child-1", @"child-2", @"child-3"]];
+        [self waitForUploadsForRealm:realm];
+        return;
+    }
+    RLMRunChildAndWait();
+
+    RLMRealmConfiguration *config = [user configurationWithURL:url fullSynchronization:YES];
+    config.readOnly = true;
+
+    RLMObjectSchema *objectSchema = [RLMObjectSchema schemaForObjectClass:SyncObject.class];
+    objectSchema.properties = [RLMObjectSchema schemaForObjectClass:HugeSyncObject.class].properties;
+    config.customSchema = [[RLMSchema alloc] init];
+    config.customSchema.objectSchema = @[objectSchema];
+
+    @autoreleasepool {
+        NSError *error = [self asyncOpenErrorWithConfiguration:config];
+        XCTAssertNotEqual([error.localizedDescription rangeOfString:@"Property 'SyncObject.dataProp' has been added."].location,
+                          NSNotFound);
+    }
+}
+
 @end

+ 30 - 0
Carthage/Checkouts/realm-cocoa/Realm/ObjectServerTests/RLMPermissionsAPITests.m

@@ -555,6 +555,36 @@ static NSURL *makeTildeSubstitutedURL(NSURL *url, RLMSyncUser *user) {
     REVOKE_PERMISSION(p, admin);
 }
 
+- (void)testReadAccessWithClassSuperset {
+    NSString *testName = NSStringFromSelector(_cmd);
+
+    // Create a Realm with only a single object type
+    NSURL *userAURL = makeTestURL(testName, nil);
+    RLMRealmConfiguration *userAConfig = [self.userA configurationWithURL:userAURL fullSynchronization:YES];
+    userAConfig.objectClasses = @[SyncObject.self];
+    RLMRealm *userARealm = [self asyncOpenRealmWithConfiguration:userAConfig];
+    [self addSyncObjectsToRealm:userARealm descriptions:@[@"child-1", @"child-2", @"child-3"]];
+    [self waitForUploadsForRealm:userARealm];
+    CHECK_COUNT(3, SyncObject, userARealm);
+
+    // Give user B read-only permissions to that Realm so that it can't add new object types
+    RLMSyncPermission *p = [[RLMSyncPermission alloc] initWithRealmPath:[userAURL path]
+                                                               identity:self.userB.identity
+                                                            accessLevel:RLMSyncAccessLevelRead];
+    APPLY_PERMISSION(p, self.userA);
+
+    // Open the same Realm s user B without limiting the set of object classes
+    NSURL *userBURL = makeTestURL(testName, self.userA);
+    RLMRealmConfiguration *userBConfig = [self.userB configurationWithURL:userBURL fullSynchronization:YES];
+    userBConfig.readOnly = YES;
+    RLMRealm *userBRealm = [self asyncOpenRealmWithConfiguration:userBConfig];
+    CHECK_COUNT(3, SyncObject, userBRealm);
+
+    // Verify that syncing is actually working and new objects written by A show up in B's Realm
+    [self addSyncObjectsToRealm:userARealm descriptions:@[@"child-4"]];
+    CHECK_COUNT_PENDING_DOWNLOAD(4, SyncObject, userBRealm);
+}
+
 #pragma mark - Permission change API
 
 /// Setting a permission should work, and then that permission should be able to be retrieved.

+ 6 - 0
Carthage/Checkouts/realm-cocoa/Realm/ObjectServerTests/RLMSyncTestCase.h

@@ -58,6 +58,12 @@ NS_ASSUME_NONNULL_BEGIN
 /// Synchronously open a synced Realm and wait until the binding process has completed or failed.
 - (RLMRealm *)openRealmWithConfiguration:(RLMRealmConfiguration *)configuration;
 
+/// Synchronously open a synced Realm via asyncOpen and return the Realm.
+- (RLMRealm *)asyncOpenRealmWithConfiguration:(RLMRealmConfiguration *)configuration;
+
+/// Synchronously open a synced Realm via asyncOpen and return the expected error.
+- (NSError *)asyncOpenErrorWithConfiguration:(RLMRealmConfiguration *)configuration;
+
 /// Synchronously open a synced Realm. Also run a block right after the Realm is created.
 - (RLMRealm *)openRealmForURL:(NSURL *)url
                          user:(RLMSyncUser *)user

+ 45 - 1
Carthage/Checkouts/realm-cocoa/Realm/ObjectServerTests/RLMSyncTestCase.mm

@@ -349,6 +349,37 @@ static NSURL *syncDirectoryForChildProcess() {
               @"Timed out while trying to asynchronously open Realm for URL: %@", syncConfig.realmURL);
     return realm;
 }
+
+- (RLMRealm *)asyncOpenRealmWithConfiguration:(RLMRealmConfiguration *)config {
+    __block RLMRealm *realm = nil;
+    XCTestExpectation *ex = [self expectationWithDescription:@"Should asynchronously open a Realm"];
+    [RLMRealm asyncOpenWithConfiguration:config
+                           callbackQueue:dispatch_get_main_queue()
+                                callback:^(RLMRealm *r, NSError *err){
+        XCTAssertNil(err);
+        XCTAssertNotNil(r);
+        realm = r;
+        [ex fulfill];
+    }];
+    [self waitForExpectationsWithTimeout:10.0 handler:nil];
+    return realm;
+}
+
+- (NSError *)asyncOpenErrorWithConfiguration:(RLMRealmConfiguration *)config {
+    __block NSError *error = nil;
+    XCTestExpectation *ex = [self expectationWithDescription:@"Should fail to asynchronously open a Realm"];
+    [RLMRealm asyncOpenWithConfiguration:config
+                           callbackQueue:dispatch_get_main_queue()
+                                callback:^(RLMRealm *r, NSError *err){
+        XCTAssertNotNil(err);
+        XCTAssertNil(r);
+        error = err;
+        [ex fulfill];
+    }];
+    [self waitForExpectationsWithTimeout:10.0 handler:nil];
+    return error;
+}
+
 - (RLMRealm *)immediatelyOpenRealmForURL:(NSURL *)url user:(RLMSyncUser *)user {
     return [self immediatelyOpenRealmForURL:url
                                        user:user
@@ -542,7 +573,20 @@ static NSURL *syncDirectoryForChildProcess() {
 }
 
 - (void)resetSyncManager {
-    [RLMSyncManager.sharedManager._allUsers makeObjectsPerformSelector:@selector(logOut)];
+    NSMutableArray *expectations = [NSMutableArray new];
+    for (RLMSyncUser *user in RLMSyncManager.sharedManager._allUsers) {
+        [user logOut];
+        // Sessions are removed from the user asynchronously after a logout.
+        // We need to wait for this to happen before calling resetForTesting as
+        // that expects all sessions to be cleaned up first. This doesn't apply
+        // to admin token users, which don't logout at all (and don't have an
+        // auth server).
+        if (user.authenticationServer && user.allSessions.count) {
+            [expectations addObject:[self expectationForPredicate:[NSPredicate predicateWithFormat:@"allSessions.@count == 0"]
+                                              evaluatedWithObject:user handler:nil]];
+        }
+    }
+    [self waitForExpectations:expectations timeout:5.0];
     [RLMSyncManager resetForTesting];
     [RLMSyncSessionRefreshHandle calculateFireDateUsingTestLogic:NO blockOnRefreshCompletion:nil];
 }

+ 6 - 1
Carthage/Checkouts/realm-cocoa/Realm/RLMRealm.mm

@@ -450,7 +450,7 @@ REALM_NOINLINE static void translateSharedGroupOpenException(NSError **error) {
     }
 
     {
-        Realm::Config& config = configuration.config;
+        Realm::Config const& config = configuration.config;
 
         // try to reuse existing realm first
         if (cache || dynamic) {
@@ -496,6 +496,11 @@ REALM_NOINLINE static void translateSharedGroupOpenException(NSError **error) {
                 throw RLMException(@"Realm opened from incorrect dispatch queue.");
             }
         }
+        else {
+            // If the source config was read from a Realm it may already have a
+            // scheduler, and we don't want to reuse it.
+            config.scheduler = nullptr;
+        }
         realm->_realm = Realm::get_shared_realm(config);
     }
     catch (...) {

+ 17 - 7
Carthage/Checkouts/realm-cocoa/Realm/RLMRealmConfiguration.h

@@ -79,13 +79,23 @@ typedef BOOL (^RLMShouldCompactOnLaunchBlock)(NSUInteger totalBytes, NSUInteger
 
 /// Whether to open the Realm in read-only mode.
 ///
-/// This is required to be able to open Realm files which are not writeable or
-/// are in a directory which is not writeable. This should only be used on files
-/// which will not be modified by anyone while they are open, and not just to
-/// get a read-only view of a file which may be written to by another thread or
-/// process. Opening in read-only mode requires disabling Realm's reader/writer
-/// coordination, so committing a write transaction from another process will
-/// result in crashes.
+/// For non-synchronized Realms, this is required to be able to open Realm
+/// files which are not writeable or are in a directory which is not writeable.
+/// This should only be used on files which will not be modified by anyone
+/// while they are open, and not just to get a read-only view of a file which
+/// may be written to by another thread or process. Opening in read-only mode
+/// requires disabling Realm's reader/writer coordination, so committing a
+/// write transaction from another process will result in crashes.
+///
+/// Syncronized Realms must always be writeable (as otherwise no
+/// synchronization could happen), and this instead merely disallows performing
+/// write transactions on the Realm. In addition, it will skip some automatic
+/// writes made to the Realm, such as to initialize the Realm's schema. Setting
+/// `readOnly = YES` is not strictly required for Realms which the sync user
+/// does not have write access to, but is highly recommended as it will improve
+/// error reporting and catch some errors earlier.
+///
+/// Realms using query-based sync cannot be opened in read-only mode.
 @property (nonatomic) BOOL readOnly;
 
 /// The current schema version.

+ 16 - 4
Carthage/Checkouts/realm-cocoa/Realm/RLMRealmConfiguration.mm

@@ -205,7 +205,14 @@ static void RLMNSStringToStdString(std::string &out, NSString *in) {
 }
 
 - (BOOL)readOnly {
-    return _config.immutable();
+    return _config.immutable() || _config.read_only_alternative();
+}
+
+static bool isSync(realm::Realm::Config const& config) {
+#if REALM_ENABLE_SYNC
+    return !!config.sync_config;
+#endif
+    return false;
 }
 
 - (void)setReadOnly:(BOOL)readOnly {
@@ -215,10 +222,15 @@ static void RLMNSStringToStdString(std::string &out, NSString *in) {
         } else if (self.shouldCompactOnLaunch) {
             @throw RLMException(@"Cannot set `readOnly` when `shouldCompactOnLaunch` is set.");
         }
-        _config.schema_mode = realm::SchemaMode::Immutable;
+#if REALM_ENABLE_SYNC
+        if (_config.sync_config && _config.sync_config->is_partial) {
+            @throw RLMException(@"Read-only mode is not supported for query-based sync.");
+        }
+#endif
+        _config.schema_mode = isSync(_config) ? realm::SchemaMode::ReadOnlyAlternative : realm::SchemaMode::Immutable;
     }
     else if (self.readOnly) {
-        _config.schema_mode = realm::SchemaMode::Automatic;
+        _config.schema_mode = isSync(_config) ? realm::SchemaMode::Additive : realm::SchemaMode::Automatic;
     }
 }
 
@@ -300,7 +312,7 @@ static void RLMNSStringToStdString(std::string &out, NSString *in) {
 
 - (void)setShouldCompactOnLaunch:(RLMShouldCompactOnLaunchBlock)shouldCompactOnLaunch {
     if (shouldCompactOnLaunch) {
-        if (self.readOnly) {
+        if (_config.immutable()) {
             @throw RLMException(@"Cannot set `shouldCompactOnLaunch` when `readOnly` is set.");
         }
         _config.should_compact_on_launch_function = [=](size_t totalBytes, size_t usedBytes) {

+ 15 - 0
Carthage/Checkouts/realm-cocoa/Realm/RLMSyncSession.mm

@@ -231,6 +231,21 @@ static RLMSyncConnectionState convertConnectionState(SyncSession::ConnectionStat
     return nil;
 }
 
+- (NSString *)description {
+    return [NSString stringWithFormat:
+            @"<RLMSyncSession: %p> {\n"
+            "\tstate = %d;\n"
+            "\tconnectionState = %d;\n"
+            "\trealmURL = %@;\n"
+            "\tuser = %@;\n"
+            "}",
+            (__bridge void *)self,
+            static_cast<int>(self.state),
+            static_cast<int>(self.connectionState),
+            self.realmURL,
+            self.parentUser.identity];
+}
+
 @end
 
 // MARK: - Error action token

+ 2 - 2
Carthage/Checkouts/realm-cocoa/Realm/Realm-Info.plist

@@ -17,11 +17,11 @@
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
-	<string>5.0.3</string>
+	<string>5.1.0</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>5.0.3</string>
+	<string>5.1.0</string>
 	<key>NSHumanReadableCopyright</key>
 	<string>Copyright © 2014 Realm. All rights reserved.</string>
 	<key>NSPrincipalClass</key>

+ 21 - 0
Carthage/Checkouts/realm-cocoa/Realm/Tests/RealmTests.mm

@@ -1621,6 +1621,27 @@
     });
 }
 
+- (void)testReusingConfigOnMultipleQueues {
+    auto config = [RLMRealmConfiguration defaultConfiguration];
+    auto q1 = dispatch_queue_create("queue 1", DISPATCH_QUEUE_SERIAL);
+    auto q2 = dispatch_queue_create("queue 2", DISPATCH_QUEUE_SERIAL);
+
+    dispatch_sync(q1, ^{
+        XCTAssertNoThrow([RLMRealm realmWithConfiguration:config queue:q1 error:nil]);
+    });
+    dispatch_sync(q2, ^{
+        XCTAssertNoThrow([RLMRealm realmWithConfiguration:config queue:q2 error:nil]);
+    });
+}
+
+- (void)testConfigurationFromExistingRealmOnNewThread {
+    auto r1 = [RLMRealm defaultRealm];
+    [self dispatchAsyncAndWait:^{
+        auto r2 = [RLMRealm realmWithConfiguration:r1.configuration error:nil];
+        XCTAssertNoThrow([r2 refresh]);
+    }];
+}
+
 #pragma mark - In-memory Realms
 
 - (void)testInMemoryRealm {

+ 15 - 5
Carthage/Checkouts/realm-cocoa/RealmSwift/RealmConfiguration.swift

@@ -160,11 +160,21 @@ extension Realm {
         /**
          Whether to open the Realm in read-only mode.
 
-         This is required to be able to open Realm files which are not writeable or are in a directory which is not
-         writeable. This should only be used on files which will not be modified by anyone while they are open, and not
-         just to get a read-only view of a file which may be written to by another thread or process. Opening in
-         read-only mode requires disabling Realm's reader/writer coordination, so committing a write transaction from
-         another process will result in crashes.
+         For non-synchronized Realms, this is required to be able to open Realm files which are not
+         writeable or are in a directory which is not writeable.  This should only be used on files
+         which will not be modified by anyone while they are open, and not just to get a read-only
+         view of a file which may be written to by another thread or process. Opening in read-only
+         mode requires disabling Realm's reader/writer coordination, so committing a write
+         transaction from another process will result in crashes.
+
+         Syncronized Realms must always be writeable (as otherwise no synchronization could happen),
+         and this instead merely disallows performing write transactions on the Realm. In addition,
+         it will skip some automatic writes made to the Realm, such as to initialize the Realm's
+         schema. Setting `readOnly = YES` is not strictly required for Realms which the sync user
+         does not have write access to, but is highly recommended as it will improve error reporting
+         and catch some errors earlier.
+
+         Realms using query-based sync cannot be opened in read-only mode.
          */
         public var readOnly: Bool = false
 

+ 1 - 1
Carthage/Checkouts/realm-cocoa/dependencies.list

@@ -1,4 +1,4 @@
-VERSION=5.0.3
+VERSION=5.1.0
 REALM_CORE_VERSION=6.0.6
 REALM_SYNC_VERSION=5.0.5
 REALM_OBJECT_SERVER_VERSION=3.28.5

+ 6 - 2
Nextcloud.xcodeproj/project.pbxproj

@@ -51,6 +51,7 @@
 		F70BFC7520E0FA7D00C67599 /* NCUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70BFC7320E0FA7C00C67599 /* NCUtility.swift */; };
 		F70CAE3A1F8CF31A008125FD /* NCEndToEndEncryption.m in Sources */ = {isa = PBXBuildFile; fileRef = F70CAE391F8CF31A008125FD /* NCEndToEndEncryption.m */; };
 		F70CEF5623E9C7E50007035B /* UIColor+adjust.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70CEF5523E9C7E50007035B /* UIColor+adjust.swift */; };
+		F70D8D8124A4A9BF000A5756 /* NCNetworkingAutoUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70D8D8024A4A9BF000A5756 /* NCNetworkingAutoUpload.swift */; };
 		F70F2BA5225F2D8900EBB73E /* ZIPFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F70F2BA4225F2D8900EBB73E /* ZIPFoundation.framework */; };
 		F710C5F02471A6D1009AD8B7 /* Sentry.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F710C5EF2471A6D1009AD8B7 /* Sentry.framework */; };
 		F710D1F52405770F00A6033D /* NCViewerPDF.swift in Sources */ = {isa = PBXBuildFile; fileRef = F710D1F42405770F00A6033D /* NCViewerPDF.swift */; };
@@ -391,6 +392,7 @@
 		F70CAE381F8CF31A008125FD /* NCEndToEndEncryption.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NCEndToEndEncryption.h; sourceTree = "<group>"; };
 		F70CAE391F8CF31A008125FD /* NCEndToEndEncryption.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NCEndToEndEncryption.m; sourceTree = "<group>"; };
 		F70CEF5523E9C7E50007035B /* UIColor+adjust.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+adjust.swift"; sourceTree = "<group>"; };
+		F70D8D8024A4A9BF000A5756 /* NCNetworkingAutoUpload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCNetworkingAutoUpload.swift; sourceTree = "<group>"; };
 		F70F2BA4225F2D8900EBB73E /* ZIPFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ZIPFoundation.framework; path = Carthage/Build/iOS/ZIPFoundation.framework; sourceTree = "<group>"; };
 		F710C5EF2471A6D1009AD8B7 /* Sentry.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sentry.framework; path = Carthage/Build/iOS/Sentry.framework; sourceTree = "<group>"; };
 		F710D1F42405770F00A6033D /* NCViewerPDF.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCViewerPDF.swift; sourceTree = "<group>"; };
@@ -954,12 +956,13 @@
 		F74D3DB81BAC1941000BAE4B /* Networking */ = {
 			isa = PBXGroup;
 			children = (
-				F755BD9A20594AC7008C5FBB /* NCService.swift */,
-				F72A47EB2487B06B005AD489 /* NCOperationQueue.swift */,
 				F75A9EE523796C6F0044CFCE /* NCNetworking.swift */,
+				F70D8D8024A4A9BF000A5756 /* NCNetworkingAutoUpload.swift */,
 				F7D96FCB246ED7E100536D73 /* NCNetworkingCheckRemoteUser.swift */,
 				F785EE9C246196DF00B3F945 /* NCNetworkingE2EE.swift */,
 				F75B0ABC244C4DBB00E58DCA /* NCNetworkingNotificationCenter.swift */,
+				F72A47EB2487B06B005AD489 /* NCOperationQueue.swift */,
+				F755BD9A20594AC7008C5FBB /* NCService.swift */,
 			);
 			path = Networking;
 			sourceTree = "<group>";
@@ -2109,6 +2112,7 @@
 				F7CA1ED920E7E3FE002CC65E /* NSLayoutConstraint+PKDownloadButton.m in Sources */,
 				F77B0ED11D118A16002130FE /* Acknowledgements.m in Sources */,
 				F711CD05246AC9B10009B204 /* DropUpMenu.swift in Sources */,
+				F70D8D8124A4A9BF000A5756 /* NCNetworkingAutoUpload.swift in Sources */,
 				F7D96FCC246ED7E200536D73 /* NCNetworkingCheckRemoteUser.swift in Sources */,
 				F7E4D9C422ED929B003675FD /* NCShareComments.swift in Sources */,
 				37C83A0D24532B7200618A3B /* AppDelegate+Swift.swift in Sources */,

+ 3 - 1
iOSClient/AppDelegate.m

@@ -33,6 +33,7 @@
 @import Sentry;
 
 @class NCViewerRichdocument;
+@class NCNetworkingAutoUpload;
 
 @interface AppDelegate() <TOPasscodeViewControllerDelegate>
 @end
@@ -160,7 +161,8 @@
     
     // Auto upload
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
-        [NCNetworking.shared loadAutoUpload];
+        [NCNetworkingAutoUpload new];
+       // [NCNetworking.shared loadAutoUpload];
     });
     
     return YES;

+ 0 - 244
iOSClient/Networking/NCNetworking.swift

@@ -469,250 +469,6 @@ import Alamofire
         }
     }
     
-    @objc func loadAutoUpload() {
-
-        var counterUpload = 0
-        var sizeUpload = 0
-        var maxConcurrentOperationUpload = k_maxConcurrentOperation
-    
-        let metadatasUpload = NCManageDatabase.sharedInstance.getMetadatas(predicate: NSPredicate(format: "status == %d OR status == %d", k_metadataStatusInUpload, k_metadataStatusUploading), freeze: true)
-        counterUpload = metadatasUpload.count
-        
-        for metadata in metadatasUpload {
-            sizeUpload = sizeUpload + Int(metadata.size)
-        }
-        
-        debugPrint("[LOG] PROCESS-AUTO-UPLOAD \(counterUpload)")
-   
-        // ------------------------- <selector Upload> -------------------------
-        
-        while counterUpload < maxConcurrentOperationUpload {
-            if sizeUpload > k_maxSizeOperationUpload { break }
-            var predicate = NSPredicate()
-            
-            if UIApplication.shared.applicationState == .background {
-                predicate = NSPredicate(format: "sessionSelector == %@ AND status == %d AND typeFile != %@", selectorUploadFile, k_metadataStatusWaitUpload, k_metadataTypeFile_video)
-            } else {
-                predicate = NSPredicate(format: "sessionSelector == %@ AND status == %d", selectorUploadFile, k_metadataStatusWaitUpload)
-            }
-            
-            if let metadata = NCManageDatabase.sharedInstance.getMetadata(predicate: predicate, freeze: true) {
-                NCManageDatabase.sharedInstance.setMetadataSession(ocId: metadata.ocId, status: Int(k_metadataStatusInUpload))
-                self.upload(metadata: metadata, background: true) { (_, _) in }
-                counterUpload += 1
-                sizeUpload = sizeUpload + Int(metadata.size)
-            } else {
-                break
-            }
-        }
-            
-        DispatchQueue.main.asyncAfter(deadline: .now() + TimeInterval(k_timerAutoUpload)) {
-            self.loadAutoUpload()
-        }
-    }
-    
-    /*
-     - (void)loadAutoUpload
-     {
-         if (self.activeAccount.length == 0 || self.maintenanceMode)
-             return;
-         
-         tableMetadata *metadataForUpload;
-         long counterUpload = 0;
-         NSUInteger sizeUpload = 0;
-         NSPredicate *predicate;
-         
-         long maxConcurrentOperationUpload = k_maxConcurrentOperation;
-         
-         NSArray *metadatasUpload = [[NCManageDatabase sharedInstance] getMetadatasWithPredicate:[NSPredicate predicateWithFormat:@"status == %d OR status == %d", k_metadataStatusInUpload, k_metadataStatusUploading] sorted:nil ascending:true];
-         
-         for(tableMetadata *metadata in metadatasUpload) {
-             if ([CCUtility isFolderEncrypted:metadata.serverUrl e2eEncrypted:metadata.e2eEncrypted account:metadata.account]) return;
-         }
-         
-         // Counter
-         counterUpload = [metadatasUpload count];
-         
-         // Size
-         for (tableMetadata *metadata in metadatasUpload) {
-             sizeUpload = sizeUpload + metadata.size;
-         }
-         
-         NSLog(@"%@", [NSString stringWithFormat:@"[LOG] PROCESS-AUTO-UPLOAD %ld - %@", counterUpload, [CCUtility transformedSize:sizeUpload]]);
-         
-             
-         // ------------------------- <selector Upload> -------------------------
-         
-         while (counterUpload < maxConcurrentOperationUpload) {
-             
-             if (sizeUpload > k_maxSizeOperationUpload) {
-                 break;
-             }
-             
-             if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) {
-                 predicate = [NSPredicate predicateWithFormat:@"sessionSelector == %@ AND status == %d AND typeFile != %@", selectorUploadFile, k_metadataStatusWaitUpload, k_metadataTypeFile_video];
-             } else {
-                 predicate = [NSPredicate predicateWithFormat:@"sessionSelector == %@ AND status == %d", selectorUploadFile, k_metadataStatusWaitUpload];
-             }
-                     
-             metadataForUpload = [[NCManageDatabase sharedInstance] getMetadataWithPredicate:predicate sorted:@"date" ascending:YES];
-             
-             if (metadataForUpload) {
-                                 
-                 if ([CCUtility isFolderEncrypted:metadataForUpload.serverUrl e2eEncrypted:metadataForUpload.e2eEncrypted account:metadataForUpload.account]) {
-                     
-                     if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) { break; }
-                     maxConcurrentOperationUpload = 1;
-                         
-                     metadataForUpload.status = k_metadataStatusInUpload;
-                     tableMetadata *metadata = [[NCManageDatabase sharedInstance] addMetadata:metadataForUpload];
-                         
-                     [[NCNetworking shared] uploadWithMetadata:metadata background:true completion:^(NSInteger errorCode, NSString *errorDescription) { }];
-                         
-                     break;
-                                             
-                 } else {
-                         
-                     metadataForUpload.status = k_metadataStatusInUpload;
-                     tableMetadata *metadata = [[NCManageDatabase sharedInstance] addMetadata:metadataForUpload];
-                         
-                     [[NCNetworking shared] uploadWithMetadata:metadata background:true completion:^(NSInteger errorCode, NSString *errorDescription) { }];
-                         
-                     counterUpload++;
-                     sizeUpload = sizeUpload + metadata.size;
-                 }
-                     
-             } else {
-                 break;
-             }
-         }
-         
-         // ------------------------- <selector Auto Upload> -------------------------
-         
-         while (counterUpload < maxConcurrentOperationUpload) {
-             
-             if (sizeUpload > k_maxSizeOperationUpload) {
-                 break;
-             }
-             
-             if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) {
-                 predicate = [NSPredicate predicateWithFormat:@"sessionSelector == %@ AND status == %d AND typeFile != %@", selectorUploadAutoUpload, k_metadataStatusWaitUpload, k_metadataTypeFile_video];
-             } else {
-                 predicate = [NSPredicate predicateWithFormat:@"sessionSelector == %@ AND status == %d", selectorUploadAutoUpload, k_metadataStatusWaitUpload];
-             }
-             
-             metadataForUpload = [[NCManageDatabase sharedInstance] getMetadataWithPredicate:predicate sorted:@"date" ascending:YES];
-             if (metadataForUpload) {
-                 
-                 if ([CCUtility isFolderEncrypted:metadataForUpload.serverUrl e2eEncrypted:metadataForUpload.e2eEncrypted account:metadataForUpload.account]) {
-                     
-                     if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) { break; }
-                     maxConcurrentOperationUpload = 1;
-                     
-                     metadataForUpload.status = k_metadataStatusInUpload;
-                     tableMetadata *metadata = [[NCManageDatabase sharedInstance] addMetadata:metadataForUpload];
-                                               
-                     [[NCNetworking shared] uploadWithMetadata:metadata background:true completion:^(NSInteger errorCode, NSString *errorDescription) { }];
-                                     
-                     break;
-                     
-                 } else {
-                     
-                     metadataForUpload.status = k_metadataStatusInUpload;
-                     tableMetadata *metadata = [[NCManageDatabase sharedInstance] addMetadata:metadataForUpload];
-                                
-                     [[NCNetworking shared] uploadWithMetadata:metadata background:true completion:^(NSInteger errorCode, NSString *errorDescription) { }];
-                                
-                     counterUpload++;
-                     sizeUpload = sizeUpload + metadata.size;
-                 }
-                
-             } else {
-                 break;
-             }
-         }
-         
-         // ------------------------- <selector Auto Upload All> ----------------------
-         
-         // Verify num error k_maxErrorAutoUploadAll after STOP (100)
-         NSArray *metadatas = [[NCManageDatabase sharedInstance] getMetadatasWithPredicate:[NSPredicate predicateWithFormat:@"sessionSelector == %@ AND status == %i", selectorUploadAutoUploadAll, k_metadataStatusUploadError] sorted:@"date" ascending:YES];
-         NSInteger errorCount = [metadatas count];
-         
-         if (errorCount >= k_maxErrorAutoUploadAll) {
-             
-             [[NCContentPresenter shared] messageNotification:@"_error_" description:@"_too_errors_automatic_all_" delay:k_dismissAfterSecond type:messageTypeError errorCode:k_CCErrorInternalError];
-             
-         } else {
-             
-             while (counterUpload < maxConcurrentOperationUpload) {
-                 
-                 if (sizeUpload > k_maxSizeOperationUpload) {
-                     break;
-                 }
-                 
-                 if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) {
-                     predicate = [NSPredicate predicateWithFormat:@"sessionSelector == %@ AND status == %d AND typeFile != %@", selectorUploadAutoUploadAll, k_metadataStatusWaitUpload, k_metadataTypeFile_video];
-                 } else {
-                     predicate = [NSPredicate predicateWithFormat:@"sessionSelector == %@ AND status == %d", selectorUploadAutoUploadAll, k_metadataStatusWaitUpload];
-                 }
-                 
-                 metadataForUpload = [[NCManageDatabase sharedInstance] getMetadataWithPredicate:predicate sorted:@"session" ascending:YES];
-                 if (metadataForUpload) {
-                     
-                     if ([CCUtility isFolderEncrypted:metadataForUpload.serverUrl e2eEncrypted:metadataForUpload.e2eEncrypted account:metadataForUpload.account]) {
-                     
-                         if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) { break; }
-                         maxConcurrentOperationUpload = 1;
-                         
-                         metadataForUpload.status = k_metadataStatusInUpload;
-                         tableMetadata *metadata = [[NCManageDatabase sharedInstance] addMetadata:metadataForUpload];
-                         
-                         [[NCNetworking shared] uploadWithMetadata:metadata background:true completion:^(NSInteger errorCode, NSString *errorDescription) { }];
-                         
-                         break;
-                         
-                     } else {
-                         
-                         metadataForUpload.status = k_metadataStatusInUpload;
-                         tableMetadata *metadata = [[NCManageDatabase sharedInstance] addMetadata:metadataForUpload];
-                         
-                         [[NCNetworking shared] uploadWithMetadata:metadata background:true completion:^(NSInteger errorCode, NSString *errorDescription) { }];
-                         
-                         counterUpload++;
-                         sizeUpload = sizeUpload + metadata.size;
-                         
-                     }
-                     
-                 } else {
-                     break;
-                 }
-             }
-         }
-         
-         // No upload available ? --> Retry Upload in Error
-         if (counterUpload == 0) {
-             
-             NSArray *metadatas = [[NCManageDatabase sharedInstance] getMetadatasWithPredicate:[NSPredicate predicateWithFormat:@"status == %d", k_metadataStatusUploadError] sorted:nil ascending:NO];
-             for (tableMetadata *metadata in metadatas) {
-                 
-                 metadata.session = NCCommunicationCommon.shared.sessionIdentifierBackground;
-                 metadata.sessionError = @"";
-                 metadata.sessionTaskIdentifier = 0;
-                 metadata.status = k_metadataStatusInUpload;
-                 
-                 [[NCManageDatabase sharedInstance] addMetadata:metadata];
-             }
-         }
-         
-         // verify delete Asset Local Identifiers in auto upload (Photos album)
-         if (counterUpload == 0 && self.passcodeViewController == nil) {
-             
-             [[NCUtility sharedInstance] deleteAssetLocalIdentifiersWithAccount:self.activeAccount sessionSelector:selectorUploadAutoUpload];
-         }
-     }
-
-     */
-
     //MARK: - Download / Upload
     
     @objc func verifyTransfer() {

+ 156 - 0
iOSClient/Networking/NCNetworkingAutoUpload.swift

@@ -0,0 +1,156 @@
+//
+//  NCNetworkingAutoUpload.swift
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 25/06/2020.
+//  Copyright © 2020 Marino Faggiana. All rights reserved.
+//
+//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+import Foundation
+import NCCommunication
+
+class NCNetworkingAutoUpload: NSObject {
+
+    let appDelegate = UIApplication.shared.delegate as! AppDelegate
+    
+    override init() {
+        super.init()
+        process()
+    }
+
+    @objc func process() {
+
+        var counterUpload = 0
+        var sizeUpload = 0
+        var maxConcurrentOperationUpload = k_maxConcurrentOperation
+     
+        let metadatasUpload = NCManageDatabase.sharedInstance.getMetadatas(predicate: NSPredicate(format: "status == %d OR status == %d", k_metadataStatusInUpload, k_metadataStatusUploading), freeze: true)
+        counterUpload = metadatasUpload.count
+         
+        for metadata in metadatasUpload {
+            sizeUpload = sizeUpload + Int(metadata.size)
+        }
+         
+        debugPrint("[LOG] PROCESS-AUTO-UPLOAD \(counterUpload)")
+    
+        // ------------------------- <selector Upload> -------------------------
+         
+        while counterUpload < maxConcurrentOperationUpload {
+            if sizeUpload > k_maxSizeOperationUpload { break }
+            var predicate = NSPredicate()
+             
+            if UIApplication.shared.applicationState == .background {
+                predicate = NSPredicate(format: "sessionSelector == %@ AND status == %d AND typeFile != %@", selectorUploadFile, k_metadataStatusWaitUpload, k_metadataTypeFile_video)
+            } else {
+                predicate = NSPredicate(format: "sessionSelector == %@ AND status == %d", selectorUploadFile, k_metadataStatusWaitUpload)
+            }
+             
+            if let metadata = NCManageDatabase.sharedInstance.getMetadata(predicate: predicate, freeze: true) {
+                if CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account) {
+                    if UIApplication.shared.applicationState == .background { break }
+                    maxConcurrentOperationUpload = 1
+                }
+                NCManageDatabase.sharedInstance.setMetadataSession(ocId: metadata.ocId, status: Int(k_metadataStatusInUpload))
+                
+                NCNetworking.shared.upload(metadata: metadata, background: true) { (_, _) in }
+                counterUpload += 1
+                sizeUpload = sizeUpload + Int(metadata.size)
+            } else {
+                break
+            }
+        }
+         
+        // ------------------------- <selector Auto Upload> -------------------------
+             
+        while counterUpload < maxConcurrentOperationUpload {
+            if sizeUpload > k_maxSizeOperationUpload { break }
+            var predicate = NSPredicate()
+             
+            if UIApplication.shared.applicationState == .background {
+                predicate = NSPredicate(format: "sessionSelector == %@ AND status == %d AND typeFile != %@", selectorUploadAutoUpload, k_metadataStatusWaitUpload, k_metadataTypeFile_video)
+            } else {
+                predicate = NSPredicate(format: "sessionSelector == %@ AND status == %d", selectorUploadAutoUpload, k_metadataStatusWaitUpload)
+            }
+             
+            if let metadata = NCManageDatabase.sharedInstance.getMetadata(predicate: predicate, freeze: true) {
+                if CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account) {
+                    if UIApplication.shared.applicationState == .background { break }
+                    maxConcurrentOperationUpload = 1
+                }
+                NCManageDatabase.sharedInstance.setMetadataSession(ocId: metadata.ocId, status: Int(k_metadataStatusInUpload))
+                NCNetworking.shared.upload(metadata: metadata, background: true) { (_, _) in }
+                counterUpload += 1
+                sizeUpload = sizeUpload + Int(metadata.size)
+            } else {
+                break
+            }
+        }
+         
+        // ------------------------- <selector Auto Upload All> ----------------------
+         
+        // Verify num error k_maxErrorAutoUploadAll after STOP (100)
+        let metadatasInError = NCManageDatabase.sharedInstance.getMetadatas(predicate: NSPredicate(format: "sessionSelector == %@ AND status == %d", selectorUploadAutoUploadAll, k_metadataStatusUploadError), freeze: true)
+        if metadatasInError.count >= k_maxErrorAutoUploadAll {
+            NCContentPresenter.shared.messageNotification("_error_", description: "_too_errors_automatic_all_", delay: TimeInterval(k_dismissAfterSecond), type: NCContentPresenter.messageType.error, errorCode: Int(k_CCErrorInternalError))
+        } else {
+            while counterUpload < maxConcurrentOperationUpload {
+                if sizeUpload > k_maxSizeOperationUpload { break }
+                var predicate = NSPredicate()
+                        
+                if UIApplication.shared.applicationState == .background {
+                    predicate = NSPredicate(format: "sessionSelector == %@ AND status == %d AND typeFile != %@", selectorUploadAutoUploadAll, k_metadataStatusWaitUpload, k_metadataTypeFile_video)
+                } else {
+                    predicate = NSPredicate(format: "sessionSelector == %@ AND status == %d", selectorUploadAutoUploadAll, k_metadataStatusWaitUpload)
+                }
+                        
+                if let metadata = NCManageDatabase.sharedInstance.getMetadata(predicate: predicate, freeze: true) {
+                    if CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account) {
+                        if UIApplication.shared.applicationState == .background { break }
+                                maxConcurrentOperationUpload = 1
+                    }
+                    NCManageDatabase.sharedInstance.setMetadataSession(ocId: metadata.ocId, status: Int(k_metadataStatusInUpload))
+                    NCNetworking.shared.upload(metadata: metadata, background: true) { (_, _) in }
+                    counterUpload += 1
+                    sizeUpload = sizeUpload + Int(metadata.size)
+                } else {
+                    break
+                }
+            }
+        }
+         
+        // No upload available ? --> Retry Upload in Error
+        if counterUpload == 0 {
+             
+            let metadatas = NCManageDatabase.sharedInstance.getMetadatas(predicate: NSPredicate(format: "status == %d", selectorUploadAutoUploadAll, k_metadataStatusUploadError), freeze: true)
+            for metadata in metadatas {
+                NCManageDatabase.sharedInstance.setMetadataSession(ocId: metadata.ocId, session: NCCommunicationCommon.shared.sessionIdentifierBackground, sessionError: "", sessionTaskIdentifier: 0 ,status: Int(k_metadataStatusInUpload))
+            }
+        }
+         
+        // verify delete Asset Local Identifiers in auto upload (Photos album)
+        if (counterUpload == 0 && appDelegate.passcodeViewController == nil) {
+            NCUtility.sharedInstance.deleteAssetLocalIdentifiers(account: appDelegate.activeAccount, sessionSelector: selectorUploadAutoUpload)
+         }
+         
+         DispatchQueue.main.asyncAfter(deadline: .now() + TimeInterval(k_timerAutoUpload)) {
+             //self.loadAutoUpload()
+         }
+     }
+
+}
+