add more metadata to sync errors to allow filtering
authorMatthieu Gallien <matthieu.gallien@nextcloud.com>
Tue, 11 Oct 2022 14:10:53 +0000 (16:10 +0200)
committerMatthieu Gallien <matthieu_gallien@yahoo.fr>
Thu, 8 Jun 2023 06:55:32 +0000 (08:55 +0200)
in order to be able to filter some errors when showing them into the
main dialog activity list, add some more info about the error to know
the origin (like a network issue or a sync issue)

Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
25 files changed:
src/gui/editlocallyjob.cpp
src/gui/folder.cpp
src/gui/folder.h
src/gui/tray/activitylistmodel.cpp
src/gui/tray/activitylistmodel.h
src/gui/tray/usermodel.cpp
src/gui/tray/usermodel.h
src/libsync/bulkpropagatorjob.cpp
src/libsync/bulkpropagatorjob.h
src/libsync/discovery.cpp
src/libsync/discoveryphase.cpp
src/libsync/discoveryphase.h
src/libsync/owncloudpropagator.cpp
src/libsync/owncloudpropagator.h
src/libsync/progressdispatcher.h
src/libsync/propagatedownload.cpp
src/libsync/propagateremotedelete.cpp
src/libsync/propagateremotemkdir.cpp
src/libsync/propagateremotemove.cpp
src/libsync/propagateupload.cpp
src/libsync/propagateupload.h
src/libsync/propagatorjobs.cpp
src/libsync/syncengine.cpp
src/libsync/syncengine.h
test/testactivitylistmodel.cpp

index 78aedd34f82a35182cc20568df988ac404c029cc..526d76ccc2bd09d8dc856451cd075b9519cbd65c 100644 (file)
@@ -438,7 +438,7 @@ void EditLocallyJob::showErrorNotification(const QString &message, const QString
     });
 
     if (foundFolder != folderMap.cend()) {
-        emit (*foundFolder)->syncEngine().addErrorToGui(SyncFileItem::SoftError, message, informativeText);
+        emit (*foundFolder)->syncEngine().addErrorToGui(SyncFileItem::SoftError, message, informativeText, OCC::ErrorCategory::GenericError);
     }
 }
 
index b16d0daf6e1527e21cb9f3254550632327257cae..31542c6bc9f6da087afab5bc05e1409918920885 100644 (file)
@@ -890,7 +890,7 @@ void Folder::startSync(const QStringList &pathList)
     _fileLog->start(path());
 
     if (!reloadExcludes()) {
-        slotSyncError(tr("Could not read system exclude file"));
+        slotSyncError(tr("Could not read system exclude file"), ErrorCategory::GenericError);
         QMetaObject::invokeMethod(this, "slotSyncFinished", Qt::QueuedConnection, Q_ARG(bool, false));
         return;
     }
@@ -1005,9 +1005,9 @@ void Folder::slotSyncError(const QString &message, ErrorCategory category)
     }
 }
 
-void Folder::slotAddErrorToGui(SyncFileItem::Status status, const QString &errorMessage, const QString &subject)
+void Folder::slotAddErrorToGui(SyncFileItem::Status status, const QString &errorMessage, const QString &subject, ErrorCategory category)
 {
-    emit ProgressDispatcher::instance()->addErrorToGui(alias(), status, errorMessage, subject);
+    emit ProgressDispatcher::instance()->addErrorToGui(alias(), status, errorMessage, subject, category);
 }
 
 void Folder::slotSyncStarted()
@@ -1128,7 +1128,7 @@ void Folder::slotTransmissionProgress(const ProgressInfo &pi)
 }
 
 // a item is completed: count the errors and forward to the ProgressDispatcher
-void Folder::slotItemCompleted(const SyncFileItemPtr &item)
+void Folder::slotItemCompleted(const SyncFileItemPtr &item, ErrorCategory errorCategory)
 {
     if (item->_instruction == CSYNC_INSTRUCTION_NONE || item->_instruction == CSYNC_INSTRUCTION_UPDATE_METADATA) {
         // We only care about the updates that deserve to be shown in the UI
@@ -1144,7 +1144,7 @@ void Folder::slotItemCompleted(const SyncFileItemPtr &item)
     _syncResult.processCompletedItem(item);
 
     _fileLog->logItem(*item);
-    emit ProgressDispatcher::instance()->itemCompleted(alias(), item);
+    emit ProgressDispatcher::instance()->itemCompleted(alias(), item, errorCategory);
 }
 
 void Folder::slotNewBigFolderDiscovered(const QString &newF, bool isExternal)
index 6f26eb5e541e2a5659a972e4da0064847721ee56..9d654baed92585d3a3befafabc48f1fa30acd32f 100644 (file)
@@ -388,12 +388,12 @@ private slots:
 
     /** Adds a error message that's not tied to a specific item.
      */
-    void slotSyncError(const QString &message, OCC::ErrorCategory category = OCC::ErrorCategory::Normal);
+    void slotSyncError(const QString &message, OCC::ErrorCategory category);
 
-    void slotAddErrorToGui(OCC::SyncFileItem::Status status, const QString &errorMessage, const QString &subject = {});
+    void slotAddErrorToGui(OCC::SyncFileItem::Status status, const QString &errorMessage, const QString &subject, OCC::ErrorCategory category);
 
     void slotTransmissionProgress(const OCC::ProgressInfo &pi);
-    void slotItemCompleted(const OCC::SyncFileItemPtr &);
+    void slotItemCompleted(const OCC::SyncFileItemPtr &, OCC::ErrorCategory errorCategory);
 
     void slotRunEtagJob();
     void etagRetrieved(const QByteArray &, const QDateTime &tp);
index f36b7b9744a24e9480a02c681bd81d0bab2d386e..658eb7936928c28b708f913586f6d574623c3615 100644 (file)
@@ -556,9 +556,9 @@ void ActivityListModel::addEntriesToActivityList(const ActivityList &activityLis
     setHasSyncConflicts(conflictsFound);
 }
 
-void ActivityListModel::addErrorToActivityList(const Activity &activity)
+void ActivityListModel::addErrorToActivityList(const Activity &activity, const ErrorType type)
 {
-    qCInfo(lcActivity) << "Error successfully added to the notification list: " << activity._message << activity._subject << activity._syncResultStatus << activity._syncFileItemStatus;
+    qCInfo(lcActivity) << "Error successfully added to the notification list: " << type << activity._message << activity._subject << activity._syncResultStatus << activity._syncFileItemStatus;
     addEntriesToActivityList({activity});
     _notificationErrorsLists.prepend(activity);
 }
index ce8364c17904b66aa21aa673fe7a6824d5231c67..ba75bb5c6165286044df9b71528c96cd3ca7a907 100644 (file)
@@ -82,6 +82,12 @@ public:
     };
     Q_ENUM(DataRole)
 
+    enum class ErrorType {
+        SyncError,
+        NetworkError,
+    };
+    Q_ENUM(ErrorType)
+
     explicit ActivityListModel(QObject *parent = nullptr);
 
     explicit ActivityListModel(AccountState *accountState,
@@ -122,7 +128,7 @@ public slots:
     void slotTriggerDismiss(const int activityIndex);
 
     void addNotificationToActivityList(const OCC::Activity &activity);
-    void addErrorToActivityList(const OCC::Activity &activity);
+    void addErrorToActivityList(const OCC::Activity &activity, const ErrorType type);
     void addIgnoredFileToList(const OCC::Activity &newActivity);
     void addSyncFileItemToActivityList(const OCC::Activity &activity);
     void removeActivityFromActivityList(int row);
index f3dc30c0870a1aae5296a1898563ef6dda574b10..d56f23f15e5a4929de6c5adc83a7e213b9662c80 100644 (file)
@@ -627,12 +627,27 @@ void User::slotAddError(const QString &folderAlias, const QString &message, Erro
             activity._links.append(link);
         }
 
+        auto errorType = ActivityListModel::ErrorType::SyncError;
         // add 'other errors' to activity list
-        _activityModel->addErrorToActivityList(activity);
+        switch (category) {
+        case ErrorCategory::GenericError:
+            errorType = ActivityListModel::ErrorType::SyncError;
+            break;
+        case ErrorCategory::InsufficientRemoteStorage:
+            errorType = ActivityListModel::ErrorType::SyncError;
+            break;
+        case ErrorCategory::NetworkError:
+            errorType = ActivityListModel::ErrorType::NetworkError;
+            break;
+        case ErrorCategory::NoError:
+            break;
+        }
+
+        _activityModel->addErrorToActivityList(activity, errorType);
     }
 }
 
-void User::slotAddErrorToGui(const QString &folderAlias, SyncFileItem::Status status, const QString &errorMessage, const QString &subject)
+void User::slotAddErrorToGui(const QString &folderAlias, const SyncFileItem::Status status, const QString &errorMessage, const QString &subject, const ErrorCategory category)
 {
     const auto folderInstance = FolderMan::instance()->folder(folderAlias);
     if (!folderInstance) {
@@ -668,7 +683,24 @@ void User::slotAddErrorToGui(const QString &folderAlias, SyncFileItem::Status st
         activity._id = -static_cast<int>(qHash(activity._subject + activity._message));
 
         // add 'other errors' to activity list
-        _activityModel->addErrorToActivityList(activity);
+        auto errorType = ActivityListModel::ErrorType::SyncError;
+        switch (category)
+        {
+        case ErrorCategory::GenericError:
+            errorType = ActivityListModel::ErrorType::SyncError;
+            break;
+        case ErrorCategory::InsufficientRemoteStorage:
+            errorType = ActivityListModel::ErrorType::SyncError;
+            break;
+        case ErrorCategory::NetworkError:
+            errorType = ActivityListModel::ErrorType::NetworkError;
+            break;
+        case ErrorCategory::NoError:
+            errorType = {};
+            break;
+        }
+
+        _activityModel->addErrorToActivityList(activity, errorType);
 
         showDesktopNotification(activity);
 
@@ -787,7 +819,7 @@ void User::processCompletedSyncItem(const Folder *folder, const SyncFileItemPtr
 
                 activity._links = {buttonActivityLink};
             }
-            _activityModel->addErrorToActivityList(activity);
+            _activityModel->addErrorToActivityList(activity, ActivityListModel::ErrorType::SyncError);
         }
     }
 }
