Skip to content

Commit

Permalink
introduce CaseClashConflictSolver and use it
Browse files Browse the repository at this point in the history
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
  • Loading branch information
mgallien committed Dec 21, 2022
1 parent 1f034f8 commit f4f2987
Show file tree
Hide file tree
Showing 5 changed files with 330 additions and 114 deletions.
119 changes: 27 additions & 92 deletions src/gui/caseclashfilenamedialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include "ui_caseclashfilenamedialog.h"

#include "account.h"
#include "propagateremotemove.h"
#include "folder.h"

#include <QPushButton>
Expand Down Expand Up @@ -71,6 +70,7 @@ CaseClashFilenameDialog::CaseClashFilenameDialog(AccountPtr account,
QWidget *parent)
: QDialog(parent)
, _ui(new Ui::CaseClashFilenameDialog)
, _conflictSolver(conflictTaggedPath, conflictFilePath, folder->remotePath(), account, folder->journalDb())
, _account(account)
, _folder(folder)
, _filePath(std::move(conflictFilePath))
Expand Down Expand Up @@ -133,6 +133,30 @@ CaseClashFilenameDialog::CaseClashFilenameDialog(AccountPtr account,
connect(_ui->filenameLineEdit, &QLineEdit::textChanged, this,
&CaseClashFilenameDialog::onFilenameLineEditTextChanged);

connect(&_conflictSolver, &CaseClashConflictSolver::errorStringChanged, this, [this] () {
_ui->errorLabel->setText(_conflictSolver.errorString());
});

connect(&_conflictSolver, &CaseClashConflictSolver::allowedToRenameChanged, this, [this] () {
_ui->buttonBox->setStandardButtons(_ui->buttonBox->standardButtons() &~ QDialogButtonBox::No);
if (_conflictSolver.allowedToRename()) {
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
_ui->filenameLineEdit->setEnabled(true);
_ui->filenameLineEdit->selectAll();
} else {
_ui->buttonBox->setStandardButtons(_ui->buttonBox->standardButtons() | QDialogButtonBox::No);
}
});

connect(&_conflictSolver, &CaseClashConflictSolver::failed, this, [this] () {
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
});

connect(&_conflictSolver, &CaseClashConflictSolver::done, this, [this] () {
Q_EMIT successfulRename(_folder->remotePath() + _newFilename);
QDialog::accept();
});

checkIfAllowedToRename();
}

Expand Down Expand Up @@ -199,39 +223,7 @@ void CaseClashFilenameDialog::updateFileWidgetGroup(const QString &filePath,

void CaseClashFilenameDialog::checkIfAllowedToRename()
{
const auto propfindJob = new PropfindJob(_account, QDir::cleanPath(_folder->remotePath() + _originalFileName));
propfindJob->setProperties({ "http://owncloud.org/ns:permissions" });
connect(propfindJob, &PropfindJob::result, this, &CaseClashFilenameDialog::onPropfindPermissionSuccess);
connect(propfindJob, &PropfindJob::finishedWithError, this, &CaseClashFilenameDialog::onPropfindPermissionError);
propfindJob->start();
}

void CaseClashFilenameDialog::onCheckIfAllowedToRenameComplete(const QVariantMap &values, QNetworkReply *reply)
{
const auto isAllowedToRename = [](const RemotePermissions remotePermissions) {
return remotePermissions.hasPermission(remotePermissions.CanRename)
&& remotePermissions.hasPermission(remotePermissions.CanMove);
};

if (values.contains("permissions") && !isAllowedToRename(RemotePermissions::fromServerString(values["permissions"].toString()))) {
_ui->errorLabel->setText(
tr("You don't have the permission to rename this file. Please ask the author of the file to rename it."));
return;
} else if (reply) {
if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 404) {
_ui->errorLabel->setText(
tr("Failed to fetch permissions with error %1").arg(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()));
return;
}
}

_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
_ui->filenameLineEdit->setEnabled(true);
_ui->filenameLineEdit->selectAll();

const auto filePathFileInfo = QFileInfo(_filePath);
const auto fileName = filePathFileInfo.fileName();
processLeadingOrTrailingSpacesError(fileName);
_conflictSolver.checkIfAllowedToRename();
}

bool CaseClashFilenameDialog::processLeadingOrTrailingSpacesError(const QString &fileName)
Expand Down Expand Up @@ -262,23 +254,10 @@ bool CaseClashFilenameDialog::processLeadingOrTrailingSpacesError(const QString
return false;
}

void CaseClashFilenameDialog::onPropfindPermissionSuccess(const QVariantMap &values)
{
onCheckIfAllowedToRenameComplete(values);
}

void CaseClashFilenameDialog::onPropfindPermissionError(QNetworkReply *reply)
{
onCheckIfAllowedToRenameComplete({}, reply);
}

void CaseClashFilenameDialog::accept()
{
_newFilename = _relativeFilePath + _ui->filenameLineEdit->text().trimmed();
const auto propfindJob = new PropfindJob(_account, QDir::cleanPath(_folder->remotePath() + _newFilename));
connect(propfindJob, &PropfindJob::result, this, &CaseClashFilenameDialog::onRemoteDestinationFileAlreadyExists);
connect(propfindJob, &PropfindJob::finishedWithError, this, &CaseClashFilenameDialog::onRemoteDestinationFileDoesNotExist);
propfindJob->start();
_conflictSolver.solveConflict(_newFilename);
}

