added support for muster login window, validator for muster connection, tweaks in muster dialog

This commit is contained in:
Ondrej Samohel 2019-10-08 13:35:26 +02:00
parent 5c4ae73046
commit 76d4fac940
No known key found for this signature in database
GPG key ID: 8A29C663C672C2B7
4 changed files with 150 additions and 18 deletions

View file

@ -38,9 +38,13 @@ class MusterModule:
pass
def process_modules(self, modules):
def api_callback():
self.aShowLogin.trigger()
if "RestApiServer" in modules:
modules["RestApiServer"].register_callback(
"muster/show_login", self.show_login, "post"
"muster/show_login", api_callback, "post"
)
# Definition of Tray menu
@ -61,7 +65,7 @@ class MusterModule:
self.menu.addAction(self.aShowLogin)
self.aShowLogin.triggered.connect(self.show_login)
return self.menu
parent.addMenu(self.menu)
def load_credentials(self):
"""

View file

@ -88,8 +88,7 @@ class MusterLogin(QtWidgets.QWidget):
self.error_label = QtWidgets.QLabel("")
self.error_label.setFont(self.font)
self.error_label.setTextFormat(QtCore.Qt.RichText)
self.error_label.setObjectName("error_label")
self.error_label.setStyleSheet('color: #FC6000')
self.error_label.setWordWrap(True)
self.error_label.hide()
@ -105,6 +104,9 @@ class MusterLogin(QtWidgets.QWidget):
self.btn_ok.clicked.connect(self.click_ok)
self.btn_cancel = QtWidgets.QPushButton("Cancel")
QtWidgets.QShortcut(
QtGui.QKeySequence(
QtCore.Qt.Key_Escape), self).activated.connect(self.close)
self.btn_cancel.clicked.connect(self.close)
self.btn_group.addWidget(self.btn_ok)
@ -115,7 +117,21 @@ class MusterLogin(QtWidgets.QWidget):
return self.main
def keyPressEvent(self, key_event):
if key_event.key() == QtCore.Qt.Key_Return:
if self.input_username.hasFocus():
self.input_password.setFocus()
elif self.input_password.hasFocus() or self.btn_ok.hasFocus():
self.click_ok()
elif self.btn_cancel.hasFocus():
self.close()
else:
super().keyPressEvent(key_event)
def setError(self, msg):
self.error_label.setText(msg)
self.error_label.show()
@ -130,8 +146,13 @@ class MusterLogin(QtWidgets.QWidget):
if not username:
self.setError("Username cannot be empty")
self.invalid_input(self.input_username)
self.save_credentials(username, password)
self._close_widget()
try:
self.save_credentials(username, password)
except Exception as e:
self.setError(
"<b>Cannot get auth token:</b>\n<code>{}</code>".format(e))
else:
self._close_widget()
def save_credentials(self, username, password):
self.parent_widget.get_auth_token(username, password)

View file

@ -1,12 +1,10 @@
from maya import cmds
import pype.maya.lib as lib
from avalon.vendor import requests
import avalon.maya
import os
import json
import appdirs
import requests
from maya import cmds
import pype.maya.lib as lib
import avalon.maya
class CreateRenderGlobals(avalon.maya.Creator):
@ -51,13 +49,17 @@ class CreateRenderGlobals(avalon.maya.Creator):
self.data["secondaryPool"] = ["-"] + pools
if muster_url is None:
self.log.warning("Muster REST API url not found.")
self.log.warning("Muster REST API URL not found.")
else:
self.log.info(">>> Loading Muster credentials ...")
self._load_credentials()
self.log.info(">>> Getting pools ...")
try:
pools = self._get_muster_pools()
except requests.exceptions.HTTPError as e:
print(e)
if e.startswith('401'):
self.log.warning('access token expired')
except requests.exceptions.ConnectionError:
self.log.error("Cannot connect to Muster API endpoint.")
raise RuntimeError("Cannot connect to {}".format(muster_url))
@ -131,13 +133,25 @@ class CreateRenderGlobals(avalon.maya.Creator):
'authToken': self._token
}
api_entry = '/api/pools/list'
response = requests.post(
response = requests.get(
self.MUSTER_REST_URL + api_entry, params=params)
if response.status_code != 200:
self.log.error(
'Cannot get pools from Muster: {}'.format(
response.status_code))
raise Exception('Cannot get pools from Muster')
if response.status_code == 401:
self.log.warning('Authentication token expired.')
# authentication token expired so we need to login to Muster
# again to get it. We use Pype API call to show login window.
api_url = "{}/muster/show_login".format(
os.environ["PYPE_REST_API_URL"])
self.log.debug(api_url)
login_response = requests.post(api_url, timeout=1)
if login_response.status_code != 200:
self.log.error('Cannot show login form to Muster')
raise Exception('Cannot show login form to Muster')
else:
self.log.error(
'Cannot get pools from Muster: {}'.format(
response.status_code))
raise Exception('Cannot get pools from Muster')
try:
pools = response.json()['ResponseData']['pools']
except ValueError as e:

View file

@ -0,0 +1,93 @@
import os
import json
import appdirs
import pyblish.api
from avalon.vendor import requests
from pype.plugin import contextplugin_should_run
import pype.maya.action
class ValidateMusterConnection(pyblish.api.ContextPlugin):
"""
Validate Muster REST API Service is running and we have valid auth token
"""
label = "Validate Muster REST API Service"
order = pyblish.api.ValidatorOrder
hosts = ["maya"]
families = ["renderlayer"]
token = None
if not os.environ.get("MUSTER_REST_URL"):
active = False
actions = [pype.api.RepairAction]
def process(self, context):
# Workaround bug pyblish-base#250
if not contextplugin_should_run(self, context):
return
# test if we have environment set (redundant as this plugin shouldn'
# be active otherwise).
try:
MUSTER_REST_URL = os.environ["MUSTER_REST_URL"]
except KeyError:
self.log.error("Muster REST API url not found.")
raise ValueError("Muster REST API url not found.")
# Load credentials
try:
self._load_credentials()
except RuntimeError:
self.log.error("invalid or missing access token")
assert self._token is not None, "Invalid or missing token"
# We have token, lets do trivial query to web api to see if we can
# connect and access token is valid.
params = {
'authToken': self._token
}
api_entry = '/api/pools/list'
response = requests.get(
MUSTER_REST_URL + api_entry, params=params)
assert response.status_code == 200, "invalid response from server"
assert response.json()['ResponseData'], "invalid data in response"
def _load_credentials(self):
"""
Load Muster credentials from file and set `MUSTER_USER`,
`MUSTER_PASSWORD`, `MUSTER_REST_URL` is loaded from presets.
.. todo::
Show login dialog if access token is invalid or missing.
"""
app_dir = os.path.normpath(
appdirs.user_data_dir('pype-app', 'pype')
)
file_name = 'muster_cred.json'
fpath = os.path.join(app_dir, file_name)
file = open(fpath, 'r')
muster_json = json.load(file)
self._token = muster_json.get('token', None)
if not self._token:
raise RuntimeError("Invalid access token for Muster")
file.close()
self.MUSTER_REST_URL = os.environ.get("MUSTER_REST_URL")
if not self.MUSTER_REST_URL:
raise AttributeError("Muster REST API url not set")
@classmethod
def repair(cls, instance):
"""
Renew authentication token by logging into Muster
"""
api_url = "{}/muster/show_login".format(
os.environ["PYPE_REST_API_URL"])
cls.log.debug(api_url)
response = requests.post(api_url, timeout=1)
if response.status_code != 200:
cls.log.error('Cannot show login form to Muster')
raise Exception('Cannot show login form to Muster')