index e17059969f348ca4e6212a3242c8b2e2709941c4..353035fb68ffe4e2962aeac6ebee0c4467df5f9e 100644 (file)
@@ -117,7 +117,7 @@ public slots:
     void slotItemCompleted(const QString &folder, const OCC::SyncFileItemPtr &item);
     void slotProgressInfo(const QString &folder, const OCC::ProgressInfo &progress);
     void slotAddError(const QString &folderAlias, const QString &message, OCC::ErrorCategory category);
-    void slotAddErrorToGui(const QString &folderAlias, OCC::SyncFileItem::Status status, const QString &errorMessage, const QString &subject = {});
+    void slotAddErrorToGui(const QString &folderAlias, const OCC::SyncFileItem::Status status, const QString &errorMessage, const QString &subject, const ErrorCategory category);
     void slotNotificationRequestFinished(int statusCode);
     void slotNotifyNetworkError(QNetworkReply *reply);
     void slotEndNotificationRequest(int replyCode);
index d6e4fe9ef947ea7b01f85b088cfba12d24386c75..698962e5a1eb8f32a7b946897baa1ef213aee4f0 100644 (file)
@@ -120,7 +120,7 @@ void BulkPropagatorJob::startUploadFile(SyncFileItemPtr item, UploadFileInfo fil
 
     // Check if the specific file can be accessed
     if (propagator()->hasCaseClashAccessibilityProblem(fileToUpload._file)) {
-        done(item, SyncFileItem::NormalError, tr("File %1 cannot be uploaded because another file with the same name, differing only in case, exists").arg(QDir::toNativeSeparators(item->_file)));
+        done(item, SyncFileItem::NormalError, tr("File %1 cannot be uploaded because another file with the same name, differing only in case, exists").arg(QDir::toNativeSeparators(item->_file)), ErrorCategory::GenericError);
         return;
     }
 
@@ -160,7 +160,7 @@ void BulkPropagatorJob::doStartUpload(SyncFileItemPtr item,
         const auto renameSuccess = QFile::rename(originalFilePathAbsolute, newFilePathAbsolute);
 
         if (!renameSuccess) {
-            done(item, SyncFileItem::NormalError, "File contains trailing spaces and couldn't be renamed");
+            done(item, SyncFileItem::NormalError, "File contains trailing spaces and couldn't be renamed", ErrorCategory::GenericError);
             return;
         }
 
@@ -172,7 +172,7 @@ void BulkPropagatorJob::doStartUpload(SyncFileItemPtr item,
         item->_modtime = FileSystem::getModTime(newFilePathAbsolute);
         if (item->_modtime <= 0) {
             _pendingChecksumFiles.remove(item->_file);
-            slotOnErrorStartFolderUnlock(item, SyncFileItem::NormalError, tr("File %1 has invalid modified time. Do not upload to the server.").arg(QDir::toNativeSeparators(item->_file)));
+            slotOnErrorStartFolderUnlock(item, SyncFileItem::NormalError, tr("File %1 has invalid modified time. Do not upload to the server.").arg(QDir::toNativeSeparators(item->_file)), ErrorCategory::GenericError);
             checkPropagationIsDone();
             return;
         }
@@ -293,7 +293,7 @@ void BulkPropagatorJob::slotStartUpload(SyncFileItemPtr item,
 
     if (!FileSystem::fileExists(fullFilePath)) {
         _pendingChecksumFiles.remove(item->_file);
-        slotOnErrorStartFolderUnlock(item, SyncFileItem::SoftError, tr("File Removed (start upload) %1").arg(fullFilePath));
+        slotOnErrorStartFolderUnlock(item, SyncFileItem::SoftError, tr("File Removed (start upload) %1").arg(fullFilePath), ErrorCategory::GenericError);
         checkPropagationIsDone();
         return;
     }
@@ -305,7 +305,7 @@ void BulkPropagatorJob::slotStartUpload(SyncFileItemPtr item,
     item->_modtime = FileSystem::getModTime(originalFilePath);
     if (item->_modtime <= 0) {
         _pendingChecksumFiles.remove(item->_file);
-        slotOnErrorStartFolderUnlock(item, SyncFileItem::NormalError, tr("File %1 has invalid modification time. Do not upload to the server.").arg(QDir::toNativeSeparators(item->_file)));
+        slotOnErrorStartFolderUnlock(item, SyncFileItem::NormalError, tr("File %1 has invalid modification time. Do not upload to the server.").arg(QDir::toNativeSeparators(item->_file)), ErrorCategory::GenericError);
         checkPropagationIsDone();
         return;
     }
@@ -317,7 +317,7 @@ void BulkPropagatorJob::slotStartUpload(SyncFileItemPtr item,
                                      << "prevModtime" << prevModtime
                                      << "Curr" << item->_modtime;
 
-        slotOnErrorStartFolderUnlock(item, SyncFileItem::SoftError, tr("Local file changed during syncing. It will be resumed."));
+        slotOnErrorStartFolderUnlock(item, SyncFileItem::SoftError, tr("Local file changed during syncing. It will be resumed."), ErrorCategory::GenericError);
         checkPropagationIsDone();
         return;
     }
@@ -331,7 +331,7 @@ void BulkPropagatorJob::slotStartUpload(SyncFileItemPtr item,
     if (fileIsStillChanging(*item)) {
         propagator()->_anotherSyncNeeded = true;
         _pendingChecksumFiles.remove(item->_file);
-        slotOnErrorStartFolderUnlock(item, SyncFileItem::SoftError, tr("Local file changed during sync."));
+        slotOnErrorStartFolderUnlock(item, SyncFileItem::SoftError, tr("Local file changed during sync."), ErrorCategory::GenericError);
         checkPropagationIsDone();
         return;
     }
@@ -340,11 +340,12 @@ void BulkPropagatorJob::slotStartUpload(SyncFileItemPtr item,
 }
 
 void BulkPropagatorJob::slotOnErrorStartFolderUnlock(SyncFileItemPtr item,
-                                                     SyncFileItem::Status status,
-                                                     const QString &errorString)
+                                                     const SyncFileItem::Status status,
+                                                     const QString &errorString,
+                                                     const ErrorCategory errorCategory)
 {
-    qCInfo(lcBulkPropagatorJob()) << status << errorString;
-    done(item, status, errorString);
+    qCInfo(lcBulkPropagatorJob()) << status << errorString << errorCategory;
+    done(item, status, errorString, errorCategory);
 }
 
 void BulkPropagatorJob::slotPutFinishedOneFile(const BulkUploadItem &singleFile,
@@ -473,10 +474,10 @@ void BulkPropagatorJob::finalizeOneFile(const BulkUploadItem &oneFile)
     // Update the database entry
     const auto result = propagator()->updateMetadata(*oneFile._item);
     if (!result) {
-        done(oneFile._item, SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()));
+        done(oneFile._item, SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()), ErrorCategory::GenericError);
         return;
     } else if (*result == Vfs::ConvertToPlaceholderResult::Locked) {
-        done(oneFile._item, SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(oneFile._item->_file));
+        done(oneFile._item, SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(oneFile._item->_file), ErrorCategory::GenericError);
         return;
     }
 
@@ -511,7 +512,7 @@ void BulkPropagatorJob::finalize(const QJsonObject &fullReply)
             finalizeOneFile(singleFile);
         }
 
-        done(singleFile._item, singleFile._item->_status, {});
+        done(singleFile._item, singleFile._item->_status, {}, ErrorCategory::GenericError);
 
         singleFileIt = _filesToUpload.erase(singleFileIt);
     }
@@ -520,8 +521,9 @@ void BulkPropagatorJob::finalize(const QJsonObject &fullReply)
 }
 
 void BulkPropagatorJob::done(SyncFileItemPtr item,
-                             SyncFileItem::Status status,
-                             const QString &errorString)
+                             const SyncFileItem::Status status,
+                             const QString &errorString,
+                             const ErrorCategory category)
 {
     item->_status = status;
     item->_errorString = errorString;
@@ -548,7 +550,7 @@ void BulkPropagatorJob::done(SyncFileItemPtr item,
 
     handleJobDoneErrors(item, status);
 
-    emit propagator()->itemCompleted(item);
+    emit propagator()->itemCompleted(item, category);
 }
 
 QMap<QByteArray, QByteArray> BulkPropagatorJob::headers(SyncFileItemPtr item) const
@@ -606,7 +608,7 @@ void BulkPropagatorJob::abortWithError(SyncFileItemPtr item,
                                        const QString &error)
 {
     abort(AbortType::Synchronous);
-    done(item, status, error);
+    done(item, status, error, ErrorCategory::GenericError);
 }
 
 void BulkPropagatorJob::checkResettingErrors(SyncFileItemPtr item) const
index 451456e9702ee5349831967d1ce03c91525b12a5..34441d324bbaed7cb1b25316a339904d51c27c97 100644 (file)
@@ -81,8 +81,9 @@ private slots:
 
     // invoked on internal error to unlock a folder and faile
     void slotOnErrorStartFolderUnlock(OCC::SyncFileItemPtr item,
-                                      OCC::SyncFileItem::Status status,
-                                      const QString &errorString);
+                                      const OCC::SyncFileItem::Status status,
+                                      const QString &errorString,
+                                      const OCC::ErrorCategory errorCategory);
 
     void slotPutFinished();
 
@@ -107,8 +108,9 @@ private:
                                 const QJsonObject &fullReplyObject);
 
     void done(SyncFileItemPtr item,
-              SyncFileItem::Status status,
-              const QString &errorString);
+              const SyncFileItem::Status status,
+              const QString &errorString,
+              const ErrorCategory category);
 
     /** Bases headers that need to be sent on the PUT, or in the MOVE for chunking-ng */
     [[nodiscard]] QMap<QByteArray, QByteArray> headers(SyncFileItemPtr item) const;
index 684c0560633db58aa045226f46a82c677218b9f4..81e180934db0724fa17835055a960e25afd75181 100644 (file)
@@ -18,6 +18,7 @@
 #include "common/syncjournaldb.h"
 #include "filesystem.h"
 #include "syncfileitem.h"
+#include "progressdispatcher.h"
 #include <QDebug>
 #include <algorithm>
 #include <QEventLoop>
