Added account object to API

CURA-5744
This commit is contained in:
Jaime van Kessel 2018-09-21 16:43:32 +02:00
parent 060ea0b762
commit b54383e685
3 changed files with 93 additions and 1 deletions

88
cura/API/Account.py Normal file
View file

@ -0,0 +1,88 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Tuple, Optional, Dict
from PyQt5.QtCore.QObject import QObject, pyqtSignal, pyqtSlot, pyqtProperty
from UM.Message import Message
from cura.OAuth2.AuthorizationService import AuthorizationService
from cura.OAuth2.Models import OAuth2Settings
from UM.Application import Application
from UM.i18n import i18nCatalog
i18n_catalog = i18nCatalog("cura")
## The account API provides a version-proof bridge to use Ultimaker Accounts
#
# Usage:
# ``from cura.API import CuraAPI
# api = CuraAPI()
# api.account.login()
# api.account.logout()
# api.account.userProfile # Who is logged in``
#
class Account(QObject):
# Signal emitted when user logged in or out.
loginStateChanged = pyqtSignal()
def __init__(self, parent = None) -> None:
super().__init__(parent)
self._callback_port = 32118
self._oauth_root = "https://account.ultimaker.com"
self._cloud_api_root = "https://api.ultimaker.com"
self._oauth_settings = OAuth2Settings(
OAUTH_SERVER_URL= self._oauth_root,
CALLBACK_PORT=self._callback_port,
CALLBACK_URL="http://localhost:{}/callback".format(self._callback_port),
CLIENT_ID="um---------------ultimaker_cura_drive_plugin",
CLIENT_SCOPES="user.read drive.backups.read drive.backups.write",
AUTH_DATA_PREFERENCE_KEY="cura_drive/auth_data",
AUTH_SUCCESS_REDIRECT="{}/cura-drive/v1/auth-success".format(self._cloud_api_root),
AUTH_FAILED_REDIRECT="{}/cura-drive/v1/auth-error".format(self._cloud_api_root)
)
self._authorization_service = AuthorizationService(Application.getInstance().getPreferences(), self._oauth_settings)
self._authorization_service.onAuthStateChanged.connect(self._onLoginStateChanged)
self._authorization_service.onAuthenticationError.connect(self._onLoginStateChanged)
self._error_message = None
self._logged_in = False
@pyqtProperty(bool, notify=loginStateChanged)
def isLoggedIn(self) -> bool:
return self._logged_in
def _onLoginStateChanged(self, logged_in: bool = False, error_message: Optional[str] = None) -> None:
if error_message:
if self._error_message:
self._error_message.hide()
self._error_message = Message(error_message, title = i18n_catalog.i18nc("@info:title", "Login failed"))
self._error_message.show()
if self._logged_in != logged_in:
self._logged_in = logged_in
self.loginStateChanged.emit()
def login(self) -> None:
if self._logged_in:
# Nothing to do, user already logged in.
return
self._authorization_service.startAuthorizationFlow()
# Get the profile of the logged in user
# @returns None if no user is logged in, a dict containing user_id, username and profile_image_url
@pyqtProperty("QVariantMap", notify = loginStateChanged)
def userProfile(self) -> Optional[Dict[str, Optional[str]]]:
user_profile = self._authorization_service.getUserProfile()
if not user_profile:
return None
return user_profile.__dict__
def logout(self) -> None:
if not self._logged_in:
return # Nothing to do, user isn't logged in.
self._authorization_service.deleteAuthData()

View file

@ -3,6 +3,8 @@
from UM.PluginRegistry import PluginRegistry
from cura.API.Backups import Backups
from cura.API.Interface import Interface
from cura.API.Account import Account
## The official Cura API that plug-ins can use to interact with Cura.
#
@ -10,7 +12,6 @@ from cura.API.Interface import Interface
# this API provides a version-safe interface with proper deprecation warnings
# etc. Usage of any other methods than the ones provided in this API can cause
# plug-ins to be unstable.
class CuraAPI:
# For now we use the same API version to be consistent.
@ -21,3 +22,5 @@ class CuraAPI:
# Interface API
interface = Interface()
account = Account()

View file

@ -49,6 +49,7 @@ class AuthorizationService:
if not self._user_profile:
# If there is still no user profile from the JWT, we have to log in again.
return None
return self._user_profile
def _parseJWT(self) -> Optional["UserProfile"]: