Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion src/gui/folderstatusmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Q_LOGGING_CATEGORY(lcFolderStatus, "nextcloud.gui.folder.model", QtInfoMsg)
static const char propertyParentIndexC[] = "oc_parentIndex";
static const char propertyPermissionMap[] = "oc_permissionMap";
static const char propertyEncryptionMap[] = "nc_encryptionMap";
static const char propertySyncEnabledMap[] = "nc_syncEnabledMap";

static QString removeTrailingSlash(const QString &path)
{
Expand Down Expand Up @@ -634,7 +635,8 @@ void FolderStatusModel::fetchMore(const QModelIndex &parent)
<< "http://owncloud.org/ns:permissions"
<< "http://nextcloud.org/ns:is-mount-root"
<< "http://owncloud.org/ns:fileid"
<< "http://nextcloud.org/ns:is-encrypted";
<< "http://nextcloud.org/ns:is-encrypted"
<< "http://nextcloud.org/ns:sync-enabled";
job->setProperties(props);

job->setTimeout(60 * 1000);
Expand All @@ -646,6 +648,8 @@ void FolderStatusModel::fetchMore(const QModelIndex &parent)
this, &FolderStatusModel::slotGatherPermissions);
connect(job, &LsColJob::directoryListingIterated,
this, &FolderStatusModel::slotGatherEncryptionStatus);
connect(job, &LsColJob::directoryListingIterated,
this, &FolderStatusModel::slotGatherSyncEnabledStatus);

job->start();

Expand Down Expand Up @@ -694,6 +698,21 @@ void FolderStatusModel::slotGatherEncryptionStatus(const QString &href, const QM
job->setProperty(propertyEncryptionMap, encryptionMap);
}

void FolderStatusModel::slotGatherSyncEnabledStatus(const QString &href, const QMap<QString, QString> &properties)
{
const auto it = properties.find("sync-enabled");
if (it == properties.end()) {
return;
}

const auto job = sender();
auto syncEnabledMap = job->property(propertySyncEnabledMap).toMap();
job->setProperty(propertySyncEnabledMap, QVariant()); // avoid a detach of the map while it is modified
ASSERT(!href.endsWith(QLatin1Char('/')), "LsColXMLParser::parse should remove the trailing slash before calling us.");
syncEnabledMap[href] = *it;
job->setProperty(propertySyncEnabledMap, syncEnabledMap);
}

void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
{
const auto job = qobject_cast<LsColJob *>(sender());
Expand Down Expand Up @@ -741,6 +760,7 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
}
const auto permissionMap = job->property(propertyPermissionMap).toMap();
const auto encryptionMap = job->property(propertyEncryptionMap).toMap();
const auto syncEnabledMap = job->property(propertySyncEnabledMap).toMap();

auto sortedSubfolders = list;
if (!sortedSubfolders.isEmpty()) {
Expand All @@ -757,6 +777,14 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
if (parentInfo->_folder->isFileExcludedRelative(relativePath)) {
continue;
}
// Server-side external storage mounts can opt out of client sync
// entirely (nc:sync-enabled == "false") while remaining browsable
// via web/mobile. Never surface them in the "choose what to sync"
// tree so they can't be selected for automatic sync, whether the
// account was just connected or already existed.
if (syncEnabledMap.value(removeTrailingSlash(path)).toString() == "false"_L1) {
continue;
}

SubFolderInfo newInfo;
newInfo._folder = parentInfo->_folder;
Expand Down
1 change: 1 addition & 0 deletions src/gui/folderstatusmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ private Q_SLOTS:
void slotUpdateDirectories(const QStringList &);
void slotGatherPermissions(const QString &name, const QMap<QString, QString> &properties);
void slotGatherEncryptionStatus(const QString &href, const QMap<QString, QString> &properties);
void slotGatherSyncEnabledStatus(const QString &href, const QMap<QString, QString> &properties);
void slotLscolFinishedWithError(QNetworkReply *r);
void slotFolderSyncStateChange(OCC::Folder *f);
void slotFolderScheduleQueueChanged();
Expand Down
29 changes: 28 additions & 1 deletion src/gui/folderwizard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,18 @@ void FolderWizardRemotePath::slotUpdateDirectories(const QStringList &list)
continue;
}

// Server-side external storage mounts can opt out of client sync
// entirely (nc:sync-enabled == "false") while remaining browsable
// on the web/mobile apps. Exclude the mount itself and everything
// beneath it from the folder picker so it can never be selected
// for automatic sync.
const auto isSyncDisabled = std::any_of(std::cbegin(_syncDisabledPaths), std::cend(_syncDisabledPaths), [=](const QString &disabledPath) {
return path.size() >= disabledPath.size() && path.startsWith(disabledPath);
});
if (isSyncDisabled) {
continue;
}

QStringList paths = path.split('/');
if (paths.last().isEmpty()) {
paths.removeLast();
Expand All @@ -408,6 +420,18 @@ void FolderWizardRemotePath::slotGatherEncryptedPaths(const QString &path, const
_encryptedPaths << path.mid(webdavFolder.size());
}

void FolderWizardRemotePath::slotGatherSyncDisabledPaths(const QString &path, const QMap<QString, QString> &properties)
{
const auto it = properties.find("sync-enabled");
if (it == properties.cend() || *it != QStringLiteral("false")) {
return;
}

const auto webdavFolder = QUrl(_account->davUrl()).path();
Q_ASSERT(path.startsWith(webdavFolder));
_syncDisabledPaths << path.mid(webdavFolder.size());
}

void FolderWizardRemotePath::slotRefreshFolders()
{
_encryptedPaths.clear();
Expand Down Expand Up @@ -478,14 +502,17 @@ LsColJob *FolderWizardRemotePath::runLsColJob(const QString &path)
{
auto *job = new LsColJob(_account, path);
const auto props = QList<QByteArray>() << "resourcetype"
<< "http://nextcloud.org/ns:is-encrypted";
<< "http://nextcloud.org/ns:is-encrypted"
<< "http://nextcloud.org/ns:sync-enabled";
job->setProperties(props);
connect(job, &LsColJob::directoryListingSubfolders,
this, &FolderWizardRemotePath::slotUpdateDirectories);
connect(job, &LsColJob::finishedWithError,
this, &FolderWizardRemotePath::slotHandleLsColNetworkError);
connect(job, &LsColJob::directoryListingIterated,
this, &FolderWizardRemotePath::slotGatherEncryptedPaths);
connect(job, &LsColJob::directoryListingIterated,
this, &FolderWizardRemotePath::slotGatherSyncDisabledPaths);
job->start();

return job;
Expand Down
6 changes: 6 additions & 0 deletions src/gui/folderwizard.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ protected Q_SLOTS:
void slotHandleLsColNetworkError(QNetworkReply *);
void slotUpdateDirectories(const QStringList &);
void slotGatherEncryptedPaths(const QString &, const QMap<QString, QString> &);
void slotGatherSyncDisabledPaths(const QString &, const QMap<QString, QString> &);
void slotRefreshFolders();
void slotItemExpanded(QTreeWidgetItem *);
void slotCurrentItemChanged(QTreeWidgetItem *);
Expand All @@ -120,6 +121,11 @@ private Q_SLOTS:
AccountPtr _account;
QTimer _lscolTimer;
QStringList _encryptedPaths;
// Paths whose external storage mount has server-side sync disabled
// (nc:sync-enabled == "false"). Excluded from the folder picker the
// same way encrypted paths are, since they are not meant to be
// auto-synced to begin with, only browsed/downloaded on demand.
QStringList _syncDisabledPaths;
};

/**
Expand Down