@@ -964,7 +965,7 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo(
             // Not locally, not on the server. The entry is stale!
             qCInfo(lcDisco) << "Stale DB entry";
             if (!_discoveryData->_statedb->deleteFileRecord(path._original, true)) {
-                emit _discoveryData->fatalError(tr("Error while deleting file record %1 from the database").arg(path._original));
+                emit _discoveryData->fatalError(tr("Error while deleting file record %1 from the database").arg(path._original), ErrorCategory::GenericError);
                 qCWarning(lcDisco) << "Failed to delete a file record from the local DB" << path._original;
             }
             return;
@@ -1214,10 +1215,10 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo(
             if (isFolderPinStateOnlineOnly && folderPinState.isValid()) {
                 qCInfo(lcDisco) << "*folderPinState:" << *folderPinState;
             }
-            emit _discoveryData->addErrorToGui(SyncFileItem::SoftError, tr("Conflict when uploading a folder. It's going to get cleared!"), path._local);
+            emit _discoveryData->addErrorToGui(SyncFileItem::SoftError, tr("Conflict when uploading a folder. It's going to get cleared!"), path._local, ErrorCategory::GenericError);
         } else {
             qCInfo(lcDisco) << "Wiping virtual file without db entry for" << path._local;
-            emit _discoveryData->addErrorToGui(SyncFileItem::SoftError, tr("Conflict when uploading a file. It's going to get removed!"), path._local);
+            emit _discoveryData->addErrorToGui(SyncFileItem::SoftError, tr("Conflict when uploading a file. It's going to get removed!"), path._local, ErrorCategory::GenericError);
         }
         item->_instruction = CSYNC_INSTRUCTION_REMOVE;
         item->_direction = SyncFileItem::Down;
@@ -1813,7 +1814,7 @@ int ProcessDirectoryJob::processSubJobs(int nbJobs)
 
 void ProcessDirectoryJob::dbError()
 {
-    emit _discoveryData->fatalError(tr("Error while reading the database"));
+    emit _discoveryData->fatalError(tr("Error while reading the database"), ErrorCategory::GenericError);
 }
 
 void ProcessDirectoryJob::addVirtualFileSuffix(QString &str) const
@@ -1880,7 +1881,7 @@ DiscoverySingleDirectoryJob *ProcessDirectoryJob::startAsyncServerQuery()
             } else {
                 // Fatal for the root job since it has no SyncFileItem, or for the network errors
                 emit _discoveryData->fatalError(tr("Server replied with an error while reading directory \"%1\" : %2")
-                    .arg(_currentFolder._server, results.error().message));
+                    .arg(_currentFolder._server, results.error().message), ErrorCategory::NetworkError);
             }
         }
     });
@@ -1910,7 +1911,7 @@ void ProcessDirectoryJob::startAsyncLocalQuery()
         if (_serverJob)
             _serverJob->abort();
 
-        emit _discoveryData->fatalError(msg);
+        emit _discoveryData->fatalError(msg, ErrorCategory::NetworkError);
     });
 
     connect(localJob, &DiscoverySingleLocalDirectoryJob::finishedNonFatalError, this, [this](const QString &msg) {
@@ -1923,7 +1924,7 @@ void ProcessDirectoryJob::startAsyncLocalQuery()
             emit this->finished();
         } else {
             // Fatal for the root job since it has no SyncFileItem
-            emit _discoveryData->fatalError(msg);
+            emit _discoveryData->fatalError(msg, ErrorCategory::GenericError);
         }
     });
 
index bc83426e0ba76de264565726dced400d25d253a9..6a60fd1c6785cfbf3539009355dc296859fc69ec 100644 (file)
@@ -15,6 +15,7 @@
 #include "discoveryphase.h"
 #include "discovery.h"
 #include "helpers.h"
+#include "progressdispatcher.h"
 
 #include "account.h"
 #include "clientsideencryptionjobs.h"
@@ -187,8 +188,8 @@ QPair<bool, QByteArray> DiscoveryPhase::findAndCancelDeletedJob(const QString &o
                 qCWarning(lcDiscovery) << "(*it)->_type" << (*it)->_type;
                 qCWarning(lcDiscovery) << "(*it)->_isRestoration " << (*it)->_isRestoration;
                 Q_ASSERT(false);
-                emit addErrorToGui(SyncFileItem::Status::FatalError, tr("Error while canceling deletion of a file"), originalPath);
-                emit fatalError(tr("Error while canceling deletion of %1").arg(originalPath));
+                emit addErrorToGui(SyncFileItem::Status::FatalError, tr("Error while canceling deletion of a file"), originalPath, ErrorCategory::GenericError);
+                emit fatalError(tr("Error while canceling deletion of %1").arg(originalPath), ErrorCategory::GenericError);
             }
             (*it)->_instruction = CSYNC_INSTRUCTION_NONE;
             result = true;
index c833fd719c67656cfb1d84836824d1f8944a2bd3..c0da6be82b7b7d383f66da5ae42926b7512c9cae 100644 (file)
@@ -51,6 +51,8 @@ class Account;
 class SyncJournalDb;
 class ProcessDirectoryJob;
 
+enum class ErrorCategory;
+
 /**
  * Represent all the meta-data about a file in the server
  */
@@ -307,7 +309,7 @@ public:
     QStringList _listExclusiveFiles;
 
 signals:
-    void fatalError(const QString &errorString);
+    void fatalError(const QString &errorString, const OCC::ErrorCategory errorCategory);
     void itemDiscovered(const OCC::SyncFileItemPtr &item);
     void finished();
 
@@ -320,7 +322,7 @@ signals:
       */
     void silentlyExcluded(const QString &folderPath);
 
-    void addErrorToGui(SyncFileItem::Status status, const QString &errorMessage, const QString &subject);
+    void addErrorToGui(const SyncFileItem::Status status, const QString &errorMessage, const QString &subject, const OCC::ErrorCategory category);
 };
 
 /// Implementation of DiscoveryPhase::adjustRenamedPath
index 19d5e61913c10df238043b82dc52dfd385911d75..31efa1af2e3c505277af3562cf835b8454f2adc0 100644 (file)
@@ -221,7 +221,7 @@ void blacklistUpdate(SyncJournalDb *journal, SyncFileItem &item)
     }
 }
 
