From 2ebfdb2cc2a9912d46a32876616f3a26789d4ecb Mon Sep 17 00:00:00 2001 From: Martchus Date: Sat, 4 May 2024 23:00:13 +0200 Subject: [PATCH] Add function to query ignore patterns --- syncthingconnector/syncthingconnection.h | 7 ++ .../syncthingconnection_requests.cpp | 71 ++++++++++++++++++- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/syncthingconnector/syncthingconnection.h b/syncthingconnector/syncthingconnection.h index 75e32e9..e0ff031 100644 --- a/syncthingconnector/syncthingconnection.h +++ b/syncthingconnector/syncthingconnection.h @@ -65,6 +65,11 @@ struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingItem { bool checked = false; // not populated but might be set to flag an item for some mass-action }; +struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingIgnores { + QStringList ignore; + QStringList expanded; +}; + class LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingConnection : public QObject { friend ConnectionTests; friend MiscTests; @@ -256,6 +261,7 @@ public: // methods to GET or POST information from/to Syncthing (non-slots) QMetaObject::Connection browse(const QString &dirId, const QString &prefix, int level, std::function> &&, QString &&)> &&callback); + QMetaObject::Connection ignores(const QString &dirId, std::function &&callback); Q_SIGNALS: void newConfig(const QJsonObject &rawConfig); @@ -371,6 +377,7 @@ private Q_SLOTS: private: // handler to evaluate results from request...() methods void readBrowse(const QString &dirId, int levels, std::function> &&, QString &&)> &&callback); + void readIgnores(const QString &dirId, std::function &&callback); // internal helper methods struct Reply { diff --git a/syncthingconnector/syncthingconnection_requests.cpp b/syncthingconnector/syncthingconnection_requests.cpp index b5b3377..5578740 100644 --- a/syncthingconnector/syncthingconnection_requests.cpp +++ b/syncthingconnector/syncthingconnection_requests.cpp @@ -1586,9 +1586,9 @@ void SyncthingConnection::readRevert() * \brief Lists items in the directory with the specified \a dirId down to \a levels (or fully if \a levels is 0) as of \a prefix. * \sa https://docs.syncthing.net/rest/db-browse-get.html * \remarks - * In contrast to other functions, this one uses a \a callback to return results (instead of a signal). This makes it easier to - * consume results of a specific request. Errors are still reported via the error() signal so there's no extra error handling - * required. Note that \a callback is *not* invoked in the error case. + * In contrast to most other functions, this one uses a \a callback to return results (instead of a signal). This makes it easier + * to consume results of a specific request. Errors are still reported via the error() signal so there's no extra error handling + * required. Note that in case of an error \a callback is invoked with a non-empty string containing the error message. */ QMetaObject::Connection SyncthingConnection::browse(const QString &dirId, const QString &prefix, int levels, std::function> &&, QString &&)> &&callback) @@ -1606,6 +1606,23 @@ QMetaObject::Connection SyncthingConnection::browse(const QString &dirId, const [this, id = dirId, l = levels, cb = std::move(callback)]() mutable { readBrowse(id, l, std::move(cb)); }, Qt::QueuedConnection); } +/*! + * \brief Queries the contents of ".stignore" and expansions of the directory with the specified \a dirId. + * \sa https://docs.syncthing.net/rest/db-ignores-get.html + * \remarks + * In contrast to most other functions, this one uses a \a callback to return results (instead of a signal). This makes it easier + * to consume results of a specific request. Errors are still reported via the error() signal so there's no extra error handling + * required. Note that in case of an error \a callback is invoked with a non-empty string containing the error message. + */ +QMetaObject::Connection SyncthingConnection::ignores(const QString &dirId, std::function &&callback) +{ + auto query = QUrlQuery(); + query.addQueryItem(QStringLiteral("folder"), formatQueryItem(dirId)); + return QObject::connect( + requestData(QStringLiteral("db/ignores"), query), &QNetworkReply::finished, this, + [this, id = dirId, cb = std::move(callback)]() mutable { readIgnores(id, std::move(cb)); }, Qt::QueuedConnection); +} + /// \cond static void readSyncthingItems(const QJsonArray &array, std::vector> &into, int level, int levels) { @@ -1683,6 +1700,54 @@ void SyncthingConnection::readBrowse( } } +/*! + * \brief Reads the response of ignores() and reports results via the specified \a callback. Emits error() in case of an error. + * \remarks The \a callback is also emitted in the error case (with the error message as second parameter and an empty list of items). + */ +void SyncthingConnection::readIgnores(const QString &dirId, std::function &&callback) +{ + auto const [reply, response] = prepareReply(); + if (!reply) { + return; + } + auto res = SyncthingIgnores(); + switch (reply->error()) { + case QNetworkReply::NoError: { + auto jsonError = QJsonParseError(); + const auto replyDoc = QJsonDocument::fromJson(response, &jsonError); + if (jsonError.error != QJsonParseError::NoError) { + auto errorMessage = tr("Unable to query ignore patterns of \"%1\": ").arg(dirId) + jsonError.errorString(); + emit error(errorMessage, SyncthingErrorCategory::Parsing, QNetworkReply::NoError); + if (callback) { + callback(std::move(res), std::move(errorMessage)); + } + return; + } + const auto docObj = replyDoc.object(); + const auto ignores = docObj.value(QLatin1String("ignore")).toArray(); + const auto expanded = docObj.value(QLatin1String("expanded")).toArray(); + res.ignore.reserve(ignores.size()); + res.expanded.reserve(expanded.size()); + for (const auto &ignore : ignores) { + res.ignore.append(ignore.toString()); + } + for (const auto &expand : expanded) { + res.expanded.append(expand.toString()); + } + if (callback) { + callback(std::move(res), QString()); + } + break; + } + default: + auto errorMessage = tr("Unable to query ignore patterns of \"%1\": ").arg(dirId); + emitError(errorMessage, SyncthingErrorCategory::SpecificRequest, reply); + if (callback) { + callback(std::move(res), std::move(errorMessage)); + } + } +} + // post config /*!