count the files deletion and warn if threshold is exceeded
authorMatthieu Gallien <matthieu.gallien@nextcloud.com>
Fri, 13 Sep 2024 10:25:29 +0000 (12:25 +0200)
committerMatthieu Gallien <matthieu.gallien@nextcloud.com>
Mon, 30 Sep 2024 12:33:49 +0000 (14:33 +0200)
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
src/libsync/configfile.cpp
src/libsync/configfile.h
src/libsync/syncengine.cpp
src/libsync/syncengine.h

index d79bbd51fe3444545d95391195c293fbbc406f06..f5efd8eb1fc9ed23992f81ffcf8289f42d782b64 100644 (file)
@@ -54,6 +54,7 @@ static constexpr char fullLocalDiscoveryIntervalC[] = "fullLocalDiscoveryInterva
 static constexpr char notificationRefreshIntervalC[] = "notificationRefreshInterval";
 static constexpr char monoIconsC[] = "monoIcons";
 static constexpr char promptDeleteC[] = "promptDeleteAllFiles";
+static constexpr char deleteFilesThresholdC[] = "deleteFilesThreshold";
 static constexpr char crashReporterC[] = "crashReporter";
 static constexpr char optionalServerNotificationsC[] = "optionalServerNotifications";
 static constexpr char showCallNotificationsC[] = "showCallNotifications";
@@ -112,6 +113,8 @@ static const QStringList defaultUpdateChannelsList { QStringLiteral("stable"), Q
 static const QString defaultUpdateChannelName = "stable";
 static const QStringList enterpriseUpdateChannelsList { QStringLiteral("stable"), QStringLiteral("enterprise") };
 static const QString defaultEnterpriseChannel = "enterprise";
+
+static constexpr int deleteFilesThresholdDefaultValue = 100;
 }
 
 namespace OCC {
@@ -1038,7 +1041,7 @@ bool ConfigFile::showMainDialogAsNormalWindow() const {
 bool ConfigFile::promptDeleteFiles() const
 {
     QSettings settings(configFile(), QSettings::IniFormat);
-    return settings.value(QLatin1String(promptDeleteC), false).toBool();
+    return settings.value(QLatin1String(promptDeleteC), true).toBool();
 }
 
 void ConfigFile::setPromptDeleteFiles(bool promptDeleteFiles)
@@ -1047,6 +1050,18 @@ void ConfigFile::setPromptDeleteFiles(bool promptDeleteFiles)
     settings.setValue(QLatin1String(promptDeleteC), promptDeleteFiles);
 }
 
+int ConfigFile::deleteFilesThreshold() const
+{
+    QSettings settings(configFile(), QSettings::IniFormat);
+    return settings.value(QLatin1String(deleteFilesThresholdC), deleteFilesThresholdDefaultValue).toInt();
+}
+
+void ConfigFile::setDeleteFilesThreshold(int thresholdValue)
+{
+    QSettings settings(configFile(), QSettings::IniFormat);
+    settings.setValue(QLatin1String(deleteFilesThresholdC), thresholdValue);
+}
+
 bool ConfigFile::monoIcons() const
 {
     QSettings settings(configFile(), QSettings::IniFormat);
index 86963df53d904628c5f80e2ad3e231b7c04014c0..ff289b1fe06054a536dc452eac0cfffb6a2de1b1 100644 (file)
@@ -93,6 +93,9 @@ public:
     [[nodiscard]] bool promptDeleteFiles() const;
     void setPromptDeleteFiles(bool promptDeleteFiles);
 
+    [[nodiscard]] int deleteFilesThreshold() const;
+    void setDeleteFilesThreshold(int thresholdValue);
+
     [[nodiscard]] bool crashReporter() const;
     void setCrashReporter(bool enabled);
 
index 61b6f0c5aa2334179262c8cdc81541558c36967c..58aad760b65f0112225eadcb42274c1a657a7130 100644 (file)
@@ -802,19 +802,7 @@ void SyncEngine::slotDiscoveryFinished()
     _progressInfo->_status = ProgressInfo::Reconcile;
     emit transmissionProgress(*_progressInfo);
 
-    const auto displayDialog = ConfigFile().promptDeleteFiles() && !_syncOptions.isCmd();
-    if (!_hasNoneFiles && _hasRemoveFile && displayDialog) {
-        qCInfo(lcEngine) << "All the files are going to be changed, asking the user";
-        int side = 0; // > 0 means more deleted on the server.  < 0 means more deleted on the client
-        for (const auto &it : _syncItems) {
-            if (it->_instruction == CSYNC_INSTRUCTION_REMOVE) {
-                side += it->_direction == SyncFileItem::Down ? 1 : -1;
-            }
-        }
-
-        promptUserBeforePropagation([this, side](auto &&callback){
-                                        emit aboutToRemoveAllFiles(side >= 0 ? SyncFileItem::Down : SyncFileItem::Up, callback);
-                                    });
+    if (handleMassDeletion()) {
         return;
     }
 
@@ -1106,6 +1094,47 @@ void SyncEngine::finishSync()
     qCInfo(lcEngine) << "#### Post-Reconcile end #################################################### " << _stopWatch.addLapTime(QStringLiteral("Post-Reconcile Finished")) << "ms";
 }
 
+bool SyncEngine::handleMassDeletion()
+{
+    const auto displayDialog = ConfigFile().promptDeleteFiles() && !_syncOptions.isCmd();
+    const auto allFilesDeleted = !_hasNoneFiles && _hasRemoveFile;
+
+    auto deletionCounter = 0;
+    for (const auto &oneItem : qAsConst(_syncItems)) {
+        if (oneItem->_instruction == CSYNC_INSTRUCTION_REMOVE) {
+            if (oneItem->isDirectory()) {
+                const auto result = _journal->listFilesInPath(oneItem->_file.toUtf8(), [&deletionCounter] (const auto &oneRecord) {
+                    if (oneRecord.isFile()) {
+                        ++deletionCounter;
+                    }
+                });
+                if (!result) {
+                    qCDebug(lcEngine()) << "unable to find the number of files within a deleted folder:" << oneItem->_file;
+                }
+            } else {
+                ++deletionCounter;
+            }
+        }
+    }
+    const auto filesDeletedThresholdExceeded = deletionCounter > ConfigFile().deleteFilesThreshold();
+
+    if ((allFilesDeleted || filesDeletedThresholdExceeded) && displayDialog) {
+        qCInfo(lcEngine) << "All the files are going to be changed, asking the user";
+        int side = 0; // > 0 means more deleted on the server.  < 0 means more deleted on the client
+        for (const auto &it : qAsConst(_syncItems)) {
+            if (it->_instruction == CSYNC_INSTRUCTION_REMOVE) {
+                side += it->_direction == SyncFileItem::Down ? 1 : -1;
+            }
+        }
+
+        promptUserBeforePropagation([this, side](auto &&callback){
+            emit aboutToRemoveAllFiles(side >= 0 ? SyncFileItem::Down : SyncFileItem::Up, callback);
+        });
+        return true;
+    }
+    return false;
+}
+
 void SyncEngine::handleRemnantReadOnlyFolders()
 {
     promptUserBeforePropagation([this](auto &&callback) {
index 2d824f3318d4e73c0bf8202fef5c89e690e82801..63ab0a787e218573eb1d773d955f0eacf46c0011 100644 (file)
@@ -369,6 +369,8 @@ private:
 
     void finishSync();
 
+    bool handleMassDeletion();
+
     void handleRemnantReadOnlyFolders();
 
     template <typename T>