diff --git a/src/gui/accountmanager.cpp b/src/gui/accountmanager.cpp index ccfcfec4cbd0f..0849fc516d650 100644 --- a/src/gui/accountmanager.cpp +++ b/src/gui/accountmanager.cpp @@ -343,7 +343,11 @@ void AccountManager::saveAccountHelper(Account *account, QSettings &settings, bo { qCDebug(lcAccountManager) << "Saving settings to" << settings.fileName(); settings.setValue(QLatin1String(versionC), maxAccountVersion); - settings.setValue(QLatin1String(urlC), account->_url.toString()); + if (account->isPublicShareLink()) { + settings.setValue(QLatin1String(urlC), account->publicShareLinkUrl().toString()); + } else { + settings.setValue(QLatin1String(urlC), account->_url.toString()); + } settings.setValue(QLatin1String(davUserC), account->_davUser); settings.setValue(QLatin1String(displayNameC), account->davDisplayName()); settings.setValue(QLatin1String(serverVersionC), account->_serverVersion); diff --git a/src/gui/connectionvalidator.cpp b/src/gui/connectionvalidator.cpp index 75cb21762fcb0..a1f59100a22a5 100644 --- a/src/gui/connectionvalidator.cpp +++ b/src/gui/connectionvalidator.cpp @@ -271,6 +271,13 @@ void ConnectionValidator::slotCapabilitiesRecieved(const QJsonDocument &json) _account->fetchDirectEditors(directEditingURL, directEditingETag); checkServerTermsOfService(); + + if (_account->isPublicShareLink()) { + slotUserFetched(nullptr); + return; + } + + fetchUser(); } void ConnectionValidator::fetchUser() diff --git a/src/gui/owncloudsetupwizard.cpp b/src/gui/owncloudsetupwizard.cpp index 58a6d613f0475..ab52a22895c82 100644 --- a/src/gui/owncloudsetupwizard.cpp +++ b/src/gui/owncloudsetupwizard.cpp @@ -34,6 +34,7 @@ #include "sslerrordialog.h" #include "wizard/owncloudwizard.h" #include "wizard/owncloudwizardcommon.h" +#include "account.h" #include "creds/credentialsfactory.h" #include "creds/abstractcredentials.h" @@ -290,7 +291,11 @@ void OwncloudSetupWizard::slotFoundServer(const QUrl &url, const QJsonObject &in qCInfo(lcWizard) << " was redirected to" << url.toString(); } - slotDetermineAuthType(); + if (_ocWizard->account()->isPublicShareLink()) { + _ocWizard->setAuthType(DetermineAuthTypeJob::Basic); + } else { + slotDetermineAuthType(); + } } void OwncloudSetupWizard::slotNoServerFound(QNetworkReply *reply) @@ -341,6 +346,19 @@ void OwncloudSetupWizard::slotConnectToOCUrl(const QString &url) _ocWizard->account()->setCredentials(creds); } + if (_ocWizard->account()->isPublicShareLink()) { + _ocWizard->account()->setDavUser(creds->user()); + _ocWizard->account()->setDavDisplayName(creds->user()); + + _ocWizard->setField(QLatin1String("OCUrl"), url); + _ocWizard->appendToConfigurationLog(tr("Trying to connect to %1 at %2 …") + .arg(Theme::instance()->appNameGUI()) + .arg(url)); + + testOwnCloudConnect(); + return; + } + const auto fetchUserNameJob = new JsonApiJob(_ocWizard->account()->sharedFromThis(), QStringLiteral("/ocs/v1.php/cloud/user")); connect(fetchUserNameJob, &JsonApiJob::jsonReceived, this, [this, url](const QJsonDocument &json, int statusCode) { if (statusCode != 100) { @@ -731,6 +749,11 @@ AccountState *OwncloudSetupWizard::applyAccountChanges() auto manager = AccountManager::instance(); auto newState = manager->addAccount(newAccount); + + if (newAccount->isPublicShareLink()) { + qCInfo(lcWizard()) << "seeting up public share link account"; + } + manager->saveAccount(newAccount.data()); return newState; } diff --git a/src/gui/tray/UserLine.qml b/src/gui/tray/UserLine.qml index 010a9391b08b9..8858dc693837e 100644 --- a/src/gui/tray/UserLine.qml +++ b/src/gui/tray/UserLine.qml @@ -152,6 +152,9 @@ AbstractButton { } MenuItem { + visible: model.canLogout + height: visible ? implicitHeight : 0 + width: parent.width text: model.isConnected ? qsTr("Log out") : qsTr("Log in") font.pixelSize: Style.topLinePixelSize hoverEnabled: true @@ -175,7 +178,7 @@ AbstractButton { MenuItem { id: removeAccountButton - text: qsTr("Remove account") + text: model.removeAccountText font.pixelSize: Style.topLinePixelSize hoverEnabled: true onClicked: { diff --git a/src/gui/tray/usermodel.cpp b/src/gui/tray/usermodel.cpp index abddeaa102d65..3c319b76e6d86 100644 --- a/src/gui/tray/usermodel.cpp +++ b/src/gui/tray/usermodel.cpp @@ -884,6 +884,16 @@ const QVariantList &User::groupFolders() const return _trayFolderInfos; } +bool User::canLogout() const +{ + return !isPublicShareLink(); +} + +bool User::isPublicShareLink() const +{ + return _account->account()->isPublicShareLink(); +} + void User::slotItemCompleted(const QString &folder, const SyncFileItemPtr &item) { auto folderInstance = FolderMan::instance()->folder(folder); @@ -988,17 +998,27 @@ void User::logout() const QString User::name() const { + if (isPublicShareLink()) { + return tr("Public Share Link"); + } + return _account->account()->prettyName(); } QString User::server(bool shortened) const { - QString serverUrl = _account->account()->url().toString(); + auto serverUrl = _account->account()->url(); + + if (isPublicShareLink()) { + serverUrl.setUserName({}); + } + QString stringServerUrl = serverUrl.toString(); if (shortened) { - serverUrl.replace(QLatin1String("https://"), QLatin1String("")); - serverUrl.replace(QLatin1String("http://"), QLatin1String("")); + stringServerUrl.replace(QLatin1String("https://"), QLatin1String("")); + stringServerUrl.replace(QLatin1String("http://"), QLatin1String("")); + } - return serverUrl; + return stringServerUrl; } UserStatus::OnlineStatus User::status() const @@ -1509,34 +1529,51 @@ int UserModel::rowCount(const QModelIndex &parent) const QVariant UserModel::data(const QModelIndex &index, int role) const { - if (index.row() < 0 || index.row() >= _users.count()) { - return QVariant(); - } - - if (role == NameRole) { - return _users[index.row()]->name(); - } else if (role == ServerRole) { - return _users[index.row()]->server(); - } else if (role == ServerHasUserStatusRole) { - return _users[index.row()]->serverHasUserStatus(); - } else if (role == StatusIconRole) { - return _users[index.row()]->statusIcon(); - } else if (role == StatusEmojiRole) { - return _users[index.row()]->statusEmoji(); - } else if (role == StatusMessageRole) { - return _users[index.row()]->statusMessage(); - } else if (role == DesktopNotificationsAllowedRole) { - return _users[index.row()]->isDesktopNotificationsAllowed(); - } else if (role == AvatarRole) { - return _users[index.row()]->avatarUrl(); - } else if (role == IsCurrentUserRole) { - return _users[index.row()]->isCurrentUser(); - } else if (role == IsConnectedRole) { - return _users[index.row()]->isConnected(); - } else if (role == IdRole) { - return index.row(); - } - return QVariant(); + auto result = QVariant{}; + switch (role) + { + case NameRole: + result = _users[index.row()]->name(); + break; + case ServerRole: + result = _users[index.row()]->server(); + break; + case ServerHasUserStatusRole: + result = _users[index.row()]->serverHasUserStatus(); + break; + case StatusIconRole: + result = _users[index.row()]->statusIcon(); + break; + case StatusEmojiRole: + result = _users[index.row()]->statusEmoji(); + break; + case StatusMessageRole: + result = _users[index.row()]->statusMessage(); + break; + case DesktopNotificationsAllowedRole: + result = _users[index.row()]->isDesktopNotificationsAllowed(); + break; + case AvatarRole: + result = _users[index.row()]->avatarUrl(); + break; + case IsCurrentUserRole: + result = _users[index.row()]->isCurrentUser(); + break; + case IsConnectedRole: + result = _users[index.row()]->isConnected(); + break; + case IdRole: + result = index.row(); + break; + case CanLogoutRole: + result = _users[index.row()]->canLogout(); + break; + case RemoveAccountTextRole: + result = _users[index.row()]->isPublicShareLink() ? tr("Leave share") : tr("Remove account"); + break; + } + + return result; } QHash UserModel::roleNames() const @@ -1545,6 +1582,8 @@ QHash UserModel::roleNames() const roles[NameRole] = "name"; roles[ServerRole] = "server"; roles[ServerHasUserStatusRole] = "serverHasUserStatus"; + roles[CanLogoutRole] = "canLogout"; + roles[RemoveAccountTextRole] = "removeAccountText"; roles[StatusIconRole] = "statusIcon"; roles[StatusEmojiRole] = "statusEmoji"; roles[StatusMessageRole] = "statusMessage"; diff --git a/src/gui/tray/usermodel.h b/src/gui/tray/usermodel.h index 3f2170ab0748e..750ceb8109af4 100644 --- a/src/gui/tray/usermodel.h +++ b/src/gui/tray/usermodel.h @@ -63,6 +63,7 @@ class User : public QObject Q_PROPERTY(bool isConnected READ isConnected NOTIFY accountStateChanged) Q_PROPERTY(UnifiedSearchResultsListModel* unifiedSearchResultsListModel READ getUnifiedSearchResultsListModel CONSTANT) Q_PROPERTY(QVariantList groupFolders READ groupFolders NOTIFY groupFoldersChanged) + Q_PROPERTY(bool canLogout READ canLogout CONSTANT) public: User(AccountStatePtr &account, const bool &isCurrent = false, QObject *parent = nullptr); @@ -104,6 +105,8 @@ class User : public QObject [[nodiscard]] QString statusEmoji() const; void processCompletedSyncItem(const Folder *folder, const SyncFileItemPtr &item); [[nodiscard]] const QVariantList &groupFolders() const; + [[nodiscard]] bool canLogout() const; + [[nodiscard]] bool isPublicShareLink() const; signals: void nameChanged(); @@ -236,6 +239,8 @@ class UserModel : public QAbstractListModel NameRole = Qt::UserRole + 1, ServerRole, ServerHasUserStatusRole, + CanLogoutRole, + RemoveAccountTextRole, StatusIconRole, StatusEmojiRole, StatusMessageRole, @@ -243,7 +248,7 @@ class UserModel : public QAbstractListModel AvatarRole, IsCurrentUserRole, IsConnectedRole, - IdRole + IdRole, }; [[nodiscard]] AccountAppList appList() const; diff --git a/src/gui/userinfo.cpp b/src/gui/userinfo.cpp index 6835cc6285b32..be5a5daead884 100644 --- a/src/gui/userinfo.cpp +++ b/src/gui/userinfo.cpp @@ -76,7 +76,7 @@ void UserInfo::slotRequestFailed() bool UserInfo::canGetInfo() const { - if (!_accountState || !_active) { + if (!_accountState || !_active || !_accountState->account() || _accountState->account()->isPublicShareLink()) { return false; } AccountPtr account = _accountState->account(); @@ -140,7 +140,7 @@ void UserInfo::slotUpdateLastInfo(const QJsonDocument &json) _jobRestartTimer.start(defaultIntervalT); _lastInfoReceived = QDateTime::currentDateTime(); - if(_fetchAvatarImage) { + if(_fetchAvatarImage && !account->isPublicShareLink()) { auto *job = new AvatarJob(account, account->davUser(), 128, this); job->setTimeout(20 * 1000); QObject::connect(job, &AvatarJob::avatarPixmap, this, &UserInfo::slotAvatarImage); diff --git a/src/gui/wizard/owncloudadvancedsetuppage.cpp b/src/gui/wizard/owncloudadvancedsetuppage.cpp index f515e1c716a65..74268645911de 100644 --- a/src/gui/wizard/owncloudadvancedsetuppage.cpp +++ b/src/gui/wizard/owncloudadvancedsetuppage.cpp @@ -226,6 +226,11 @@ void OwncloudAdvancedSetupPage::fetchUserAvatar() if (Theme::isHidpi()) { avatarSize *= 2; } + + if (account->isPublicShareLink()) { + return; + } + const auto avatarJob = new AvatarJob(account, account->davUser(), avatarSize, this); avatarJob->setTimeout(20 * 1000); QObject::connect(avatarJob, &AvatarJob::avatarPixmap, this, [this](const QImage &avatarImage) { diff --git a/src/gui/wizard/owncloudhttpcredspage.cpp b/src/gui/wizard/owncloudhttpcredspage.cpp index ed514b72a459c..069f142061fe6 100644 --- a/src/gui/wizard/owncloudhttpcredspage.cpp +++ b/src/gui/wizard/owncloudhttpcredspage.cpp @@ -104,11 +104,15 @@ void OwncloudHttpCredsPage::initializePage() const QString user = url.userName(); const QString password = url.password(); + _ui.leUsername->setText(user); + _ui.lePassword->setText(password); + if (!user.isEmpty()) { - _ui.leUsername->setText(user); - } - if (!password.isEmpty()) { - _ui.lePassword->setText(password); + _ui.errorLabel->setVisible(false); + startSpinner(); + + emit completeChanged(); + emit connectToOCUrl(field("OCUrl").toString().simplified()); } } _ui.tokenLabel->setText(HttpCredentialsGui::requestAppPasswordText(ocWizard->account().data())); @@ -124,7 +128,7 @@ void OwncloudHttpCredsPage::cleanupPage() bool OwncloudHttpCredsPage::validatePage() { - if (_ui.leUsername->text().isEmpty() || _ui.lePassword->text().isEmpty()) { + if (_ui.leUsername->text().isEmpty()) { return false; } diff --git a/src/libsync/account.cpp b/src/libsync/account.cpp index 82f0376dd5e85..f2972fd59a363 100644 --- a/src/libsync/account.cpp +++ b/src/libsync/account.cpp @@ -104,7 +104,11 @@ QString Account::davPath() const QString Account::davPathRoot() const { - return davPathBase() + QLatin1Char('/') + davUser(); + if (_isPublicLink) { + return QStringLiteral("/public.php/webdav"); + } else { + return davPathBase() + QLatin1Char('/') + davUser(); + } } void Account::setSharedThis(AccountPtr sharedThis) @@ -526,10 +530,26 @@ void Account::setSslErrorHandler(AbstractSslErrorHandler *handler) void Account::setUrl(const QUrl &url) { - _url = url; + const QRegularExpression discoverPublicLinks(R"((http.://[^/]*).*/s/([^/]*))"); + const auto isPublicLink = discoverPublicLinks.match(url.toString()); + if (isPublicLink.hasMatch()) { + _url = QUrl::fromUserInput(isPublicLink.captured(1)); + _url.setUserName(isPublicLink.captured(2)); + setDavUser(isPublicLink.captured(2)); + _isPublicLink = true; + _publicShareLinkUrl = url; + } else { + _url = url; + } + _userVisibleUrl = url; } +QUrl Account::publicShareLinkUrl() const +{ + return _publicShareLinkUrl; +} + void Account::setUserVisibleHost(const QString &host) { _userVisibleUrl.setHost(host); diff --git a/src/libsync/account.h b/src/libsync/account.h index dcf1fb623bd64..bd9b006cc5a83 100644 --- a/src/libsync/account.h +++ b/src/libsync/account.h @@ -165,6 +165,12 @@ class OWNCLOUDSYNC_EXPORT Account : public QObject /** Server url of the account */ void setUrl(const QUrl &url); [[nodiscard]] QUrl url() const { return _url; } + [[nodiscard]] QUrl publicShareLinkUrl() const; + + [[nodiscard]] bool isPublicShareLink() const + { + return _isPublicLink; + } /// Adjusts _userVisibleUrl once the host to use is discovered. void setUserVisibleHost(const QString &host); @@ -501,6 +507,8 @@ private slots: #endif QMap _settingsMap; QUrl _url; + QUrl _publicShareLinkUrl; + bool _isPublicLink = false; /** If url to use for any user-visible urls. * diff --git a/src/libsync/networkjobs.cpp b/src/libsync/networkjobs.cpp index 3369050033374..cd6a516466ae2 100644 --- a/src/libsync/networkjobs.cpp +++ b/src/libsync/networkjobs.cpp @@ -1061,6 +1061,9 @@ void DetermineAuthTypeJob::start() } else { _resultGet = LoginFlowV2; } + if (_account->isPublicShareLink()) { + _resultGet = Basic; + } _getDone = true; checkAllDone(); }); @@ -1101,6 +1104,9 @@ void DetermineAuthTypeJob::start() } else { _resultOldFlow = Basic; } + if (_account->isPublicShareLink()) { + _resultOldFlow = Basic; + } _oldFlowDone = true; checkAllDone(); });