mirror of
https://github.com/nextcloud/desktop.git
synced 2024-10-25 05:45:42 +03:00
Refactor edit locally into its own class, rather than bolting onto FolderMan
Signed-off-by: Claudio Cambra <claudio.cambra@nextcloud.com>
This commit is contained in:
parent
224621bb85
commit
9a00aa6e66
6 changed files with 353 additions and 252 deletions
|
@ -81,6 +81,8 @@ set(client_SRCS
|
|||
conflictsolver.cpp
|
||||
connectionvalidator.h
|
||||
connectionvalidator.cpp
|
||||
editlocallyhandler.h
|
||||
editlocallyhandler.cpp
|
||||
folder.h
|
||||
folder.cpp
|
||||
foldercreationdialog.h
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "config.h"
|
||||
#include "account.h"
|
||||
#include "accountstate.h"
|
||||
#include "editlocallyhandler.h"
|
||||
#include "connectionvalidator.h"
|
||||
#include "folder.h"
|
||||
#include "folderman.h"
|
||||
|
@ -774,7 +775,14 @@ void Application::handleEditLocally(const QUrl &url) const
|
|||
qCWarning(lcApplication) << "Invalid URL for file local editing: missing token";
|
||||
}
|
||||
|
||||
FolderMan::instance()->editFileLocally(userId, fileRemotePath, token);
|
||||
// We need to make sure the handler sticks around until it is finished
|
||||
const auto editLocallyHandler = new EditLocallyHandler(userId, fileRemotePath, token);
|
||||
if (editLocallyHandler->ready()) {
|
||||
connect(editLocallyHandler, &EditLocallyHandler::finished, this, [&editLocallyHandler] { delete editLocallyHandler; });
|
||||
editLocallyHandler->startEditLocally();
|
||||
} else {
|
||||
delete editLocallyHandler;
|
||||
}
|
||||
}
|
||||
|
||||
QString substLang(const QString &lang)
|
||||
|
|
271
src/gui/editlocallyhandler.cpp
Normal file
271
src/gui/editlocallyhandler.cpp
Normal file
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* Copyright (C) by Claudio Cambra <claudio.cambra@nextcloud.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "editlocallyhandler.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QDesktopServices>
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include "accountmanager.h"
|
||||
#include "folder.h"
|
||||
#include "folderman.h"
|
||||
#include "syncengine.h"
|
||||
#include "systray.h"
|
||||
|
||||
namespace OCC {
|
||||
|
||||
Q_LOGGING_CATEGORY(lcEditLocallyHandler, "nextcloud.gui.editlocallyhandler", QtInfoMsg)
|
||||
|
||||
static QHash<QString, QMetaObject::Connection> editLocallySyncFinishedConnections;
|
||||
|
||||
EditLocallyHandler::EditLocallyHandler(const QString &userId,
|
||||
const QString &relPath,
|
||||
const QString &token,
|
||||
QObject *parent)
|
||||
: QObject{parent}
|
||||
, _relPath(relPath)
|
||||
, _token(token)
|
||||
{
|
||||
_accountState = AccountManager::instance()->accountFromUserId(userId);
|
||||
|
||||
if (!_accountState) {
|
||||
qCWarning(lcEditLocallyHandler) << "Could not find an account " << userId << " to edit file " << relPath << " locally.";
|
||||
showError(tr("Could not find an account for local editing"), userId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isTokenValid(token)) {
|
||||
qCWarning(lcEditLocallyHandler) << "Edit locally request is missing a valid token, will not open file. Token received was:" << token;
|
||||
showError(tr("Invalid token received."), tr("Please try again."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isRelPathValid(relPath)) {
|
||||
qCWarning(lcEditLocallyHandler) << "Provided relPath was:" << relPath << "which is not canonical.";
|
||||
showError(tr("Invalid file path was provided."), tr("Please try again."));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto foundFiles = FolderMan::instance()->findFileInLocalFolders(relPath, _accountState->account());
|
||||
|
||||
if (foundFiles.isEmpty()) {
|
||||
if (isRelPathExcluded(relPath)) {
|
||||
showError(tr("Could not find a file for local editing. Make sure it is not excluded via selective sync."), relPath);
|
||||
} else {
|
||||
showError(tr("Could not find a file for local editing. Make sure its path is valid and it is synced locally."), relPath);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_localFilePath = foundFiles.first();
|
||||
_folderForFile = FolderMan::instance()->folderForPath(_localFilePath);
|
||||
|
||||
if (!_folderForFile) {
|
||||
showError(tr("Could not find a folder to sync."), relPath);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto relPathSplit = relPath.split(QLatin1Char('/'));
|
||||
if (relPathSplit.size() == 0) {
|
||||
showError(tr("Could not find a file for local editing. Make sure its path is valid and it is synced locally."), relPath);
|
||||
return;
|
||||
}
|
||||
|
||||
_fileName = relPathSplit.last();
|
||||
|
||||
_ready = true;
|
||||
}
|
||||
|
||||
bool EditLocallyHandler::ready() const
|
||||
{
|
||||
return _ready;
|
||||
}
|
||||
|
||||
QString EditLocallyHandler::prefixSlashToPath(const QString &path)
|
||||
{
|
||||
auto slashPrefixedPath = path;
|
||||
if (!slashPrefixedPath.startsWith('/')) {
|
||||
slashPrefixedPath.prepend('/');
|
||||
}
|
||||
|
||||
return slashPrefixedPath;
|
||||
}
|
||||
|
||||
bool EditLocallyHandler::isTokenValid(const QString &token)
|
||||
{
|
||||
if (token.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Token is an alphanumeric string 128 chars long.
|
||||
// Ensure that is what we received and what we are sending to the server.
|
||||
const QRegularExpression tokenRegex("^[a-zA-Z0-9]{128}$");
|
||||
const auto regexMatch = tokenRegex.match(token);
|
||||
|
||||
// Means invalid token type received, be cautious with bad token
|
||||
if(!regexMatch.hasMatch()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EditLocallyHandler::isRelPathValid(const QString &relPath)
|
||||
{
|
||||
if (relPath.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We want to check that the path is canonical and not relative
|
||||
// (i.e. that it doesn't contain ../../) but we always receive
|
||||
// a relative path, so let's make it absolute by prepending a
|
||||
// slash
|
||||
const auto slashPrefixedPath = prefixSlashToPath(relPath);
|
||||
|
||||
// Let's check that the filepath is canonical, and that the request
|
||||
// contains no funny behaviour regarding paths
|
||||
const auto cleanedPath = QDir::cleanPath(slashPrefixedPath);
|
||||
|
||||
if (cleanedPath != slashPrefixedPath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EditLocallyHandler::isRelPathExcluded(const QString &relPath)
|
||||
{
|
||||
if (relPath.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto folderMap = FolderMan::instance()->map();
|
||||
for (const auto &folder : folderMap) {
|
||||
bool result = false;
|
||||
const auto excludedThroughSelectiveSync = folder->journalDb()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &result);
|
||||
for (const auto &excludedPath : excludedThroughSelectiveSync) {
|
||||
if (relPath.startsWith(excludedPath)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void EditLocallyHandler::showError(const QString &message, const QString &informativeText) const
|
||||
{
|
||||
showErrorNotification(message, informativeText);
|
||||
// to make sure the error is not missed, show a message box in addition
|
||||
showErrorMessageBox(message, informativeText);
|
||||
}
|
||||
|
||||
void EditLocallyHandler::showErrorNotification(const QString &message, const QString &informativeText) const
|
||||
{
|
||||
if (!_accountState || !_accountState->account()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto folderMap = FolderMan::instance()->map();
|
||||
const auto foundFolder = std::find_if(folderMap.cbegin(), folderMap.cend(), [this](const auto &folder) {
|
||||
return _accountState->account()->davUrl() == folder->remoteUrl();
|
||||
});
|
||||
|
||||
if (foundFolder != folderMap.cend()) {
|
||||
(*foundFolder)->syncEngine().addErrorToGui(SyncFileItem::SoftError, message, informativeText);
|
||||
}
|
||||
}
|
||||
|
||||
void EditLocallyHandler::showErrorMessageBox(const QString &message, const QString &informativeText) const
|
||||
{
|
||||
const auto messageBox = new QMessageBox;
|
||||
messageBox->setAttribute(Qt::WA_DeleteOnClose);
|
||||
messageBox->setText(message);
|
||||
messageBox->setInformativeText(informativeText);
|
||||
messageBox->setIcon(QMessageBox::Warning);
|
||||
messageBox->addButton(QMessageBox::StandardButton::Ok);
|
||||
messageBox->show();
|
||||
messageBox->activateWindow();
|
||||
messageBox->raise();
|
||||
}
|
||||
|
||||
void EditLocallyHandler::startEditLocally()
|
||||
{
|
||||
if (!_ready) {
|
||||
return;
|
||||
}
|
||||
|
||||
Systray::instance()->createEditFileLocallyLoadingDialog(_fileName);
|
||||
|
||||
const auto encodedToken = QString::fromUtf8(QUrl::toPercentEncoding(_token)); // Sanitise the token
|
||||
const auto encodedRelPath = QUrl::toPercentEncoding(_relPath); // Sanitise the relPath
|
||||
const auto checkEditLocallyToken = new SimpleApiJob(_accountState->account(), QStringLiteral("/ocs/v2.php/apps/files/api/v1/openlocaleditor/%1").arg(encodedToken));
|
||||
|
||||
QUrlQuery params;
|
||||
params.addQueryItem(QStringLiteral("path"), prefixSlashToPath(_relPath));
|
||||
checkEditLocallyToken->addQueryParams(params);
|
||||
checkEditLocallyToken->setVerb(SimpleApiJob::Verb::Post);
|
||||
connect(checkEditLocallyToken, &SimpleApiJob::resultReceived, this, &EditLocallyHandler::remoteTokenCheckFinished);
|
||||
|
||||
checkEditLocallyToken->start();
|
||||
}
|
||||
|
||||
void EditLocallyHandler::remoteTokenCheckFinished(const int statusCode)
|
||||
{
|
||||
constexpr auto HTTP_OK_CODE = 200;
|
||||
if (statusCode != HTTP_OK_CODE) {
|
||||
Systray::instance()->destroyEditFileLocallyLoadingDialog();
|
||||
|
||||
showError(tr("Could not validate the request to open a file from server."), _relPath);
|
||||
qCInfo(lcEditLocallyHandler) << "token check result" << statusCode;
|
||||
return;
|
||||
}
|
||||
|
||||
_folderForFile->startSync();
|
||||
const auto syncFinishedConnection = connect(_folderForFile, &Folder::syncFinished,
|
||||
this, &EditLocallyHandler::folderSyncFinished);
|
||||
editLocallySyncFinishedConnections.insert(_localFilePath, syncFinishedConnection);
|
||||
}
|
||||
|
||||
void EditLocallyHandler::folderSyncFinished(const OCC::SyncResult &result)
|
||||
{
|
||||
Q_UNUSED(result)
|
||||
disconnectSyncFinished();
|
||||
openFile();
|
||||
}
|
||||
|
||||
void EditLocallyHandler::disconnectSyncFinished() const
|
||||
{
|
||||
if (const auto existingConnection = editLocallySyncFinishedConnections.value(_localFilePath)) {
|
||||
disconnect(existingConnection);
|
||||
editLocallySyncFinishedConnections.remove(_localFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
void EditLocallyHandler::openFile()
|
||||
{
|
||||
const auto localFilePath = _localFilePath;
|
||||
// In case the VFS mode is enabled and a file is not yet hydrated, we must call QDesktopServices::openUrl
|
||||
// from a separate thread, or, there will be a freeze. To avoid searching for a specific folder and checking
|
||||
// if the VFS is enabled - we just always call it from a separate thread.
|
||||
QtConcurrent::run([localFilePath]() {
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(localFilePath));
|
||||
Systray::instance()->destroyEditFileLocallyLoadingDialog();
|
||||
});
|
||||
|
||||
Q_EMIT finished();
|
||||
}
|
||||
|
||||
}
|
71
src/gui/editlocallyhandler.h
Normal file
71
src/gui/editlocallyhandler.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (C) by Claudio Cambra <claudio.cambra@nextcloud.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "accountmanager.h"
|
||||
#include "folder.h"
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class EditLocallyHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EditLocallyHandler(const QString &userId,
|
||||
const QString &relPath,
|
||||
const QString &token,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
[[nodiscard]] static bool isTokenValid(const QString &token);
|
||||
[[nodiscard]] static bool isRelPathValid(const QString &relPath);
|
||||
[[nodiscard]] static bool isRelPathExcluded(const QString &relPath);
|
||||
[[nodiscard]] static QString prefixSlashToPath(const QString &path);
|
||||
|
||||
[[nodiscard]] bool ready() const;
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
public slots:
|
||||
void startEditLocally();
|
||||
void startTokenRemoteCheck();
|
||||
|
||||
private slots:
|
||||
void showError(const QString &message, const QString &informativeText) const;
|
||||
void showErrorNotification(const QString &message, const QString &informativeText) const;
|
||||
void showErrorMessageBox(const QString &message, const QString &informativeText) const;
|
||||
|
||||
void remoteTokenCheckFinished(const int statusCode);
|
||||
void folderSyncFinished(const OCC::SyncResult &result);
|
||||
|
||||
void disconnectSyncFinished() const;
|
||||
void openFile();
|
||||
|
||||
private:
|
||||
bool _ready = false;
|
||||
|
||||
AccountStatePtr _accountState;
|
||||
QString _relPath;
|
||||
QString _token;
|
||||
|
||||
QString _fileName;
|
||||
QString _localFilePath;
|
||||
Folder *_folderForFile = nullptr;
|
||||
};
|
||||
|
||||
}
|
|
@ -36,8 +36,6 @@
|
|||
#include <QMutableSetIterator>
|
||||
#include <QSet>
|
||||
#include <QNetworkProxy>
|
||||
#include <QDesktopServices>
|
||||
#include <QtConcurrent>
|
||||
|
||||
static const char versionC[] = "version";
|
||||
static const int maxFoldersVersion = 1;
|
||||
|
@ -1437,224 +1435,6 @@ void FolderMan::setDirtyNetworkLimits()
|
|||
}
|
||||
}
|
||||
|
||||
void FolderMan::editFileLocally(const QString &userId, const QString &relPath, const QString &token)
|
||||
{
|
||||
const auto accountFound = AccountManager::instance()->accountFromUserId(userId);
|
||||
|
||||
if (!accountFound) {
|
||||
qCWarning(lcFolderMan) << "Could not find an account " << userId << " to edit file " << relPath << " locally.";
|
||||
showEditLocallyError(accountFound, tr("Could not find an account for local editing"), userId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isEditLocallyTokenValid(token)) {
|
||||
qCWarning(lcFolderMan) << "Edit locally request is missing a valid token, will not open file. Token received was:" << token;
|
||||
showEditLocallyError(accountFound, tr("Invalid token received."), tr("Please try again."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isEditLocallyRelPathValid(relPath)) {
|
||||
qCWarning(lcFolderMan) << "Provided relPath was:" << relPath << "which is not canonical.";
|
||||
showEditLocallyError(accountFound, tr("Invalid file path was provided."), tr("Please try again."));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto foundFiles = findFileInLocalFolders(relPath, accountFound->account());
|
||||
|
||||
if (foundFiles.isEmpty()) {
|
||||
if (isEditLocallyRelPathExcluded(relPath)) {
|
||||
showEditLocallyError(accountFound, tr("Could not find a file for local editing. Make sure it is not excluded via selective sync."), relPath);
|
||||
} else {
|
||||
showEditLocallyError(accountFound, tr("Could not find a file for local editing. Make sure its path is valid and it is synced locally."), relPath);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const auto localFilePath = foundFiles.first();
|
||||
const auto folderForFile = folderForPath(localFilePath);
|
||||
|
||||
if (!folderForFile) {
|
||||
showEditLocallyError(accountFound, tr("Could not find a folder to sync."), relPath);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto relPathSplit = relPath.split(QLatin1Char('/'));
|
||||
if (relPathSplit.size() == 0) {
|
||||
showEditLocallyError(accountFound, tr("Could not find a file for local editing. Make sure its path is valid and it is synced locally."), relPath);
|
||||
return;
|
||||
}
|
||||
|
||||
startEditLocally(accountFound, relPath, token, relPathSplit.last(), localFilePath, folderForFile);
|
||||
}
|
||||
|
||||
bool FolderMan::isEditLocallyTokenValid(const QString &token) const
|
||||
{
|
||||
if (token.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Token is an alphanumeric string 128 chars long.
|
||||
// Ensure that is what we received and what we are sending to the server.
|
||||
const QRegularExpression tokenRegex("^[a-zA-Z0-9]{128}$");
|
||||
const auto regexMatch = tokenRegex.match(token);
|
||||
|
||||
// Means invalid token type received, be cautious with bad token
|
||||
if(!regexMatch.hasMatch()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FolderMan::isEditLocallyRelPathValid(const QString &relPath) const
|
||||
{
|
||||
if (relPath.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We want to check that the path is canonical and not relative
|
||||
// (i.e. that it doesn't contain ../../) but we always receive
|
||||
// a relative path, so let's make it absolute by prepending a
|
||||
// slash
|
||||
|
||||
auto slashPrefixedPath = relPath;
|
||||
if (!slashPrefixedPath.startsWith('/')) {
|
||||
slashPrefixedPath.prepend('/');
|
||||
}
|
||||
|
||||
// Let's check that the filepath is canonical, and that the request
|
||||
// contains no funny behaviour regarding paths
|
||||
const auto cleanedPath = QDir::cleanPath(slashPrefixedPath);
|
||||
|
||||
if (cleanedPath != slashPrefixedPath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FolderMan::isEditLocallyRelPathExcluded(const QString &relPath) const
|
||||
{
|
||||
if (relPath.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto &folder : map()) {
|
||||
bool result = false;
|
||||
const auto excludedThroughSelectiveSync = folder->journalDb()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &result);
|
||||
for (const auto &excludedPath : excludedThroughSelectiveSync) {
|
||||
if (relPath.startsWith(excludedPath)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FolderMan::showEditLocallyError(const AccountStatePtr &accountState, const QString &message, const QString &informativeText) const
|
||||
{
|
||||
showEditLocallyErrorNotification(accountState, message, informativeText);
|
||||
// to make sure the error is not missed, show a message box in addition
|
||||
showEditLocallyErrorMessageBox(message, informativeText);
|
||||
}
|
||||
|
||||
void FolderMan::showEditLocallyErrorNotification(const AccountStatePtr &accountState, const QString &message, const QString &informativeText) const
|
||||
{
|
||||
if (accountState && accountState->account()) {
|
||||
const auto foundFolder = std::find_if(std::cbegin(map()), std::cend(map()), [accountState](const auto &folder) {
|
||||
return accountState->account()->davUrl() == folder->remoteUrl();
|
||||
});
|
||||
|
||||
if (foundFolder != std::cend(map())) {
|
||||
(*foundFolder)->syncEngine().addErrorToGui(SyncFileItem::SoftError, message, informativeText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FolderMan::showEditLocallyErrorMessageBox(const QString &message, const QString &informativeText) const
|
||||
{
|
||||
const auto messageBox = new QMessageBox;
|
||||
messageBox->setAttribute(Qt::WA_DeleteOnClose);
|
||||
messageBox->setText(message);
|
||||
messageBox->setInformativeText(informativeText);
|
||||
messageBox->setIcon(QMessageBox::Warning);
|
||||
messageBox->addButton(QMessageBox::StandardButton::Ok);
|
||||
messageBox->show();
|
||||
messageBox->activateWindow();
|
||||
messageBox->raise();
|
||||
}
|
||||
|
||||
void FolderMan::startEditLocally(const AccountStatePtr &accountState,
|
||||
const QString &relPath,
|
||||
const QString &token,
|
||||
const QString &fileName,
|
||||
const QString &localFilePath,
|
||||
Folder *folderForFile)
|
||||
{
|
||||
Systray::instance()->createEditFileLocallyLoadingDialog(fileName);
|
||||
|
||||
const auto encodedToken = QString::fromUtf8(QUrl::toPercentEncoding(token)); // Sanitise the token
|
||||
const auto encodedRelPath = QUrl::toPercentEncoding(relPath); // Sanitise the relPath
|
||||
const auto checkEditLocallyToken = new SimpleApiJob(accountState->account(), QStringLiteral("/ocs/v2.php/apps/files/api/v1/openlocaleditor/%1").arg(encodedToken));
|
||||
|
||||
QUrlQuery params;
|
||||
params.addQueryItem(QStringLiteral("path"), QString{"/" + relPath});
|
||||
checkEditLocallyToken->addQueryParams(params);
|
||||
|
||||
connect(checkEditLocallyToken, &SimpleApiJob::resultReceived, checkEditLocallyToken, [this, folderForFile, localFilePath, accountState, relPath] (int statusCode) {
|
||||
editLocallyTokenCheckFinished(accountState, relPath, localFilePath, folderForFile, statusCode);
|
||||
});
|
||||
checkEditLocallyToken->start();
|
||||
}
|
||||
|
||||
void FolderMan::editLocallyTokenCheckFinished(const AccountStatePtr &accountState,
|
||||
const QString &relPath,
|
||||
const QString &localFilePath,
|
||||
Folder *folderForFile,
|
||||
const int statusCode)
|
||||
{
|
||||
constexpr auto HTTP_OK_CODE = 200;
|
||||
if (statusCode != HTTP_OK_CODE) {
|
||||
Systray::instance()->destroyEditFileLocallyLoadingDialog();
|
||||
showEditLocallyError(accountState, tr("Could not validate the request to open a file from server."), relPath);
|
||||
qCInfo(lcFolderMan()) << "token check result" << statusCode;
|
||||
return;
|
||||
}
|
||||
|
||||
folderForFile->startSync();
|
||||
const auto syncFinishedConnection = connect(folderForFile, &Folder::syncFinished, this, [this, localFilePath](const OCC::SyncResult &result) {
|
||||
Q_UNUSED(result);
|
||||
editLocallyFolderSyncFinished(localFilePath);
|
||||
});
|
||||
_editLocallySyncFinishedConnections.insert(localFilePath, syncFinishedConnection);
|
||||
}
|
||||
|
||||
void FolderMan::editLocallyFolderSyncFinished(const QString &localFilePath)
|
||||
{
|
||||
disconnectEditLocallySyncFinishedConnections(localFilePath);
|
||||
openEditLocallyFile(localFilePath);
|
||||
}
|
||||
|
||||
void FolderMan::disconnectEditLocallySyncFinishedConnections(const QString &localFilePath)
|
||||
{
|
||||
if (const auto existingConnection = _editLocallySyncFinishedConnections.value(localFilePath)) {
|
||||
disconnect(existingConnection);
|
||||
_editLocallySyncFinishedConnections.remove(localFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
void FolderMan::openEditLocallyFile(const QString &localFilePath) const
|
||||
{
|
||||
// In case the VFS mode is enabled and a file is not yet hydrated, we must call QDesktopServices::openUrl
|
||||
// from a separate thread, or, there will be a freeze. To avoid searching for a specific folder and checking
|
||||
// if the VFS is enabled - we just always call it from a separate thread.
|
||||
QtConcurrent::run([localFilePath]() {
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(localFilePath));
|
||||
Systray::instance()->destroyEditFileLocallyLoadingDialog();
|
||||
});
|
||||
}
|
||||
|
||||
void FolderMan::trayOverallStatus(const QList<Folder *> &folders,
|
||||
SyncResult::Status *status, bool *unresolvedConflicts)
|
||||
{
|
||||
|
|
|
@ -213,9 +213,6 @@ public:
|
|||
void setDirtyProxy();
|
||||
void setDirtyNetworkLimits();
|
||||
|
||||
/** opens a file with default app, if the file is present **/
|
||||
void editFileLocally(const QString &userId, const QString &relPath, const QString &token);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* signal to indicate a folder has changed its sync state.
|
||||
|
@ -311,27 +308,6 @@ private slots:
|
|||
void slotProcessFilesPushNotification(Account *account);
|
||||
void slotConnectToPushNotifications(Account *account);
|
||||
|
||||
void showEditLocallyError(const AccountStatePtr &accountState, const QString &message, const QString &informativeText) const;
|
||||
void showEditLocallyErrorNotification(const AccountStatePtr &accountState, const QString &message, const QString &informativeText) const;
|
||||
void showEditLocallyErrorMessageBox(const QString &message, const QString &informativeText) const;
|
||||
|
||||
void startEditLocally(const AccountStatePtr &accountState,
|
||||
const QString &relPath,
|
||||
const QString &token,
|
||||
const QString &fileName,
|
||||
const QString &localFilePath,
|
||||
Folder *folderForFile);
|
||||
|
||||
void editLocallyTokenCheckFinished(const AccountStatePtr &accountState,
|
||||
const QString &relPath,
|
||||
const QString &localFilePath,
|
||||
Folder *folderForFile,
|
||||
const int statusCode);
|
||||
|
||||
void disconnectEditLocallySyncFinishedConnections(const QString &localFilePath);
|
||||
void editLocallyFolderSyncFinished(const QString &localFilePath);
|
||||
void openEditLocallyFile(const QString &localFilePath) const;
|
||||
|
||||
private:
|
||||
/** Adds a new folder, does not add it to the account settings and
|
||||
* does not set an account on the new folder.
|
||||
|
@ -364,11 +340,6 @@ private:
|
|||
|
||||
[[nodiscard]] bool isSwitchToVfsNeeded(const FolderDefinition &folderDefinition) const;
|
||||
|
||||
[[nodiscard]] bool isEditLocallyTokenValid(const QString &token) const;
|
||||
[[nodiscard]] bool isEditLocallyRelPathValid(const QString &relPath) const;
|
||||
[[nodiscard]] bool isEditLocallyRelPathExcluded(const QString &relPath) const;
|
||||
[[nodiscard]] bool editLocallyAccount(const AccountStatePtr &acountState) const;
|
||||
|
||||
QSet<Folder *> _disabledFolders;
|
||||
Folder::Map _folderMap;
|
||||
QString _folderConfigPath;
|
||||
|
@ -403,8 +374,6 @@ private:
|
|||
|
||||
bool _appRestartRequired = false;
|
||||
|
||||
QHash<QString, QMetaObject::Connection> _editLocallySyncFinishedConnections;
|
||||
|
||||
static FolderMan *_instance;
|
||||
explicit FolderMan(QObject *parent = nullptr);
|
||||
friend class OCC::Application;
|
||||
|
|
Loading…
Reference in a new issue