...
 
Commits (6)
include_directories(${CMAKE_SOURCE_DIR})
include_directories(${CMAKE_BINARY_DIR})
add_subdirectory(integration)
set(kio_gdrive_SRCS
kio_gdrive.cpp
pathcache.cpp
......@@ -43,12 +45,3 @@ target_link_libraries(kio_gdrive
${BACKEND_LIBS})
set_target_properties(kio_gdrive PROPERTIES OUTPUT_NAME "gdrive")
kcoreaddons_add_plugin(copyurlitemaction
SOURCES copyurlitemaction.cpp
JSON copyurlitemaction.json
INSTALL_NAMESPACE "kf5/kfileitemaction")
target_link_libraries(copyurlitemaction
KF5::I18n
KF5::KIOWidgets)
/*
* Copyright 2020 David Barchiesi <david@barchie.si>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GDRIVEUDSENTRY_H
#define GDRIVEUDSENTRY_H
#include <KIO/UDSEntry>
enum class GDriveUDSEntryExtras : unsigned int {
Url = KIO::UDSEntry::UDS_EXTRA,
Id,
Md5,
Owners,
Version,
LastModifyingUser,
Description
};
#endif // GDRIVEUDSENTRY_H
......@@ -30,7 +30,11 @@ GDriveUrl::GDriveUrl(const QUrl &url)
: m_url(url)
{
const auto path = url.adjusted(QUrl::StripTrailingSlash).path();
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
m_components = path.split(QLatin1Char('/'), QString::SkipEmptyParts);
#else
m_components = path.split(QLatin1Char('/'), Qt::SkipEmptyParts);
#endif
}
QString GDriveUrl::account() const
......@@ -112,3 +116,8 @@ QStringList GDriveUrl::pathComponents() const
{
return m_components;
}
QString GDriveUrl::buildSharedDrivePath(const QString &accountId, const QString &drive)
{
return QStringLiteral("/%1/%2/%3").arg(accountId, SharedDrivesDir, drive);
}
......@@ -43,6 +43,8 @@ public:
QString parentPath() const;
QStringList pathComponents() const;
static QString buildSharedDrivePath(const QString &accountId, const QString &drive);
static const QString Scheme;
static const QString SharedDrivesDir;
static const QString TrashDir;
......
add_subdirectory(copyurlitemaction)
kcoreaddons_add_plugin(gdrivecopyurlitemaction
SOURCES copyurlitemaction.cpp
JSON copyurlitemaction.json
INSTALL_NAMESPACE "kf5/kfileitemaction")
target_link_libraries(gdrivecopyurlitemaction
KF5::I18n
KF5::KIOWidgets)
......@@ -18,6 +18,7 @@
*/
#include "copyurlitemaction.h"
#include "../../gdrive_udsentry.h"
#include <QGuiApplication>
#include <QClipboard>
......@@ -50,7 +51,7 @@ QList<QAction*> CopyUrlItemAction::actions(const KFileItemListProperties& fileIt
}
const KIO::UDSEntry entry = item.entry();
const QString gdriveLink = entry.stringValue(KIO::UDSEntry::UDS_EXTRA);
const QString gdriveLink = entry.stringValue(static_cast<unsigned int>(GDriveUDSEntryExtras::Url));
// Ignore if missing a shareable link
if (gdriveLink.isEmpty()) {
return {};
......
......@@ -23,6 +23,7 @@
#include "gdrivehelper.h"
#include "gdriveurl.h"
#include "gdriveversion.h"
#include "gdrive_udsentry.h"
#include <QApplication>
#include <QMimeDatabase>
......@@ -236,7 +237,7 @@ KIO::UDSEntry KIOGDrive::fileToUDSEntry(const FilePtr &origFile, const QString &
entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH);
}
entry.fastInsert(KIO::UDSEntry::UDS_EXTRA, file->alternateLink().toString());
entry.fastInsert(static_cast<unsigned int>(GDriveUDSEntryExtras::Url), file->alternateLink().toString());
return entry;
}
......@@ -409,7 +410,14 @@ void KIOGDrive::statSharedDrive(const QUrl &url)
{
const auto gdriveUrl = GDriveUrl(url);
const QString accountId = gdriveUrl.account();
DrivesFetchJob sharedDriveFetchJob(gdriveUrl.filename(), getAccount(accountId));
const auto sharedDriveId = resolveSharedDriveId(gdriveUrl.filename(), accountId);
if (sharedDriveId.isEmpty()) {
error(KIO::ERR_DOES_NOT_EXIST, url.path());
return;
}
DrivesFetchJob sharedDriveFetchJob(sharedDriveId, getAccount(accountId));
sharedDriveFetchJob.setFields({
Drives::Fields::Kind,
Drives::Fields::Id,
......@@ -426,7 +434,6 @@ void KIOGDrive::statSharedDrive(const QUrl &url)
const DrivesPtr sharedDrive = object.dynamicCast<Drives>();
const auto entry = sharedDriveToUDSEntry(sharedDrive);
statEntry(entry);
finished();
}
KIO::UDSEntry KIOGDrive::fetchSharedDrivesRootEntry(const QString &accountId, FetchEntryFlags flags)
......@@ -526,8 +533,11 @@ QString KIOGDrive::resolveFileIdFromPath(const QString &path, PathFlags flags)
}
if (gdriveUrl.isSharedDrive()) {
qCDebug(GDRIVE) << "Resolved" << path << "to Shared Drive" << gdriveUrl.filename();
return gdriveUrl.filename();
// The gdriveUrl.filename() could be the Shared Drive id or
// the name depending on whether we are navigating from a parent
// or accessing the url directly, use the shared drive specific
// solver to disambiguate
return resolveSharedDriveId(gdriveUrl.filename(), gdriveUrl.account());
}
if (gdriveUrl.isSharedDrivesRoot()) {
......@@ -575,6 +585,83 @@ QString KIOGDrive::resolveFileIdFromPath(const QString &path, PathFlags flags)
return file->id();
}
QString KIOGDrive::resolveSharedDriveId(const QString &idOrName, const QString &accountId)
{
qCDebug(GDRIVE) << "Resolving shared drive id for" << idOrName;
const auto idOrNamePath = GDriveUrl::buildSharedDrivePath(accountId, idOrName);
QString fileId = m_cache.idForPath(idOrNamePath);
if (!fileId.isEmpty()) {
qCDebug(GDRIVE) << "Resolved shared drive id" << idOrName << "to" << fileId << "(from cache)";
return fileId;
}
// We start by trying to fetch a shared drive with the filename as id
DrivesFetchJob searchByIdJob(idOrName, getAccount(accountId));
searchByIdJob.setFields({
Drives::Fields::Kind,
Drives::Fields::Id,
Drives::Fields::Name
});
QEventLoop eventLoop;
QObject::connect(&searchByIdJob, &KGAPI2::Job::finished,
&eventLoop, &QEventLoop::quit);
eventLoop.exec();
if (searchByIdJob.error() == KGAPI2::OK || searchByIdJob.error() == KGAPI2::NoError) {
// A Shared Drive with that id exists so we return it
const auto objects = searchByIdJob.items();
const DrivesPtr sharedDrive = objects.at(0).dynamicCast<Drives>();
fileId = sharedDrive->id();
qCDebug(GDRIVE) << "Resolved shared drive id" << idOrName << "to" << fileId;
const auto idPath = idOrNamePath;
const auto namePath = GDriveUrl::buildSharedDrivePath(accountId, sharedDrive->name());
m_cache.insertPath(idPath, fileId);
m_cache.insertPath(namePath, fileId);
return fileId;
}
// The gdriveUrl's filename is not a shared drive id, we must
// search for a shared drive with the filename name.
// Unfortunately searching by name is only allowed for admin
// accounts (i.e. useDomainAdminAccess=true) so we retrieve all
// shared drives and search by name here
DrivesFetchJob sharedDrivesFetchJob(getAccount(accountId));
sharedDrivesFetchJob.setFields({
Drives::Fields::Kind,
Drives::Fields::Id,
Drives::Fields::Name
});
QObject::connect(&sharedDrivesFetchJob, &KGAPI2::Job::finished,
&eventLoop, &QEventLoop::quit);
eventLoop.exec();
if (sharedDrivesFetchJob.error() == KGAPI2::OK || sharedDrivesFetchJob.error() == KGAPI2::NoError) {
const auto objects = sharedDrivesFetchJob.items();
for (const auto &object : objects) {
const DrivesPtr sharedDrive = object.dynamicCast<Drives>();
// If we have one or more hits we will take the first as good because we
// don't have any other measures for picking the correct drive
if (sharedDrive->name() == idOrName) {
fileId = sharedDrive->id();
qCDebug(GDRIVE) << "Resolved shared drive id" << idOrName << "to" << fileId;
const auto idPath = GDriveUrl::buildSharedDrivePath(accountId, fileId);
const auto namePath = idOrNamePath;
m_cache.insertPath(idPath, fileId);
m_cache.insertPath(namePath, fileId);
return fileId;
}
}
}
// We couldn't find any shared drive with that id or name
qCDebug(GDRIVE) << "Failed resolving shared drive" << idOrName << "(couldn't find drive with that id or name)";
return QString();
}
QString KIOGDrive::rootFolderId(const QString &accountId)
{
auto it = m_rootIds.constFind(accountId);
......@@ -780,6 +867,7 @@ void KIOGDrive::stat(const QUrl &url)
if (gdriveUrl.isSharedDrive()) {
qCDebug(GDRIVE) << "stat()ing Shared Drive" << url;
statSharedDrive(url);
finished();
return;
}
......
......@@ -96,6 +96,7 @@ private:
KIO::UDSEntry fetchSharedDrivesRootEntry(const QString &accountId, FetchEntryFlags flags = FetchEntryFlags::None);
QString resolveFileIdFromPath(const QString &path, PathFlags flags = None);
QString resolveSharedDriveId(const QString &idOrName, const QString &accountId);
Action handleError(const KGAPI2::Job &job, const QUrl &url);
KIO::UDSEntry fileToUDSEntry(const KGAPI2::Drive::FilePtr &file, const QString &path) const;
......