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
This commit is contained in:
Kostas Karmas 2020-05-11 17:47:09 +02:00
parent 5ccf8e412d
commit b717755f20
3 changed files with 58 additions and 6 deletions

View file

@ -96,6 +96,18 @@ class Account(QObject):
return return
self._authorization_service.startAuthorizationFlow() 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) @pyqtProperty(str, notify=loginStateChanged)
def userName(self): def userName(self):
user_profile = self._authorization_service.getUserProfile() user_profile = self._authorization_service.getUserProfile()

View file

@ -4,7 +4,7 @@
import json import json
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Optional, TYPE_CHECKING from typing import Optional, TYPE_CHECKING
from urllib.parse import urlencode from urllib.parse import urlencode, quote_plus
import requests.exceptions import requests.exceptions
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl
@ -142,7 +142,7 @@ class AuthorizationService:
self.onAuthStateChanged.emit(logged_in = False) self.onAuthStateChanged.emit(logged_in = False)
## Start the flow to become authenticated. This will start a new webbrowser tap, prompting the user to login. ## 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...") Logger.log("d", "Starting new OAuth2 flow...")
# Create the tokens needed for the code challenge (PKCE) extension for OAuth2. # 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() title=i18n_catalog.i18nc("@info:title", "Warning")).show()
return return
# Open the authorization page in a new browser window. # Open the authorization page in a new browser window. If a force logout is requested during the authorization
QDesktopServices.openUrl(QUrl("{}?{}".format(self._auth_url, query_string))) # 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. ## Callback method for the authentication flow.

View file

@ -51,11 +51,11 @@ Item
} }
// Component that contains a busy indicator and a message, while it waits for Cura to discover a cloud printer // Component that contains a busy indicator and a message, while it waits for Cura to discover a cloud printer
Rectangle Item
{ {
id: waitingContent id: waitingContent
width: parent.width width: parent.width
height: waitingIndicator.height + waitingLabel.height height: childrenRect.height
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
BusyIndicator BusyIndicator
@ -74,6 +74,37 @@ Item
font: UM.Theme.getFont("large") font: UM.Theme.getFont("large")
renderType: Text.NativeRendering 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 visible: discoveredCloudPrintersModel.count == 0
} }