-void PropagateItemJob::done(SyncFileItem::Status statusArg, const QString &errorString)
+void PropagateItemJob::done(const SyncFileItem::Status statusArg, const QString &errorString, const ErrorCategory category)
 {
     // Duplicate calls to done() are a logic error
     ENFORCE(_state != Finished);
@@ -283,7 +283,7 @@ void PropagateItemJob::done(SyncFileItem::Status statusArg, const QString &error
         qCWarning(lcPropagator) << "Could not complete propagation of" << _item->destination() << "by" << this << "with status" << _item->_status << "and error:" << _item->_errorString;
     else
         qCInfo(lcPropagator) << "Completed propagation of" << _item->destination() << "by" << this << "with status" << _item->_status;
-    emit propagator()->itemCompleted(_item);
+    emit propagator()->itemCompleted(_item, category);
     emit finished(_item->_status);
 
     if (_item->_status == SyncFileItem::FatalError) {
@@ -302,9 +302,9 @@ void PropagateItemJob::slotRestoreJobFinished(SyncFileItem::Status status)
 
     if (status == SyncFileItem::Success || status == SyncFileItem::Conflict
         || status == SyncFileItem::Restoration) {
-        done(SyncFileItem::SoftError, msg);
+        done(SyncFileItem::SoftError, msg, ErrorCategory::GenericError);
     } else {
-        done(status, tr("A file or folder was removed from a read only share, but restoring failed: %1").arg(msg));
+        done(status, tr("A file or folder was removed from a read only share, but restoring failed: %1").arg(msg), ErrorCategory::GenericError);
     }
 }
 
@@ -661,7 +661,7 @@ void OwncloudPropagator::startDirectoryPropagation(const SyncFileItemPtr &item,
             item->_instruction = CSyncEnums::CSYNC_INSTRUCTION_ERROR;
             item->_errorString = tr("Error with the metadata. Getting unexpected metadata format.");
             item->_status = SyncFileItem::NormalError;
-            emit itemCompleted(item);
+            emit itemCompleted(item, OCC::ErrorCategory::GenericError);
         } else {
             directoryPropagationJob->appendJob(new UpdateFileDropMetadataJob(this, item->_file));
             item->_instruction = CSYNC_INSTRUCTION_NONE;
@@ -1087,6 +1087,56 @@ OwncloudPropagator *PropagatorJob::propagator() const
     return qobject_cast<OwncloudPropagator *>(parent());
 }
 
+ErrorCategory PropagatorJob::errorCategoryFromNetworkError(const QNetworkReply::NetworkError error)
+{
+    auto result = ErrorCategory::NoError;
+    switch (error)
+    {
+    case QNetworkReply::NoError:
+        result = ErrorCategory::NoError;
+        break;
+    case QNetworkReply::TemporaryNetworkFailureError:
+    case QNetworkReply::RemoteHostClosedError:
+        result = ErrorCategory::NetworkError;
+        break;
+    case QNetworkReply::ConnectionRefusedError:
+    case QNetworkReply::HostNotFoundError:
+    case QNetworkReply::TimeoutError:
+    case QNetworkReply::OperationCanceledError:
+    case QNetworkReply::SslHandshakeFailedError:
+    case QNetworkReply::NetworkSessionFailedError:
+    case QNetworkReply::BackgroundRequestNotAllowedError:
+    case QNetworkReply::TooManyRedirectsError:
+    case QNetworkReply::InsecureRedirectError:
+    case QNetworkReply::UnknownNetworkError:
+    case QNetworkReply::ProxyConnectionRefusedError:
+    case QNetworkReply::ProxyConnectionClosedError:
+    case QNetworkReply::ProxyNotFoundError:
+    case QNetworkReply::ProxyTimeoutError:
+    case QNetworkReply::ProxyAuthenticationRequiredError:
+    case QNetworkReply::UnknownProxyError:
+    case QNetworkReply::ContentAccessDenied:
+    case QNetworkReply::ContentOperationNotPermittedError:
+    case QNetworkReply::ContentNotFoundError:
+    case QNetworkReply::AuthenticationRequiredError:
+    case QNetworkReply::ContentReSendError:
+    case QNetworkReply::ContentConflictError:
+    case QNetworkReply::ContentGoneError:
+    case QNetworkReply::UnknownContentError:
+    case QNetworkReply::ProtocolUnknownError:
+    case QNetworkReply::ProtocolInvalidOperationError:
+    case QNetworkReply::ProtocolFailure:
+    case QNetworkReply::InternalServerError:
+    case QNetworkReply::OperationNotImplementedError:
+    case QNetworkReply::ServiceUnavailableError:
+    case QNetworkReply::UnknownServerError:
+        result = ErrorCategory::GenericError;
+        break;
+    }
+
+    return result;
+}
+
 // ================================================================================
 
 PropagatorJob::JobParallelism PropagatorCompositeJob::parallelism() const
@@ -1521,7 +1571,7 @@ void CleanupPollsJob::slotPollFinished()
     auto *job = qobject_cast<PollJob *>(sender());
     ASSERT(job);
     if (job->_item->_status == SyncFileItem::FatalError) {
-        emit aborted(job->_item->_errorString);
+        emit aborted(job->_item->_errorString, ErrorCategory::GenericError);
         deleteLater();
         return;
     } else if (job->_item->_status != SyncFileItem::Success) {
@@ -1531,7 +1581,7 @@ void CleanupPollsJob::slotPollFinished()
             qCWarning(lcCleanupPolls) << "database error";
             job->_item->_status = SyncFileItem::FatalError;
             job->_item->_errorString = tr("Error writing metadata to the database");
-            emit aborted(job->_item->_errorString);
+            emit aborted(job->_item->_errorString, ErrorCategory::GenericError);
             deleteLater();
             return;
         }
@@ -1554,7 +1604,7 @@ QString OwncloudPropagator::remotePath() const
 
 void PropagateIgnoreJob::start()
 {
-    SyncFileItem::Status status = _item->_status;
+    auto status = _item->_status;
     if (status == SyncFileItem::NoStatus) {
         if (_item->_instruction == CSYNC_INSTRUCTION_ERROR) {
             status = SyncFileItem::NormalError;
@@ -1568,7 +1618,7 @@ void PropagateIgnoreJob::start()
             _item->_file = conflictRecord.initialBasePath;
         }
     }
-    done(status, _item->_errorString);
+    done(status, _item->_errorString, ErrorCategory::NoError);
 }
 
 }
index dd0525d225cbc253d335e8e725dece293ad04f6d..c422542419a4d38aac7b16671d47770360b1c4b9 100644 (file)
@@ -23,6 +23,7 @@
 #include <QPointer>
 #include <QIODevice>
 #include <QMutex>
+#include <QNetworkReply>
 
 #include "csync.h"
 #include "syncfileitem.h"
@@ -30,6 +31,7 @@
 #include "bandwidthmanager.h"
 #include "accountfwd.h"
 #include "syncoptions.h"
+#include "progressdispatcher.h"
 
 #include <deque>
 
@@ -147,6 +149,8 @@ signals:
 protected:
     [[nodiscard]] OwncloudPropagator *propagator() const;
 
+    static ErrorCategory errorCategoryFromNetworkError(const QNetworkReply::NetworkError error);
+
     /** If this job gets added to a composite job, this will point to the parent.
      *
      * For the PropagateDirectory::_firstJob it will point to
@@ -165,7 +169,7 @@ class PropagateItemJob : public PropagatorJob
 {
     Q_OBJECT
 protected:
-    virtual void done(SyncFileItem::Status status, const QString &errorString = QString());
+    virtual void done(const SyncFileItem::Status status, const QString &errorString, const ErrorCategory category);
 
     /*
      * set a custom restore job message that is used if the restore job succeeded.
@@ -640,7 +644,7 @@ private slots:
 
 signals:
     void newItem(const OCC::SyncFileItemPtr &);
-    void itemCompleted(const OCC::SyncFileItemPtr &);
+    void itemCompleted(const SyncFileItemPtr &item, OCC::ErrorCategory category);
     void progress(const OCC::SyncFileItem &, qint64 bytes);
     void finished(bool success);
 
@@ -721,7 +725,7 @@ public:
     void start();
 signals:
     void finished();
-    void aborted(const QString &error);
+    void aborted(const QString &error, const ErrorCategory errorCategory);
 private slots:
     void slotPollFinished();
 };
index 4724fb7e4f63cb324ddb60598331fd1342ff137b..5447810ee08b7737d32458f877f140caa408c4bd 100644 (file)
@@ -251,7 +251,9 @@ namespace Progress {
  * in IssuesWidget.
  */
 enum class ErrorCategory {
-    Normal,
+    NoError,
+    GenericError,
+    NetworkError,
     InsufficientRemoteStorage,
 };
 Q_ENUM_NS(OCC::ErrorCategory)
@@ -286,7 +288,7 @@ signals:
     /**
      * @brief: the item was completed by a job
      */
-    void itemCompleted(const QString &folder, const OCC::SyncFileItemPtr &item);
+    void itemCompleted(const QString &folder, const OCC::SyncFileItemPtr &item, const OCC::ErrorCategory category);
 
     /**
      * @brief A new folder-wide sync error was seen.
@@ -300,7 +302,7 @@ signals:
      * @param[out] full error message
      * @param[out] subject (optional)
      */
-    void addErrorToGui(const QString &folder, OCC::SyncFileItem::Status status, const QString &errorMessage, const QString &subject);
+    void addErrorToGui(const QString &folder, const OCC::SyncFileItem::Status status, const QString &errorMessage, const QString &subject, const OCC::ErrorCategory category);
 
     /**
      * @brief Emitted for a folder when a sync is done, listing all pending conflicts
index 970c8e246df3a1028cae5f24e1772e09295d73c3..b82f80a7c0926c6646f6d908d8369c104bf0fb8f 100644 (file)
@@ -461,7 +461,7 @@ void PropagateDownloadFile::start()
     SyncJournalFileRecord parentRec;
     if (!propagator()->_journal->getFileRecord(parentPath, &parentRec)) {
         qCWarning(lcPropagateDownload) << "could not get file from local DB" << parentPath;
-        done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(parentPath));
+        done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(parentPath), ErrorCategory::GenericError);
         return;
     }
 
@@ -478,7 +478,7 @@ void PropagateDownloadFile::start()
         });
         connect(_downloadEncryptedHelper, &PropagateDownloadEncrypted::failed, [this] {
           done(SyncFileItem::NormalError,
-               tr("File %1 cannot be downloaded because encryption information is missing.").arg(QDir::toNativeSeparators(_item->_file)));
+               tr("File %1 cannot be downloaded because encryption information is missing.").arg(QDir::toNativeSeparators(_item->_file)), ErrorCategory::GenericError);
         });
         _downloadEncryptedHelper->start();
     }
@@ -496,20 +496,20 @@ void PropagateDownloadFile::startAfterIsEncryptedIsChecked()
         QString fsPath = propagator()->fullLocalPath(_item->_file);
         if (!FileSystem::verifyFileUnchanged(fsPath, _item->_previousSize, _item->_previousModtime)) {
             propagator()->_anotherSyncNeeded = true;
-            done(SyncFileItem::SoftError, tr("File has changed since discovery"));
+            done(SyncFileItem::SoftError, tr("File has changed since discovery"), ErrorCategory::GenericError);
             return;
         }
 
         qCDebug(lcPropagateDownload) << "dehydrating file" << _item->_file;
         auto r = vfs->dehydratePlaceholder(*_item);
         if (!r) {
-            done(SyncFileItem::NormalError, r.error());
+            done(SyncFileItem::NormalError, r.error(), ErrorCategory::GenericError);
             return;
         }
 
         if (!propagator()->_journal->deleteFileRecord(_item->_originalFile)) {
             qCWarning(lcPropagateDownload) << "could not delete file from local DB" << _item->_originalFile;
-            done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile));
+            done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile), ErrorCategory::GenericError);
             return;
         }
 
@@ -530,12 +530,12 @@ void PropagateDownloadFile::startAfterIsEncryptedIsChecked()
         qCDebug(lcPropagateDownload) << "creating virtual file" << _item->_file;
         // do a klaas' case clash check.
         if (propagator()->localFileNameClash(_item->_file)) {
-            done(SyncFileItem::FileNameClash, tr("File %1 can not be downloaded because of a local file name clash!").arg(QDir::toNativeSeparators(_item->_file)));
+            done(SyncFileItem::FileNameClash, tr("File %1 can not be downloaded because of a local file name clash!").arg(QDir::toNativeSeparators(_item->_file)), ErrorCategory::GenericError);
             return;
         }
         auto r = vfs->createPlaceholder(*_item);
         if (!r) {
-            done(SyncFileItem::NormalError, r.error());
+            done(SyncFileItem::NormalError, r.error(), ErrorCategory::GenericError);
             return;
         }
         updateMetadata(false);
@@ -675,7 +675,7 @@ void PropagateDownloadFile::startDownload()
         FileSystem::setFileReadOnly(_tmpFile.fileName(), false);
     if (!_tmpFile.open(QIODevice::Append | QIODevice::Unbuffered)) {
         qCWarning(lcPropagateDownload) << "could not open temporary file" << _tmpFile.fileName();
-        done(SyncFileItem::NormalError, _tmpFile.errorString());
+        done(SyncFileItem::NormalError, _tmpFile.errorString(), ErrorCategory::GenericError);
         return;
     }
     // Hide temporary after creation
@@ -689,11 +689,11 @@ void PropagateDownloadFile::startDownload()
             // tab: instead we'll generate a general "disk space low" message and show
             // these detail errors only in the error view.
             done(SyncFileItem::DetailError,
-                tr("The download would reduce free local disk space below the limit"));
+                tr("The download would reduce free local disk space below the limit"), ErrorCategory::GenericError);
             emit propagator()->insufficientLocalStorage();
         } else if (diskSpaceResult == OwncloudPropagator::DiskSpaceCritical) {
             done(SyncFileItem::FatalError,
-                tr("Free space on disk is less than %1").arg(Utility::octetsToString(criticalFreeSpaceLimit())));
+                tr("Free space on disk is less than %1").arg(Utility::octetsToString(criticalFreeSpaceLimit())), ErrorCategory::GenericError);
         }
 
         // Remove the temporary, if empty.
@@ -832,7 +832,7 @@ void PropagateDownloadFile::slotGetFinished()
                 &propagator()->_anotherSyncNeeded, errorBody);
         }
 
-        done(status, errorString);
+        done(status, errorString, errorCategoryFromNetworkError(err));
         return;
     }
 
@@ -880,14 +880,14 @@ void PropagateDownloadFile::slotGetFinished()
         // This happened when trying to resume a file. The Content-Range header was files, Content-Length was == 0
         qCDebug(lcPropagateDownload) << bodySize << _item->_size << _tmpFile.size() << job->resumeStart();
         FileSystem::remove(_tmpFile.fileName());
-        done(SyncFileItem::SoftError, QLatin1String("Broken webserver returning empty content length for non-empty file on resume"));
+        done(SyncFileItem::SoftError, QLatin1String("Broken webserver returning empty content length for non-empty file on resume"), ErrorCategory::GenericError);
         return;
     }
 
     if (bodySize > 0 && bodySize != _tmpFile.size() - job->resumeStart()) {
         qCDebug(lcPropagateDownload) << bodySize << _tmpFile.size() << job->resumeStart();
         propagator()->_anotherSyncNeeded = true;
-        done(SyncFileItem::SoftError, tr("The file could not be downloaded completely."));
+        done(SyncFileItem::SoftError, tr("The file could not be downloaded completely."), ErrorCategory::GenericError);
         return;
     }
 
@@ -895,7 +895,7 @@ void PropagateDownloadFile::slotGetFinished()
         FileSystem::remove(_tmpFile.fileName());
         done(SyncFileItem::NormalError,
             tr("The downloaded file is empty, but the server said it should have been %1.")
-                .arg(Utility::octetsToString(_item->_size)));
+                .arg(Utility::octetsToString(_item->_size)), ErrorCategory::GenericError);
         return;
     }
 
@@ -984,7 +984,7 @@ void PropagateDownloadFile::checksumValidateFailedAbortDownload(const QString &e
 {
     FileSystem::remove(_tmpFile.fileName());
     propagator()->_anotherSyncNeeded = true;
-    done(SyncFileItem::SoftError, errMsg); // tr("The file downloaded with a broken checksum, will be redownloaded."));
+    done(SyncFileItem::SoftError, errMsg, ErrorCategory::GenericError); // tr("The file downloaded with a broken checksum, will be redownloaded."));
 }
 
 void PropagateDownloadFile::deleteExistingFolder()
@@ -1005,7 +1005,7 @@ void PropagateDownloadFile::deleteExistingFolder()
 
     QString error;
     if (!propagator()->createConflict(_item, _associatedComposite, &error)) {
-        done(SyncFileItem::NormalError, error);
+        done(SyncFileItem::NormalError, error, ErrorCategory::GenericError);
     }
 }
 
@@ -1141,7 +1141,7 @@ void PropagateDownloadFile::finalizeDownload()
         if (_downloadEncryptedHelper->decryptFile(_tmpFile)) {
             downloadFinished();
         } else {
-            done(SyncFileItem::NormalError, _downloadEncryptedHelper->errorString());
+            done(SyncFileItem::NormalError, _downloadEncryptedHelper->errorString(), ErrorCategory::GenericError);
         }
     } else {
         downloadFinished();
@@ -1155,7 +1155,7 @@ void PropagateDownloadFile::downloadFinished()
 
     if (_item->_modtime <= 0) {
         FileSystem::remove(_tmpFile.fileName());
-        done(SyncFileItem::NormalError, tr("File %1 has invalid modified time reported by server. Do not save it.").arg(QDir::toNativeSeparators(_item->_file)));
+        done(SyncFileItem::NormalError, tr("File %1 has invalid modified time reported by server. Do not save it.").arg(QDir::toNativeSeparators(_item->_file)), ErrorCategory::GenericError);
         return;
     }
     Q_ASSERT(_item->_modtime > 0);
@@ -1168,7 +1168,7 @@ void PropagateDownloadFile::downloadFinished()
     _item->_modtime = FileSystem::getModTime(_tmpFile.fileName());
     if (_item->_modtime <= 0) {
         FileSystem::remove(_tmpFile.fileName());
-        done(SyncFileItem::NormalError, tr("File %1 has invalid modified time reported by server. Do not save it.").arg(QDir::toNativeSeparators(_item->_file)));
+        done(SyncFileItem::NormalError, tr("File %1 has invalid modified time reported by server. Do not save it.").arg(QDir::toNativeSeparators(_item->_file)), ErrorCategory::GenericError);
         return;
     }
     Q_ASSERT(_item->_modtime > 0);
@@ -1193,7 +1193,7 @@ void PropagateDownloadFile::downloadFinished()
         // Make the file a hydrated placeholder if possible
         const auto result = propagator()->syncOptions()._vfs->convertToPlaceholder(_tmpFile.fileName(), *_item, filename);
         if (!result) {
-            done(SyncFileItem::NormalError, result.error());
+            done(SyncFileItem::NormalError, result.error(), ErrorCategory::GenericError);
             return;
         }
     }
@@ -1210,15 +1210,15 @@ void PropagateDownloadFile::downloadFinished()
             qCInfo(lcPropagateDownload) << "downloading case clashed file" << _item->_file;
             const auto caseClashConflictResult = propagator()->createCaseClashConflict(_item, _tmpFile.fileName());
             if (caseClashConflictResult) {
-                done(SyncFileItem::SoftError, *caseClashConflictResult);
+                done(SyncFileItem::SoftError, *caseClashConflictResult, ErrorCategory::GenericError);
             } else {
-                done(SyncFileItem::FileNameClash, tr("File %1 downloaded but it resulted in a local file name clash!").arg(QDir::toNativeSeparators(_item->_file)));
+                done(SyncFileItem::FileNameClash, tr("File %1 downloaded but it resulted in a local file name clash!").arg(QDir::toNativeSeparators(_item->_file)), ErrorCategory::GenericError);
             }
             return;
         } else {
             QString error;
             if (!propagator()->createConflict(_item, _associatedComposite, &error)) {
-                done(SyncFileItem::SoftError, error);
+                done(SyncFileItem::SoftError, error, ErrorCategory::GenericError);
             } else {
                 previousFileExists = false;
             }
@@ -1240,7 +1240,7 @@ void PropagateDownloadFile::downloadFinished()
         const time_t expectedMtime = _item->_previousModtime;
         if (!FileSystem::verifyFileUnchanged(filename, expectedSize, expectedMtime)) {
             propagator()->_anotherSyncNeeded = true;
-            done(SyncFileItem::SoftError, tr("File has changed since discovery"));
+            done(SyncFileItem::SoftError, tr("File has changed since discovery"), ErrorCategory::GenericError);
             return;
         }
     }
@@ -1258,7 +1258,7 @@ void PropagateDownloadFile::downloadFinished()
             propagator()->_anotherSyncNeeded = true;
         }
 
-        done(SyncFileItem::SoftError, error);
+        done(SyncFileItem::SoftError, error, ErrorCategory::GenericError);
         return;
     }
 
@@ -1290,7 +1290,7 @@ void PropagateDownloadFile::downloadFinished()
 
             if (!propagator()->_journal->deleteFileRecord(virtualFile)) {
                 qCWarning(lcPropagateDownload) << "could not delete file from local DB" << virtualFile;
-                done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(virtualFile));
+                done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(virtualFile), ErrorCategory::GenericError);
                 return;
             }
 
@@ -1322,10 +1322,10 @@ void PropagateDownloadFile::updateMetadata(bool isConflict)
     const QString fn = propagator()->fullLocalPath(_item->_file);
     const auto result = propagator()->updateMetadata(*_item);
     if (!result) {
-        done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()));
+        done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()), ErrorCategory::GenericError);
         return;
     } else if (*result == Vfs::ConvertToPlaceholderResult::Locked) {
-        done(SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(_item->_file));
+        done(SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(_item->_file), ErrorCategory::GenericError);
         return;
     }
 
@@ -1337,7 +1337,7 @@ void PropagateDownloadFile::updateMetadata(bool isConflict)
 
     propagator()->_journal->commit("download file start2");
 
-    done(isConflict ? SyncFileItem::Conflict : SyncFileItem::Success);
+    done(isConflict ? SyncFileItem::Conflict : SyncFileItem::Success, {}, ErrorCategory::NoError);
 
     // handle the special recall file
     if (!_item->_remotePerm.hasPermission(RemotePermissions::IsShared)
index 84aab6fe40af679be85ce07fba3ca3a35c71f44e..ede4f07b40943de15bdd22ad03cac7ae3752e17d 100644 (file)
@@ -45,9 +45,9 @@ void PropagateRemoteDelete::start()
                 if (_deleteEncryptedHelper->networkError() != QNetworkReply::NoError && _deleteEncryptedHelper->networkError() != QNetworkReply::ContentNotFoundError) {
                     status = classifyError(_deleteEncryptedHelper->networkError(), _item->_httpErrorCode, &propagator()->_anotherSyncNeeded);
                 }
-                done(status, _deleteEncryptedHelper->errorString());
+                done(status, _deleteEncryptedHelper->errorString(), ErrorCategory::GenericError);
             } else {
-                done(SyncFileItem::Success);
+                done(SyncFileItem::Success, {}, ErrorCategory::NoError);
             }
         });
         _deleteEncryptedHelper->start();
@@ -94,7 +94,8 @@ void PropagateRemoteDelete::slotDeleteJobFinished()
     if (err != QNetworkReply::NoError && err != QNetworkReply::ContentNotFoundError) {
         SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
             &propagator()->_anotherSyncNeeded);
-        done(status, _job->errorString());
+
+        done(status, _job->errorString(), errorCategoryFromNetworkError(err));
         return;
     }
 
@@ -109,18 +110,18 @@ void PropagateRemoteDelete::slotDeleteJobFinished()
         done(SyncFileItem::NormalError,
             tr("Wrong HTTP code returned by server. Expected 204, but received \"%1 %2\".")
                 .arg(_item->_httpErrorCode)
-                .arg(_job->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()));
+                .arg(_job->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()), ErrorCategory::GenericError);
         return;
     }
 
     if (!propagator()->_journal->deleteFileRecord(_item->_originalFile, _item->isDirectory())) {
         qCWarning(lcPropagateRemoteDelete) << "could not delete file from local DB" << _item->_originalFile;
-        done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile));
+        done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile), ErrorCategory::GenericError);
         return;
     }
 
     propagator()->_journal->commit("Remote Remove");
 
-    done(SyncFileItem::Success);
+    done(SyncFileItem::Success, {}, ErrorCategory::NoError);
 }
 }
index 62bd3b344c4242b733aa2762841b482b0c2e0dc5..805b7dc8e8de688cad80c7228e2ea940cdf95151 100644 (file)
@@ -123,7 +123,7 @@ void PropagateRemoteMkdir::finalizeMkColJob(QNetworkReply::NetworkError err, con
     } else if (err != QNetworkReply::NoError) {
         SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
             &propagator()->_anotherSyncNeeded);
-        done(status, _item->_errorString);
+        done(status, _item->_errorString, errorCategoryFromNetworkError(err));
         return;
     } else if (_item->_httpErrorCode != 201) {
         // Normally we expect "201 Created"
@@ -132,7 +132,7 @@ void PropagateRemoteMkdir::finalizeMkColJob(QNetworkReply::NetworkError err, con
         done(SyncFileItem::NormalError,
             tr("Wrong HTTP code returned by server. Expected 201, but received \"%1 %2\".")
                 .arg(_item->_httpErrorCode)
-                .arg(jobHttpReasonPhraseString));
+                .arg(jobHttpReasonPhraseString), ErrorCategory::GenericError);
         return;
     }
 
@@ -161,10 +161,10 @@ void PropagateRemoteMkdir::finalizeMkColJob(QNetworkReply::NetworkError err, con
             job->start();
         }
     });
-    connect(propfindJob, &PropfindJob::finishedWithError, this, [this]{
-        // ignore the PROPFIND error
+    connect(propfindJob, &PropfindJob::finishedWithError, this, [this] (QNetworkReply *reply) {
+        const auto err = reply ? reply->error() : QNetworkReply::NetworkError::UnknownNetworkError;
         propagator()->_activeJobList.removeOne(this);
-        done(SyncFileItem::NormalError);
+        done(SyncFileItem::NormalError, {}, errorCategoryFromNetworkError(err));
     });
     propfindJob->start();
 }
@@ -176,7 +176,7 @@ void PropagateRemoteMkdir::slotMkdir()
         const auto targetFile = propagator()->fullLocalPath(_item->_renameTarget);
         QString renameError;
         if (!FileSystem::rename(existingFile, targetFile, &renameError)) {
-            done(SyncFileItem::NormalError, renameError);
+            done(SyncFileItem::NormalError, renameError, ErrorCategory::GenericError);
             return;
         }
         emit propagator()->touchedFile(existingFile);
@@ -190,7 +190,7 @@ void PropagateRemoteMkdir::slotMkdir()
     SyncJournalFileRecord parentRec;
     bool ok = propagator()->_journal->getFileRecord(parentPath, &parentRec);
     if (!ok) {
-        done(SyncFileItem::NormalError);
+        done(SyncFileItem::NormalError, {}, ErrorCategory::GenericError);
         return;
     }
 
@@ -257,13 +257,13 @@ void PropagateRemoteMkdir::success()
     // save the file id already so we can detect rename or remove
     const auto result = propagator()->updateMetadata(itemCopy);
     if (!result) {
-        done(SyncFileItem::FatalError, tr("Error writing metadata to the database: %1").arg(result.error()));
+        done(SyncFileItem::FatalError, tr("Error writing metadata to the database: %1").arg(result.error()), ErrorCategory::GenericError);
         return;
     } else if (*result == Vfs::ConvertToPlaceholderResult::Locked) {
-        done(SyncFileItem::FatalError, tr("The file %1 is currently in use").arg(_item->_file));
+        done(SyncFileItem::FatalError, tr("The file %1 is currently in use").arg(_item->_file), ErrorCategory::GenericError);
         return;
     }
 
-    done(SyncFileItem::Success);
+    done(SyncFileItem::Success, {}, ErrorCategory::NoError);
 }
 }
index 64ad05641e7c10be4ce9a8f594f9b7293c54b7c2..09cb179d385a943ea154c818aada329c180adbc7 100644 (file)
@@ -98,7 +98,7 @@ void PropagateRemoteMove::start()
             SyncJournalFileRecord parentRec;
             bool ok = propagator()->_journal->getFileRecord(parentPath, &parentRec);
             if (!ok) {
-                done(SyncFileItem::NormalError);
+                done(SyncFileItem::NormalError, {}, ErrorCategory::GenericError);
                 return;
             }
 
@@ -167,7 +167,7 @@ void PropagateRemoteMove::start()
             QString error;
             if (!FileSystem::uncheckedRenameReplace(localTargetAlt, localTarget, &error)) {
                 done(SyncFileItem::NormalError, tr("Could not rename %1 to %2, error: %3")
-                     .arg(folderTargetAlt, folderTarget, error));
+                     .arg(folderTargetAlt, folderTarget, error), ErrorCategory::GenericError);
                 return;
             }
             qCInfo(lcPropagateRemoteMove) << "Suffix vfs required local rename of"
@@ -217,7 +217,7 @@ void PropagateRemoteMove::slotMoveJobFinished()
                 << "Could not MOVE file" << filePathOriginal << " to" << filePath
                 << " with error:" << _job->errorString() << " and successfully restored it.";
         }
-        done(status, _job->errorString());
+        done(status, _job->errorString(), ErrorCategory::GenericError);
         return;
     }
 
@@ -228,7 +228,7 @@ void PropagateRemoteMove::slotMoveJobFinished()
         done(SyncFileItem::NormalError,
             tr("Wrong HTTP code returned by server. Expected 201, but received \"%1 %2\".")
                 .arg(_item->_httpErrorCode)
-                .arg(_job->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()));
+                .arg(_job->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()), ErrorCategory::GenericError);
         return;
     }
 
@@ -245,7 +245,7 @@ void PropagateRemoteMove::finalize()
     SyncJournalFileRecord oldRecord;
     if (!propagator()->_journal->getFileRecord(_item->_originalFile, &oldRecord)) {
         qCWarning(lcPropagateRemoteMove) << "could not get file from local DB" << _item->_originalFile;
-        done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(_item->_originalFile));
+        done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(_item->_originalFile), ErrorCategory::GenericError);
         return;
     }
     auto &vfs = propagator()->syncOptions()._vfs;
@@ -257,7 +257,7 @@ void PropagateRemoteMove::finalize()
         // Delete old db data.
         if (!propagator()->_journal->deleteFileRecord(_item->_originalFile)) {
             qCWarning(lcPropagateRemoteMove) << "could not delete file from local DB" << _item->_originalFile;
-            done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile));
+            done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile), ErrorCategory::GenericError);
             return;
         }
         if (!vfs->setPinState(_item->_originalFile, PinState::Inherited)) {
@@ -279,34 +279,34 @@ void PropagateRemoteMove::finalize()
 
     if (!QFileInfo::exists(targetFile)) {
         propagator()->_journal->commit("Remote Rename");
-        done(SyncFileItem::Success);
+        done(SyncFileItem::Success, {}, ErrorCategory::NoError);
         return;
     }
 
     const auto result = propagator()->updateMetadata(newItem);
     if (!result) {
-        done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()));
+        done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()), ErrorCategory::GenericError);
         return;
     } else if (*result == Vfs::ConvertToPlaceholderResult::Locked) {
-        done(SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(newItem._file));
+        done(SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(newItem._file), ErrorCategory::GenericError);
         return;
     }
     if (pinState && *pinState != PinState::Inherited
         && !vfs->setPinState(newItem._renameTarget, *pinState)) {
-        done(SyncFileItem::NormalError, tr("Error setting pin state"));
+        done(SyncFileItem::NormalError, tr("Error setting pin state"), ErrorCategory::GenericError);
         return;
     }
 
     if (_item->isDirectory()) {
         propagator()->_renamedDirectories.insert(_item->_file, _item->_renameTarget);
         if (!adjustSelectiveSync(propagator()->_journal, _item->_file, _item->_renameTarget)) {
-            done(SyncFileItem::FatalError, tr("Error writing metadata to the database"));
+            done(SyncFileItem::FatalError, tr("Error writing metadata to the database"), ErrorCategory::GenericError);
             return;
         }
     }
 
     propagator()->_journal->commit("Remote Rename");
-    done(SyncFileItem::Success);
+    done(SyncFileItem::Success, {}, ErrorCategory::NoError);
 }
 
 bool PropagateRemoteMove::adjustSelectiveSync(SyncJournalDb *journal, const QString &from_, const QString &to_)
index 6f70ce5db6239b4a91d22f62a4cc346d58fe742f..76e164b6e30f7b94b92dda9c777ad5e1c76927fc 100644 (file)
@@ -629,10 +629,10 @@ void PropagateUploadFileCommon::slotPollFinished()
     finalize();
 }
 
-void PropagateUploadFileCommon::done(SyncFileItem::Status status, const QString &errorString)
+void PropagateUploadFileCommon::done(SyncFileItem::Status status, const QString &errorString, const ErrorCategory category)
 {
     _finished = true;
-    PropagateItemJob::done(status, errorString);
+    PropagateItemJob::done(status, errorString, category);
 }
 
 void PropagateUploadFileCommon::checkResettingErrors()
index 2340108e475249c91f292a83b4f9fa2ec08688e6..535255b38d2566c9df47edcf8719e643fc75f7eb 100644 (file)
@@ -281,7 +281,7 @@ private slots:
     void slotPollFinished();
 
 protected:
-    void done(SyncFileItem::Status status, const QString &errorString = QString()) override;
+    void done(SyncFileItem::Status status, const QString &errorString = QString(), const ErrorCategory category = ErrorCategory::NoError) override;
 
     /**
      * Aborts all running network jobs, except for the ones that mayAbortJob
index 84005cdb9b4d0ec2f9e76137c0c9d17a7424119b..9749f5a1d0b790c92ead052d302a90c980c5f859 100644 (file)
@@ -102,7 +102,7 @@ void PropagateLocalRemove::start()
     qCInfo(lcPropagateLocalRemove) << "Going to delete:" << filename;
 
     if (propagator()->localFileNameClash(_item->_file)) {
-        done(SyncFileItem::FileNameClash, tr("Could not remove %1 because of a local file name clash").arg(QDir::toNativeSeparators(filename)));
+        done(SyncFileItem::FileNameClash, tr("Could not remove %1 because of a local file name clash").arg(QDir::toNativeSeparators(filename)), ErrorCategory::GenericError);
         return;
     }
 
@@ -110,19 +110,19 @@ void PropagateLocalRemove::start()
     if (_moveToTrash) {
         if ((QDir(filename).exists() || FileSystem::fileExists(filename))
             && !FileSystem::moveToTrash(filename, &removeError)) {
-            done(SyncFileItem::NormalError, removeError);
+            done(SyncFileItem::NormalError, removeError, ErrorCategory::GenericError);
             return;
         }
     } else {
         if (_item->isDirectory()) {
             if (QDir(filename).exists() && !removeRecursively(QString())) {
-                done(SyncFileItem::NormalError, _error);
+                done(SyncFileItem::NormalError, _error, ErrorCategory::GenericError);
                 return;
             }
         } else {
             if (FileSystem::fileExists(filename)
                 && !FileSystem::remove(filename, &removeError)) {
-                done(SyncFileItem::NormalError, removeError);
+                done(SyncFileItem::NormalError, removeError, ErrorCategory::GenericError);
                 return;
             }
         }
@@ -130,11 +130,11 @@ void PropagateLocalRemove::start()
     propagator()->reportProgress(*_item, 0);
     if (!propagator()->_journal->deleteFileRecord(_item->_originalFile, _item->isDirectory())) {
         qCWarning(lcPropagateLocalRename) << "could not delete file from local DB" << _item->_originalFile;
-        done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile));
+        done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile), ErrorCategory::GenericError);
         return;
     }
     propagator()->_journal->commit("Local remove");
-    done(SyncFileItem::Success);
+    done(SyncFileItem::Success, {}, ErrorCategory::NoError);
 }
 
 void PropagateLocalMkdir::start()
@@ -164,13 +164,13 @@ void PropagateLocalMkdir::startLocalMkdir()
             if (!FileSystem::remove(newDirStr, &removeError)) {
                 done(SyncFileItem::NormalError,
                     tr("could not delete file %1, error: %2")
-                        .arg(newDirStr, removeError));
+                        .arg(newDirStr, removeError), ErrorCategory::GenericError);
                 return;
             }
         } else if (_item->_instruction == CSYNC_INSTRUCTION_CONFLICT) {
             QString error;
             if (!propagator()->createConflict(_item, _associatedComposite, &error)) {
-                done(SyncFileItem::SoftError, error);
+                done(SyncFileItem::SoftError, error, ErrorCategory::GenericError);
                 return;
             }
         }
@@ -178,13 +178,13 @@ void PropagateLocalMkdir::startLocalMkdir()
 
     if (Utility::fsCasePreserving() && propagator()->localFileNameClash(_item->_file)) {
         qCWarning(lcPropagateLocalMkdir) << "New folder to create locally already exists with different case:" << _item->_file;
-        done(SyncFileItem::FileNameClash, tr("Folder %1 cannot be created because of a local file or folder name clash!").arg(newDirStr));
+        done(SyncFileItem::FileNameClash, tr("Folder %1 cannot be created because of a local file or folder name clash!").arg(newDirStr), ErrorCategory::GenericError);
         return;
     }
     emit propagator()->touchedFile(newDirStr);
     QDir localDir(propagator()->localPath());
     if (!localDir.mkpath(_item->_file)) {
-        done(SyncFileItem::NormalError, tr("Could not create folder %1").arg(newDirStr));
+        done(SyncFileItem::NormalError, tr("Could not create folder %1").arg(newDirStr), ErrorCategory::GenericError);
         return;
     }
 
@@ -197,10 +197,10 @@ void PropagateLocalMkdir::startLocalMkdir()
     newItem._etag = "_invalid_";
     const auto result = propagator()->updateMetadata(newItem);
     if (!result) {
-        done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()));
+        done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()), ErrorCategory::GenericError);
         return;
     } else if (*result == Vfs::ConvertToPlaceholderResult::Locked) {
-        done(SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(newItem._file));
+        done(SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(newItem._file), ErrorCategory::GenericError);
         return;
     }
     propagator()->_journal->commit("localMkdir");
@@ -208,7 +208,7 @@ void PropagateLocalMkdir::startLocalMkdir()
     auto resultStatus = _item->_instruction == CSYNC_INSTRUCTION_CONFLICT
         ? SyncFileItem::Conflict
         : SyncFileItem::Success;
-    done(resultStatus);
+    done(resultStatus, {}, ErrorCategory::NoError);
 }
 
 PropagateLocalRename::PropagateLocalRename(OwncloudPropagator *propagator, const SyncFileItemPtr &item)
@@ -249,9 +249,9 @@ void PropagateLocalRename::start()
             qCInfo(lcPropagateLocalRename) << "renaming a case clashed file" << _item->_file << _item->_renameTarget;
             const auto caseClashConflictResult = propagator()->createCaseClashConflict(_item, existingFile);
             if (caseClashConflictResult) {
-                done(SyncFileItem::SoftError, *caseClashConflictResult);
+                done(SyncFileItem::SoftError, *caseClashConflictResult, ErrorCategory::GenericError);
             } else {
-                done(SyncFileItem::FileNameClash, tr("File %1 downloaded but it resulted in a local file name clash!").arg(QDir::toNativeSeparators(_item->_file)));
+                done(SyncFileItem::FileNameClash, tr("File %1 downloaded but it resulted in a local file name clash!").arg(QDir::toNativeSeparators(_item->_file)), ErrorCategory::GenericError);
             }
             return;
         }
@@ -259,7 +259,7 @@ void PropagateLocalRename::start()
         emit propagator()->touchedFile(existingFile);
         emit propagator()->touchedFile(targetFile);
         if (QString renameError; !FileSystem::rename(existingFile, targetFile, &renameError)) {
-            done(SyncFileItem::NormalError, renameError);
+            done(SyncFileItem::NormalError, renameError, ErrorCategory::GenericError);
             return;
         }
     }
@@ -267,19 +267,20 @@ void PropagateLocalRename::start()
     SyncJournalFileRecord oldRecord;
     if (!propagator()->_journal->getFileRecord(fileAlreadyMoved ? previousNameInDb : _item->_originalFile, &oldRecord)) {
         qCWarning(lcPropagateLocalRename) << "could not get file from local DB" << _item->_originalFile;
-        done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(_item->_originalFile));
+        done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(_item->_originalFile), ErrorCategory::GenericError);
         return;
     }
 
     if (fileAlreadyMoved && !deleteOldDbRecord(previousNameInDb)) {
         return;
     } else if (!deleteOldDbRecord(_item->_originalFile)) {
+        qCWarning(lcPropagateLocalRename) << "could not delete file from local DB" << _item->_originalFile;
         return;
     }
 
     if (!vfs->setPinState(_item->_renameTarget, pinState)) {
         qCWarning(lcPropagateLocalRename) << "Could not set pin state of" << _item->_renameTarget << "to old value" << pinState;
-        done(SyncFileItem::NormalError, tr("Error setting pin state"));
+        done(SyncFileItem::NormalError, tr("Error setting pin state"), ErrorCategory::GenericError);
         return;
     }
 
@@ -292,10 +293,10 @@ void PropagateLocalRename::start()
         }
         const auto result = propagator()->updateMetadata(newItem);
         if (!result) {
-            done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()));
+            done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()), ErrorCategory::GenericError);
             return;
         } else if (*result == Vfs::ConvertToPlaceholderResult::Locked) {
-            done(SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(newItem._file));
+            done(SyncFileItem::SoftError, tr("The file %1 is currently in use").arg(newItem._file), ErrorCategory::GenericError);
             return;
         }
     } else {
@@ -312,12 +313,12 @@ void PropagateLocalRename::start()
             SyncJournalFileRecord oldRecord;
             if (!propagator()->_journal->getFileRecord(oldFileName, &oldRecord)) {
                 qCWarning(lcPropagateLocalRename) << "could not get file from local DB" << oldFileName;
-                done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(oldFileNameString));
+                done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(oldFileNameString), OCC::ErrorCategory::GenericError);
                 return;
             }
             if (!propagator()->_journal->deleteFileRecord(oldFileName)) {
                 qCWarning(lcPropagateLocalRename) << "could not delete file from local DB" << oldFileName;
-                done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(oldFileNameString));
+                done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(oldFileNameString), OCC::ErrorCategory::GenericError);
                 return;
             }
 
@@ -325,36 +326,40 @@ void PropagateLocalRename::start()
             newItem->_file = newFileNameString;
             const auto result = propagator()->updateMetadata(*newItem);
             if (!result) {
-                done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()));
+                done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()), OCC::ErrorCategory::GenericError);
                 return;
             }
         });
         if (!dbQueryResult) {
-            done(SyncFileItem::FatalError, tr("Failed to propagate directory rename in hierarchy"));
+            done(SyncFileItem::FatalError, tr("Failed to propagate directory rename in hierarchy"), OCC::ErrorCategory::GenericError);
             return;
         }
         propagator()->_renamedDirectories.insert(oldFile, _item->_renameTarget);
         if (!PropagateRemoteMove::adjustSelectiveSync(propagator()->_journal, oldFile, _item->_renameTarget)) {
-            done(SyncFileItem::FatalError, tr("Failed to rename file"));
+            done(SyncFileItem::FatalError, tr("Failed to rename file"), ErrorCategory::GenericError);
             return;
         }
     }
+    if (pinState != PinState::Inherited && !vfs->setPinState(_item->_renameTarget, pinState)) {
+        done(SyncFileItem::NormalError, tr("Error setting pin state"), ErrorCategory::GenericError);
+        return;
+    }
 
     propagator()->_journal->commit("localRename");
 
-    done(SyncFileItem::Success);
+    done(SyncFileItem::Success, {}, ErrorCategory::NoError);
 }
 
 bool PropagateLocalRename::deleteOldDbRecord(const QString &fileName)
 {
     if (SyncJournalFileRecord oldRecord; !propagator()->_journal->getFileRecord(fileName, &oldRecord)) {
         qCWarning(lcPropagateLocalRename) << "could not get file from local DB" << fileName;
-        done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(fileName));
+        done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(fileName), OCC::ErrorCategory::GenericError);
         return false;
     }
     if (!propagator()->_journal->deleteFileRecord(fileName)) {
         qCWarning(lcPropagateLocalRename) << "could not delete file from local DB" << fileName;
-        done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(fileName));
+        done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(fileName), OCC::ErrorCategory::GenericError);
         return false;
     }
 
index e8ec169d7d09b9f7bfb5d3623ed41bf903213770..f162b0ed5afc6d9f2632ca009167bafbb22431e7 100644 (file)
@@ -379,7 +379,7 @@ void OCC::SyncEngine::slotItemDiscovered(const OCC::SyncFileItemPtr &item)
                     item->_status = SyncFileItem::Status::NormalError;
                     item->_instruction = CSYNC_INSTRUCTION_ERROR;
                     item->_errorString = tr("Could not update file: %1").arg(result.error());
-                    emit itemCompleted(item);
+                    emit itemCompleted(item, ErrorCategory::GenericError);
                     return;
                 }
             }
@@ -391,14 +391,14 @@ void OCC::SyncEngine::slotItemDiscovered(const OCC::SyncFileItemPtr &item)
                     item->_status = SyncFileItem::Status::NormalError;
                     item->_instruction = CSYNC_INSTRUCTION_ERROR;
                     item->_errorString = tr("Could not update virtual file metadata: %1").arg(r.error());
-                    emit itemCompleted(item);
+                    emit itemCompleted(item, ErrorCategory::GenericError);
                     return;
                 }
             } else {
                 if (!FileSystem::setModTime(filePath, item->_modtime)) {
                     item->_instruction = CSYNC_INSTRUCTION_ERROR;
                     item->_errorString = tr("Could not update file metadata: %1").arg(filePath);
-                    emit itemCompleted(item);
+                    emit itemCompleted(item, ErrorCategory::GenericError);
                     return;
                 }
             }
@@ -412,7 +412,7 @@ void OCC::SyncEngine::slotItemDiscovered(const OCC::SyncFileItemPtr &item)
             }
 
             // This might have changed the shared flag, so we must notify SyncFileStatusTracker for example
-            emit itemCompleted(item);
+            emit itemCompleted(item, ErrorCategory::NoError);
         } else {
             // Update only outdated data from the disk.
 
@@ -516,7 +516,7 @@ void SyncEngine::startSync()
     if (!QDir(_localPath).exists()) {
         _anotherSyncNeeded = DelayedFollowUp;
         // No _tr, it should only occur in non-mirall
-        Q_EMIT syncError(QStringLiteral("Unable to find local sync folder."));
+        Q_EMIT syncError(QStringLiteral("Unable to find local sync folder."), ErrorCategory::GenericError);
         finalize(false);
         return;
     }
@@ -533,7 +533,7 @@ void SyncEngine::startSync()
                 "Placeholders are postfixed with file sizes using Utility::octetsToString()")
                                  .arg(
                                      Utility::octetsToString(freeBytes),
-                                     Utility::octetsToString(minFree)));
+                                     Utility::octetsToString(minFree)), ErrorCategory::GenericError);
             finalize(false);
             return;
         } else {
@@ -562,7 +562,7 @@ void SyncEngine::startSync()
     // This creates the DB if it does not exist yet.
     if (!_journal->open()) {
         qCWarning(lcEngine) << "No way to create a sync journal!";
-        Q_EMIT syncError(tr("Unable to open or create the local sync database. Make sure you have write access in the sync folder."));
+        Q_EMIT syncError(tr("Unable to open or create the local sync database. Make sure you have write access in the sync folder."), ErrorCategory::GenericError);
         finalize(false);
         return;
         // database creation error!
@@ -578,7 +578,7 @@ void SyncEngine::startSync()
     _lastLocalDiscoveryStyle = _localDiscoveryStyle;
 
     if (_syncOptions._vfs->mode() == Vfs::WithSuffix && _syncOptions._vfs->fileSuffix().isEmpty()) {
-        Q_EMIT syncError(tr("Using virtual files with suffix, but suffix is not set"));
+        Q_EMIT syncError(tr("Using virtual files with suffix, but suffix is not set"), ErrorCategory::GenericError);
         finalize(false);
         return;
     }
@@ -590,7 +590,7 @@ void SyncEngine::startSync()
         qCInfo(lcEngine) << (usingSelectiveSync ? "Using Selective Sync" : "NOT Using Selective Sync");
     } else {
         qCWarning(lcEngine) << "Could not retrieve selective sync list from DB";
-        Q_EMIT syncError(tr("Unable to read the blacklist from the local database"));
+        Q_EMIT syncError(tr("Unable to read the blacklist from the local database"), ErrorCategory::GenericError);
         finalize(false);
         return;
     }
@@ -631,7 +631,7 @@ void SyncEngine::startSync()
     _discoveryPhase->setSelectiveSyncWhiteList(_journal->getSelectiveSyncList(SyncJournalDb::SelectiveSyncWhiteList, &ok));
     if (!ok) {
         qCWarning(lcEngine) << "Unable to read selective sync list, aborting.";
-        Q_EMIT syncError(tr("Unable to read from the sync journal."));
+        Q_EMIT syncError(tr("Unable to read from the sync journal."), ErrorCategory::GenericError);
         finalize(false);
         return;
     }
@@ -654,8 +654,8 @@ void SyncEngine::startSync()
 
     connect(_discoveryPhase.data(), &DiscoveryPhase::itemDiscovered, this, &SyncEngine::slotItemDiscovered);
     connect(_discoveryPhase.data(), &DiscoveryPhase::newBigFolder, this, &SyncEngine::newBigFolder);
-    connect(_discoveryPhase.data(), &DiscoveryPhase::fatalError, this, [this](const QString &errorString) {
-        Q_EMIT syncError(errorString);
+    connect(_discoveryPhase.data(), &DiscoveryPhase::fatalError, this, [this](const QString &errorString, ErrorCategory errorCategory) {
+        Q_EMIT syncError(errorString, errorCategory);
         finalize(false);
     });
     connect(_discoveryPhase.data(), &DiscoveryPhase::finished, this, &SyncEngine::slotDiscoveryFinished);
@@ -760,7 +760,7 @@ void SyncEngine::slotDiscoveryFinished()
     // Sanity check
     if (!_journal->open()) {
         qCWarning(lcEngine) << "Bailing out, DB failure";
-        Q_EMIT syncError(tr("Cannot open the sync journal"));
+        Q_EMIT syncError(tr("Cannot open the sync journal"), ErrorCategory::GenericError);
         finalize(false);
         return;
     } else {
@@ -892,9 +892,9 @@ void SyncEngine::slotDiscoveryFinished()
     finish();
 }
 
-void SyncEngine::slotCleanPollsJobAborted(const QString &error)
+void SyncEngine::slotCleanPollsJobAborted(const QString &error, const ErrorCategory errorCategory)
 {
-    syncError(error);
+    syncError(error, errorCategory);
     finalize(false);
 }
 
@@ -914,12 +914,12 @@ void SyncEngine::setNetworkLimits(int upload, int download)
     }
 }
 
-void SyncEngine::slotItemCompleted(const SyncFileItemPtr &item)
+void SyncEngine::slotItemCompleted(const SyncFileItemPtr &item, const ErrorCategory category)
 {
     _progressInfo->setProgressComplete(*item);
 
     emit transmissionProgress(*_progressInfo);
-    emit itemCompleted(item);
+    emit itemCompleted(item, category);
 }
 
 void SyncEngine::slotPropagationFinished(bool success)
@@ -1211,7 +1211,7 @@ void SyncEngine::slotSummaryError(const QString &message)
         return;
 
     _uniqueErrors.insert(message);
-    emit syncError(message, ErrorCategory::Normal);
+    emit syncError(message, ErrorCategory::GenericError);
 }
 
 void SyncEngine::slotInsufficientLocalStorage()
index 3db1b3f2ae01c51f9f80f5ba06e359a81cda41b6..ba81fe237438d44f52a62044952422ee6559943c 100644 (file)
@@ -163,16 +163,16 @@ signals:
     void aboutToPropagate(OCC::SyncFileItemVector &);
 
     // after each item completed by a job (successful or not)
-    void itemCompleted(const OCC::SyncFileItemPtr &);
+    void itemCompleted(const OCC::SyncFileItemPtr &item, const OCC::ErrorCategory category);
 
     void transmissionProgress(const OCC::ProgressInfo &progress);
 
     void itemDiscovered(const OCC::SyncFileItemPtr &);
 
     /// We've produced a new sync error of a type.
-    void syncError(const QString &message, OCC::ErrorCategory category = OCC::ErrorCategory::Normal);
+    void syncError(const QString &message, const OCC::ErrorCategory category);
 
-    void addErrorToGui(OCC::SyncFileItem::Status status, const QString &errorMessage, const QString &subject);
+    void addErrorToGui(const OCC::SyncFileItem::Status status, const QString &errorMessage, const QString &subject, const OCC::ErrorCategory category);
 
     void finished(bool success);
     void started();
@@ -208,11 +208,11 @@ private slots:
      */
     void slotNewItem(const OCC::SyncFileItemPtr &item);
 
-    void slotItemCompleted(const OCC::SyncFileItemPtr &item);
+    void slotItemCompleted(const OCC::SyncFileItemPtr &item, const OCC::ErrorCategory category);
     void slotDiscoveryFinished();
     void slotPropagationFinished(bool success);
     void slotProgress(const OCC::SyncFileItem &item, qint64 curent);
-    void slotCleanPollsJobAborted(const QString &error);
+    void slotCleanPollsJobAborted(const QString &error, const OCC::ErrorCategory category);
 
     /** Records that a file was touched by a job. */
     void slotAddTouchedFile(const QString &fn);
index 2c537ac0fba138565c8788f64074e0e6b58b392d..c050a091d21a46b2b224c359dd44774fac6efc17 100644 (file)
@@ -456,6 +456,17 @@ public:
         QVERIFY(index.isValid());
     }
 
