Merge pull request #6347 from nextcloud/feature/filelocking-keep-user-lock

Feature/filelocking keep user lock
This commit is contained in:
allexzander 2024-01-18 20:30:42 +01:00 committed by GitHub
commit 8bb36566c7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 70 additions and 24 deletions

View file

@ -650,7 +650,8 @@ void EditLocallyJob::lockFile()
_folderForFile->remotePathTrailingSlash(),
_folderForFile->path(),
_folderForFile->journalDb(),
SyncFileItem::LockStatus::LockedItem);
SyncFileItem::LockStatus::LockedItem,
SyncFileItem::LockOwnerType::TokenLock);
}
void EditLocallyJob::disconnectFolderSignals()

View file

@ -649,7 +649,7 @@ void Folder::slotFilesLockReleased(const QSet<QString> &files)
}
const auto canUnlockFile = isFileRecordValid
&& rec._lockstate._locked
&& rec._lockstate._lockOwnerType == static_cast<qint64>(SyncFileItem::LockOwnerType::UserLock)
&& rec._lockstate._lockOwnerType == static_cast<qint64>(SyncFileItem::LockOwnerType::TokenLock)
&& rec._lockstate._lockOwnerId == _accountState->account()->davUser();
if (!canUnlockFile) {
@ -668,11 +668,13 @@ void Folder::slotFilesLockReleased(const QSet<QString> &files)
disconnect(_officeFileLockReleaseUnlockFailure);
qCWarning(lcFolder) << "Failed to unlock a file:" << remoteFilePath << message;
});
const auto lockOwnerType = static_cast<SyncFileItem::LockOwnerType>(rec._lockstate._lockOwnerType);
_accountState->account()->setLockFileState(remoteFilePath,
remotePathTrailingSlash(),
path(),
journalDb(),
SyncFileItem::LockStatus::UnlockedItem);
SyncFileItem::LockStatus::UnlockedItem,
lockOwnerType);
}
}
@ -719,7 +721,8 @@ void Folder::slotLockedFilesFound(const QSet<QString> &files)
remotePathTrailingSlash(),
path(),
journalDb(),
SyncFileItem::LockStatus::LockedItem);
SyncFileItem::LockStatus::LockedItem,
SyncFileItem::LockOwnerType::TokenLock);
}
}

View file

@ -1091,11 +1091,18 @@ void SocketApi::setFileLock(const QString &localFile, const SyncFileItem::LockSt
return;
}
const auto record = fileData.journalRecord();
if (static_cast<SyncFileItem::LockOwnerType>(record._lockstate._lockOwnerType) != SyncFileItem::LockOwnerType::UserLock) {
qCDebug(lcSocketApi) << "Only user lock state or non-locked files can be affected manually!";
return;
}
shareFolder->accountState()->account()->setLockFileState(fileData.serverRelativePath,
shareFolder->remotePathTrailingSlash(),
shareFolder->path(),
shareFolder->journalDb(),
lockState);
lockState,
SyncFileItem::LockOwnerType::UserLock);
shareFolder->journalDb()->schedulePathForRemoteDiscovery(fileData.serverRelativePath);
shareFolder->scheduleThisFolderSoon();

View file

