mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-29 12:19:03 +03:00
Private links: Retrieve link through propfind property #6020
* The sharing ui does a propfind anyway: use that to query the new property as well! * For the socket api, asynchronously query the server for the right url when an action that needs it is triggered. The old, manually generated URL will be used as fallback in case the server doesn't support the new property or the property can't be retrieved for some reason. Depends on owncloud/core#29021
This commit is contained in:
parent
b3f90111e2
commit
05927b68a8
11 changed files with 102 additions and 50 deletions
|
@ -37,7 +37,7 @@ class OCSYNC_EXPORT SyncJournalFileRecord
|
|||
public:
|
||||
SyncJournalFileRecord();
|
||||
|
||||
bool isValid()
|
||||
bool isValid() const
|
||||
{
|
||||
return !_path.isEmpty();
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ ShareDialog::ShareDialog(QPointer<AccountState> accountState,
|
|||
, _sharePath(sharePath)
|
||||
, _localPath(localPath)
|
||||
, _maxSharingPermissions(maxSharingPermissions)
|
||||
, _numericFileId(numericFileId)
|
||||
, _privateLinkUrl(accountState->account()->deprecatedPrivateLinkUrl(numericFileId).toString(QUrl::FullyEncoded))
|
||||
, _linkWidget(NULL)
|
||||
, _userGroupWidget(NULL)
|
||||
, _progressIndicator(NULL)
|
||||
|
@ -130,10 +130,13 @@ ShareDialog::ShareDialog(QPointer<AccountState> accountState,
|
|||
// Server versions >= 9.1 support the "share-permissions" property
|
||||
// older versions will just return share-permissions: ""
|
||||
auto job = new PropfindJob(accountState->account(), _sharePath);
|
||||
job->setProperties(QList<QByteArray>() << "http://open-collaboration-services.org/ns:share-permissions");
|
||||
job->setProperties(
|
||||
QList<QByteArray>()
|
||||
<< "http://open-collaboration-services.org/ns:share-permissions"
|
||||
<< "http://owncloud.org/ns:privatelink");
|
||||
job->setTimeout(10 * 1000);
|
||||
connect(job, SIGNAL(result(QVariantMap)), SLOT(slotMaxSharingPermissionsReceived(QVariantMap)));
|
||||
connect(job, SIGNAL(finishedWithError(QNetworkReply *)), SLOT(slotMaxSharingPermissionsError()));
|
||||
connect(job, SIGNAL(result(QVariantMap)), SLOT(slotPropfindReceived(QVariantMap)));
|
||||
connect(job, SIGNAL(finishedWithError(QNetworkReply *)), SLOT(slotPropfindError()));
|
||||
job->start();
|
||||
}
|
||||
|
||||
|
@ -149,18 +152,23 @@ void ShareDialog::done(int r)
|
|||
QDialog::done(r);
|
||||
}
|
||||
|
||||
void ShareDialog::slotMaxSharingPermissionsReceived(const QVariantMap &result)
|
||||
void ShareDialog::slotPropfindReceived(const QVariantMap &result)
|
||||
{
|
||||
const QVariant receivedPermissions = result["share-permissions"];
|
||||
if (!receivedPermissions.toString().isEmpty()) {
|
||||
_maxSharingPermissions = static_cast<SharePermissions>(receivedPermissions.toInt());
|
||||
qCInfo(lcSharing) << "Received sharing permissions for" << _sharePath << _maxSharingPermissions;
|
||||
}
|
||||
auto privateLinkUrl = result["privatelink"].toString();
|
||||
if (!privateLinkUrl.isEmpty()) {
|
||||
qCInfo(lcSharing) << "Received private link url for" << _sharePath << privateLinkUrl;
|
||||
_privateLinkUrl = privateLinkUrl;
|
||||
}
|
||||
|
||||
showSharingUi();
|
||||
}
|
||||
|
||||
void ShareDialog::slotMaxSharingPermissionsError()
|
||||
void ShareDialog::slotPropfindError()
|
||||
{
|
||||
// On error show the share ui anyway. The user can still see shares,
|
||||
// delete them and so on, even though adding new shares or granting
|
||||
|
@ -194,7 +202,7 @@ void ShareDialog::showSharingUi()
|
|||
&& _accountState->account()->serverVersionInt() >= Account::makeServerVersion(8, 2, 0);
|
||||
|
||||
if (userGroupSharing) {
|
||||
_userGroupWidget = new ShareUserGroupWidget(_accountState->account(), _sharePath, _localPath, _maxSharingPermissions, _numericFileId, this);
|
||||
_userGroupWidget = new ShareUserGroupWidget(_accountState->account(), _sharePath, _localPath, _maxSharingPermissions, _privateLinkUrl, this);
|
||||
_ui->shareWidgets->addTab(_userGroupWidget, tr("Users and Groups"));
|
||||
_userGroupWidget->getShares();
|
||||
}
|
||||
|
|
|
@ -49,8 +49,8 @@ public:
|
|||
|
||||
private slots:
|
||||
void done(int r);
|
||||
void slotMaxSharingPermissionsReceived(const QVariantMap &result);
|
||||
void slotMaxSharingPermissionsError();
|
||||
void slotPropfindReceived(const QVariantMap &result);
|
||||
void slotPropfindError();
|
||||
void slotThumbnailFetched(const int &statusCode, const QByteArray &reply);
|
||||
void slotAccountStateChanged(int state);
|
||||
|
||||
|
@ -63,6 +63,7 @@ private:
|
|||
QString _localPath;
|
||||
SharePermissions _maxSharingPermissions;
|
||||
QByteArray _numericFileId;
|
||||
QString _privateLinkUrl;
|
||||
|
||||
ShareLinkWidget *_linkWidget;
|
||||
ShareUserGroupWidget *_userGroupWidget;
|
||||
|
|
|
@ -48,7 +48,7 @@ ShareUserGroupWidget::ShareUserGroupWidget(AccountPtr account,
|
|||
const QString &sharePath,
|
||||
const QString &localPath,
|
||||
SharePermissions maxSharingPermissions,
|
||||
const QByteArray &numericFileId,
|
||||
const QString &privateLinkUrl,
|
||||
QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, _ui(new Ui::ShareUserGroupWidget)
|
||||
|
@ -56,7 +56,7 @@ ShareUserGroupWidget::ShareUserGroupWidget(AccountPtr account,
|
|||
, _sharePath(sharePath)
|
||||
, _localPath(localPath)
|
||||
, _maxSharingPermissions(maxSharingPermissions)
|
||||
, _numericFileId(numericFileId)
|
||||
, _privateLinkUrl(privateLinkUrl)
|
||||
, _disableCompleterActivated(false)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
@ -323,19 +323,19 @@ void ShareUserGroupWidget::displayError(int code, const QString &message)
|
|||
|
||||
void ShareUserGroupWidget::slotPrivateLinkOpenBrowser()
|
||||
{
|
||||
Utility::openBrowser(_account->filePermalinkUrl(_numericFileId), this);
|
||||
Utility::openBrowser(_privateLinkUrl, this);
|
||||
}
|
||||
|
||||
void ShareUserGroupWidget::slotPrivateLinkCopy()
|
||||
{
|
||||
QApplication::clipboard()->setText(_account->filePermalinkUrl(_numericFileId).toString());
|
||||
QApplication::clipboard()->setText(_privateLinkUrl);
|
||||
}
|
||||
|
||||
void ShareUserGroupWidget::slotPrivateLinkEmail()
|
||||
{
|
||||
Utility::openEmailComposer(
|
||||
tr("I shared something with you"),
|
||||
_account->filePermalinkUrl(_numericFileId).toString(),
|
||||
_privateLinkUrl,
|
||||
this);
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ public:
|
|||
const QString &sharePath,
|
||||
const QString &localPath,
|
||||
SharePermissions maxSharingPermissions,
|
||||
const QByteArray &numericFileId,
|
||||
const QString &privateLinkUrl,
|
||||
QWidget *parent = 0);
|
||||
~ShareUserGroupWidget();
|
||||
|
||||
|
@ -89,7 +89,7 @@ private:
|
|||
QString _sharePath;
|
||||
QString _localPath;
|
||||
SharePermissions _maxSharingPermissions;
|
||||
QByteArray _numericFileId;
|
||||
QString _privateLinkUrl;
|
||||
|
||||
QCompleter *_completer;
|
||||
ShareeModel *_completerModel;
|
||||
|
|
|
@ -491,23 +491,70 @@ void SocketApi::command_SHARE_MENU_TITLE(const QString &, SocketListener *listen
|
|||
listener->sendMessage(QLatin1String("SHARE_MENU_TITLE:") + tr("Share with %1", "parameter is ownCloud").arg(Theme::instance()->appNameGUI()));
|
||||
}
|
||||
|
||||
// Fetches the private link url asynchronously and then calls the target slot
|
||||
void fetchPrivateLinkUrl(const QString &localFile, SocketApi *target, void (SocketApi::*targetFun)(const QString &url) const)
|
||||
{
|
||||
Folder *shareFolder = FolderMan::instance()->folderForPath(localFile);
|
||||
if (!shareFolder) {
|
||||
qCWarning(lcSocketApi) << "Unknown path" << localFile;
|
||||
return;
|
||||
}
|
||||
|
||||
const QString localFileClean = QDir::cleanPath(localFile);
|
||||
const QString file = localFileClean.mid(shareFolder->cleanPath().length() + 1);
|
||||
|
||||
// Generate private link ourselves: used as a fallback
|
||||
const SyncJournalFileRecord rec = shareFolder->journalDb()->getFileRecord(file);
|
||||
if (!rec.isValid())
|
||||
return;
|
||||
const QString oldUrl =
|
||||
shareFolder->accountState()->account()->deprecatedPrivateLinkUrl(rec.numericFileId()).toString(QUrl::FullyEncoded);
|
||||
|
||||
// If the server doesn't have the property, use the old url directly.
|
||||
if (!shareFolder->accountState()->account()->capabilities().privateLinkPropertyAvailable()) {
|
||||
(target->*targetFun)(oldUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the new link by PROPFIND
|
||||
PropfindJob *job = new PropfindJob(shareFolder->accountState()->account(), file, target);
|
||||
job->setProperties(QList<QByteArray>() << "http://owncloud.org/ns:privatelink");
|
||||
job->setTimeout(10 * 1000);
|
||||
QObject::connect(job, &PropfindJob::result, target, [=](const QVariantMap &result) {
|
||||
auto privateLinkUrl = result["privatelink"].toString();
|
||||
if (!privateLinkUrl.isEmpty()) {
|
||||
(target->*targetFun)(privateLinkUrl);
|
||||
} else {
|
||||
(target->*targetFun)(oldUrl);
|
||||
}
|
||||
});
|
||||
QObject::connect(job, &PropfindJob::finishedWithError, target, [=](QNetworkReply *) {
|
||||
(target->*targetFun)(oldUrl);
|
||||
});
|
||||
job->start();
|
||||
}
|
||||
|
||||
void SocketApi::command_COPY_PRIVATE_LINK(const QString &localFile, SocketListener *)
|
||||
{
|
||||
auto url = getPrivateLinkUrl(localFile);
|
||||
if (!url.isEmpty()) {
|
||||
QApplication::clipboard()->setText(url.toString());
|
||||
}
|
||||
fetchPrivateLinkUrl(localFile, this, &SocketApi::copyPrivateLinkToClipboard);
|
||||
}
|
||||
|
||||
void SocketApi::command_EMAIL_PRIVATE_LINK(const QString &localFile, SocketListener *)
|
||||
{
|
||||
auto url = getPrivateLinkUrl(localFile);
|
||||
if (!url.isEmpty()) {
|
||||
Utility::openEmailComposer(
|
||||
tr("I shared something with you"),
|
||||
url.toString(QUrl::FullyEncoded),
|
||||
0);
|
||||
}
|
||||
fetchPrivateLinkUrl(localFile, this, &SocketApi::emailPrivateLink);
|
||||
}
|
||||
|
||||
void SocketApi::copyPrivateLinkToClipboard(const QString &link) const
|
||||
{
|
||||
QApplication::clipboard()->setText(link);
|
||||
}
|
||||
|
||||
void SocketApi::emailPrivateLink(const QString &link) const
|
||||
{
|
||||
Utility::openEmailComposer(
|
||||
tr("I shared something with you"),
|
||||
link,
|
||||
0);
|
||||
}
|
||||
|
||||
void SocketApi::command_GET_STRINGS(const QString &, SocketListener *listener)
|
||||
|
@ -533,22 +580,4 @@ QString SocketApi::buildRegisterPathMessage(const QString &path)
|
|||
return message;
|
||||
}
|
||||
|
||||
QUrl SocketApi::getPrivateLinkUrl(const QString &localFile) const
|
||||
{
|
||||
Folder *shareFolder = FolderMan::instance()->folderForPath(localFile);
|
||||
if (!shareFolder) {
|
||||
qCWarning(lcSocketApi) << "Unknown path" << localFile;
|
||||
return QUrl();
|
||||
}
|
||||
|
||||
const QString localFileClean = QDir::cleanPath(localFile);
|
||||
const QString file = localFileClean.mid(shareFolder->cleanPath().length() + 1);
|
||||
|
||||
SyncJournalFileRecord rec = shareFolder->journalDb()->getFileRecord(file);
|
||||
if (rec.isValid()) {
|
||||
return shareFolder->accountState()->account()->filePermalinkUrl(rec.numericFileId());
|
||||
}
|
||||
return QUrl();
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
|
|
|
@ -64,6 +64,9 @@ private slots:
|
|||
void slotReadSocket();
|
||||
void broadcastStatusPushMessage(const QString &systemPath, SyncFileStatus fileStatus);
|
||||
|
||||
void copyPrivateLinkToClipboard(const QString &link) const;
|
||||
void emailPrivateLink(const QString &link) const;
|
||||
|
||||
private:
|
||||
void broadcastMessage(const QString &msg, bool doWait = false);
|
||||
|
||||
|
@ -84,7 +87,6 @@ private:
|
|||
Q_INVOKABLE void command_GET_STRINGS(const QString &argument, SocketListener *listener);
|
||||
|
||||
QString buildRegisterPathMessage(const QString &path);
|
||||
QUrl getPrivateLinkUrl(const QString &localFile) const;
|
||||
|
||||
QSet<QString> _registeredAliases;
|
||||
QList<SocketListener> _listeners;
|
||||
|
|
|
@ -162,7 +162,7 @@ QUrl Account::davUrl() const
|
|||
return Utility::concatUrlPath(url(), davPath());
|
||||
}
|
||||
|
||||
QUrl Account::filePermalinkUrl(const QByteArray &numericFileId) const
|
||||
QUrl Account::deprecatedPrivateLinkUrl(const QByteArray &numericFileId) const
|
||||
{
|
||||
return Utility::concatUrlPath(url(),
|
||||
QLatin1String("/index.php/f/") + QUrl::toPercentEncoding(QString::fromLatin1(numericFileId)));
|
||||
|
|
|
@ -108,8 +108,12 @@ public:
|
|||
/** Returns webdav entry URL, based on url() */
|
||||
QUrl davUrl() const;
|
||||
|
||||
/** Returns a permalink url for a file */
|
||||
QUrl filePermalinkUrl(const QByteArray &numericFileId) const;
|
||||
/** Returns the legacy permalink url for a file.
|
||||
*
|
||||
* This uses the old way of manually building the url. New code should
|
||||
* use the "privatelink" property accessible via PROPFIND.
|
||||
*/
|
||||
QUrl deprecatedPrivateLinkUrl(const QByteArray &numericFileId) const;
|
||||
|
||||
/** Holds the accounts credentials */
|
||||
AbstractCredentials *credentials() const;
|
||||
|
|
|
@ -132,6 +132,11 @@ bool Capabilities::chunkingParallelUploadDisabled() const
|
|||
return _capabilities["dav"].toMap()["chunkingParallelUploadDisabled"].toBool();
|
||||
}
|
||||
|
||||
bool Capabilities::privateLinkPropertyAvailable() const
|
||||
{
|
||||
return _capabilities["files"].toMap()["privateLinks"].toBool();
|
||||
}
|
||||
|
||||
QList<int> Capabilities::httpErrorCodesThatResetFailingChunkedUploads() const
|
||||
{
|
||||
QList<int> list;
|
||||
|
|
|
@ -47,6 +47,9 @@ public:
|
|||
/// disable parallel upload in chunking
|
||||
bool chunkingParallelUploadDisabled() const;
|
||||
|
||||
/// Whether the "privatelink" DAV property is available
|
||||
bool privateLinkPropertyAvailable() const;
|
||||
|
||||
/// returns true if the capabilities report notifications
|
||||
bool notificationsAvailable() const;
|
||||
|
||||
|
|
Loading…
Reference in a new issue