diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index 8f5621704d47b..490438feed28f 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -1312,6 +1312,9 @@ void AccountSettings::slotAccountStateChanged() // we can't end up here as the whole block is ifdeffed Q_UNREACHABLE(); break; + case AccountState::NeedToSignTermsOfService: + showConnectionLabel(tr("You need to accept the terms of service")); + break; } } else { // ownCloud is not yet configured. diff --git a/src/gui/accountstate.cpp b/src/gui/accountstate.cpp index fc18efbd09230..8434b4a9a3f84 100644 --- a/src/gui/accountstate.cpp +++ b/src/gui/accountstate.cpp @@ -60,6 +60,10 @@ AccountState::AccountState(const AccountPtr &account) this, &AccountState::slotPushNotificationsReady); connect(account.data(), &Account::serverUserStatusChanged, this, &AccountState::slotServerUserStatusChanged); + connect(account.data(), &Account::termsOfServiceNeedToBeChecked, + this, [this] () { + checkConnectivity(); + }); connect(this, &AccountState::isConnectedChanged, [=]{ // Get the Apps available on the server if we're now connected. @@ -155,6 +159,8 @@ QString AccountState::stateString(State state) return tr("Configuration error"); case AskingCredentials: return tr("Asking Credentials"); + case NeedToSignTermsOfService: + return tr("Need the user to accept the terms of service"); } return tr("Unknown account state"); } @@ -342,6 +348,12 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta _lastConnectionValidatorStatus = status; + if ((_lastConnectionValidatorStatus == ConnectionValidator::NeedToSignTermsOfService && status == ConnectionValidator::Connected) || + status == ConnectionValidator::NeedToSignTermsOfService) { + + emit termsOfServiceChanged(_account); + } + // Come online gradually from 503, captive portal(redirection) or maintenance mode if (status == ConnectionValidator::Connected && (_connectionStatus == ConnectionValidator::ServiceUnavailable @@ -420,6 +432,9 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta setState(NetworkError); updateRetryCount(); break; + case ConnectionValidator::NeedToSignTermsOfService: + setState(NeedToSignTermsOfService); + break; } } diff --git a/src/gui/accountstate.h b/src/gui/accountstate.h index 77caa1b4051ca..019b96d70cfd3 100644 --- a/src/gui/accountstate.h +++ b/src/gui/accountstate.h @@ -82,7 +82,10 @@ class AccountState : public QObject, public QSharedData ConfigurationError, /// We are currently asking the user for credentials - AskingCredentials + AskingCredentials, + + /// Need to sign terms of service by going to web UI + NeedToSignTermsOfService, }; /// The actual current connectivity status. @@ -192,6 +195,7 @@ public slots: void hasFetchedNavigationApps(); void statusChanged(); void desktopNotificationsAllowedChanged(); + void termsOfServiceChanged(OCC::AccountPtr account); protected Q_SLOTS: void slotConnectionValidatorResult(OCC::ConnectionValidator::Status status, const QStringList &errors); diff --git a/src/gui/application.cpp b/src/gui/application.cpp index 48fb06682f109..2255fcab6b676 100644 --- a/src/gui/application.cpp +++ b/src/gui/application.cpp @@ -588,6 +588,8 @@ void Application::slotAccountStateAdded(AccountState *accountState) _gui.data(), &ownCloudGui::slotAccountStateChanged); connect(accountState->account().data(), &Account::serverVersionChanged, _gui.data(), &ownCloudGui::slotTrayMessageIfServerUnsupported); + connect(accountState, &AccountState::termsOfServiceChanged, + _gui.data(), &ownCloudGui::slotNeedToAcceptTermsOfService); connect(accountState, &AccountState::stateChanged, _folderManager.data(), &FolderMan::slotAccountStateChanged); connect(accountState->account().data(), &Account::serverVersionChanged, diff --git a/src/gui/connectionvalidator.cpp b/src/gui/connectionvalidator.cpp index 9cc24de4a7521..9f69ced881be2 100644 --- a/src/gui/connectionvalidator.cpp +++ b/src/gui/connectionvalidator.cpp @@ -267,7 +267,20 @@ void ConnectionValidator::slotCapabilitiesRecieved(const QJsonDocument &json) QString directEditingETag = caps["files"].toObject()["directEditing"].toObject()["etag"].toString(); _account->fetchDirectEditors(directEditingURL, directEditingETag); - fetchUser(); + checkServerTermsOfService(); +} + +void ConnectionValidator::checkServerTermsOfService() +{ + // The main flow now needs the capabilities + auto *job = new JsonApiJob(_account, QLatin1String("ocs/v2.php/apps/terms_of_service/terms"), this); + job->setTimeout(timeoutToUseMsec); + QObject::connect(job, &JsonApiJob::jsonReceived, this, &ConnectionValidator::slotServerTermsOfServiceRecieved); + QObject::connect(job, &JsonApiJob::networkError, this, [] (QNetworkReply *reply) + { + qCInfo(lcConnectionValidator()) << "network error" << reply->error(); + }); + job->start(); } void ConnectionValidator::fetchUser() @@ -321,6 +334,22 @@ void ConnectionValidator::slotUserFetched(UserInfo *userInfo) #endif } +void ConnectionValidator::slotServerTermsOfServiceRecieved(const QJsonDocument &reply) +{ + qCDebug(lcConnectionValidator) << "Terms of service status" << reply; + + if (reply.object().contains("ocs")) { + const auto hasSigned = reply.object().value("ocs").toObject().value("data").toObject().value("hasSigned").toBool(false); + + if (!hasSigned) { + reportResult(NeedToSignTermsOfService); + return; + } + } + + fetchUser(); +} + #ifndef TOKEN_AUTH_ONLY void ConnectionValidator::reportConnected() { reportResult(Connected); diff --git a/src/gui/connectionvalidator.h b/src/gui/connectionvalidator.h index 4b7193b0c8004..99e2b3d9bb222 100644 --- a/src/gui/connectionvalidator.h +++ b/src/gui/connectionvalidator.h @@ -95,7 +95,8 @@ class ConnectionValidator : public QObject StatusRedirect, // 204 URL received one of redirect HTTP codes (301-307), possibly a captive portal ServiceUnavailable, // 503 on authed request MaintenanceMode, // maintenance enabled in status.php - Timeout // actually also used for other errors on the authed request + Timeout, // actually also used for other errors on the authed request + NeedToSignTermsOfService, }; Q_ENUM(Status); @@ -129,6 +130,7 @@ protected slots: void slotCapabilitiesRecieved(const QJsonDocument &); void slotUserFetched(OCC::UserInfo *userInfo); + void slotServerTermsOfServiceRecieved(const QJsonDocument &reply); private: #ifndef TOKEN_AUTH_ONLY @@ -136,6 +138,7 @@ protected slots: #endif void reportResult(Status status); void checkServerCapabilities(); + void checkServerTermsOfService(); void fetchUser(); /** Sets the account's server version diff --git a/src/gui/folder.cpp b/src/gui/folder.cpp index d63f5980b0c15..da4445e2d951a 100644 --- a/src/gui/folder.cpp +++ b/src/gui/folder.cpp @@ -92,6 +92,12 @@ Folder::Folder(const FolderDefinition &definition, if (!reloadExcludes()) qCWarning(lcFolder, "Could not read system exclude file"); + connect(_accountState.data(), &AccountState::termsOfServiceChanged, + this, [this] () + { + setSyncPaused(_accountState->state() == AccountState::NeedToSignTermsOfService); + }); + connect(_accountState.data(), &AccountState::isConnectedChanged, this, &Folder::canSyncChanged); connect(_engine.data(), &SyncEngine::rootEtag, this, &Folder::etagRetrievedFromSyncEngine); diff --git a/src/gui/owncloudgui.cpp b/src/gui/owncloudgui.cpp index c14b5125a0861..9d1331fa93d12 100644 --- a/src/gui/owncloudgui.cpp +++ b/src/gui/owncloudgui.cpp @@ -275,6 +275,16 @@ void ownCloudGui::slotTrayMessageIfServerUnsupported(Account *account) } } +void ownCloudGui::slotNeedToAcceptTermsOfService(OCC::AccountPtr account) +{ + slotShowTrayMessage( + tr("Terms of service"), + tr("Your account %1 requires you to accept the terms of service of your server. " + "You will be redirected to %2 to acknowledge that you have read it and agrees with it.") + .arg(account->displayName(), account->url().toString())); + QDesktopServices::openUrl(account->url()); +} + void ownCloudGui::slotComputeOverallSyncStatus() { bool allSignedOut = true; diff --git a/src/gui/owncloudgui.h b/src/gui/owncloudgui.h index 8315fe228caa6..1cfc44876d525 100644 --- a/src/gui/owncloudgui.h +++ b/src/gui/owncloudgui.h @@ -94,7 +94,7 @@ public slots: void slotOpenPath(const QString &path); void slotAccountStateChanged(); void slotTrayMessageIfServerUnsupported(OCC::Account *account); - + void slotNeedToAcceptTermsOfService(OCC::AccountPtr account); /** * Open a share dialog for a file or folder. diff --git a/src/libsync/account.h b/src/libsync/account.h index 0ac43606c0d61..b7e4066fe451c 100644 --- a/src/libsync/account.h +++ b/src/libsync/account.h @@ -377,6 +377,8 @@ public slots: void lockFileSuccess(); void lockFileError(const QString&); + void termsOfServiceNeedToBeChecked(); + protected Q_SLOTS: void slotCredentialsFetched(); void slotCredentialsAsked(); diff --git a/src/libsync/discoveryphase.cpp b/src/libsync/discoveryphase.cpp index cb7674ab40f0e..9b1030875ac7d 100644 --- a/src/libsync/discoveryphase.cpp +++ b/src/libsync/discoveryphase.cpp @@ -651,6 +651,10 @@ void DiscoverySingleDirectoryJob::lsJobFinishedWithErrorSlot(QNetworkReply *r) msg = tr("Server error: PROPFIND reply is not XML formatted!"); } + if (r->error() == QNetworkReply::ContentAccessDenied) { + emit _account->termsOfServiceNeedToBeChecked(); + } + emit finished(HttpError{ httpCode, msg }); deleteLater(); }