From c53d1eae645426ac7d91bb19ad5d96a1cf6b8bea Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Oct 2019 19:31:14 +0200 Subject: [PATCH 1/7] created simple user module that sets username to environment that can be used in future --- pype/user_module/__init__.py | 5 ++ pype/user_module/user_module.py | 94 +++++++++++++++++++++++++++++ pype/user_module/widget_user.py | 101 ++++++++++++++++++++++++++++++++ 3 files changed, 200 insertions(+) create mode 100644 pype/user_module/__init__.py create mode 100644 pype/user_module/user_module.py create mode 100644 pype/user_module/widget_user.py diff --git a/pype/user_module/__init__.py b/pype/user_module/__init__.py new file mode 100644 index 0000000000..04fe392c2c --- /dev/null +++ b/pype/user_module/__init__.py @@ -0,0 +1,5 @@ +from .user_module import UserModule + + +def tray_init(tray_widget, main_widget): + return UserModule(main_widget, tray_widget) diff --git a/pype/user_module/user_module.py b/pype/user_module/user_module.py new file mode 100644 index 0000000000..55df91c4de --- /dev/null +++ b/pype/user_module/user_module.py @@ -0,0 +1,94 @@ +import os +import json +import getpass + +import appdirs +from pypeapp import style +from Qt import QtWidgets +from .widget_user import UserWidget + + +class UserModule: + cred_folder_path = os.path.normpath( + appdirs.user_data_dir('pype-app', 'pype') + ) + cred_filename = 'user_info.json' + + def __init__(self, main_parent=None, parent=None): + self.cred = None + self.cred_path = os.path.join( + self.cred_folder_path, self.cred_filename + ) + self.main_parent = main_parent + self.parent = parent + + self.widget_login = UserWidget(self) + + self.load_credentials() + + def tray_start(self): + """Store credentials to env and preset them to widget""" + + if self.cred: + username = self.cred.get("username") or "" + os.environ["PYPE_USERNAME"] = username + self.widget_login.set_user(username) + + def process_modules(self, modules): + """ Gives ability to connect with imported modules from TrayManager. + + :param modules: All imported modules from TrayManager + :type modules: dict + """ + + if "RestApiServer" in modules: + def api_get_username(): + return self.cred + + def api_show_widget(): + self.action_show_widget.trigger() + + modules["RestApiServer"].register_callback( + "user_module/username", api_get_username, "get" + ) + modules["RestApiServer"].register_callback( + "user_module/show_widget", api_show_widget, "post" + ) + + # Definition of Tray menu + def tray_menu(self, parent_menu): + """Add menu or action to Tray(or parent)'s menu""" + action = QtWidgets.QAction("Username", parent_menu) + action.triggered.connect(self.show_widget) + parent_menu.addAction(action) + + self.action_show_widget = action + + def load_credentials(self): + """Get credentials from JSON file """ + credentials = {} + try: + file = open(self.cred_path, "r") + credentials = json.load(file) + file.close() + + except FileNotFoundError: + username = getpass.getuser() + self.save_credentials(username) + + self.cred = credentials + + def save_credentials(self, username): + """Save credentials to JSON file""" + self.cred = {"username": str(username)} + if username: + os.environ["PYPE_USERNAME"] = username + self.widget_login.set_user(username) + + file = open(self.cred_path, "w") + file.write(json.dumps(self.cred)) + file.close() + + def show_widget(self): + """Show dialog to enter credentials""" + self.widget_login.show() diff --git a/pype/user_module/widget_user.py b/pype/user_module/widget_user.py new file mode 100644 index 0000000000..96f7a27fa5 --- /dev/null +++ b/pype/user_module/widget_user.py @@ -0,0 +1,101 @@ +import os +from Qt import QtCore, QtGui, QtWidgets +from pypeapp import style + + +class UserWidget(QtWidgets.QWidget): + + # loginSignal = QtCore.Signal(object, object, object) + WIDTH = 300 + def __init__(self, module): + + super(UserWidget, self).__init__() + + self.module = module + + # Icon + try: + icon = module.icon + except AttributeError: + try: + icon = module.parent.icon + except AttributeError: + pype_setup = os.getenv('PYPE_ROOT') + fname = os.path.sep.join( + [pype_setup, "app", "resources", "icon.png"] + ) + icon = QtGui.QIcon(fname) + + self.setWindowIcon(icon) + + self.setWindowFlags( + QtCore.Qt.WindowCloseButtonHint | + QtCore.Qt.WindowMinimizeButtonHint + ) + + # Size setting + self.setMinimumWidth(self.WIDTH) + self.setStyleSheet(style.load_stylesheet()) + + self.setLayout(self._main()) + self.setWindowTitle('Username Settings') + + def show(self, *args, **kwargs): + super().show(*args, **kwargs) + # Move widget to center of active screen + screen = QtWidgets.QApplication.desktop().screen() + screen_center = lambda self: ( + screen.rect().center() - self.rect().center() + ) + self.move(screen_center(self)) + + def _main(self): + main_layout = QtWidgets.QVBoxLayout() + + form_layout = QtWidgets.QFormLayout() + form_layout.setContentsMargins(10, 15, 10, 5) + + label_username = QtWidgets.QLabel("Username:") + label_username.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) + label_username.setTextFormat(QtCore.Qt.RichText) + + input_username = QtWidgets.QLineEdit() + input_username.setPlaceholderText( + QtCore.QCoreApplication.translate("main", "e.g. John Smith") + ) + + form_layout.addRow(label_username, input_username) + + btn_save = QtWidgets.QPushButton("Save") + btn_save.clicked.connect(self.click_save) + + btn_cancel = QtWidgets.QPushButton("Cancel") + btn_cancel.clicked.connect(self.close) + + btn_group = QtWidgets.QHBoxLayout() + btn_group.addStretch(1) + btn_group.addWidget(btn_save) + btn_group.addWidget(btn_cancel) + + main_layout.addLayout(form_layout) + main_layout.addLayout(btn_group) + + self.input_username = input_username + + return main_layout + + def set_user(self, username): + self.input_username.setText(username) + + def click_save(self): + # all what should happen - validations and saving into appsdir + username = self.input_username.text() + self.module.save_credentials(username) + self._close_widget() + + def closeEvent(self, event): + event.ignore() + self._close_widget() + + def _close_widget(self): + self.hide() From ea9eac1470f133a5c19182eab8a68b6f67f5314b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Oct 2019 10:15:38 +0200 Subject: [PATCH 2/7] renamed "user_module" folder to "user" --- pype/{user_module => user}/__init__.py | 0 pype/{user_module => user}/user_module.py | 0 pype/{user_module => user}/widget_user.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename pype/{user_module => user}/__init__.py (100%) rename pype/{user_module => user}/user_module.py (100%) rename pype/{user_module => user}/widget_user.py (100%) diff --git a/pype/user_module/__init__.py b/pype/user/__init__.py similarity index 100% rename from pype/user_module/__init__.py rename to pype/user/__init__.py diff --git a/pype/user_module/user_module.py b/pype/user/user_module.py similarity index 100% rename from pype/user_module/user_module.py rename to pype/user/user_module.py diff --git a/pype/user_module/widget_user.py b/pype/user/widget_user.py similarity index 100% rename from pype/user_module/widget_user.py rename to pype/user/widget_user.py From 07166e60c6d71745347b1cfe77005d620029063f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Oct 2019 12:13:32 +0200 Subject: [PATCH 3/7] added exception catches, logging and made few optimalizations --- pype/user/user_module.py | 77 +++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/pype/user/user_module.py b/pype/user/user_module.py index 55df91c4de..d70885b211 100644 --- a/pype/user/user_module.py +++ b/pype/user/user_module.py @@ -3,36 +3,39 @@ import json import getpass import appdirs -from pypeapp import style from Qt import QtWidgets from .widget_user import UserWidget +from pype import api as pype + class UserModule: cred_folder_path = os.path.normpath( appdirs.user_data_dir('pype-app', 'pype') ) cred_filename = 'user_info.json' + env_name = "PYPE_USERNAME" + + log = pype.Logger().get_logger("UserModule", "user") def __init__(self, main_parent=None, parent=None): - self.cred = None - self.cred_path = os.path.join( - self.cred_folder_path, self.cred_filename - ) - self.main_parent = main_parent - self.parent = parent + self.cred = {} + self.cred_path = os.path.normpath(os.path.join( + self.cred_folder_path, self.cred_filename + )) self.widget_login = UserWidget(self) self.load_credentials() def tray_start(self): """Store credentials to env and preset them to widget""" - + username = "" if self.cred: username = self.cred.get("username") or "" - os.environ["PYPE_USERNAME"] = username - self.widget_login.set_user(username) + + os.environ[self.env_name] = username + self.widget_login.set_user(username) def process_modules(self, modules): """ Gives ability to connect with imported modules from TrayManager. @@ -49,10 +52,10 @@ class UserModule: self.action_show_widget.trigger() modules["RestApiServer"].register_callback( - "user_module/username", api_get_username, "get" + "user/username", api_get_username, "get" ) modules["RestApiServer"].register_callback( - "user_module/show_widget", api_show_widget, "post" + "user/show_widget", api_show_widget, "post" ) # Definition of Tray menu @@ -61,6 +64,7 @@ class UserModule: action = QtWidgets.QAction("Username", parent_menu) action.triggered.connect(self.show_widget) parent_menu.addAction(action) + parent_menu.addSeparator() self.action_show_widget = action @@ -72,22 +76,47 @@ class UserModule: credentials = json.load(file) file.close() - except FileNotFoundError: - username = getpass.getuser() - self.save_credentials(username) + self.cred = credentials + username = credentials.get("username") + if username: + self.log.debug("Loaded Username \"{}\"".format(username)) + else: + self.log.debug("Pype Username is not set") - self.cred = credentials + return credentials + + except FileNotFoundError: + return self.save_credentials(getpass.getuser()) + + except json.decoder.JSONDecodeError: + self.log.warning(( + "File where users credentials should be stored" + " has invalid json format. Loading system username." + )) + return self.save_credentials(getpass.getuser()) def save_credentials(self, username): - """Save credentials to JSON file""" - self.cred = {"username": str(username)} - if username: - os.environ["PYPE_USERNAME"] = username - self.widget_login.set_user(username) + """Save credentials to JSON file, env and widget""" + if username is None: + username = "" - file = open(self.cred_path, "w") - file.write(json.dumps(self.cred)) - file.close() + username = str(username).strip() + + self.cred = {"username": username} + os.environ[self.env_name] = username + self.widget_login.set_user(username) + try: + file = open(self.cred_path, "w") + file.write(json.dumps(self.cred)) + file.close() + self.log.debug("Username \"{}\" stored".format(username)) + except Exception: + self.log.error( + "Could not store username to file \"{}\"".format(self.cred_path), + exc_info=True + ) + + return self.cred def show_widget(self): """Show dialog to enter credentials""" From a6d1e6ce23a5fa692c25c25ffa38c3c04183da41 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Oct 2019 12:17:59 +0200 Subject: [PATCH 4/7] icon in widget is loaded with pypeapp resources --- pype/user/widget_user.py | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/pype/user/widget_user.py b/pype/user/widget_user.py index 96f7a27fa5..d778708739 100644 --- a/pype/user/widget_user.py +++ b/pype/user/widget_user.py @@ -1,12 +1,12 @@ import os from Qt import QtCore, QtGui, QtWidgets -from pypeapp import style +from pypeapp import style, resources class UserWidget(QtWidgets.QWidget): - # loginSignal = QtCore.Signal(object, object, object) WIDTH = 300 + def __init__(self, module): super(UserWidget, self).__init__() @@ -14,18 +14,7 @@ class UserWidget(QtWidgets.QWidget): self.module = module # Icon - try: - icon = module.icon - except AttributeError: - try: - icon = module.parent.icon - except AttributeError: - pype_setup = os.getenv('PYPE_ROOT') - fname = os.path.sep.join( - [pype_setup, "app", "resources", "icon.png"] - ) - icon = QtGui.QIcon(fname) - + icon = QtGui.QIcon(resources.get_resource("icon.png")) self.setWindowIcon(icon) self.setWindowFlags( From d0cbab7d315df5364a403ce2fdc4d7e23a1dcc51 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Oct 2019 12:19:38 +0200 Subject: [PATCH 5/7] formatting changes --- pype/user/widget_user.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/pype/user/widget_user.py b/pype/user/widget_user.py index d778708739..7ca12ec4d4 100644 --- a/pype/user/widget_user.py +++ b/pype/user/widget_user.py @@ -5,7 +5,7 @@ from pypeapp import style, resources class UserWidget(QtWidgets.QWidget): - WIDTH = 300 + MIN_WIDTH = 300 def __init__(self, module): @@ -13,25 +13,23 @@ class UserWidget(QtWidgets.QWidget): self.module = module - # Icon + # Style icon = QtGui.QIcon(resources.get_resource("icon.png")) self.setWindowIcon(icon) + self.setWindowTitle("Username Settings") + self.setMinimumWidth(self.MIN_WIDTH) + self.setStyleSheet(style.load_stylesheet()) self.setWindowFlags( QtCore.Qt.WindowCloseButtonHint | QtCore.Qt.WindowMinimizeButtonHint ) - # Size setting - self.setMinimumWidth(self.WIDTH) - self.setStyleSheet(style.load_stylesheet()) - self.setLayout(self._main()) - self.setWindowTitle('Username Settings') def show(self, *args, **kwargs): super().show(*args, **kwargs) - # Move widget to center of active screen + # Move widget to center of active screen on show screen = QtWidgets.QApplication.desktop().screen() screen_center = lambda self: ( screen.rect().center() - self.rect().center() From c540cfe1a954134e347ea3b96756412bafc60929 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Oct 2019 13:55:21 +0200 Subject: [PATCH 6/7] added user collector that overrides user stored with default pyblish collctor --- .../global/publish/collect_current_user.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 pype/plugins/global/publish/collect_current_user.py diff --git a/pype/plugins/global/publish/collect_current_user.py b/pype/plugins/global/publish/collect_current_user.py new file mode 100644 index 0000000000..359e6b852c --- /dev/null +++ b/pype/plugins/global/publish/collect_current_user.py @@ -0,0 +1,19 @@ +import os +import getpass +import pyblish.api + + +class CollectCurrentUserPype(pyblish.api.ContextPlugin): + """Inject the currently logged on user into the Context""" + + # Order must be after default pyblish-base CollectCurrentUser + order = pyblish.api.CollectorOrder + 0.001 + label = "Collect Pype User" + + def process(self, context): + user = os.getenv("PYPE_USERNAME", "").strip() + if not user: + return + + context.data["user"] = user + self.log.debug("Pype user is \"{}\"".format(user)) From 1d87f37869c36fd2312e4c9ec222c9fa9c0b2e88 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Oct 2019 14:10:01 +0200 Subject: [PATCH 7/7] renamed collector --- .../{collect_current_user.py => collect_current_pype_user.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pype/plugins/global/publish/{collect_current_user.py => collect_current_pype_user.py} (100%) diff --git a/pype/plugins/global/publish/collect_current_user.py b/pype/plugins/global/publish/collect_current_pype_user.py similarity index 100% rename from pype/plugins/global/publish/collect_current_user.py rename to pype/plugins/global/publish/collect_current_pype_user.py