mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge pull request #1632 from pypeclub/feature/admin_and_project_manager
This commit is contained in:
commit
ac43d8c254
19 changed files with 227 additions and 52 deletions
|
|
@ -97,7 +97,8 @@ from .local_settings import (
|
|||
OpenPypeSettingsRegistry,
|
||||
get_local_site_id,
|
||||
change_openpype_mongo_url,
|
||||
get_openpype_username
|
||||
get_openpype_username,
|
||||
is_admin_password_required
|
||||
)
|
||||
|
||||
from .applications import (
|
||||
|
|
@ -209,6 +210,7 @@ __all__ = [
|
|||
"get_local_site_id",
|
||||
"change_openpype_mongo_url",
|
||||
"get_openpype_username",
|
||||
"is_admin_password_required",
|
||||
|
||||
"ApplicationLaunchFailed",
|
||||
"ApplictionExecutableNotFound",
|
||||
|
|
|
|||
|
|
@ -29,7 +29,10 @@ except ImportError:
|
|||
import six
|
||||
import appdirs
|
||||
|
||||
from openpype.settings import get_local_settings
|
||||
from openpype.settings import (
|
||||
get_local_settings,
|
||||
get_system_settings
|
||||
)
|
||||
|
||||
from .import validate_mongo_connection
|
||||
|
||||
|
|
@ -562,3 +565,16 @@ def get_openpype_username():
|
|||
if not username:
|
||||
username = getpass.getuser()
|
||||
return username
|
||||
|
||||
|
||||
def is_admin_password_required():
|
||||
system_settings = get_system_settings()
|
||||
password = system_settings["general"].get("admin_password")
|
||||
if not password:
|
||||
return False
|
||||
|
||||
local_settings = get_local_settings()
|
||||
is_admin = local_settings.get("general", {}).get("is_admin", False)
|
||||
if is_admin:
|
||||
return False
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ from .clockify import ClockifyModule
|
|||
from .log_viewer import LogViewModule
|
||||
from .muster import MusterModule
|
||||
from .deadline import DeadlineModule
|
||||
from .project_manager_action import ProjectManagerAction
|
||||
from .standalonepublish_action import StandAlonePublishAction
|
||||
from .sync_server import SyncServerModule
|
||||
|
||||
|
|
@ -73,6 +74,7 @@ __all__ = (
|
|||
"LogViewModule",
|
||||
"MusterModule",
|
||||
"DeadlineModule",
|
||||
"ProjectManagerAction",
|
||||
"StandAlonePublishAction",
|
||||
|
||||
"SyncServerModule"
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ class AvalonModule(PypeModule, ITrayModule, IWebServerRoutes):
|
|||
from Qt import QtWidgets
|
||||
# Actions
|
||||
action_library_loader = QtWidgets.QAction(
|
||||
"Library loader", tray_menu
|
||||
"Loader", tray_menu
|
||||
)
|
||||
|
||||
action_library_loader.triggered.connect(self.show_library_loader)
|
||||
|
|
|
|||
|
|
@ -184,6 +184,9 @@ class ITrayAction(ITrayModule):
|
|||
necessary.
|
||||
"""
|
||||
|
||||
admin_action = False
|
||||
_admin_submenu = None
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def label(self):
|
||||
|
|
@ -197,9 +200,19 @@ class ITrayAction(ITrayModule):
|
|||
|
||||
def tray_menu(self, tray_menu):
|
||||
from Qt import QtWidgets
|
||||
action = QtWidgets.QAction(self.label, tray_menu)
|
||||
|
||||
if self.admin_action:
|
||||
menu = self.admin_submenu(tray_menu)
|
||||
action = QtWidgets.QAction(self.label, menu)
|
||||
menu.addAction(action)
|
||||
if not menu.menuAction().isVisible():
|
||||
menu.menuAction().setVisible(True)
|
||||
|
||||
else:
|
||||
action = QtWidgets.QAction(self.label, tray_menu)
|
||||
tray_menu.addAction(action)
|
||||
|
||||
action.triggered.connect(self.on_action_trigger)
|
||||
tray_menu.addAction(action)
|
||||
|
||||
def tray_start(self):
|
||||
return
|
||||
|
|
@ -207,6 +220,16 @@ class ITrayAction(ITrayModule):
|
|||
def tray_exit(self):
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
def admin_submenu(tray_menu):
|
||||
if ITrayAction._admin_submenu is None:
|
||||
from Qt import QtWidgets
|
||||
|
||||
admin_submenu = QtWidgets.QMenu("Admin", tray_menu)
|
||||
admin_submenu.menuAction().setVisible(False)
|
||||
ITrayAction._admin_submenu = admin_submenu
|
||||
return ITrayAction._admin_submenu
|
||||
|
||||
|
||||
class ITrayService(ITrayModule):
|
||||
# Module's property
|
||||
|
|
@ -233,6 +256,7 @@ class ITrayService(ITrayModule):
|
|||
def services_submenu(tray_menu):
|
||||
if ITrayService._services_submenu is None:
|
||||
from Qt import QtWidgets
|
||||
|
||||
services_submenu = QtWidgets.QMenu("Services", tray_menu)
|
||||
services_submenu.menuAction().setVisible(False)
|
||||
ITrayService._services_submenu = services_submenu
|
||||
|
|
|
|||
59
openpype/modules/project_manager_action.py
Normal file
59
openpype/modules/project_manager_action.py
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
from . import PypeModule, ITrayAction
|
||||
|
||||
|
||||
class ProjectManagerAction(PypeModule, ITrayAction):
|
||||
label = "Project Manager (beta)"
|
||||
name = "project_manager"
|
||||
admin_action = True
|
||||
|
||||
def initialize(self, modules_settings):
|
||||
enabled = False
|
||||
module_settings = modules_settings.get(self.name)
|
||||
if module_settings:
|
||||
enabled = module_settings.get("enabled", enabled)
|
||||
self.enabled = enabled
|
||||
|
||||
# Tray attributes
|
||||
self.project_manager_window = None
|
||||
|
||||
def connect_with_modules(self, *_a, **_kw):
|
||||
return
|
||||
|
||||
def tray_init(self):
|
||||
"""Initialization in tray implementation of ITrayAction."""
|
||||
self.create_project_manager_window()
|
||||
|
||||
def on_action_trigger(self):
|
||||
"""Implementation for action trigger of ITrayAction."""
|
||||
self.show_project_manager_window()
|
||||
|
||||
def create_project_manager_window(self):
|
||||
"""Initializa Settings Qt window."""
|
||||
if self.project_manager_window:
|
||||
return
|
||||
from openpype.tools.project_manager import ProjectManagerWindow
|
||||
|
||||
self.project_manager_window = ProjectManagerWindow()
|
||||
|
||||
def show_project_manager_window(self):
|
||||
"""Show project manager tool window.
|
||||
|
||||
Raises:
|
||||
AssertionError: Window must be already created. Call
|
||||
`create_project_manager_window` before calling this method.
|
||||
"""
|
||||
if not self.project_manager_window:
|
||||
raise AssertionError("Window is not initialized.")
|
||||
|
||||
# Store if was visible
|
||||
was_minimized = self.project_manager_window.isMinimized()
|
||||
|
||||
# Show settings gui
|
||||
self.project_manager_window.show()
|
||||
|
||||
if was_minimized:
|
||||
self.project_manager_window.showNormal()
|
||||
|
||||
# Pull window to the front.
|
||||
self.project_manager_window.raise_()
|
||||
self.project_manager_window.activateWindow()
|
||||
|
|
@ -37,7 +37,8 @@ class ISettingsChangeListener:
|
|||
class SettingsAction(PypeModule, ITrayAction):
|
||||
"""Action to show Setttings tool."""
|
||||
name = "settings"
|
||||
label = "Settings"
|
||||
label = "Studio Settings"
|
||||
admin_action = True
|
||||
|
||||
def initialize(self, _modules_settings):
|
||||
# This action is always enabled
|
||||
|
|
@ -78,7 +79,7 @@ class SettingsAction(PypeModule, ITrayAction):
|
|||
|
||||
Raises:
|
||||
AssertionError: Window must be already created. Call
|
||||
`create_settings_window` before callint this method.
|
||||
`create_settings_window` before calling this method.
|
||||
"""
|
||||
if not self.settings_window:
|
||||
raise AssertionError("Window is not initialized.")
|
||||
|
|
@ -105,7 +106,7 @@ class SettingsAction(PypeModule, ITrayAction):
|
|||
class LocalSettingsAction(PypeModule, ITrayAction):
|
||||
"""Action to show Setttings tool."""
|
||||
name = "local_settings"
|
||||
label = "Local Settings"
|
||||
label = "Settings"
|
||||
|
||||
def initialize(self, _modules_settings):
|
||||
# This action is always enabled
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
|
@ -164,5 +164,8 @@
|
|||
},
|
||||
"standalonepublish_tool": {
|
||||
"enabled": true
|
||||
},
|
||||
"project_manager": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
|
|
@ -192,6 +192,20 @@
|
|||
"label": "Enabled"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "project_manager",
|
||||
"label": "Project Manager (beta)",
|
||||
"collapsible": true,
|
||||
"checkbox_key": "enabled",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -504,6 +504,21 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
|
|||
|
||||
#IconBtn {}
|
||||
|
||||
/* Password dialog*/
|
||||
#PasswordBtn {
|
||||
border: none;
|
||||
padding:0.1em;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
#PasswordBtn:hover {
|
||||
background: {color:bg-buttons};
|
||||
}
|
||||
|
||||
#RememberCheckbox {
|
||||
spacing: 0.5em;
|
||||
}
|
||||
|
||||
/* Project Manager stylesheets */
|
||||
#HierarchyView::item {
|
||||
padding-top: 3px;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ from . import (
|
|||
)
|
||||
from openpype.style import load_stylesheet
|
||||
from .style import ResourceCache
|
||||
from openpype.lib import is_admin_password_required
|
||||
from openpype.widgets import PasswordDialog
|
||||
|
||||
from openpype import resources
|
||||
from avalon.api import AvalonMongoDB
|
||||
|
|
@ -20,6 +22,10 @@ class ProjectManagerWindow(QtWidgets.QWidget):
|
|||
def __init__(self, parent=None):
|
||||
super(ProjectManagerWindow, self).__init__(parent)
|
||||
|
||||
self._initial_reset = False
|
||||
self._password_dialog = None
|
||||
self._user_passed = False
|
||||
|
||||
self.setWindowTitle("OpenPype Project Manager")
|
||||
self.setWindowIcon(QtGui.QIcon(resources.pype_icon_filepath()))
|
||||
|
||||
|
|
@ -33,6 +39,9 @@ class ProjectManagerWindow(QtWidgets.QWidget):
|
|||
|
||||
project_model = ProjectModel(dbcon)
|
||||
project_combobox = QtWidgets.QComboBox(project_widget)
|
||||
project_combobox.setSizeAdjustPolicy(
|
||||
QtWidgets.QComboBox.AdjustToContents
|
||||
)
|
||||
project_combobox.setModel(project_model)
|
||||
project_combobox.setRootModelIndex(QtCore.QModelIndex())
|
||||
style_delegate = QtWidgets.QStyledItemDelegate()
|
||||
|
|
@ -135,13 +144,15 @@ class ProjectManagerWindow(QtWidgets.QWidget):
|
|||
self.resize(1200, 600)
|
||||
self.setStyleSheet(load_stylesheet())
|
||||
|
||||
self.refresh_projects()
|
||||
|
||||
def _set_project(self, project_name=None):
|
||||
self.hierarchy_view.set_project(project_name)
|
||||
|
||||
def showEvent(self, event):
|
||||
super(ProjectManagerWindow, self).showEvent(event)
|
||||
|
||||
if not self._initial_reset:
|
||||
self.reset()
|
||||
|
||||
font_size = self._refresh_projects_btn.fontMetrics().height()
|
||||
icon_size = QtCore.QSize(font_size, font_size)
|
||||
self._refresh_projects_btn.setIconSize(icon_size)
|
||||
|
|
@ -193,3 +204,45 @@ class ProjectManagerWindow(QtWidgets.QWidget):
|
|||
project_name = dialog.project_name
|
||||
self.show_message("Created project \"{}\"".format(project_name))
|
||||
self.refresh_projects(project_name)
|
||||
|
||||
def _show_password_dialog(self):
|
||||
if self._password_dialog:
|
||||
self._password_dialog.open()
|
||||
|
||||
def _on_password_dialog_close(self, password_passed):
|
||||
# Store result for future settings reset
|
||||
self._user_passed = password_passed
|
||||
# Remove reference to password dialog
|
||||
self._password_dialog = None
|
||||
if password_passed:
|
||||
self.reset()
|
||||
else:
|
||||
self.close()
|
||||
|
||||
def reset(self):
|
||||
if self._password_dialog:
|
||||
return
|
||||
|
||||
if not self._user_passed:
|
||||
self._user_passed = not is_admin_password_required()
|
||||
|
||||
if not self._user_passed:
|
||||
self.setEnabled(False)
|
||||
# Avoid doubled dialog
|
||||
dialog = PasswordDialog(self)
|
||||
dialog.setModal(True)
|
||||
dialog.finished.connect(self._on_password_dialog_close)
|
||||
|
||||
self._password_dialog = dialog
|
||||
|
||||
QtCore.QTimer.singleShot(100, self._show_password_dialog)
|
||||
|
||||
return
|
||||
|
||||
self.setEnabled(True)
|
||||
|
||||
# Mark as was reset
|
||||
if not self._initial_reset:
|
||||
self._initial_reset = True
|
||||
|
||||
self.refresh_projects()
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
import sys
|
||||
from Qt import QtWidgets, QtGui
|
||||
from .lib import (
|
||||
is_password_required,
|
||||
BTN_FIXED_SIZE,
|
||||
CHILD_OFFSET
|
||||
)
|
||||
from .widgets import PasswordDialog
|
||||
from .local_settings import LocalSettingsWindow
|
||||
from .settings import (
|
||||
style,
|
||||
|
|
@ -35,13 +33,11 @@ def main(user_role=None):
|
|||
|
||||
|
||||
__all__ = (
|
||||
"is_password_required",
|
||||
"BTN_FIXED_SIZE",
|
||||
"CHILD_OFFSET",
|
||||
|
||||
"style",
|
||||
|
||||
"PasswordDialog",
|
||||
"MainWidget",
|
||||
"ProjectListWidget",
|
||||
"LocalSettingsWindow",
|
||||
|
|
|
|||
|
|
@ -1,20 +1,2 @@
|
|||
CHILD_OFFSET = 15
|
||||
BTN_FIXED_SIZE = 20
|
||||
|
||||
|
||||
def is_password_required():
|
||||
from openpype.settings import (
|
||||
get_system_settings,
|
||||
get_local_settings
|
||||
)
|
||||
|
||||
system_settings = get_system_settings()
|
||||
password = system_settings["general"].get("admin_password")
|
||||
if not password:
|
||||
return False
|
||||
|
||||
local_settings = get_local_settings()
|
||||
is_admin = local_settings.get("general", {}).get("is_admin", False)
|
||||
if is_admin:
|
||||
return False
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
import getpass
|
||||
|
||||
from Qt import QtWidgets, QtCore
|
||||
from openpype.tools.settings import (
|
||||
is_password_required,
|
||||
PasswordDialog
|
||||
)
|
||||
from openpype.lib import is_admin_password_required
|
||||
from openpype.widgets import PasswordDialog
|
||||
|
||||
|
||||
class LocalGeneralWidgets(QtWidgets.QWidget):
|
||||
|
|
@ -57,7 +55,7 @@ class LocalGeneralWidgets(QtWidgets.QWidget):
|
|||
if not self.is_admin_input.isChecked():
|
||||
return
|
||||
|
||||
if not is_password_required():
|
||||
if not is_admin_password_required():
|
||||
return
|
||||
|
||||
dialog = PasswordDialog(self, False)
|
||||
|
|
|
|||
|
|
@ -7,10 +7,8 @@ from .categories import (
|
|||
from .widgets import ShadowWidget, RestartDialog
|
||||
from . import style
|
||||
|
||||
from openpype.tools.settings import (
|
||||
is_password_required,
|
||||
PasswordDialog
|
||||
)
|
||||
from openpype.lib import is_admin_password_required
|
||||
from openpype.widgets import PasswordDialog
|
||||
|
||||
|
||||
class MainWidget(QtWidgets.QWidget):
|
||||
|
|
@ -117,7 +115,7 @@ class MainWidget(QtWidgets.QWidget):
|
|||
return
|
||||
|
||||
if not self._user_passed:
|
||||
self._user_passed = not is_password_required()
|
||||
self._user_passed = not is_admin_password_required()
|
||||
|
||||
self._on_state_change()
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,11 @@ from openpype.api import (
|
|||
get_system_settings
|
||||
)
|
||||
from openpype.lib import get_pype_execute_args
|
||||
from openpype.modules import TrayModulesManager, ITrayService
|
||||
from openpype.modules import (
|
||||
TrayModulesManager,
|
||||
ITrayAction,
|
||||
ITrayService
|
||||
)
|
||||
from openpype import style
|
||||
|
||||
from .pype_info_widget import PypeInfoWidget
|
||||
|
|
@ -67,6 +71,9 @@ class TrayManager:
|
|||
|
||||
self.modules_manager.initialize(self, self.tray_widget.menu)
|
||||
|
||||
admin_submenu = ITrayAction.admin_submenu(self.tray_widget.menu)
|
||||
self.tray_widget.menu.addMenu(admin_submenu)
|
||||
|
||||
# Add services if they are
|
||||
services_submenu = ITrayService.services_submenu(self.tray_widget.menu)
|
||||
self.tray_widget.menu.addMenu(services_submenu)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
from .password_dialog import PasswordDialog
|
||||
|
||||
|
||||
__all__ = (
|
||||
"PasswordDialog",
|
||||
)
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
from Qt import QtWidgets, QtCore, QtGui
|
||||
|
||||
from .resources import get_resource
|
||||
from openpype import style
|
||||
from openpype.resources import get_resource
|
||||
|
||||
from openpype.api import get_system_settings
|
||||
from openpype.settings.lib import (
|
||||
|
|
@ -43,7 +44,7 @@ class PasswordDialog(QtWidgets.QDialog):
|
|||
def __init__(self, parent=None, allow_remember=True):
|
||||
super(PasswordDialog, self).__init__(parent)
|
||||
|
||||
self.setWindowTitle("Settings Password")
|
||||
self.setWindowTitle("Admin Password")
|
||||
self.resize(300, 120)
|
||||
|
||||
system_settings = get_system_settings()
|
||||
|
|
@ -62,13 +63,11 @@ class PasswordDialog(QtWidgets.QDialog):
|
|||
password_input = QtWidgets.QLineEdit(password_widget)
|
||||
password_input.setEchoMode(QtWidgets.QLineEdit.Password)
|
||||
|
||||
show_password_icon_path = get_resource("images", "eye.png")
|
||||
show_password_icon_path = get_resource("icons", "eye.png")
|
||||
show_password_icon = QtGui.QIcon(show_password_icon_path)
|
||||
show_password_btn = PressHoverButton(password_widget)
|
||||
show_password_btn.setObjectName("PasswordBtn")
|
||||
show_password_btn.setIcon(show_password_icon)
|
||||
show_password_btn.setStyleSheet((
|
||||
"border: none;padding:0.1em;"
|
||||
))
|
||||
show_password_btn.setFocusPolicy(QtCore.Qt.ClickFocus)
|
||||
|
||||
password_layout = QtWidgets.QHBoxLayout(password_widget)
|
||||
|
|
@ -83,10 +82,8 @@ class PasswordDialog(QtWidgets.QDialog):
|
|||
buttons_widget = QtWidgets.QWidget(self)
|
||||
|
||||
remember_checkbox = QtWidgets.QCheckBox("Remember", buttons_widget)
|
||||
remember_checkbox.setObjectName("RememberCheckbox")
|
||||
remember_checkbox.setVisible(allow_remember)
|
||||
remember_checkbox.setStyleSheet((
|
||||
"spacing: 0.5em;"
|
||||
))
|
||||
|
||||
ok_btn = QtWidgets.QPushButton("Ok", buttons_widget)
|
||||
cancel_btn = QtWidgets.QPushButton("Cancel", buttons_widget)
|
||||
|
|
@ -114,6 +111,8 @@ class PasswordDialog(QtWidgets.QDialog):
|
|||
self.remember_checkbox = remember_checkbox
|
||||
self.message_label = message_label
|
||||
|
||||
self.setStyleSheet(style.load_stylesheet())
|
||||
|
||||
def remember_password(self):
|
||||
if not self._allow_remember:
|
||||
return False
|
||||
Loading…
Add table
Add a link
Reference in a new issue