void CaseClashFilenameDialog::onFilenameLineEditTextChanged(const QString &text)
Expand All @@ -297,48 +276,4 @@ void CaseClashFilenameDialog::onFilenameLineEditTextChanged(const QString &text)
_ui->buttonBox->button(QDialogButtonBox::Ok)
->setEnabled(isTextValid);
}

void CaseClashFilenameDialog::onMoveJobFinished()
{
const auto job = qobject_cast<MoveJob *>(sender());
const auto error = job->reply()->error();

if (error != QNetworkReply::NoError) {
_ui->errorLabel->setText(tr("Could not rename file. Please make sure you are connected to the server."));
return;
}

Q_EMIT successfulRename(_folder->remotePath() + _newFilename);
QDialog::accept();
}

void CaseClashFilenameDialog::onRemoteDestinationFileAlreadyExists(const QVariantMap &values)
{
Q_UNUSED(values);

_ui->errorLabel->setText(tr("Cannot rename file because a file with the same name does already exist on the server. Please pick another name."));
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
}

void CaseClashFilenameDialog::onRemoteDestinationFileDoesNotExist(QNetworkReply *reply)
{
Q_UNUSED(reply);

const auto propfindJob = new PropfindJob(_account, QDir::cleanPath(_folder->remotePath() + _originalFileName));
connect(propfindJob, &PropfindJob::result, this, &CaseClashFilenameDialog::onRemoteSourceFileAlreadyExists);
connect(propfindJob, &PropfindJob::finishedWithError, this, &QDialog::accept);
propfindJob->start();
}

void CaseClashFilenameDialog::onRemoteSourceFileAlreadyExists(const QVariantMap &values)
{
Q_UNUSED(values);

// Remote source file exists. We need to start MoveJob to rename it
const auto remoteSource = QDir::cleanPath(_folder->remotePath() + _originalFileName);
const auto remoteDestionation = QDir::cleanPath(_account->davUrl().path() + _folder->remotePath() + _newFilename);
const auto moveJob = new MoveJob(_account, remoteSource, remoteDestionation, this);
connect(moveJob, &MoveJob::finishedSignal, this, &CaseClashFilenameDialog::onMoveJobFinished);
moveJob->start();
}
}
39 changes: 17 additions & 22 deletions src/gui/caseclashfilenamedialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#pragma once

#include "accountfwd.h"
#include "caseclashconflictsolver.h"

#include <QDialog>
#include <QLabel>
Expand Down Expand Up @@ -50,37 +51,31 @@ class CaseClashFilenameDialog : public QDialog
signals:
void successfulRename(const QString &filePath);

private slots:
void updateFileWidgetGroup(const QString &filePath,
const QString &linkText,
QLabel *filenameLabel,
QLabel *linkLabel,
QLabel *mtimeLabel,
QLabel *sizeLabel,
QToolButton *button) const;

private:
// Find the conflicting file path
static QString caseClashConflictFile(const QString &conflictFilePath);

std::unique_ptr<Ui::CaseClashFilenameDialog> _ui;
void onFilenameLineEditTextChanged(const QString &text);
void checkIfAllowedToRename();
bool processLeadingOrTrailingSpacesError(const QString &fileName);

std::unique_ptr<Ui::CaseClashFilenameDialog> _ui;
CaseClashConflictSolver _conflictSolver;
AccountPtr _account;
Folder *_folder;
Folder *_folder = nullptr;

QString _filePath;
QString _relativeFilePath;
QString _originalFileName;
QString _newFilename;

void onFilenameLineEditTextChanged(const QString &text);
void onMoveJobFinished();
void onRemoteDestinationFileAlreadyExists(const QVariantMap &values);
void onRemoteDestinationFileDoesNotExist(QNetworkReply *reply);
void onRemoteSourceFileAlreadyExists(const QVariantMap &values);
void checkIfAllowedToRename();
void onCheckIfAllowedToRenameComplete(const QVariantMap &values, QNetworkReply *reply = nullptr);
bool processLeadingOrTrailingSpacesError(const QString &fileName);
void onPropfindPermissionSuccess(const QVariantMap &values);
void onPropfindPermissionError(QNetworkReply *reply = nullptr);

private slots:
void updateFileWidgetGroup(const QString &filePath,
const QString &linkText,
QLabel *filenameLabel,
QLabel *linkLabel,
QLabel *mtimeLabel,
QLabel *sizeLabel,
QToolButton *button) const;
};
}
2 changes: 2 additions & 0 deletions src/libsync/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ set(libsync_SRCS
creds/credentialscommon.cpp
creds/keychainchunk.h
creds/keychainchunk.cpp
caseclashconflictsolver.h
caseclashconflictsolver.cpp
)

if (WIN32)
Expand Down
Loading

0 comments on commit f4f2987

Please sign in to comment.