@ -959,7 +959,8 @@ void Account::setLockFileState(const QString &serverRelativePath,
const QString &remoteSyncPathWithTrailingSlash,
const QString &localSyncPath,
SyncJournalDb * const journal,
const SyncFileItem::LockStatus lockStatus)
const SyncFileItem::LockStatus lockStatus,
const SyncFileItem::LockOwnerType lockOwnerType)
{
auto& lockStatusJobInProgress = _lockStatusChangeInprogress[serverRelativePath];
if (lockStatusJobInProgress.contains(lockStatus)) {
@ -967,7 +968,7 @@ void Account::setLockFileState(const QString &serverRelativePath,
return;
}
lockStatusJobInProgress.push_back(lockStatus);
auto job = std::make_unique<LockFileJob>(sharedFromThis(), journal, serverRelativePath, remoteSyncPathWithTrailingSlash, localSyncPath, lockStatus);
auto job = std::make_unique<LockFileJob>(sharedFromThis(), journal, serverRelativePath, remoteSyncPathWithTrailingSlash, localSyncPath, lockStatus, lockOwnerType);
connect(job.get(), &LockFileJob::finishedWithoutError, this, [this, serverRelativePath, lockStatus]() {
removeLockStatusChangeInprogress(serverRelativePath, lockStatus);
Q_EMIT lockFileSuccess();

View file

@ -316,7 +316,8 @@ public:
const QString &remoteSyncPathWithTrailingSlash,
const QString &localSyncPath,
SyncJournalDb * const journal,
const SyncFileItem::LockStatus lockStatus);
const SyncFileItem::LockStatus lockStatus,
const SyncFileItem::LockOwnerType lockOwnerType);
SyncFileItem::LockStatus fileLockStatus(SyncJournalDb * const journal,
const QString &folderRelativePath) const;

View file

@ -254,6 +254,11 @@ bool Capabilities::filesLockAvailable() const
return _capabilities["files"].toMap()["locking"].toByteArray() >= "1.0";
}
bool Capabilities::filesLockTypeAvailable() const
{
return _capabilities["files"].toMap()["api-feature-lock-type"].toByteArray() >= "1.0";
}
bool Capabilities::userStatus() const
{
if (!_capabilities.contains("user_status")) {

View file

@ -66,6 +66,7 @@ public:
[[nodiscard]] bool chunkingNg() const;
[[nodiscard]] bool bulkUpload() const;
[[nodiscard]] bool filesLockAvailable() const;
[[nodiscard]] bool filesLockTypeAvailable() const;
[[nodiscard]] bool userStatus() const;
[[nodiscard]] bool userStatusSupportsEmoji() const;
[[nodiscard]] QColor serverColor() const;

View file

@ -31,10 +31,12 @@ LockFileJob::LockFileJob(const AccountPtr account,
const QString &remoteSyncPathWithTrailingSlash,
const QString &localSyncPath,
const SyncFileItem::LockStatus requestedLockState,
const SyncFileItem::LockOwnerType lockOwnerType,
QObject *parent)
: AbstractNetworkJob(account, path, parent)
, _journal(journal)
, _requestedLockState(requestedLockState)
, _requestedLockOwnerType(lockOwnerType)
, _remoteSyncPathWithTrailingSlash(remoteSyncPathWithTrailingSlash)
, _localSyncPath(localSyncPath)
{
@ -48,7 +50,14 @@ void LockFileJob::start()
qCInfo(lcLockFileJob()) << "start" << path() << _requestedLockState;
QNetworkRequest request;
request.setRawHeader("X-User-Lock", "1");
request.setRawHeader(QByteArrayLiteral("X-User-Lock"), QByteArrayLiteral("1"));
if (_account->capabilities().filesLockTypeAvailable()) {
if (_requestedLockOwnerType == SyncFileItem::LockOwnerType::UserLock) {
request.setRawHeader(QByteArrayLiteral("X-User-Lock-Type"), ("0"));
} else if (_requestedLockOwnerType == SyncFileItem::LockOwnerType::TokenLock) {
request.setRawHeader(QByteArrayLiteral("X-User-Lock-Type"), ("2"));
}
}
QByteArray verb;
switch(_requestedLockState)
@ -174,7 +183,7 @@ SyncJournalFileRecord LockFileJob::handleReply()
if (_journal->getFileRecord(relativePathInDb, &record) && record.isValid()) {
setFileRecordLocked(record);
if ((_lockStatus == SyncFileItem::LockStatus::LockedItem)
&& (_lockOwnerType != SyncFileItem::LockOwnerType::UserLock || _userId != account()->davUser())) {
&& (_lockOwnerType == SyncFileItem::LockOwnerType::AppLock || _userId != account()->davUser())) {
FileSystem::setFileReadOnly(_localSyncPath + relativePathInDb, true);
}
const auto result = _journal->setFileRecord(record);
@ -205,6 +214,8 @@ void LockFileJob::decodeStartElement(const QString &name,
const auto convertedValue = valueText.toInt(&isValid);
if (isValid) {
_lockOwnerType = static_cast<SyncFileItem::LockOwnerType>(convertedValue);
} else {
_lockOwnerType = SyncFileItem::LockOwnerType::UserLock;
}
} else if (name == QStringLiteral("lock-owner-displayname")) {
_userDisplayName = reader.readElementText();

View file

@ -25,6 +25,7 @@ public:
const QString &remoteSyncPathWithTrailingSlash,
const QString &localSyncPath,
const SyncFileItem::LockStatus requestedLockState,
const SyncFileItem::LockOwnerType lockOwnerType,
QObject *parent = nullptr);
void start() override;
@ -48,6 +49,7 @@ private:
SyncJournalDb* _journal = nullptr;
SyncFileItem::LockStatus _requestedLockState = SyncFileItem::LockStatus::LockedItem;
SyncFileItem::LockOwnerType _requestedLockOwnerType = SyncFileItem::LockOwnerType::UserLock;
SyncFileItem::LockStatus _lockStatus = SyncFileItem::LockStatus::UnlockedItem;
SyncFileItem::LockOwnerType _lockOwnerType = SyncFileItem::LockOwnerType::UserLock;

View file

@ -40,7 +40,8 @@ private slots:
QStringLiteral("/"),
fakeFolder.localPath(),
&fakeFolder.syncJournal(),
OCC::SyncFileItem::LockStatus::LockedItem);
OCC::SyncFileItem::LockStatus::LockedItem,
OCC::SyncFileItem::LockOwnerType::UserLock);
QVERIFY(lockFileSuccessSpy.wait());
QCOMPARE(lockFileErrorSpy.count(), 0);
@ -85,7 +86,8 @@ private slots:
QStringLiteral("/"),
fakeFolder.localPath(),
&fakeFolder.syncJournal(),
OCC::SyncFileItem::LockStatus::LockedItem);
OCC::SyncFileItem::LockStatus::LockedItem,
OCC::SyncFileItem::LockOwnerType::UserLock);
QVERIFY(lockFileErrorSpy.wait());
QCOMPARE(lockFileSuccessSpy.count(), 0);
@ -109,7 +111,8 @@ private slots:
QStringLiteral("/"),
fakeFolder.localPath(),
&fakeFolder.syncJournal(),
OCC::SyncFileItem::LockStatus::LockedItem);
OCC::SyncFileItem::LockStatus::LockedItem,
OCC::SyncFileItem::LockOwnerType::UserLock);
QVERIFY(lockFileSuccessSpy.wait());
QCOMPARE(lockFileErrorSpy.count(), 0);
@ -136,7 +139,8 @@ private slots:
QStringLiteral("/"),
fakeFolder.localPath(),
&fakeFolder.syncJournal(),
OCC::SyncFileItem::LockStatus::LockedItem);
OCC::SyncFileItem::LockStatus::LockedItem,
OCC::SyncFileItem::LockOwnerType::UserLock);
QVERIFY(lockFileSuccessSpy.wait());
QCOMPARE(lockFileErrorSpy.count(), 0);
@ -160,7 +164,8 @@ private slots:
QStringLiteral("/") + testFileName,
QStringLiteral("/"),
fakeFolder.localPath(),
OCC::SyncFileItem::LockStatus::LockedItem);
OCC::SyncFileItem::LockStatus::LockedItem,
OCC::SyncFileItem::LockOwnerType::UserLock);
QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
@ -198,7 +203,8 @@ private slots:
QStringLiteral("/") + testFileName,
QStringLiteral("/"),
fakeFolder.localPath(),
OCC::SyncFileItem::LockStatus::LockedItem);
OCC::SyncFileItem::LockStatus::LockedItem,
OCC::SyncFileItem::LockOwnerType::UserLock);
QSignalSpy lockFileJobSuccess(lockFileJob, &OCC::LockFileJob::finishedWithoutError);
QSignalSpy lockFileJobFailure(lockFileJob, &OCC::LockFileJob::finishedWithError);
@ -215,7 +221,8 @@ private slots:
QStringLiteral("/") + testFileName,
QStringLiteral("/"),
fakeFolder.localPath(),
OCC::SyncFileItem::LockStatus::UnlockedItem);
OCC::SyncFileItem::LockStatus::UnlockedItem,
OCC::SyncFileItem::LockOwnerType::UserLock);
QSignalSpy unlockFileJobSuccess(unlockFileJob, &OCC::LockFileJob::finishedWithoutError);
QSignalSpy unlockFileJobFailure(unlockFileJob, &OCC::LockFileJob::finishedWithError);
@ -274,7 +281,8 @@ private slots:
QStringLiteral("/") + testFileName,
QStringLiteral("/"),
fakeFolder.localPath(),
OCC::SyncFileItem::LockStatus::LockedItem);
OCC::SyncFileItem::LockStatus::LockedItem,
OCC::SyncFileItem::LockOwnerType::UserLock);
QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
@ -327,7 +335,8 @@ private slots:
QStringLiteral("/") + testFileName,
QStringLiteral("/"),
fakeFolder.localPath(),
OCC::SyncFileItem::LockStatus::LockedItem);
OCC::SyncFileItem::LockStatus::LockedItem,
OCC::SyncFileItem::LockOwnerType::UserLock);
QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
@ -380,7 +389,8 @@ private slots:
QStringLiteral("/") + testFileName,
QStringLiteral("/"),
fakeFolder.localPath(),
OCC::SyncFileItem::LockStatus::UnlockedItem);
OCC::SyncFileItem::LockStatus::UnlockedItem,
OCC::SyncFileItem::LockOwnerType::UserLock);
QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
@ -431,7 +441,8 @@ private slots:
QStringLiteral("/") + testFileName,
QStringLiteral("/"),
fakeFolder.localPath(),
OCC::SyncFileItem::LockStatus::UnlockedItem);
OCC::SyncFileItem::LockStatus::UnlockedItem,
OCC::SyncFileItem::LockOwnerType::UserLock);
QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);
@ -469,7 +480,8 @@ private slots:
QStringLiteral("/") + testFileName,
QStringLiteral("/"),
fakeFolder.localPath(),
OCC::SyncFileItem::LockStatus::LockedItem);
OCC::SyncFileItem::LockStatus::LockedItem,
OCC::SyncFileItem::LockOwnerType::UserLock);
QSignalSpy lockFileJobSuccess(lockFileJob, &OCC::LockFileJob::finishedWithoutError);
QSignalSpy lockFileJobFailure(lockFileJob, &OCC::LockFileJob::finishedWithError);
@ -486,7 +498,8 @@ private slots:
QStringLiteral("/") + testFileName,
QStringLiteral("/"),
fakeFolder.localPath(),
OCC::SyncFileItem::LockStatus::UnlockedItem);
OCC::SyncFileItem::LockStatus::UnlockedItem,
OCC::SyncFileItem::LockOwnerType::UserLock);
QSignalSpy unlockFileJobSuccess(unlockFileJob, &OCC::LockFileJob::finishedWithoutError);
QSignalSpy unlockFileJobFailure(unlockFileJob, &OCC::LockFileJob::finishedWithError);
@ -539,7 +552,8 @@ private slots:
QStringLiteral("/") + testFileName,
QStringLiteral("/"),
fakeFolder.localPath(),
OCC::SyncFileItem::LockStatus::UnlockedItem);
OCC::SyncFileItem::LockStatus::UnlockedItem,
OCC::SyncFileItem::LockOwnerType::UserLock);
QSignalSpy jobSuccess(job, &OCC::LockFileJob::finishedWithoutError);
QSignalSpy jobFailure(job, &OCC::LockFileJob::finishedWithError);