mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-22 04:55:48 +03:00
Introduce private link sharing #5023
* SocketAPI has COPL_LOCAL_LINK / EMAIL_LOCAL_LINK commands * The nautilus and dolphing shell integrations show a submenu from which one can share as well as access the private link. * The SocketAPI provides a new GET_STRINGS command to access localized strings. * The private link can also be accessed from the user/group sharing dialog. * The numeric file id is extracted from the full id to create the private link url.
This commit is contained in:
parent
d01065b9a1
commit
0238a29c7c
25 changed files with 386 additions and 103 deletions
|
@ -24,6 +24,7 @@
|
||||||
#include <KIOCore/kfileitem.h>
|
#include <KIOCore/kfileitem.h>
|
||||||
#include <KIOCore/KFileItemListProperties>
|
#include <KIOCore/KFileItemListProperties>
|
||||||
#include <QtWidgets/QAction>
|
#include <QtWidgets/QAction>
|
||||||
|
#include <QtWidgets/QMenu>
|
||||||
#include <QtCore/QDir>
|
#include <QtCore/QDir>
|
||||||
#include <QtCore/QTimer>
|
#include <QtCore/QTimer>
|
||||||
#include "ownclouddolphinpluginhelper.h"
|
#include "ownclouddolphinpluginhelper.h"
|
||||||
|
@ -53,12 +54,31 @@ public:
|
||||||
} ))
|
} ))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto act = new QAction(parentWidget);
|
auto menuaction = new QAction(parentWidget);
|
||||||
act->setText(helper->shareActionString());
|
menuaction->setText(helper->contextMenuTitle());
|
||||||
connect(act, &QAction::triggered, this, [localFile, helper] {
|
auto menu = new QMenu(parentWidget);
|
||||||
|
menuaction->setMenu(menu);
|
||||||
|
|
||||||
|
auto shareAction = menu->addAction(helper->shareActionTitle());
|
||||||
|
connect(shareAction, &QAction::triggered, this, [localFile, helper] {
|
||||||
helper->sendCommand(QByteArray("SHARE:"+localFile.toUtf8()+"\n"));
|
helper->sendCommand(QByteArray("SHARE:"+localFile.toUtf8()+"\n"));
|
||||||
} );
|
} );
|
||||||
return { act };
|
|
||||||
|
if (!helper->copyPrivateLinkTitle().isEmpty()) {
|
||||||
|
auto copyPrivateLinkAction = menu->addAction(helper->copyPrivateLinkTitle());
|
||||||
|
connect(copyPrivateLinkAction, &QAction::triggered, this, [localFile, helper] {
|
||||||
|
helper->sendCommand(QByteArray("COPY_PRIVATE_LINK:" + localFile.toUtf8() + "\n"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!helper->emailPrivateLinkTitle().isEmpty()) {
|
||||||
|
auto emailPrivateLinkAction = menu->addAction(helper->emailPrivateLinkTitle());
|
||||||
|
connect(emailPrivateLinkAction, &QAction::triggered, this, [localFile, helper] {
|
||||||
|
helper->sendCommand(QByteArray("EMAIL_PRIVATE_LINK:" + localFile.toUtf8() + "\n"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { menuaction };
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -59,7 +59,7 @@ void OwncloudDolphinPluginHelper::sendCommand(const char* data)
|
||||||
|
|
||||||
void OwncloudDolphinPluginHelper::slotConnected()
|
void OwncloudDolphinPluginHelper::slotConnected()
|
||||||
{
|
{
|
||||||
sendCommand("SHARE_MENU_TITLE:\n");
|
sendCommand("GET_STRINGS:\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void OwncloudDolphinPluginHelper::tryConnect()
|
void OwncloudDolphinPluginHelper::tryConnect()
|
||||||
|
@ -92,9 +92,11 @@ void OwncloudDolphinPluginHelper::slotReadyRead()
|
||||||
QString file = QString::fromUtf8(line.constData() + col + 1, line.size() - col - 1);
|
QString file = QString::fromUtf8(line.constData() + col + 1, line.size() - col - 1);
|
||||||
_paths.append(file);
|
_paths.append(file);
|
||||||
continue;
|
continue;
|
||||||
} else if (line.startsWith("SHARE_MENU_TITLE:")) {
|
} else if (line.startsWith("STRING:")) {
|
||||||
auto col = line.indexOf(':');
|
auto args = QString::fromUtf8(line).split(QLatin1Char(':'));
|
||||||
_shareActionString = QString::fromUtf8(line.constData() + col + 1, line.size() - col - 1);
|
if (args.size() >= 3) {
|
||||||
|
_strings[args[1]] = args.mid(2).join(QLatin1Char(':'));
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
emit commandRecieved(line);
|
emit commandRecieved(line);
|
||||||
|
|
|
@ -28,11 +28,22 @@ class OWNCLOUDDOLPHINPLUGINHELPER_EXPORT OwncloudDolphinPluginHelper : public QO
|
||||||
public:
|
public:
|
||||||
static OwncloudDolphinPluginHelper *instance();
|
static OwncloudDolphinPluginHelper *instance();
|
||||||
|
|
||||||
QString shareActionString() const { return _shareActionString; }
|
|
||||||
bool isConnected() const;
|
bool isConnected() const;
|
||||||
void sendCommand(const char *data);
|
void sendCommand(const char *data);
|
||||||
QVector<QString> paths() const { return _paths; }
|
QVector<QString> paths() const { return _paths; }
|
||||||
|
|
||||||
|
QString contextMenuTitle() const
|
||||||
|
{
|
||||||
|
return _strings.value("CONTEXT_MENU_TITLE", "ownCloud");
|
||||||
|
}
|
||||||
|
QString shareActionTitle() const
|
||||||
|
{
|
||||||
|
return _strings.value("SHARE_MENU_TITLE", "Share...");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString copyPrivateLinkTitle() const { return _strings["COPY_PRIVATE_LINK_TITLE"]; }
|
||||||
|
QString emailPrivateLinkTitle() const { return _strings["EMAIL_PRIVATE_LINK_TITLE"]; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void commandRecieved(const QByteArray &cmd);
|
void commandRecieved(const QByteArray &cmd);
|
||||||
|
|
||||||
|
@ -47,6 +58,7 @@ private:
|
||||||
QLocalSocket _socket;
|
QLocalSocket _socket;
|
||||||
QByteArray _line;
|
QByteArray _line;
|
||||||
QVector<QString> _paths;
|
QVector<QString> _paths;
|
||||||
QString _shareActionString;
|
|
||||||
QBasicTimer _connectTimer;
|
QBasicTimer _connectTimer;
|
||||||
|
|
||||||
|
QMap<QString, QString> _strings;
|
||||||
};
|
};
|
||||||
|
|
|
@ -95,6 +95,9 @@ class SocketConnect(GObject.GObject):
|
||||||
print("Setting connected to %r." % self.connected )
|
print("Setting connected to %r." % self.connected )
|
||||||
self._watch_id = GObject.io_add_watch(self._sock, GObject.IO_IN, self._handle_notify)
|
self._watch_id = GObject.io_add_watch(self._sock, GObject.IO_IN, self._handle_notify)
|
||||||
print("Socket watch id: " + str(self._watch_id))
|
print("Socket watch id: " + str(self._watch_id))
|
||||||
|
|
||||||
|
self.sendCommand('GET_STRINGS:\n')
|
||||||
|
|
||||||
return False # Don't run again
|
return False # Don't run again
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Could not connect to unix socket. " + str(e))
|
print("Could not connect to unix socket. " + str(e))
|
||||||
|
@ -153,6 +156,13 @@ class MenuExtension(GObject.GObject, Nautilus.MenuProvider):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
GObject.GObject.__init__(self)
|
GObject.GObject.__init__(self)
|
||||||
|
|
||||||
|
self.strings = {}
|
||||||
|
socketConnect.addListener(self.handle_commands)
|
||||||
|
|
||||||
|
def handle_commands(self, action, args):
|
||||||
|
if action == 'STRING':
|
||||||
|
self.strings[args[0]] = ':'.join(args[1:])
|
||||||
|
|
||||||
def check_registered_paths(self, filename):
|
def check_registered_paths(self, filename):
|
||||||
topLevelFolder = False
|
topLevelFolder = False
|
||||||
internalFile = False
|
internalFile = False
|
||||||
|
@ -178,7 +188,6 @@ class MenuExtension(GObject.GObject, Nautilus.MenuProvider):
|
||||||
if len(files) != 1:
|
if len(files) != 1:
|
||||||
return
|
return
|
||||||
file = files[0]
|
file = files[0]
|
||||||
items = []
|
|
||||||
|
|
||||||
filename = get_local_path(file.get_uri())
|
filename = get_local_path(file.get_uri())
|
||||||
# Check if its a folder (ends with an /), if yes add a "/"
|
# Check if its a folder (ends with an /), if yes add a "/"
|
||||||
|
@ -190,12 +199,14 @@ class MenuExtension(GObject.GObject, Nautilus.MenuProvider):
|
||||||
# Check if toplevel folder, we need to ignore those as they cannot be shared
|
# Check if toplevel folder, we need to ignore those as they cannot be shared
|
||||||
topLevelFolder, internalFile = self.check_registered_paths(filename)
|
topLevelFolder, internalFile = self.check_registered_paths(filename)
|
||||||
if topLevelFolder or not internalFile:
|
if topLevelFolder or not internalFile:
|
||||||
return items
|
return []
|
||||||
|
|
||||||
entry = socketConnect.nautilusVFSFile_table.get(filename)
|
entry = socketConnect.nautilusVFSFile_table.get(filename)
|
||||||
if not entry:
|
if not entry:
|
||||||
return items
|
return []
|
||||||
|
|
||||||
|
# Currently 'sharable' also controls access to private link actions,
|
||||||
|
# and we definitely don't want to show them for IGNORED.
|
||||||
shareable = False
|
shareable = False
|
||||||
state = entry['state']
|
state = entry['state']
|
||||||
state_ok = state.startswith('OK')
|
state_ok = state.startswith('OK')
|
||||||
|
@ -212,22 +223,42 @@ class MenuExtension(GObject.GObject, Nautilus.MenuProvider):
|
||||||
break
|
break
|
||||||
|
|
||||||
if not shareable:
|
if not shareable:
|
||||||
return items
|
return []
|
||||||
|
|
||||||
# Create a menu item
|
# Set up the 'ownCloud...' submenu
|
||||||
labelStr = "Share with " + appname + "..."
|
item_owncloud = Nautilus.MenuItem(
|
||||||
item = Nautilus.MenuItem(name='NautilusPython::ShareItem', label=labelStr,
|
name='IntegrationMenu', label=self.strings.get('CONTEXT_MENU_TITLE', appname))
|
||||||
tip='Share file {} through {}'.format(file.get_name(), appname) )
|
menu = Nautilus.Menu()
|
||||||
item.connect("activate", self.menu_share, file)
|
item_owncloud.set_submenu(menu)
|
||||||
items.append(item)
|
|
||||||
|
|
||||||
return items
|
# Add share menu option
|
||||||
|
item = Nautilus.MenuItem(
|
||||||
|
name='NautilusPython::ShareItem',
|
||||||
|
label=self.strings.get('SHARE_MENU_TITLE', 'Share...'))
|
||||||
|
item.connect("activate", self.context_menu_action, 'SHARE', file)
|
||||||
|
menu.append_item(item)
|
||||||
|
|
||||||
|
# Add permalink menu options, but hide these options for older clients
|
||||||
|
# that don't have these actions.
|
||||||
|
if 'COPY_PRIVATE_LINK_TITLE' in self.strings:
|
||||||
|
item_copyprivatelink = Nautilus.MenuItem(
|
||||||
|
name='CopyPrivateLink', label=self.strings.get('COPY_PRIVATE_LINK_TITLE', 'Copy private link to clipboard'))
|
||||||
|
item_copyprivatelink.connect("activate", self.context_menu_action, 'COPY_PRIVATE_LINK', file)
|
||||||
|
menu.append_item(item_copyprivatelink)
|
||||||
|
|
||||||
|
if 'EMAIL_PRIVATE_LINK_TITLE' in self.strings:
|
||||||
|
item_emailprivatelink = Nautilus.MenuItem(
|
||||||
|
name='EmailPrivateLink', label=self.strings.get('EMAIL_PRIVATE_LINK_TITLE', 'Send private link by email...'))
|
||||||
|
item_emailprivatelink.connect("activate", self.context_menu_action, 'EMAIL_PRIVATE_LINK', file)
|
||||||
|
menu.append_item(item_emailprivatelink)
|
||||||
|
|
||||||
|
return [item_owncloud]
|
||||||
|
|
||||||
|
|
||||||
def menu_share(self, menu, file):
|
def context_menu_action(self, menu, action, file):
|
||||||
filename = get_local_path(file.get_uri())
|
filename = get_local_path(file.get_uri())
|
||||||
print("Share file " + filename)
|
print("Context menu: " + action + ' ' + filename)
|
||||||
socketConnect.sendCommand("SHARE:" + filename + "\n")
|
socketConnect.sendCommand(action + ":" + filename + "\n")
|
||||||
|
|
||||||
|
|
||||||
class SyncStateExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.InfoProvider):
|
class SyncStateExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.InfoProvider):
|
||||||
|
|
|
@ -94,6 +94,7 @@ set(client_SRCS
|
||||||
notificationwidget.cpp
|
notificationwidget.cpp
|
||||||
notificationconfirmjob.cpp
|
notificationconfirmjob.cpp
|
||||||
servernotificationhandler.cpp
|
servernotificationhandler.cpp
|
||||||
|
guiutility.cpp
|
||||||
creds/credentialsfactory.cpp
|
creds/credentialsfactory.cpp
|
||||||
creds/httpcredentialsgui.cpp
|
creds/httpcredentialsgui.cpp
|
||||||
creds/oauth.cpp
|
creds/oauth.cpp
|
||||||
|
@ -129,7 +130,6 @@ IF( APPLE )
|
||||||
list(APPEND client_SRCS settingsdialogmac.cpp)
|
list(APPEND client_SRCS settingsdialogmac.cpp)
|
||||||
list(APPEND client_SRCS socketapisocket_mac.mm)
|
list(APPEND client_SRCS socketapisocket_mac.mm)
|
||||||
list(APPEND client_SRCS systray.mm)
|
list(APPEND client_SRCS systray.mm)
|
||||||
list(APPEND client_SRCS clipboard.mm)
|
|
||||||
|
|
||||||
if(SPARKLE_FOUND)
|
if(SPARKLE_FOUND)
|
||||||
# Define this, we need to check in updater.cpp
|
# Define this, we need to check in updater.cpp
|
||||||
|
|
|
@ -206,8 +206,8 @@ Application::Application(int &argc, char **argv)
|
||||||
slotAccountStateAdded(ai.data());
|
slotAccountStateAdded(ai.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(FolderMan::instance()->socketApi(), SIGNAL(shareCommandReceived(QString, QString, bool)),
|
connect(FolderMan::instance()->socketApi(), SIGNAL(shareCommandReceived(QString, QString)),
|
||||||
_gui, SLOT(slotShowShareDialog(QString, QString, bool)));
|
_gui, SLOT(slotShowShareDialog(QString, QString)));
|
||||||
|
|
||||||
// startup procedure.
|
// startup procedure.
|
||||||
connect(&_checkConnectionTimer, SIGNAL(timeout()), this, SLOT(slotCheckConnection()));
|
connect(&_checkConnectionTimer, SIGNAL(timeout()), this, SLOT(slotCheckConnection()));
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
#include <QString>
|
|
||||||
#import <Cocoa/Cocoa.h>
|
|
||||||
|
|
||||||
namespace OCC {
|
|
||||||
|
|
||||||
// https://github.com/owncloud/client/issues/3300
|
|
||||||
void copyToPasteboard(const QString &string)
|
|
||||||
{
|
|
||||||
[[NSPasteboard generalPasteboard] clearContents];
|
|
||||||
[[NSPasteboard generalPasteboard] setString:[NSString stringWithUTF8String:string.toUtf8().data()]
|
|
||||||
forType:NSStringPboardType];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
56
src/gui/guiutility.cpp
Normal file
56
src/gui/guiutility.cpp
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) by Christian Kamm <mail@ckamm.de>
|
||||||
|
*
|
||||||
|
* 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 "guiutility.h"
|
||||||
|
|
||||||
|
#include <QClipboard>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
using namespace OCC;
|
||||||
|
|
||||||
|
bool Utility::openBrowser(const QUrl &url, QWidget *errorWidgetParent)
|
||||||
|
{
|
||||||
|
if (!QDesktopServices::openUrl(url) && errorWidgetParent) {
|
||||||
|
QMessageBox::warning(
|
||||||
|
errorWidgetParent,
|
||||||
|
QCoreApplication::translate("utility", "Could not open browser"),
|
||||||
|
QCoreApplication::translate("utility",
|
||||||
|
"There was an error when launching the browser to go to "
|
||||||
|
"URL %1. Maybe no default browser is configured?")
|
||||||
|
.arg(url.toString()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Utility::openEmailComposer(const QString &subject, const QString &body, QWidget *errorWidgetParent)
|
||||||
|
{
|
||||||
|
QUrl url(QLatin1String("mailto: "));
|
||||||
|
url.setQueryItems({ { QLatin1String("subject"), subject },
|
||||||
|
{ QLatin1String("body"), body } });
|
||||||
|
|
||||||
|
if (!QDesktopServices::openUrl(url) && errorWidgetParent) {
|
||||||
|
QMessageBox::warning(
|
||||||
|
errorWidgetParent,
|
||||||
|
QCoreApplication::translate("utility", "Could not open email client"),
|
||||||
|
QCoreApplication::translate("utility",
|
||||||
|
"There was an error when launching the email client to "
|
||||||
|
"create a new message. Maybe no default email client is "
|
||||||
|
"configured?"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
41
src/gui/guiutility.h
Normal file
41
src/gui/guiutility.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) by Christian Kamm <mail@ckamm.de>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GUIUTILITY_H
|
||||||
|
#define GUIUTILITY_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
namespace OCC {
|
||||||
|
namespace Utility {
|
||||||
|
|
||||||
|
/** Open an url in the browser.
|
||||||
|
*
|
||||||
|
* If launching the browser fails, display a message.
|
||||||
|
*/
|
||||||
|
bool openBrowser(const QUrl &url, QWidget *errorWidgetParent);
|
||||||
|
|
||||||
|
/** Start composing a new email message.
|
||||||
|
*
|
||||||
|
* If launching the email program fails, display a message.
|
||||||
|
*/
|
||||||
|
bool openEmailComposer(const QString &subject, const QString &body,
|
||||||
|
QWidget *errorWidgetParent);
|
||||||
|
|
||||||
|
} // namespace Utility
|
||||||
|
} // namespace OCC
|
||||||
|
|
||||||
|
#endif
|
|
@ -33,6 +33,7 @@
|
||||||
#include "accountstate.h"
|
#include "accountstate.h"
|
||||||
#include "openfilemanager.h"
|
#include "openfilemanager.h"
|
||||||
#include "accountmanager.h"
|
#include "accountmanager.h"
|
||||||
|
#include "syncjournalfilerecord.h"
|
||||||
#include "creds/abstractcredentials.h"
|
#include "creds/abstractcredentials.h"
|
||||||
|
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
|
@ -1039,7 +1040,7 @@ void ownCloudGui::raiseDialog(QWidget *raiseWidget)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ownCloudGui::slotShowShareDialog(const QString &sharePath, const QString &localPath, bool resharingAllowed)
|
void ownCloudGui::slotShowShareDialog(const QString &sharePath, const QString &localPath)
|
||||||
{
|
{
|
||||||
const auto folder = FolderMan::instance()->folderForPath(localPath);
|
const auto folder = FolderMan::instance()->folderForPath(localPath);
|
||||||
if (!folder) {
|
if (!folder) {
|
||||||
|
@ -1052,6 +1053,17 @@ void ownCloudGui::slotShowShareDialog(const QString &sharePath, const QString &l
|
||||||
|
|
||||||
const auto accountState = folder->accountState();
|
const auto accountState = folder->accountState();
|
||||||
|
|
||||||
|
const QString file = localPath.mid(folder->cleanPath().length() + 1);
|
||||||
|
SyncJournalFileRecord fileRecord = folder->journalDb()->getFileRecord(file);
|
||||||
|
|
||||||
|
bool resharingAllowed = true; // lets assume the good
|
||||||
|
if (fileRecord.isValid()) {
|
||||||
|
// check the permission: Is resharing allowed?
|
||||||
|
if (!fileRecord._remotePerm.contains('R')) {
|
||||||
|
resharingAllowed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// As a first approximation, set the set of permissions that can be granted
|
// As a first approximation, set the set of permissions that can be granted
|
||||||
// either to everything (resharing allowed) or nothing (no resharing).
|
// either to everything (resharing allowed) or nothing (no resharing).
|
||||||
//
|
//
|
||||||
|
@ -1072,7 +1084,7 @@ void ownCloudGui::slotShowShareDialog(const QString &sharePath, const QString &l
|
||||||
w = _shareDialogs[localPath];
|
w = _shareDialogs[localPath];
|
||||||
} else {
|
} else {
|
||||||
qCInfo(lcApplication) << "Opening share dialog" << sharePath << localPath << maxSharingPermissions;
|
qCInfo(lcApplication) << "Opening share dialog" << sharePath << localPath << maxSharingPermissions;
|
||||||
w = new ShareDialog(accountState, sharePath, localPath, maxSharingPermissions);
|
w = new ShareDialog(accountState, sharePath, localPath, maxSharingPermissions, fileRecord.numericFileId());
|
||||||
w->setAttribute(Qt::WA_DeleteOnClose, true);
|
w->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
|
|
||||||
_shareDialogs[localPath] = w;
|
_shareDialogs[localPath] = w;
|
||||||
|
|
|
@ -86,7 +86,16 @@ public slots:
|
||||||
void slotOpenPath(const QString &path);
|
void slotOpenPath(const QString &path);
|
||||||
void slotAccountStateChanged();
|
void slotAccountStateChanged();
|
||||||
void slotTrayMessageIfServerUnsupported(Account *account);
|
void slotTrayMessageIfServerUnsupported(Account *account);
|
||||||
void slotShowShareDialog(const QString &sharePath, const QString &localPath, bool resharingAllowed);
|
|
||||||
|
/**
|
||||||
|
* Open a share dialog for a file or folder.
|
||||||
|
*
|
||||||
|
* sharePath is the full remote path to the item,
|
||||||
|
* localPath is the absolute local path to it (so not relative
|
||||||
|
* to the folder).
|
||||||
|
*/
|
||||||
|
void slotShowShareDialog(const QString &sharePath, const QString &localPath);
|
||||||
|
|
||||||
void slotRemoveDestroyedShareDialogs();
|
void slotRemoveDestroyedShareDialogs();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
|
@ -38,6 +38,7 @@ ShareDialog::ShareDialog(QPointer<AccountState> accountState,
|
||||||
const QString &sharePath,
|
const QString &sharePath,
|
||||||
const QString &localPath,
|
const QString &localPath,
|
||||||
SharePermissions maxSharingPermissions,
|
SharePermissions maxSharingPermissions,
|
||||||
|
const QByteArray &numericFileId,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
, _ui(new Ui::ShareDialog)
|
, _ui(new Ui::ShareDialog)
|
||||||
|
@ -45,6 +46,7 @@ ShareDialog::ShareDialog(QPointer<AccountState> accountState,
|
||||||
, _sharePath(sharePath)
|
, _sharePath(sharePath)
|
||||||
, _localPath(localPath)
|
, _localPath(localPath)
|
||||||
, _maxSharingPermissions(maxSharingPermissions)
|
, _maxSharingPermissions(maxSharingPermissions)
|
||||||
|
, _numericFileId(numericFileId)
|
||||||
, _linkWidget(NULL)
|
, _linkWidget(NULL)
|
||||||
, _userGroupWidget(NULL)
|
, _userGroupWidget(NULL)
|
||||||
, _progressIndicator(NULL)
|
, _progressIndicator(NULL)
|
||||||
|
@ -192,7 +194,7 @@ void ShareDialog::showSharingUi()
|
||||||
&& _accountState->account()->serverVersionInt() >= Account::makeServerVersion(8, 2, 0);
|
&& _accountState->account()->serverVersionInt() >= Account::makeServerVersion(8, 2, 0);
|
||||||
|
|
||||||
if (userGroupSharing) {
|
if (userGroupSharing) {
|
||||||
_userGroupWidget = new ShareUserGroupWidget(_accountState->account(), _sharePath, _localPath, _maxSharingPermissions, this);
|
_userGroupWidget = new ShareUserGroupWidget(_accountState->account(), _sharePath, _localPath, _maxSharingPermissions, _numericFileId, this);
|
||||||
_ui->shareWidgets->addTab(_userGroupWidget, tr("Users and Groups"));
|
_ui->shareWidgets->addTab(_userGroupWidget, tr("Users and Groups"));
|
||||||
_userGroupWidget->getShares();
|
_userGroupWidget->getShares();
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ public:
|
||||||
const QString &sharePath,
|
const QString &sharePath,
|
||||||
const QString &localPath,
|
const QString &localPath,
|
||||||
SharePermissions maxSharingPermissions,
|
SharePermissions maxSharingPermissions,
|
||||||
|
const QByteArray &numericFileId,
|
||||||
QWidget *parent = 0);
|
QWidget *parent = 0);
|
||||||
~ShareDialog();
|
~ShareDialog();
|
||||||
|
|
||||||
|
@ -60,8 +61,8 @@ private:
|
||||||
QPointer<AccountState> _accountState;
|
QPointer<AccountState> _accountState;
|
||||||
QString _sharePath;
|
QString _sharePath;
|
||||||
QString _localPath;
|
QString _localPath;
|
||||||
|
|
||||||
SharePermissions _maxSharingPermissions;
|
SharePermissions _maxSharingPermissions;
|
||||||
|
QByteArray _numericFileId;
|
||||||
|
|
||||||
ShareLinkWidget *_linkWidget;
|
ShareLinkWidget *_linkWidget;
|
||||||
ShareUserGroupWidget *_userGroupWidget;
|
ShareUserGroupWidget *_userGroupWidget;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "capabilities.h"
|
#include "capabilities.h"
|
||||||
|
|
||||||
#include "sharemanager.h"
|
#include "sharemanager.h"
|
||||||
|
#include "guiutility.h"
|
||||||
|
|
||||||
#include "QProgressIndicator.h"
|
#include "QProgressIndicator.h"
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
|
@ -494,51 +495,18 @@ void ShareLinkWidget::slotCheckBoxExpireClicked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
extern void copyToPasteboard(const QString &string);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void ShareLinkWidget::copyShareLink(const QUrl &url)
|
|
||||||
{
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
copyToPasteboard(url.toString());
|
|
||||||
#else
|
|
||||||
QClipboard *clipboard = QApplication::clipboard();
|
|
||||||
clipboard->setText(url.toString());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShareLinkWidget::emailShareLink(const QUrl &url)
|
void ShareLinkWidget::emailShareLink(const QUrl &url)
|
||||||
{
|
{
|
||||||
QString fileName = _sharePath.mid(_sharePath.lastIndexOf('/') + 1);
|
QString fileName = _sharePath.mid(_sharePath.lastIndexOf('/') + 1);
|
||||||
|
Utility::openEmailComposer(
|
||||||
if (!QDesktopServices::openUrl(QUrl(QString(
|
QString("I shared %1 with you").arg(fileName),
|
||||||
"mailto: "
|
url.toString(),
|
||||||
"?subject=I shared %1 with you"
|
this);
|
||||||
"&body=%2")
|
|
||||||
.arg(
|
|
||||||
fileName,
|
|
||||||
url.toString()),
|
|
||||||
QUrl::TolerantMode))) {
|
|
||||||
QMessageBox::warning(
|
|
||||||
this,
|
|
||||||
tr("Could not open email client"),
|
|
||||||
tr("There was an error when launching the email client to "
|
|
||||||
"create a new message. Maybe no default email client is "
|
|
||||||
"configured?"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShareLinkWidget::openShareLink(const QUrl &url)
|
void ShareLinkWidget::openShareLink(const QUrl &url)
|
||||||
{
|
{
|
||||||
if (!QDesktopServices::openUrl(url)) {
|
Utility::openBrowser(url, this);
|
||||||
QMessageBox::warning(
|
|
||||||
this,
|
|
||||||
tr("Could not open browser"),
|
|
||||||
tr("There was an error when launching the browser to "
|
|
||||||
"view the public link share. Maybe no default browser is "
|
|
||||||
"configured?"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShareLinkWidget::slotShareLinkButtonTriggered(QAction *action)
|
void ShareLinkWidget::slotShareLinkButtonTriggered(QAction *action)
|
||||||
|
@ -546,9 +514,9 @@ void ShareLinkWidget::slotShareLinkButtonTriggered(QAction *action)
|
||||||
auto share = sender()->property(propertyShareC).value<QSharedPointer<LinkShare>>();
|
auto share = sender()->property(propertyShareC).value<QSharedPointer<LinkShare>>();
|
||||||
|
|
||||||
if (action == _copyLinkAction) {
|
if (action == _copyLinkAction) {
|
||||||
copyShareLink(share->getLink());
|
QApplication::clipboard()->setText(share->getLink().toString());
|
||||||
} else if (action == _copyDirectLinkAction) {
|
} else if (action == _copyDirectLinkAction) {
|
||||||
copyShareLink(share->getDirectDownloadLink());
|
QApplication::clipboard()->setText(share->getDirectDownloadLink().toString());
|
||||||
} else if (action == _emailLinkAction) {
|
} else if (action == _emailLinkAction) {
|
||||||
emailShareLink(share->getLink());
|
emailShareLink(share->getLink());
|
||||||
} else if (action == _emailDirectLinkAction) {
|
} else if (action == _emailDirectLinkAction) {
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
#include "configfile.h"
|
#include "configfile.h"
|
||||||
#include "capabilities.h"
|
#include "capabilities.h"
|
||||||
|
#include "guiutility.h"
|
||||||
#include "thumbnailjob.h"
|
#include "thumbnailjob.h"
|
||||||
#include "sharee.h"
|
#include "sharee.h"
|
||||||
#include "sharemanager.h"
|
#include "sharemanager.h"
|
||||||
|
@ -39,6 +39,8 @@
|
||||||
#include <QPropertyAnimation>
|
#include <QPropertyAnimation>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
|
@ -46,6 +48,7 @@ ShareUserGroupWidget::ShareUserGroupWidget(AccountPtr account,
|
||||||
const QString &sharePath,
|
const QString &sharePath,
|
||||||
const QString &localPath,
|
const QString &localPath,
|
||||||
SharePermissions maxSharingPermissions,
|
SharePermissions maxSharingPermissions,
|
||||||
|
const QByteArray &numericFileId,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, _ui(new Ui::ShareUserGroupWidget)
|
, _ui(new Ui::ShareUserGroupWidget)
|
||||||
|
@ -53,6 +56,7 @@ ShareUserGroupWidget::ShareUserGroupWidget(AccountPtr account,
|
||||||
, _sharePath(sharePath)
|
, _sharePath(sharePath)
|
||||||
, _localPath(localPath)
|
, _localPath(localPath)
|
||||||
, _maxSharingPermissions(maxSharingPermissions)
|
, _maxSharingPermissions(maxSharingPermissions)
|
||||||
|
, _numericFileId(numericFileId)
|
||||||
, _disableCompleterActivated(false)
|
, _disableCompleterActivated(false)
|
||||||
{
|
{
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
@ -80,6 +84,7 @@ ShareUserGroupWidget::ShareUserGroupWidget(AccountPtr account,
|
||||||
connect(_manager, SIGNAL(shareCreated(QSharedPointer<Share>)), SLOT(getShares()));
|
connect(_manager, SIGNAL(shareCreated(QSharedPointer<Share>)), SLOT(getShares()));
|
||||||
connect(_manager, SIGNAL(serverError(int, QString)), this, SLOT(displayError(int, QString)));
|
connect(_manager, SIGNAL(serverError(int, QString)), this, SLOT(displayError(int, QString)));
|
||||||
connect(_ui->shareeLineEdit, SIGNAL(returnPressed()), SLOT(slotLineEditReturn()));
|
connect(_ui->shareeLineEdit, SIGNAL(returnPressed()), SLOT(slotLineEditReturn()));
|
||||||
|
connect(_ui->privateLinkText, SIGNAL(linkActivated(QString)), SLOT(slotPrivateLinkShare()));
|
||||||
|
|
||||||
// By making the next two QueuedConnections we can override
|
// By making the next two QueuedConnections we can override
|
||||||
// the strings the completer sets on the line edit.
|
// the strings the completer sets on the line edit.
|
||||||
|
@ -222,6 +227,21 @@ void ShareUserGroupWidget::slotAdjustScrollWidgetSize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShareUserGroupWidget::slotPrivateLinkShare()
|
||||||
|
{
|
||||||
|
auto menu = new QMenu(this);
|
||||||
|
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
|
menu->addAction(tr("Open link in browser"),
|
||||||
|
this, SLOT(slotPrivateLinkOpenBrowser()));
|
||||||
|
menu->addAction(tr("Copy link to clipboard"),
|
||||||
|
this, SLOT(slotPrivateLinkCopy()));
|
||||||
|
menu->addAction(tr("Send link by email"),
|
||||||
|
this, SLOT(slotPrivateLinkEmail()));
|
||||||
|
|
||||||
|
menu->exec(QCursor::pos());
|
||||||
|
}
|
||||||
|
|
||||||
void ShareUserGroupWidget::slotShareesReady()
|
void ShareUserGroupWidget::slotShareesReady()
|
||||||
{
|
{
|
||||||
_pi_sharee.stopAnimation();
|
_pi_sharee.stopAnimation();
|
||||||
|
@ -301,6 +321,24 @@ void ShareUserGroupWidget::displayError(int code, const QString &message)
|
||||||
_ui->shareeLineEdit->setEnabled(true);
|
_ui->shareeLineEdit->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShareUserGroupWidget::slotPrivateLinkOpenBrowser()
|
||||||
|
{
|
||||||
|
Utility::openBrowser(_account->filePermalinkUrl(_numericFileId), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShareUserGroupWidget::slotPrivateLinkCopy()
|
||||||
|
{
|
||||||
|
QApplication::clipboard()->setText(_account->filePermalinkUrl(_numericFileId).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShareUserGroupWidget::slotPrivateLinkEmail()
|
||||||
|
{
|
||||||
|
Utility::openEmailComposer(
|
||||||
|
tr("I shared something with you"),
|
||||||
|
_account->filePermalinkUrl(_numericFileId).toString(),
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
|
||||||
ShareUserLine::ShareUserLine(QSharedPointer<Share> share,
|
ShareUserLine::ShareUserLine(QSharedPointer<Share> share,
|
||||||
SharePermissions maxSharingPermissions,
|
SharePermissions maxSharingPermissions,
|
||||||
bool isFile,
|
bool isFile,
|
||||||
|
|
|
@ -57,6 +57,7 @@ public:
|
||||||
const QString &sharePath,
|
const QString &sharePath,
|
||||||
const QString &localPath,
|
const QString &localPath,
|
||||||
SharePermissions maxSharingPermissions,
|
SharePermissions maxSharingPermissions,
|
||||||
|
const QByteArray &numericFileId,
|
||||||
QWidget *parent = 0);
|
QWidget *parent = 0);
|
||||||
~ShareUserGroupWidget();
|
~ShareUserGroupWidget();
|
||||||
|
|
||||||
|
@ -75,19 +76,25 @@ private slots:
|
||||||
void slotCompleterHighlighted(const QModelIndex &index);
|
void slotCompleterHighlighted(const QModelIndex &index);
|
||||||
void slotShareesReady();
|
void slotShareesReady();
|
||||||
void slotAdjustScrollWidgetSize();
|
void slotAdjustScrollWidgetSize();
|
||||||
|
void slotPrivateLinkShare();
|
||||||
void displayError(int code, const QString &message);
|
void displayError(int code, const QString &message);
|
||||||
|
|
||||||
|
void slotPrivateLinkOpenBrowser();
|
||||||
|
void slotPrivateLinkCopy();
|
||||||
|
void slotPrivateLinkEmail();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::ShareUserGroupWidget *_ui;
|
Ui::ShareUserGroupWidget *_ui;
|
||||||
AccountPtr _account;
|
AccountPtr _account;
|
||||||
QString _sharePath;
|
QString _sharePath;
|
||||||
QString _localPath;
|
QString _localPath;
|
||||||
|
SharePermissions _maxSharingPermissions;
|
||||||
|
QByteArray _numericFileId;
|
||||||
|
|
||||||
QCompleter *_completer;
|
QCompleter *_completer;
|
||||||
ShareeModel *_completerModel;
|
ShareeModel *_completerModel;
|
||||||
QTimer _completionTimer;
|
QTimer _completionTimer;
|
||||||
|
|
||||||
SharePermissions _maxSharingPermissions;
|
|
||||||
bool _isFile;
|
bool _isFile;
|
||||||
bool _disableCompleterActivated; // in order to avoid that we share the contents twice
|
bool _disableCompleterActivated; // in order to avoid that we share the contents twice
|
||||||
ShareManager *_manager;
|
ShareManager *_manager;
|
||||||
|
|
|
@ -94,14 +94,24 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>395</width>
|
<width>377</width>
|
||||||
<height>221</height>
|
<height>169</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3"/>
|
<layout class="QVBoxLayout" name="verticalLayout_3"/>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="privateLinkText">
|
||||||
|
<property name="text">
|
||||||
|
<string><html><head/><body><p>You can direct people to this shared file or folder <a href="private link menu"><span style=" text-decoration: underline; color:#0000ff;">by giving them a private link</span></a>.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
|
|
|
@ -32,7 +32,9 @@
|
||||||
#include "account.h"
|
#include "account.h"
|
||||||
#include "capabilities.h"
|
#include "capabilities.h"
|
||||||
#include "asserts.h"
|
#include "asserts.h"
|
||||||
|
#include "guiutility.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <QBitArray>
|
#include <QBitArray>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QMetaMethod>
|
#include <QMetaMethod>
|
||||||
|
@ -45,6 +47,8 @@
|
||||||
#include <QLocalSocket>
|
#include <QLocalSocket>
|
||||||
#include <QStringBuilder>
|
#include <QStringBuilder>
|
||||||
|
|
||||||
|
#include <QClipboard>
|
||||||
|
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -436,19 +440,10 @@ void SocketApi::command_SHARE(const QString &localFile, SocketListener *listener
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SyncJournalFileRecord rec = shareFolder->journalDb()->getFileRecord(localFileClean);
|
|
||||||
|
|
||||||
bool allowReshare = true; // lets assume the good
|
|
||||||
if (rec.isValid()) {
|
|
||||||
// check the permission: Is resharing allowed?
|
|
||||||
if (!rec._remotePerm.contains('R')) {
|
|
||||||
allowReshare = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const QString message = QLatin1String("SHARE:OK:") + QDir::toNativeSeparators(localFile);
|
const QString message = QLatin1String("SHARE:OK:") + QDir::toNativeSeparators(localFile);
|
||||||
listener->sendMessage(message);
|
listener->sendMessage(message);
|
||||||
|
|
||||||
emit shareCommandReceived(remotePath, localFileClean, allowReshare);
|
emit shareCommandReceived(remotePath, localFileClean);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -514,6 +509,39 @@ 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()));
|
listener->sendMessage(QLatin1String("SHARE_MENU_TITLE:") + tr("Share with %1", "parameter is ownCloud").arg(Theme::instance()->appNameGUI()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SocketApi::command_COPY_PRIVATE_LINK(const QString &localFile, SocketListener *)
|
||||||
|
{
|
||||||
|
auto url = getPrivateLinkUrl(localFile);
|
||||||
|
if (!url.isEmpty()) {
|
||||||
|
QApplication::clipboard()->setText(url.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(),
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketApi::command_GET_STRINGS(const QString &, SocketListener *listener)
|
||||||
|
{
|
||||||
|
static std::array<std::pair<const char *, QString>, 5> strings { {
|
||||||
|
{ "SHARE_MENU_TITLE", tr("Share with %1...", "parameter is ownCloud").arg(Theme::instance()->appNameGUI()) },
|
||||||
|
{ "APPNAME", Theme::instance()->appNameGUI() },
|
||||||
|
{ "CONTEXT_MENU_TITLE", Theme::instance()->appNameGUI() },
|
||||||
|
{ "COPY_PRIVATE_LINK_TITLE", tr("Copy private link to clipboard") },
|
||||||
|
{ "EMAIL_PRIVATE_LINK_TITLE", tr("Send private link by email...") },
|
||||||
|
} };
|
||||||
|
for (auto key_value : strings) {
|
||||||
|
listener->sendMessage(QString("STRING:%1:%2").arg(key_value.first, key_value.second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString SocketApi::buildRegisterPathMessage(const QString &path)
|
QString SocketApi::buildRegisterPathMessage(const QString &path)
|
||||||
{
|
{
|
||||||
QFileInfo fi(path);
|
QFileInfo fi(path);
|
||||||
|
@ -522,4 +550,22 @@ QString SocketApi::buildRegisterPathMessage(const QString &path)
|
||||||
return message;
|
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
|
} // namespace OCC
|
||||||
|
|
|
@ -55,8 +55,7 @@ public slots:
|
||||||
void slotRegisterPath(const QString &alias);
|
void slotRegisterPath(const QString &alias);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void shareCommandReceived(const QString &sharePath, const QString &localPath, bool resharingAllowed);
|
void shareCommandReceived(const QString &sharePath, const QString &localPath);
|
||||||
void shareUserGroupCommandReceived(const QString &sharePath, const QString &localPath, bool resharingAllowed);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void slotNewConnection();
|
void slotNewConnection();
|
||||||
|
@ -70,13 +69,22 @@ private:
|
||||||
|
|
||||||
Q_INVOKABLE void command_RETRIEVE_FOLDER_STATUS(const QString &argument, SocketListener *listener);
|
Q_INVOKABLE void command_RETRIEVE_FOLDER_STATUS(const QString &argument, SocketListener *listener);
|
||||||
Q_INVOKABLE void command_RETRIEVE_FILE_STATUS(const QString &argument, SocketListener *listener);
|
Q_INVOKABLE void command_RETRIEVE_FILE_STATUS(const QString &argument, SocketListener *listener);
|
||||||
Q_INVOKABLE void command_SHARE(const QString &localFile, SocketListener *listener);
|
|
||||||
|
|
||||||
Q_INVOKABLE void command_VERSION(const QString &argument, SocketListener *listener);
|
Q_INVOKABLE void command_VERSION(const QString &argument, SocketListener *listener);
|
||||||
|
|
||||||
Q_INVOKABLE void command_SHARE_STATUS(const QString &localFile, SocketListener *listener);
|
Q_INVOKABLE void command_SHARE_STATUS(const QString &localFile, SocketListener *listener);
|
||||||
Q_INVOKABLE void command_SHARE_MENU_TITLE(const QString &argument, SocketListener *listener);
|
Q_INVOKABLE void command_SHARE_MENU_TITLE(const QString &argument, SocketListener *listener);
|
||||||
|
|
||||||
|
// The context menu actions
|
||||||
|
Q_INVOKABLE void command_SHARE(const QString &localFile, SocketListener *listener);
|
||||||
|
Q_INVOKABLE void command_COPY_PRIVATE_LINK(const QString &localFile, SocketListener *listener);
|
||||||
|
Q_INVOKABLE void command_EMAIL_PRIVATE_LINK(const QString &localFile, SocketListener *listener);
|
||||||
|
|
||||||
|
/** Sends translated/branded strings that may be useful to the integration */
|
||||||
|
Q_INVOKABLE void command_GET_STRINGS(const QString &argument, SocketListener *listener);
|
||||||
|
|
||||||
QString buildRegisterPathMessage(const QString &path);
|
QString buildRegisterPathMessage(const QString &path);
|
||||||
|
QUrl getPrivateLinkUrl(const QString &localFile) const;
|
||||||
|
|
||||||
QSet<QString> _registeredAliases;
|
QSet<QString> _registeredAliases;
|
||||||
QList<SocketListener> _listeners;
|
QList<SocketListener> _listeners;
|
||||||
|
|
|
@ -160,6 +160,12 @@ QUrl Account::davUrl() const
|
||||||
return Utility::concatUrlPath(url(), davPath());
|
return Utility::concatUrlPath(url(), davPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QUrl Account::filePermalinkUrl(const QByteArray &numericFileId) const
|
||||||
|
{
|
||||||
|
return Utility::concatUrlPath(url(),
|
||||||
|
QLatin1String("/index.php/f/") + QUrl::toPercentEncoding(QString::fromLatin1(numericFileId)));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clear all cookies. (Session cookies or not)
|
* clear all cookies. (Session cookies or not)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -107,6 +107,9 @@ public:
|
||||||
/** Returns webdav entry URL, based on url() */
|
/** Returns webdav entry URL, based on url() */
|
||||||
QUrl davUrl() const;
|
QUrl davUrl() const;
|
||||||
|
|
||||||
|
/** Returns a permalink url for a file */
|
||||||
|
QUrl filePermalinkUrl(const QByteArray &numericFileId) const;
|
||||||
|
|
||||||
/** Holds the accounts credentials */
|
/** Holds the accounts credentials */
|
||||||
AbstractCredentials *credentials() const;
|
AbstractCredentials *credentials() const;
|
||||||
void setCredentials(AbstractCredentials *cred);
|
void setCredentials(AbstractCredentials *cred);
|
||||||
|
|
|
@ -42,6 +42,11 @@ Q_LOGGING_CATEGORY(lcPropagateLocalRemove, "sync.propagator.localremove", QtInfo
|
||||||
Q_LOGGING_CATEGORY(lcPropagateLocalMkdir, "sync.propagator.localmkdir", QtInfoMsg)
|
Q_LOGGING_CATEGORY(lcPropagateLocalMkdir, "sync.propagator.localmkdir", QtInfoMsg)
|
||||||
Q_LOGGING_CATEGORY(lcPropagateLocalRename, "sync.propagator.localrename", QtInfoMsg)
|
Q_LOGGING_CATEGORY(lcPropagateLocalRename, "sync.propagator.localrename", QtInfoMsg)
|
||||||
|
|
||||||
|
QByteArray localFileIdFromFullId(const QByteArray &id)
|
||||||
|
{
|
||||||
|
return id.left(8);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Code inspired from Qt5's QDir::removeRecursively
|
* Code inspired from Qt5's QDir::removeRecursively
|
||||||
* The code will update the database in case of error.
|
* The code will update the database in case of error.
|
||||||
|
|
|
@ -109,6 +109,17 @@ SyncFileItem SyncJournalFileRecord::toSyncFileItem()
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray SyncJournalFileRecord::numericFileId() const
|
||||||
|
{
|
||||||
|
// Use the id up until the first non-numeric character
|
||||||
|
for (int i = 0; i < _fileId.size(); ++i) {
|
||||||
|
if (_fileId[i] < '0' || _fileId[i] > '9') {
|
||||||
|
return _fileId.left(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _fileId;
|
||||||
|
}
|
||||||
|
|
||||||
bool SyncJournalErrorBlacklistRecord::isValid() const
|
bool SyncJournalErrorBlacklistRecord::isValid() const
|
||||||
{
|
{
|
||||||
return !_file.isEmpty()
|
return !_file.isEmpty()
|
||||||
|
|
|
@ -48,6 +48,14 @@ public:
|
||||||
return !_path.isEmpty();
|
return !_path.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the numeric part of the full id in _fileId.
|
||||||
|
*
|
||||||
|
* On the server this is sometimes known as the internal file id.
|
||||||
|
*
|
||||||
|
* It is used in the construction of private links.
|
||||||
|
*/
|
||||||
|
QByteArray numericFileId() const;
|
||||||
|
|
||||||
QString _path;
|
QString _path;
|
||||||
quint64 _inode;
|
quint64 _inode;
|
||||||
QDateTime _modtime;
|
QDateTime _modtime;
|
||||||
|
|
|
@ -55,6 +55,7 @@ list(APPEND FolderMan_SRC ../src/gui/socketapi.cpp )
|
||||||
list(APPEND FolderMan_SRC ../src/gui/accountstate.cpp )
|
list(APPEND FolderMan_SRC ../src/gui/accountstate.cpp )
|
||||||
list(APPEND FolderMan_SRC ../src/gui/syncrunfilelog.cpp )
|
list(APPEND FolderMan_SRC ../src/gui/syncrunfilelog.cpp )
|
||||||
list(APPEND FolderMan_SRC ../src/gui/lockwatcher.cpp )
|
list(APPEND FolderMan_SRC ../src/gui/lockwatcher.cpp )
|
||||||
|
list(APPEND FolderMan_SRC ../src/gui/guiutility.cpp )
|
||||||
list(APPEND FolderMan_SRC ${FolderWatcher_SRC})
|
list(APPEND FolderMan_SRC ${FolderWatcher_SRC})
|
||||||
list(APPEND FolderMan_SRC stub.cpp )
|
list(APPEND FolderMan_SRC stub.cpp )
|
||||||
owncloud_add_test(FolderMan "${FolderMan_SRC}")
|
owncloud_add_test(FolderMan "${FolderMan_SRC}")
|
||||||
|
|
Loading…
Reference in a new issue