mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-28 19:58:56 +03:00
detect remnants read-only folders to delete: try to delete them
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
This commit is contained in:
parent
ab2002596e
commit
5b8144f806
5 changed files with 157 additions and 0 deletions
|
@ -101,6 +101,8 @@ Folder::Folder(const FolderDefinition &definition,
|
|||
|
||||
connect(_engine.data(), &SyncEngine::aboutToRemoveAllFiles,
|
||||
this, &Folder::slotAboutToRemoveAllFiles);
|
||||
connect(_engine.data(), &SyncEngine::aboutToRemoveRemnantsReadOnlyFolders,
|
||||
this, &Folder::slotNeedToRemoveRemnantsReadOnlyFolders);
|
||||
connect(_engine.data(), &SyncEngine::transmissionProgress, this, &Folder::slotTransmissionProgress);
|
||||
connect(_engine.data(), &SyncEngine::itemCompleted,
|
||||
this, &Folder::slotItemCompleted);
|
||||
|
@ -1664,6 +1666,34 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction dir, std::functio
|
|||
msgBox->open();
|
||||
}
|
||||
|
||||
void Folder::slotNeedToRemoveRemnantsReadOnlyFolders(const QList<SyncFileItemPtr> &folders,
|
||||
const QString &localPath,
|
||||
std::function<void (bool)> callback)
|
||||
{
|
||||
const auto msg = tr("Do you want to clean up remnant read-only folders left over from previous failed synchronization attempts.");
|
||||
auto msgBox = new QMessageBox(QMessageBox::Question, tr("Remove remnant invalid folders?"),
|
||||
msg, QMessageBox::NoButton);
|
||||
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
||||
msgBox->setWindowFlags(msgBox->windowFlags() | Qt::WindowStaysOnTopHint);
|
||||
msgBox->addButton(tr("Proceed to remove remnant folders"), QMessageBox::AcceptRole);
|
||||
const auto keepBtn = msgBox->addButton(tr("Do nothing"), QMessageBox::RejectRole);
|
||||
setSyncPaused(true);
|
||||
connect(msgBox, &QMessageBox::finished, this, [msgBox, keepBtn, callback, folders, localPath, this] {
|
||||
const bool cancel = msgBox->clickedButton() == keepBtn;
|
||||
if (!cancel) {
|
||||
for(const auto &oneFolder : folders) {
|
||||
FileSystem::removeRecursively(localPath + oneFolder->_file);
|
||||
}
|
||||
}
|
||||
callback(cancel);
|
||||
if (cancel) {
|
||||
setSyncPaused(true);
|
||||
}
|
||||
});
|
||||
connect(this, &Folder::destroyed, msgBox, &QMessageBox::deleteLater);
|
||||
msgBox->open();
|
||||
}
|
||||
|
||||
void Folder::removeLocalE2eFiles()
|
||||
{
|
||||
qCDebug(lcFolder) << "Removing local E2EE files";
|
||||
|
|
|
@ -335,6 +335,10 @@ public slots:
|
|||
// connected to the corresponding signals in the SyncEngine
|
||||
void slotAboutToRemoveAllFiles(OCC::SyncFileItem::Direction, std::function<void(bool)> callback);
|
||||
|
||||
void slotNeedToRemoveRemnantsReadOnlyFolders(const QList<SyncFileItemPtr> &folders,
|
||||
const QString &localPath,
|
||||
std::function<void(bool)> callback);
|
||||
|
||||
/**
|
||||
* Starts a sync operation
|
||||
*
|
||||
|
|
|
@ -817,6 +817,10 @@ void SyncEngine::slotDiscoveryFinished()
|
|||
return;
|
||||
}
|
||||
|
||||
if (!_remnantReadOnlyFolders.isEmpty()) {
|
||||
handleRemnantReadOnlyFolders();
|
||||
return;
|
||||
}
|
||||
|
||||
finishSync();
|
||||
}
|
||||
|
@ -1101,6 +1105,13 @@ void SyncEngine::finishSync()
|
|||
qCInfo(lcEngine) << "#### Post-Reconcile end #################################################### " << _stopWatch.addLapTime(QStringLiteral("Post-Reconcile Finished")) << "ms";
|
||||
}
|
||||
|
||||
void SyncEngine::handleRemnantReadOnlyFolders()
|
||||
{
|
||||
promptUserBeforePropagation([this](auto &&callback) {
|
||||
emit aboutToRemoveRemnantsReadOnlyFolders(_remnantReadOnlyFolders, _localPath, callback);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void SyncEngine::promptUserBeforePropagation(T &&lambda)
|
||||
{
|
||||
|
|
|
@ -189,6 +189,10 @@ signals:
|
|||
*/
|
||||
void aboutToRemoveAllFiles(OCC::SyncFileItem::Direction direction, std::function<void(bool)> f);
|
||||
|
||||
void aboutToRemoveRemnantsReadOnlyFolders(const QList<SyncFileItemPtr> &folders,
|
||||
const QString &localPath,
|
||||
std::function<void(bool)> f);
|
||||
|
||||
// A new folder was discovered and was not synced because of the confirmation feature
|
||||
void newBigFolder(const QString &folder, bool isExternal);
|
||||
|
||||
|
@ -365,6 +369,8 @@ private:
|
|||
|
||||
void finishSync();
|
||||
|
||||
void handleRemnantReadOnlyFolders();
|
||||
|
||||
template <typename T>
|
||||
void promptUserBeforePropagation(T &&lambda);
|
||||
|
||||
|
|
|
@ -59,12 +59,22 @@ SyncFileItemPtr findDiscoveryItem(const SyncFileItemVector &spy, const QString &
|
|||
bool itemInstruction(const ItemCompletedSpy &spy, const QString &path, const SyncInstructions instr)
|
||||
{
|
||||
auto item = spy.findItem(path);
|
||||
const auto checkHelper = [item, instr]() {
|
||||
QCOMPARE(item->_instruction, instr);
|
||||
};
|
||||
|
||||
checkHelper();
|
||||
return item->_instruction == instr;
|
||||
}
|
||||
|
||||
bool discoveryInstruction(const SyncFileItemVector &spy, const QString &path, const SyncInstructions instr)
|
||||
{
|
||||
auto item = findDiscoveryItem(spy, path);
|
||||
const auto checkHelper = [item, instr]() {
|
||||
QCOMPARE(item->_instruction, instr);
|
||||
};
|
||||
|
||||
checkHelper();
|
||||
return item->_instruction == instr;
|
||||
}
|
||||
|
||||
|
@ -87,6 +97,14 @@ private slots:
|
|||
FakeFolder fakeFolder{ FileInfo() };
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToRemoveRemnantsReadOnlyFolders,
|
||||
[&](const QList<SyncFileItemPtr> &folders, const QString &localPath, std::function<void(bool)> callback) {
|
||||
qDebug() << "aboutToRemoveRemnantsReadOnlyFolders called";
|
||||
Q_UNUSED(folders);
|
||||
Q_UNUSED(localPath);
|
||||
callback(false);
|
||||
});
|
||||
|
||||
// Some of this test depends on the order of discovery. With threading
|
||||
// that order becomes effectively random, but we want to make sure to test
|
||||
// all cases and thus disable threading.
|
||||
|
@ -424,6 +442,13 @@ private slots:
|
|||
{
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
|
||||
QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToRemoveRemnantsReadOnlyFolders,
|
||||
[&](const QList<SyncFileItemPtr> &folders, const QString &localPath, std::function<void(bool)> callback) {
|
||||
Q_UNUSED(folders)
|
||||
Q_UNUSED(localPath)
|
||||
callback(false);
|
||||
});
|
||||
|
||||
// Some of this test depends on the order of discovery. With threading
|
||||
// that order becomes effectively random, but we want to make sure to test
|
||||
// all cases and thus disable threading.
|
||||
|
@ -543,6 +568,14 @@ private slots:
|
|||
void testAllowedMoveForbiddenDelete() {
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
|
||||
QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToRemoveRemnantsReadOnlyFolders,
|
||||
[&](const QList<SyncFileItemPtr> &folders, const QString &localPath, std::function<void(bool)> callback) {
|
||||
for(const auto &oneFolder : folders) {
|
||||
FileSystem::removeRecursively(localPath + oneFolder->_file);
|
||||
}
|
||||
callback(false);
|
||||
});
|
||||
|
||||
// Some of this test depends on the order of discovery. With threading
|
||||
// that order becomes effectively random, but we want to make sure to test
|
||||
// all cases and thus disable threading.
|
||||
|
@ -591,6 +624,15 @@ private slots:
|
|||
void testParentMoveNotAllowedChildrenRestored()
|
||||
{
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
|
||||
QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToRemoveRemnantsReadOnlyFolders,
|
||||
[&](const QList<SyncFileItemPtr> &folders, const QString &localPath, std::function<void(bool)> callback) {
|
||||
for(const auto &oneFolder : folders) {
|
||||
FileSystem::removeRecursively(localPath + oneFolder->_file);
|
||||
}
|
||||
callback(false);
|
||||
});
|
||||
|
||||
auto &lm = fakeFolder.localModifier();
|
||||
auto &rm = fakeFolder.remoteModifier();
|
||||
rm.mkdir("forbidden-move");
|
||||
|
@ -643,6 +685,14 @@ private slots:
|
|||
{
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
|
||||
QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToRemoveRemnantsReadOnlyFolders,
|
||||
[&](const QList<SyncFileItemPtr> &folders, const QString &localPath, std::function<void(bool)> callback) {
|
||||
for(const auto &oneFolder : folders) {
|
||||
FileSystem::removeRecursively(localPath + oneFolder->_file);
|
||||
}
|
||||
callback(false);
|
||||
});
|
||||
|
||||
auto &remote = fakeFolder.remoteModifier();
|
||||
|
||||
remote.mkdir("readOnlyFolder");
|
||||
|
@ -660,6 +710,14 @@ private slots:
|
|||
{
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
|
||||
QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToRemoveRemnantsReadOnlyFolders,
|
||||
[&](const QList<SyncFileItemPtr> &folders, const QString &localPath, std::function<void(bool)> callback) {
|
||||
for(const auto &oneFolder : folders) {
|
||||
FileSystem::removeRecursively(localPath + oneFolder->_file);
|
||||
}
|
||||
callback(false);
|
||||
});
|
||||
|
||||
auto &remote = fakeFolder.remoteModifier();
|
||||
|
||||
remote.mkdir("readWriteFolder");
|
||||
|
@ -678,6 +736,14 @@ private slots:
|
|||
{
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
|
||||
QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToRemoveRemnantsReadOnlyFolders,
|
||||
[&](const QList<SyncFileItemPtr> &folders, const QString &localPath, std::function<void(bool)> callback) {
|
||||
for(const auto &oneFolder : folders) {
|
||||
FileSystem::removeRecursively(localPath + oneFolder->_file);
|
||||
}
|
||||
callback(false);
|
||||
});
|
||||
|
||||
auto &remote = fakeFolder.remoteModifier();
|
||||
|
||||
remote.mkdir("testFolder");
|
||||
|
@ -714,6 +780,14 @@ private slots:
|
|||
{
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
|
||||
QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToRemoveRemnantsReadOnlyFolders,
|
||||
[&](const QList<SyncFileItemPtr> &folders, const QString &localPath, std::function<void(bool)> callback) {
|
||||
for(const auto &oneFolder : folders) {
|
||||
FileSystem::removeRecursively(localPath + oneFolder->_file);
|
||||
}
|
||||
callback(false);
|
||||
});
|
||||
|
||||
auto &remote = fakeFolder.remoteModifier();
|
||||
|
||||
remote.mkdir("testFolder");
|
||||
|
@ -774,6 +848,14 @@ private slots:
|
|||
{
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
|
||||
QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToRemoveRemnantsReadOnlyFolders,
|
||||
[&](const QList<SyncFileItemPtr> &folders, const QString &localPath, std::function<void(bool)> callback) {
|
||||
for(const auto &oneFolder : folders) {
|
||||
FileSystem::removeRecursively(localPath + oneFolder->_file);
|
||||
}
|
||||
callback(false);
|
||||
});
|
||||
|
||||
auto &remote = fakeFolder.remoteModifier();
|
||||
|
||||
remote.mkdir("readOnlyFolder");
|
||||
|
@ -804,6 +886,14 @@ private slots:
|
|||
{
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
|
||||
QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToRemoveRemnantsReadOnlyFolders,
|
||||
[&](const QList<SyncFileItemPtr> &folders, const QString &localPath, std::function<void(bool)> callback) {
|
||||
for(const auto &oneFolder : folders) {
|
||||
FileSystem::removeRecursively(localPath + oneFolder->_file);
|
||||
}
|
||||
callback(false);
|
||||
});
|
||||
|
||||
auto &remote = fakeFolder.remoteModifier();
|
||||
|
||||
remote.mkdir("readOnlyFolder");
|
||||
|
@ -836,6 +926,14 @@ private slots:
|
|||
{
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
|
||||
QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToRemoveRemnantsReadOnlyFolders,
|
||||
[&](const QList<SyncFileItemPtr> &folders, const QString &localPath, std::function<void(bool)> callback) {
|
||||
for(const auto &oneFolder : folders) {
|
||||
FileSystem::removeRecursively(localPath + oneFolder->_file);
|
||||
}
|
||||
callback(false);
|
||||
});
|
||||
|
||||
auto &remote = fakeFolder.remoteModifier();
|
||||
|
||||
remote.mkdir("readOnlyFolder");
|
||||
|
@ -871,6 +969,14 @@ private slots:
|
|||
{
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
|
||||
QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToRemoveRemnantsReadOnlyFolders,
|
||||
[&](const QList<SyncFileItemPtr> &folders, const QString &localPath, std::function<void(bool)> callback) {
|
||||
for(const auto &oneFolder : folders) {
|
||||
FileSystem::removeRecursively(localPath + oneFolder->_file);
|
||||
}
|
||||
callback(false);
|
||||
});
|
||||
|
||||
auto &remote = fakeFolder.remoteModifier();
|
||||
|
||||
remote.mkdir("readOnlyFolder");
|
||||
|
|
Loading…
Reference in a new issue