Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sharing: fix overlay icons directly after sharing a file #6115

Merged
merged 4 commits into from
Oct 24, 2017
Merged
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
5 changes: 5 additions & 0 deletions src/gui/folder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,11 @@ void Folder::slotTransmissionProgress(const ProgressInfo &pi)
// a item is completed: count the errors and forward to the ProgressDispatcher
void Folder::slotItemCompleted(const SyncFileItemPtr &item)
{
if (item->_instruction == CSYNC_INSTRUCTION_NONE || item->_instruction == CSYNC_INSTRUCTION_UPDATE_METADATA) {
// We only care about the updates that deserve to be shown in the UI
return;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Including CSYNC_INSTRUCTION_NONE sounds wrong, would it be possible to check at the emit point?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CSYNC_INSTRUCTION_NONE should never happen. But i'm putting it there as it goes hand to hand with UPDATE_METADATA. (Should the sync engine change, and emit the signal with CSYNC_INSTRUCTION_NONE in the future, we probably want to filter it there anyway)
I could remove it from this check if you think this is confusing.


// add new directories or remove gone away dirs to the watcher
if (item->isDirectory() && item->_instruction == CSYNC_INSTRUCTION_NEW) {
FolderMan::instance()->addMonitorPath(alias(), path() + item->_file);
Expand Down
114 changes: 62 additions & 52 deletions src/gui/sharemanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,41 @@
#include "sharemanager.h"
#include "ocssharejob.h"
#include "account.h"
#include "folderman.h"
#include "accountstate.h"

#include <QUrl>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>

namespace {
struct CreateShare
{
QString path;
OCC::Share::ShareType shareType;
QString shareWith;
OCC::Share::Permissions permissions;
};
} // anonymous namespace
Q_DECLARE_METATYPE(CreateShare)

namespace OCC {

/**
* When a share is modified, we need to tell the folders so they can adjust overlay icons
*/
static void updateFolder(const AccountPtr &account, const QString &path)
{
foreach (Folder *f, FolderMan::instance()->map()) {
if (f->accountState()->account() != account)
continue;
auto folderPath = f->remotePath();
if (path.startsWith(folderPath) && (path == folderPath || folderPath.endsWith('/') || path[folderPath.size()] == '/')) {
// Workaround the fact that the server does not invalidate the etags of parent directories
// when something is shared.
auto relative = path.midRef(folderPath.size());
if (relative.startsWith('/'))
relative = relative.mid(1);
f->journalDb()->avoidReadFromDbOnNextSync(relative.toString());

// Schedule a sync so it can update the remote permission flag and let the socket API
// know about the shared icon.
f->scheduleThisFolderSoon();
}
}
}


Share::Share(AccountPtr account,
const QString &id,
const QString &path,
Expand All @@ -54,6 +70,11 @@ AccountPtr Share::account() const
return _account;
}

QString Share::path() const
{
return _path;
}

QString Share::getId() const
{
return _id;
Expand Down Expand Up @@ -99,6 +120,8 @@ void Share::deleteShare()
void Share::slotDeleted()
{
emit shareDeleted();

updateFolder(_account, _path);
}

void Share::slotOcsError(int statusCode, const QString &message)
Expand Down Expand Up @@ -258,6 +281,8 @@ void ShareManager::slotLinkShareCreated(const QJsonDocument &reply)
QSharedPointer<LinkShare> share(parseLinkShare(data));

emit linkShareCreated(share);

updateFolder(_account, share->path());
}


Expand All @@ -267,51 +292,34 @@ void ShareManager::createShare(const QString &path,
const Share::Permissions permissions)
{
auto job = new OcsShareJob(_account);

// Store values that we need for creating this share later.
CreateShare continuation;
continuation.path = path;
continuation.shareType = shareType;
continuation.shareWith = shareWith;
continuation.permissions = permissions;
_jobContinuation[job] = QVariant::fromValue(continuation);

connect(job, &OcsShareJob::shareJobFinished, this, &ShareManager::slotCreateShare);
connect(job, &OcsJob::ocsError, this, &ShareManager::slotOcsError);
connect(job, &OcsShareJob::shareJobFinished, this,
[=](const QJsonDocument &reply) {
// Find existing share permissions (if this was shared with us)
Share::Permissions existingPermissions = SharePermissionDefault;
foreach (const QJsonValue &element, reply.object()["ocs"].toObject()["data"].toArray()) {
auto map = element.toObject();
if (map["file_target"] == path)
existingPermissions = Share::Permissions(map["permissions"].toInt());
}

// Limit the permissions we request for a share to the ones the item
// was shared with initially.
auto perm = permissions;
if (permissions == SharePermissionDefault) {
perm = existingPermissions;
} else if (existingPermissions != SharePermissionDefault) {
perm &= existingPermissions;
}

OcsShareJob *job = new OcsShareJob(_account);
connect(job, &OcsShareJob::shareJobFinished, this, &ShareManager::slotShareCreated);
connect(job, &OcsJob::ocsError, this, &ShareManager::slotOcsError);
job->createShare(path, shareType, shareWith, permissions);
});
job->getSharedWithMe();
}

void ShareManager::slotCreateShare(const QJsonDocument &reply)
{
if (!_jobContinuation.contains(sender()))
return;

CreateShare cont = _jobContinuation[sender()].value<CreateShare>();
if (cont.path.isEmpty())
return;
_jobContinuation.remove(sender());

// Find existing share permissions (if this was shared with us)
Share::Permissions existingPermissions = SharePermissionDefault;
foreach (const QJsonValue &element, reply.object()["ocs"].toObject()["data"].toArray()) {
auto map = element.toObject();
if (map["file_target"] == cont.path)
existingPermissions = Share::Permissions(map["permissions"].toInt());
}

// Limit the permissions we request for a share to the ones the item
// was shared with initially.
if (cont.permissions == SharePermissionDefault) {
cont.permissions = existingPermissions;
} else if (existingPermissions != SharePermissionDefault) {
cont.permissions &= existingPermissions;
}

OcsShareJob *job = new OcsShareJob(_account);
connect(job, &OcsShareJob::shareJobFinished, this, &ShareManager::slotShareCreated);
connect(job, &OcsJob::ocsError, this, &ShareManager::slotOcsError);
job->createShare(cont.path, cont.shareType, cont.shareWith, cont.permissions);
}

void ShareManager::slotShareCreated(const QJsonDocument &reply)
{
Expand All @@ -320,6 +328,8 @@ void ShareManager::slotShareCreated(const QJsonDocument &reply)
QSharedPointer<Share> share(parseShare(data));

emit shareCreated(share);

updateFolder(_account, share->path());
}

void ShareManager::fetchShares(const QString &path)
Expand Down
5 changes: 2 additions & 3 deletions src/gui/sharemanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ class Share : public QObject
*/
AccountPtr account() const;

QString path() const;

/*
* Get the id
*/
Expand Down Expand Up @@ -293,13 +295,10 @@ private slots:
void slotLinkShareCreated(const QJsonDocument &reply);
void slotShareCreated(const QJsonDocument &reply);
void slotOcsError(int statusCode, const QString &message);
void slotCreateShare(const QJsonDocument &reply);

private:
QSharedPointer<LinkShare> parseLinkShare(const QJsonObject &data);
QSharedPointer<Share> parseShare(const QJsonObject &data);

QMap<QObject *, QVariant> _jobContinuation;
AccountPtr _account;
};
}
Expand Down
6 changes: 3 additions & 3 deletions src/libsync/syncengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,6 @@ int SyncEngine::treewalkFile(csync_file_stat_t *file, csync_file_stat_t *other,
dir = SyncFileItem::None;
// For directories, metadata-only updates will be done after all their files are propagated.
if (!isDirectory) {
emit syncItemDiscovered(*item);

// Update the database now already: New remote fileid or Etag or RemotePerm
// Or for files that were detected as "resolved conflict".
Expand Down Expand Up @@ -608,6 +607,9 @@ int SyncEngine::treewalkFile(csync_file_stat_t *file, csync_file_stat_t *other,
}

_journal->setFileRecordMetadata(item->toSyncJournalFileRecordWithInode(filePath));

// This might have changed the shared flag, so we must notify SyncFileStatusTracker for example
emit itemCompleted(item);
} else {
// The local tree is walked first and doesn't have all the info from the server.
// Update only outdated data from the disk.
Expand Down Expand Up @@ -683,8 +685,6 @@ int SyncEngine::treewalkFile(csync_file_stat_t *file, csync_file_stat_t *other,
}

_syncItemMap.insert(key, item);

emit syncItemDiscovered(*item);
return re;
}

Expand Down
2 changes: 0 additions & 2 deletions src/libsync/syncengine.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,6 @@ class OWNCLOUDSYNC_EXPORT SyncEngine : public QObject
// During update, before reconcile
void rootEtag(QString);

// before actual syncing (after update+reconcile) for each item
void syncItemDiscovered(const SyncFileItem &);
// after the above signals. with the items that actually need propagating
void aboutToPropagate(SyncFileItemVector &);

Expand Down
2 changes: 1 addition & 1 deletion test/testsyncengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ bool itemDidComplete(const QSignalSpy &spy, const QString &path)
for(const QList<QVariant> &args : spy) {
auto item = args[0].value<SyncFileItemPtr>();
if (item->destination() == path)
return true;
return item->_instruction != CSYNC_INSTRUCTION_NONE && item->_instruction != CSYNC_INSTRUCTION_UPDATE_METADATA;
}
return false;
}
Expand Down
3 changes: 3 additions & 0 deletions test/testsyncfilestatustracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,8 @@ private slots:
fakeFolder.remoteModifier().appendByte("S/s1");
fakeFolder.remoteModifier().insert("B/b3");
fakeFolder.remoteModifier().find("B/b3")->extraDavProperties = "<oc:share-types><oc:share-type>0</oc:share-type></oc:share-types>";
fakeFolder.remoteModifier().find("A/a1")->isShared = true; // becomes shared
fakeFolder.remoteModifier().find("A", true); // change the etags of the parent

StatusPushSpy statusSpy(fakeFolder.syncEngine());

Expand All @@ -458,6 +460,7 @@ private slots:
QCOMPARE(statusSpy.statusOf("S/s1"), sharedUpToDateStatus);
QCOMPARE(statusSpy.statusOf("B/b1").shared(), false);
QCOMPARE(statusSpy.statusOf("B/b3"), sharedUpToDateStatus);
QCOMPARE(statusSpy.statusOf("A/a1"), sharedUpToDateStatus);

QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
}
Expand Down