+    void testActivityAdd(void(OCC::ActivityListModel::*addingMethod)(const OCC::Activity&, OCC::ActivityListModel::ErrorType), OCC::Activity &activity, OCC::ActivityListModel::ErrorType type) {
+        const auto model = testingALM();
+        QCOMPARE(model->rowCount(), 0);
+
+        (model.data()->*addingMethod)(activity, type);
+        QCOMPARE(model->rowCount(), 1);
+
+        const auto index = model->index(0, 0);
+        QVERIFY(index.isValid());
+    }
+
 private slots:
     void initTestCase()
     {
@@ -555,7 +566,7 @@ private slots:
     };
 
     void testAddError() {
-        testActivityAdd(&TestingALM::addErrorToActivityList, testSyncResultErrorActivity);
+        testActivityAdd(&TestingALM::addErrorToActivityList, testSyncResultErrorActivity, OCC::ActivityListModel::ErrorType::SyncError);
     };
 
     void testAddIgnoredFile() {
@@ -615,7 +626,7 @@ private slots:
         model->addSyncFileItemToActivityList(testSyncFileItemActivity);
         QCOMPARE(model->rowCount(), 51);
 
-        model->addErrorToActivityList(testSyncResultErrorActivity);
+        model->addErrorToActivityList(testSyncResultErrorActivity, OCC::ActivityListModel::ErrorType::SyncError);
         QCOMPARE(model->rowCount(), 52);
 
         model->addIgnoredFileToList(testFileIgnoredActivity);