From b717755f2062d691444e1c29ac0f5273ca092aa7 Mon Sep 17 00:00:00 2001 From: Kostas Karmas Date: Mon, 11 May 2020 17:47:09 +0200 Subject: [PATCH] Add "Sign in with another account" button in AddCloudPrintersView There are cases where Cura and the browser fall out of sync when it comes to accounts. In such cases, you may be logged in cura with an account that has no cloud printers and in the browser with an account that has printers. So when you press the "Add cloud printer" button, you are redirected to mycloud and you see cloud printers that are not detected by Cura (because Cura is in a different acconut). In such cases, the user can now press the "Sign in with a different account" link in the "Waiting for cloud response" page, which will log him/her out in Cura AND in the browser, and then reinitiate the whole authorization flow, to make sure the accounts are in sync. CURA-7427 --- cura/API/Account.py | 12 +++++++ cura/OAuth2/AuthorizationService.py | 17 ++++++--- .../qml/WelcomePages/AddCloudPrintersView.qml | 35 +++++++++++++++++-- 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/cura/API/Account.py b/cura/API/Account.py index 7273479de4..acf507e23f 100644 --- a/cura/API/Account.py +++ b/cura/API/Account.py @@ -96,6 +96,18 @@ class Account(QObject): return self._authorization_service.startAuthorizationFlow() + @pyqtSlot() + def loginWithForcedLogout(self) -> None: + """ + Forces a logout from Cura and then initiates the authorization flow with the force_logout_from_mycloud variable + as true, to sync the accounts in Cura and in the browser. + + :return: None + """ + if self._logged_in: + self.logout() + self._authorization_service.startAuthorizationFlow(True) + @pyqtProperty(str, notify=loginStateChanged) def userName(self): user_profile = self._authorization_service.getUserProfile() diff --git a/cura/OAuth2/AuthorizationService.py b/cura/OAuth2/AuthorizationService.py index 2f865456b6..ee1cdff19d 100644 --- a/cura/OAuth2/AuthorizationService.py +++ b/cura/OAuth2/AuthorizationService.py @@ -4,7 +4,7 @@ import json from datetime import datetime, timedelta from typing import Optional, TYPE_CHECKING -from urllib.parse import urlencode +from urllib.parse import urlencode, quote_plus import requests.exceptions from PyQt5.QtCore import QUrl @@ -142,7 +142,7 @@ class AuthorizationService: self.onAuthStateChanged.emit(logged_in = False) ## Start the flow to become authenticated. This will start a new webbrowser tap, prompting the user to login. - def startAuthorizationFlow(self) -> None: + def startAuthorizationFlow(self, force_logout_from_mycloud = False) -> None: Logger.log("d", "Starting new OAuth2 flow...") # Create the tokens needed for the code challenge (PKCE) extension for OAuth2. @@ -173,8 +173,17 @@ class AuthorizationService: title=i18n_catalog.i18nc("@info:title", "Warning")).show() return - # Open the authorization page in a new browser window. - QDesktopServices.openUrl(QUrl("{}?{}".format(self._auth_url, query_string))) + # Open the authorization page in a new browser window. If a force logout is requested during the authorization + # flow, the "mycloud logoff" link will be prepended to the authorization url to make sure that the user will be + # logged off from the browser before being redirected to login again. This case is used to sync the accounts + # between Cura and the browser. + auth_url = "{}?{}".format(self._auth_url, query_string) + if force_logout_from_mycloud: + mycloud_logoff_link = "https://mycloud.ultimaker.com/logoff" + logoff_auth_url = "{}?next={}".format(mycloud_logoff_link, quote_plus(auth_url)) + QDesktopServices.openUrl(QUrl(logoff_auth_url)) + else: + QDesktopServices.openUrl(QUrl(auth_url)) ## Callback method for the authentication flow. diff --git a/resources/qml/WelcomePages/AddCloudPrintersView.qml b/resources/qml/WelcomePages/AddCloudPrintersView.qml index f97d68f776..511328b0c8 100644 --- a/resources/qml/WelcomePages/AddCloudPrintersView.qml +++ b/resources/qml/WelcomePages/AddCloudPrintersView.qml @@ -51,11 +51,11 @@ Item } // Component that contains a busy indicator and a message, while it waits for Cura to discover a cloud printer - Rectangle + Item { id: waitingContent width: parent.width - height: waitingIndicator.height + waitingLabel.height + height: childrenRect.height anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter BusyIndicator @@ -74,6 +74,37 @@ Item font: UM.Theme.getFont("large") renderType: Text.NativeRendering } + Label + { + id: noPrintersFoundLabel + anchors.top: waitingLabel.bottom + anchors.topMargin: 2 * UM.Theme.getSize("wide_margin").height + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + text: catalog.i18nc("@label", "No printers found in your account?") + font: UM.Theme.getFont("medium") + } + Label + { + text: "Sign in with a different account" + anchors.top: noPrintersFoundLabel.bottom + anchors.horizontalCenter: parent.horizontalCenter + font: UM.Theme.getFont("medium") + color: UM.Theme.getColor("text_link") + MouseArea { + anchors.fill: parent; + onClicked: Cura.API.account.loginWithForcedLogout() + hoverEnabled: true + onEntered: + { + parent.font.underline = true + } + onExited: + { + parent.font.underline = false + } + } + } visible: discoveredCloudPrintersModel.count == 0 }