diff --git a/autotests/urltest.cpp b/autotests/urltest.cpp --- a/autotests/urltest.cpp +++ b/autotests/urltest.cpp @@ -28,6 +28,8 @@ private Q_SLOTS: void testGDriveUrl_data(); void testGDriveUrl(); + void testGDriveParent_data(); + void testGDriveParent(); }; QTEST_GUILESS_MAIN(UrlTest) @@ -36,7 +38,7 @@ { const auto gdriveUrl = [](const QString &path) { QUrl url; - url.setScheme(QStringLiteral("gdrive")); + url.setScheme(GDriveUrl::Scheme); url.setPath(path); return url; }; @@ -45,65 +47,154 @@ QTest::addColumn("expectedToString"); QTest::addColumn("expectedAccount"); QTest::addColumn("expectedParentPath"); + QTest::addColumn("expectedInTrash"); QTest::addColumn("expectedPathComponents"); + QTest::addColumn("expectedFilename"); QTest::newRow("root url") << gdriveUrl(QStringLiteral("/")) << QStringLiteral("gdrive:/") << QString() << QString() - << QStringList(); + << false + << QStringList() + << ""; QTest::newRow("account root url") << gdriveUrl(QStringLiteral("/foo@gmail.com")) << QStringLiteral("gdrive:/foo@gmail.com") << QStringLiteral("foo@gmail.com") << QStringLiteral("/") - << QStringList {QStringLiteral("foo@gmail.com")}; + << false + << QStringList {QStringLiteral("foo@gmail.com")} + << QStringLiteral("foo@gmail.com"); + + QTest::newRow("account trash url") + << gdriveUrl(QStringLiteral("/foo@gmail.com/") + GDriveUrl::TrashDir) + << QStringLiteral("gdrive:/foo@gmail.com/") + GDriveUrl::TrashDir + << QStringLiteral("foo@gmail.com") + << QStringLiteral("/foo@gmail.com") + << false + << QStringList {QStringLiteral("foo@gmail.com"), GDriveUrl::TrashDir} + << GDriveUrl::TrashDir; + + QTest::newRow("file in trash") + << gdriveUrl(QStringLiteral("/foo@gmail.com/") + GDriveUrl::TrashDir + ("/baz.txt")) + << QStringLiteral("gdrive:/foo@gmail.com/") + GDriveUrl::TrashDir + ("/baz.txt") + << QStringLiteral("foo@gmail.com") + << QStringLiteral("/foo@gmail.com/") + GDriveUrl::TrashDir + << true + << QStringList {QStringLiteral("foo@gmail.com"), GDriveUrl::TrashDir, QStringLiteral("baz.txt")} + << QStringLiteral("baz.txt"); QTest::newRow("file in account root") << gdriveUrl(QStringLiteral("/foo@gmail.com/bar.txt")) << QStringLiteral("gdrive:/foo@gmail.com/bar.txt") << QStringLiteral("foo@gmail.com") << QStringLiteral("/foo@gmail.com") - << QStringList {QStringLiteral("foo@gmail.com"), QStringLiteral("bar.txt")}; + << false + << QStringList {QStringLiteral("foo@gmail.com"), QStringLiteral("bar.txt")} + << QStringLiteral("bar.txt"); QTest::newRow("folder in account root - no trailing slash") << gdriveUrl(QStringLiteral("/foo@gmail.com/bar")) << QStringLiteral("gdrive:/foo@gmail.com/bar") << QStringLiteral("foo@gmail.com") << QStringLiteral("/foo@gmail.com") - << QStringList {QStringLiteral("foo@gmail.com"), QStringLiteral("bar")}; + << false + << QStringList {QStringLiteral("foo@gmail.com"), QStringLiteral("bar")} + << QStringLiteral("bar"); + QTest::newRow("folder in account root - trailing slash") << gdriveUrl(QStringLiteral("/foo@gmail.com/bar/")) << QStringLiteral("gdrive:/foo@gmail.com/bar/") << QStringLiteral("foo@gmail.com") << QStringLiteral("/foo@gmail.com") - << QStringList {QStringLiteral("foo@gmail.com"), QStringLiteral("bar")}; + << false + << QStringList {QStringLiteral("foo@gmail.com"), QStringLiteral("bar")} + << QStringLiteral("bar"); QTest::newRow("file in subfolder") << gdriveUrl(QStringLiteral("/foo@gmail.com/bar/baz.txt")) << QStringLiteral("gdrive:/foo@gmail.com/bar/baz.txt") << QStringLiteral("foo@gmail.com") << QStringLiteral("/foo@gmail.com/bar") - << QStringList {QStringLiteral("foo@gmail.com"), QStringLiteral("bar"), QStringLiteral("baz.txt")}; + << false + << QStringList {QStringLiteral("foo@gmail.com"), QStringLiteral("bar"), QStringLiteral("baz.txt")} + << QStringLiteral("baz.txt"); } void UrlTest::testGDriveUrl() { QFETCH(QUrl, url); + const auto gdriveUrl = GDriveUrl(url); + QFETCH(QString, expectedToString); - QCOMPARE(url.toString(), expectedToString); + QCOMPARE(gdriveUrl.url(), QUrl(expectedToString)); QFETCH(QString, expectedAccount); QFETCH(QString, expectedParentPath); + QFETCH(bool, expectedInTrash); QFETCH(QStringList, expectedPathComponents); + QFETCH(QString, expectedFilename); - const auto gdriveUrl = GDriveUrl(url); + QCOMPARE(gdriveUrl.account(), expectedAccount); + QCOMPARE(gdriveUrl.parentPath(), expectedParentPath); + QCOMPARE(gdriveUrl.pathComponents(), expectedPathComponents); + QCOMPARE(gdriveUrl.inTrash(), expectedInTrash); + QCOMPARE(gdriveUrl.filename(), expectedFilename); + + if (expectedPathComponents.isEmpty()) { + QVERIFY(gdriveUrl.isRoot()); + } else if (expectedPathComponents.count() == 1) { + QVERIFY(gdriveUrl.isAccountRoot()); + } +} + +void UrlTest::testGDriveParent_data() { + const auto gdriveUrl = [](const QString &path) { + QUrl url; + url.setScheme(GDriveUrl::Scheme); + url.setPath(path); + return url; + }; + + QTest::addColumn("url"); + QTest::addColumn("expectedUrl"); + QTest::addColumn("expectedAccount"); + QTest::addColumn("expectedParentPath"); + QTest::addColumn("expectedInTrash"); + QTest::addColumn("expectedPathComponents"); + QTest::addColumn("expectedFilename"); + + QTest::newRow("file parent") + << gdriveUrl(QStringLiteral("/foo@gmail.com/bar.txt")) + << QUrl("gdrive:/foo@gmail.com") + << QStringLiteral("foo@gmail.com") + << QStringLiteral("/") + << false + << QStringList {QStringLiteral("foo@gmail.com")} + << QStringLiteral("foo@gmail.com"); +} + +void UrlTest::testGDriveParent() { + QFETCH(QUrl, url); + const auto gdriveUrl = GDriveUrl(url).parent(); + + QFETCH(QUrl, expectedUrl); + QCOMPARE(gdriveUrl.url(), expectedUrl); + + QFETCH(QString, expectedAccount); + QFETCH(QString, expectedParentPath); + QFETCH(bool, expectedInTrash); + QFETCH(QStringList, expectedPathComponents); + QFETCH(QString, expectedFilename); QCOMPARE(gdriveUrl.account(), expectedAccount); QCOMPARE(gdriveUrl.parentPath(), expectedParentPath); QCOMPARE(gdriveUrl.pathComponents(), expectedPathComponents); + QCOMPARE(gdriveUrl.inTrash(), expectedInTrash); + QCOMPARE(gdriveUrl.filename(), expectedFilename); if (expectedPathComponents.isEmpty()) { QVERIFY(gdriveUrl.isRoot()); diff --git a/src/gdrivehelper.cpp b/src/gdrivehelper.cpp --- a/src/gdrivehelper.cpp +++ b/src/gdrivehelper.cpp @@ -136,7 +136,7 @@ KIO::UDSEntry GDriveHelper::trash() { KIO::UDSEntry trashEntry; - trashEntry.insert(KIO::UDSEntry::UDS_NAME, QStringLiteral("trash")); + trashEntry.insert(KIO::UDSEntry::UDS_NAME, GDriveUrl::TrashDir); trashEntry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, i18n("Trash")); trashEntry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); trashEntry.insert(KIO::UDSEntry::UDS_ICON_NAME, QStringLiteral("user-trash")); diff --git a/src/gdriveurl.h b/src/gdriveurl.h --- a/src/gdriveurl.h +++ b/src/gdriveurl.h @@ -29,12 +29,20 @@ explicit GDriveUrl(const QUrl &url); QString account() const; + QString filename() const; bool isRoot() const; bool isAccountRoot() const; + bool isTrashDir() const; + bool inTrash() const; + QUrl url() const; QString parentPath() const; + GDriveUrl parent() const; QStringList pathComponents() const; + static const QString Scheme; + static const QString TrashDir; private: + GDriveUrl(const QUrl url, const QStringList components); QUrl m_url; QStringList m_components; }; diff --git a/src/gdriveurl.cpp b/src/gdriveurl.cpp --- a/src/gdriveurl.cpp +++ b/src/gdriveurl.cpp @@ -20,6 +20,9 @@ #include "gdriveurl.h" +const QString GDriveUrl::Scheme = QStringLiteral("gdrive"); +const QString GDriveUrl::TrashDir = QStringLiteral("trash"); + GDriveUrl::GDriveUrl(const QUrl &url) : m_url(url) { @@ -27,6 +30,11 @@ m_components = path.split(QLatin1Char('/'), QString::SkipEmptyParts); } +GDriveUrl::GDriveUrl(const QUrl url, const QStringList components) + : m_url(url), + m_components(components) +{ } + QString GDriveUrl::account() const { if (isRoot()) { @@ -36,6 +44,15 @@ return m_components.at(0); } +QString GDriveUrl::filename() const +{ + if (m_components.isEmpty()) { + return QString(); + } + + return m_components.last(); +} + bool GDriveUrl::isRoot() const { return m_components.isEmpty(); @@ -46,6 +63,21 @@ return m_components.length() == 1; } +bool GDriveUrl::isTrashDir() const +{ + return m_components.length() == 2 && m_components.at(1) == TrashDir; +} + +bool GDriveUrl::inTrash() const +{ + return m_components.length() > 2 && m_components.at(1) == TrashDir; +} + +QUrl GDriveUrl::url() const +{ + return m_url; +} + QString GDriveUrl::parentPath() const { if (isRoot()) { @@ -58,6 +90,15 @@ return QLatin1Char('/') + path.join(QLatin1Char('/')); } +GDriveUrl GDriveUrl::parent() const +{ + auto parent_components = m_components; + parent_components.removeLast(); + + QUrl parent_url = QUrl(GDriveUrl::Scheme + QStringLiteral(":/") + parent_components.join(QLatin1Char('/'))); + return GDriveUrl(parent_url, parent_components); +} + QStringList GDriveUrl::pathComponents() const { return m_components; diff --git a/src/kio_gdrive.cpp b/src/kio_gdrive.cpp --- a/src/kio_gdrive.cpp +++ b/src/kio_gdrive.cpp @@ -81,7 +81,7 @@ KIOGDrive::KIOGDrive(const QByteArray &protocol, const QByteArray &pool_socket, const QByteArray &app_socket): - SlaveBase("gdrive", pool_socket, app_socket) + SlaveBase(GDriveUrl::Scheme.toLatin1(), pool_socket, app_socket) { Q_UNUSED(protocol); @@ -226,7 +226,7 @@ QUrl KIOGDrive::fileToUrl(const FilePtr &file, const QString &path) const { QUrl url; - url.setScheme(QStringLiteral("gdrive")); + url.setScheme(GDriveUrl::Scheme); url.setPath(path + QLatin1Char('/') + file->title()); QUrlQuery urlQuery; @@ -348,15 +348,14 @@ } QUrl url; - url.setScheme(QStringLiteral("gdrive")); + url.setScheme(GDriveUrl::Scheme); url.setPath(path); const auto gdriveUrl = GDriveUrl(url); Q_ASSERT(!gdriveUrl.isRoot()); - const QStringList components = gdriveUrl.pathComponents(); - if (gdriveUrl.isAccountRoot() || (components.size() == 2 && components[1] == QLatin1String("trash"))) { + if (gdriveUrl.isAccountRoot() || gdriveUrl.isTrashDir()) { qCDebug(GDRIVE) << "Resolved" << path << "to \"root\""; - return rootFolderId(components[0]); + return rootFolderId(gdriveUrl.account()); } // Try to recursively resolve ID of parent path - either from cache, or by @@ -373,9 +372,9 @@ (flags & KIOGDrive::PathIsFolder ? FileSearchQuery::Equals : FileSearchQuery::NotEquals), GDriveHelper::folderMimeType()); } - query.addQuery(FileSearchQuery::Title, FileSearchQuery::Equals, components.last()); + query.addQuery(FileSearchQuery::Title, FileSearchQuery::Equals, gdriveUrl.filename()); query.addQuery(FileSearchQuery::Parents, FileSearchQuery::In, parentId); - query.addQuery(FileSearchQuery::Trashed, FileSearchQuery::Equals, components[1] == QLatin1String("trash")); + query.addQuery(FileSearchQuery::Trashed, FileSearchQuery::Equals, gdriveUrl.inTrash()); const QString accountId = gdriveUrl.account(); FileFetchJob fetchJob(query, getAccount(accountId)); @@ -501,8 +500,7 @@ return; } QString parentId; - const auto components = gdriveUrl.pathComponents(); - if (components.size() == 2) { + if (gdriveUrl.parent().isAccountRoot()) { parentId = rootFolderId(accountId); } else { parentId = resolveFileIdFromPath(gdriveUrl.parentPath(), KIOGDrive::PathIsFolder); @@ -513,10 +511,8 @@ return; } - const QString folderName = components.last(); - FilePtr file(new File()); - file->setTitle(folderName); + file->setTitle(gdriveUrl.filename()); file->setMimeType(File::folderMimeType()); ParentReferencePtr parent(new ParentReference(parentId)); @@ -754,8 +750,8 @@ error(KIO::ERR_ACCESS_DENIED, url.path()); return false; } - const auto components = gdriveUrl.pathComponents(); - if (components.length() == 2) { + + if (gdriveUrl.parent().isAccountRoot()) { // Creating in root directory } else { const QString parentId = resolveFileIdFromPath(gdriveUrl.parentPath()); @@ -767,7 +763,7 @@ } FilePtr file(new File); - file->setTitle(components.last()); + file->setTitle(gdriveUrl.filename()); file->setParents(parentReferences); /* if (hasMetaData(QLatin1String("modified"))) { @@ -885,9 +881,8 @@ } QString destDirId; - const auto destPathComps = destGDriveUrl.pathComponents(); - const QString destFileName = destPathComps.last(); - if (destPathComps.size() == 2) { + const QString destFileName = destGDriveUrl.filename(); + if (destGDriveUrl.parent().isAccountRoot()) { destDirId = rootFolderId(destAccountId); } else { destDirId = resolveFileIdFromPath(destGDriveUrl.parentPath(), KIOGDrive::PathIsFolder); @@ -1026,8 +1021,6 @@ error(KIO::ERR_ACCESS_DENIED, dest.fileName()); return; } - const auto srcPathComps = srcGDriveUrl.pathComponents(); - const auto destPathComps = destGDriveUrl.pathComponents(); if (destGDriveUrl.isAccountRoot()) { // user is trying to move to root -> we are only renaming } else { @@ -1057,7 +1050,7 @@ parentReferences << ParentReferencePtr(new ParentReference(destDirId)); } - const QString destFileName = destPathComps.last(); + const QString destFileName = destGDriveUrl.filename(); FilePtr destFile(sourceFile); destFile->setTitle(destFileName);