From 54c59d2da18b8276192f36499906919176c546e5 Mon Sep 17 00:00:00 2001 From: themanyfaceddemon Date: Sun, 22 Sep 2024 20:15:51 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B2=20=D0=BF=D1=80=D0=B8=D0=BD=D1=86=D0=B8?= =?UTF-8?q?=D0=BF=D0=B5=20=D0=B2=D1=81=D1=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Code/dpg_tools.py | 19 +- Code/gui/dm_client_app.py | 14 +- Code/gui/windows/admin/main.py | 13 +- .../windows/admin/manage_server_settings.py | 48 ++++- Code/gui/windows/admin/manage_users.py | 204 +++++++++++++++++- Code/gui/windows/admin/user_access_control.py | 95 -------- Content/Client/loc/rus/admin.loc | 29 ++- 7 files changed, 285 insertions(+), 137 deletions(-) delete mode 100644 Code/gui/windows/admin/user_access_control.py diff --git a/Code/dpg_tools.py b/Code/dpg_tools.py index eb888b6..79cb35d 100644 --- a/Code/dpg_tools.py +++ b/Code/dpg_tools.py @@ -19,12 +19,23 @@ def decode_string(instr: str): return instr.translate(translation_table) -def center_window(tag, width, height): - """Центрируем окно с тегом tag относительно размеров экрана""" +def center_window(tag): + """Центрируем окно с тегом tag относительно текущих размеров окна и экрана""" + if not dpg.does_item_exist(tag): + return + + window_width = dpg.get_item_width(tag) + window_height = dpg.get_item_height(tag) + + if window_height is None or window_width is None: + return + vp_width = dpg.get_viewport_client_width() vp_height = dpg.get_viewport_client_height() - x_pos = (vp_width - width) // 2 - y_pos = (vp_height - height) // 2 + + x_pos = (vp_width - window_width) // 2 + y_pos = (vp_height - window_height) // 2 + dpg.set_item_pos(tag, [x_pos, y_pos]) diff --git a/Code/gui/dm_client_app.py b/Code/gui/dm_client_app.py index 0fe1106..8a92bb2 100644 --- a/Code/gui/dm_client_app.py +++ b/Code/gui/dm_client_app.py @@ -57,7 +57,7 @@ def _create_warning_window(cls): label=loc.get_string("no_warning_window"), callback=lambda: cls._on_no() ) - dpg_tools.center_window("warning_window", 380, 150) + dpg_tools.center_window("warning_window") @classmethod async def _on_yes(cls, *args): @@ -91,16 +91,22 @@ async def _create_connect_window(cls): dpg.add_input_text( hint=loc.get_string("connect_login_hint"), tag="connect_login" ) + dpg.add_input_text( hint=loc.get_string("connect_password_hint"), tag="connect_password", password=True, ) + dpg.add_input_text( hint=loc.get_string("connect_host_hint"), tag="connect_host" ) + dpg.add_input_int( - label=loc.get_string("connect_port_lable"), tag="connect_port" + label=loc.get_string("connect_port_lable"), + tag="connect_port", + min_clamped=True, + min_value=0, ) dpg.add_button( @@ -114,7 +120,7 @@ async def _create_connect_window(cls): user_data=True, ) - dpg_tools.center_window("connect_window", 380, 380) + dpg_tools.center_window("connect_window") @classmethod async def _connect_to_server(cls, sender, app_data, user_data): @@ -191,7 +197,7 @@ def _err_window(cls, msg): label=loc.get_string("ok"), callback=lambda: dpg.delete_item(err_window) ) - dpg_tools.center_window(err_window, 400, 200) + dpg_tools.center_window(err_window) @classmethod async def setup_start_windows(cls) -> None: diff --git a/Code/gui/windows/admin/main.py b/Code/gui/windows/admin/main.py index 3d5e866..447bb17 100644 --- a/Code/gui/windows/admin/main.py +++ b/Code/gui/windows/admin/main.py @@ -2,8 +2,7 @@ from systems.loc import Localization as loc from .manage_server_settings import manage_server_settings -from .manage_users import manage_users -from .user_access_control import user_access_control +from .manage_users import user_management async def admin_main_window(): @@ -14,9 +13,9 @@ async def admin_main_window(): ) dpg.add_menu_item( - label=loc.get_string("user_access_control_lable"), + label=loc.get_string("user_management_label"), parent="admin_control_menu_bar", - callback=user_access_control, + callback=user_management, ) dpg.add_menu_item( @@ -24,9 +23,3 @@ async def admin_main_window(): parent="admin_control_menu_bar", callback=manage_server_settings, ) - - dpg.add_menu_item( - label=loc.get_string("manage_users_lable"), - parent="admin_control_menu_bar", - callback=manage_users, - ) diff --git a/Code/gui/windows/admin/manage_server_settings.py b/Code/gui/windows/admin/manage_server_settings.py index 5d1ce48..b6150bf 100644 --- a/Code/gui/windows/admin/manage_server_settings.py +++ b/Code/gui/windows/admin/manage_server_settings.py @@ -1,4 +1,6 @@ import dearpygui.dearpygui as dpg +import dpg_tools +from DMBotNetwork import Client from systems.loc import Localization as loc @@ -12,10 +14,46 @@ async def manage_server_settings(sender, app_data, user_data) -> None: tag="manage_server_settings_window", width=400, height=200, - on_close=_on_close + on_close=lambda: dpg.delete_item("manage_server_settings_window"), ): - pass + cur_server_settings: dict = await Client.req_get_data( + "get_server_settings", None + ) + with dpg.child_window(autosize_x=True, autosize_y=True): + with dpg.group(horizontal=True): + dpg.add_text(loc.get_string("allow_registration_text"), wrap=0) + dpg.add_checkbox( + default_value=cur_server_settings.get("allow_registration", False), + callback=_change_server_settings, + user_data="allow_registration", + ) + dpg.add_spacer(width=0, height=10) -def _on_close(): - if dpg.does_item_exist("manage_server_settings_window"): - dpg.delete_item("manage_server_settings_window") + dpg.add_text(loc.get_string("max_players_text"), wrap=0) + dpg.add_input_int( + min_value=-1, + min_clamped=True, + max_value=100, + max_clamped=True, + default_value=cur_server_settings.get("max_players", 0), + callback=_change_server_settings, + user_data="max_players", + ) + dpg.add_spacer(width=0, height=10) + + dpg.add_text(loc.get_string("timeout_text"), wrap=0) + dpg.add_input_double( + min_value=1.0, + min_clamped=True, + max_value=60.0, + max_clamped=True, + default_value=cur_server_settings.get("timeout", 1), + callback=_change_server_settings, + user_data="timeout", + ) + + dpg_tools.center_window("manage_server_settings_window") + + +async def _change_server_settings(sender, app_data, user_data) -> None: + await Client.req_net_func("change_server_settings", type=user_data, value=app_data) diff --git a/Code/gui/windows/admin/manage_users.py b/Code/gui/windows/admin/manage_users.py index cc7b495..9e730e6 100644 --- a/Code/gui/windows/admin/manage_users.py +++ b/Code/gui/windows/admin/manage_users.py @@ -1,21 +1,205 @@ +import logging + import dearpygui.dearpygui as dpg +import dpg_tools +from DMBotNetwork import Client from systems.loc import Localization as loc -async def manage_users(sender, app_data, user_data) -> None: - if dpg.does_item_exist("manage_users_window"): - dpg.focus_item("manage_users_window") +async def user_management(sender, app_data, user_data) -> None: + if dpg.does_item_exist("user_management_window"): + dpg.focus_item("user_management_window") + return + + with dpg.window( + label=loc.get_string("user_management_label"), + tag="user_management_window", + width=600, + height=400, + on_close=lambda: dpg.delete_item("user_management_window"), + ): + # Поле для поиска по пользователям + dpg.add_input_text( + tag="search_user_input", + callback=filter_users, + hint=loc.get_string("user_management_search_hint"), + ) + await update_user_list() + + dpg_tools.center_window("user_management_window") + + +async def update_user_list(filter_term="") -> None: + if dpg.does_item_exist("user_management_content"): + dpg.delete_item("user_management_content") + + users: list = await Client.req_get_data("get_all_users", None) + + # Фильтрация пользователей по поисковому запросу + filtered_users = [user for user in users if filter_term.lower() in user.lower()] + + with dpg.group(tag="user_management_content", parent="user_management_window"): + with dpg.group(horizontal=True): + with dpg.child_window(width=200, autosize_y=True): + dpg.add_button( + label=loc.get_string("create_new_user_button"), + callback=open_create_user_window, + ) + + dpg.add_text(loc.get_string("user_management_user_logins"), wrap=0) + for user in filtered_users: + dpg.add_button( + label=user, + callback=load_user_management_controls, + user_data=user, + ) + + with dpg.child_window( + width=300, tag="user_access_admin", autosize_y=True, autosize_x=True + ): + with dpg.group(tag="user_access_group"): + dpg.add_text(loc.get_string("user_not_loaded"), wrap=0) + + +async def load_user_management_controls(sender, app_data, user_data): + if dpg.does_item_exist("user_controls"): + dpg.delete_item("user_controls") + + with dpg.group(tag="user_controls", parent="user_access_admin"): + dpg.add_button( + label=loc.get_string("delete_user_button"), + callback=confirm_delete_user, + user_data=user_data, + ) + + await load_user_access(None, None, user_data) + + +async def confirm_delete_user(sender, app_data, user_data): + if not dpg.is_key_down(dpg.mvKey_Shift): + with dpg.window( + label=loc.get_string("delete_confirmation_window"), + modal=True, + tag="delete_confirmation_window", + width=300, + height=150, + ): + dpg.add_text(loc.get_string("confirm_deletion_text"), wrap=0) + with dpg.group(horizontal=True): + dpg.add_button( + label=loc.get_string("yes"), + callback=delete_user, + user_data=user_data, + ) + + dpg.add_button( + label=loc.get_string("no"), + callback=lambda: dpg.delete_item("delete_confirmation_window"), + ) + + dpg_tools.center_window("delete_confirmation_window") + else: + await delete_user(None, None, user_data) + + +async def delete_user(sender, app_data, user_data): + await Client.req_get_data("delete_user", None, login=user_data) + dpg.delete_item("delete_confirmation_window") + await update_user_list() + + +async def load_user_access(sender, app_data, user_data): + if dpg.does_item_exist("user_access_group"): + dpg.delete_item("user_access_group") + + user: dict[str, bool] = await Client.req_get_data( + "get_access", None, login=user_data + ) + + if user is None: + logging.error(f"User '{user_data}' not found.") + return + + with dpg.group(tag="user_access_group", parent="user_access_admin"): + if "full_access" in user: + dpg.add_text(loc.get_string("full_access_warning_message"), wrap=0) + return + + with dpg.child_window(): + for access_key, access_value in user.items(): + with dpg.group(horizontal=True): + uuid_text = dpg.generate_uuid() + dpg.add_text( + loc.get_string(f"text-{access_key}"), wrap=0, tag=uuid_text + ) + + dpg.add_checkbox( + default_value=access_value, + callback=toggle_user_access, + user_data=(user_data, access_key), + ) + + with dpg.tooltip(uuid_text): + dpg.add_text(loc.get_string(f"desc-{access_key}"), wrap=300) + + dpg.add_spacer(width=0, height=10) + + +async def toggle_user_access(sender, app_data, user_data): + user_id = user_data[0] + access_key = user_data[1] + new_value = app_data + + changes = {access_key: new_value} + + await Client.req_net_func("change_access", login=user_id, changes=changes) + + +async def open_create_user_window(sender, app_data): + if dpg.does_item_exist("create_user_window"): + dpg.focus_item("create_user_window") return with dpg.window( - label=loc.get_string("manage_users_lable"), - tag="manage_users_window", + label=loc.get_string("new_user_window_title"), + tag="create_user_window", width=400, height=200, - on_close=_on_close + modal=True, + on_close=lambda: dpg.delete_item("create_user_window"), ): - pass + dpg.add_text(loc.get_string("enter_new_user_login"), wrap=0) + dpg.add_input_text(tag="new_user_login_input") + + dpg.add_text(loc.get_string("enter_new_user_password"), wrap=0) + dpg.add_input_text( + tag="new_user_password_input", + password=True, + ) + + dpg.add_button( + label=loc.get_string("create_new_user_button"), + callback=create_user_button, + ) + + dpg_tools.center_window("create_user_window") + + +async def create_user_button(sender, app_data): + new_login = dpg.get_value("new_user_login_input") + new_password = dpg.get_value("new_user_password_input") + + if new_login and new_password: + await create_new_user(None, None, [new_login, new_password]) + await update_user_list() + + +async def create_new_user(sender, app_data, user_data): + await Client.req_get_data( + "create_user", None, login=user_data[0], password=user_data[1] + ) + -def _on_close(): - if dpg.does_item_exist("manage_users_window"): - dpg.delete_item("manage_users_window") +async def filter_users(sender, app_data): + search_term = dpg.get_value("search_user_input") + await update_user_list(filter_term=search_term) diff --git a/Code/gui/windows/admin/user_access_control.py b/Code/gui/windows/admin/user_access_control.py deleted file mode 100644 index 88f3b86..0000000 --- a/Code/gui/windows/admin/user_access_control.py +++ /dev/null @@ -1,95 +0,0 @@ -import logging - -import dearpygui.dearpygui as dpg -from DMBotNetwork import Client -from systems.loc import Localization as loc - - -async def user_access_control(sender, app_data, user_data) -> None: - if dpg.does_item_exist("user_access_control_window"): - dpg.focus_item("user_access_control_window") - return - - with dpg.window( - label=loc.get_string("user_access_control_lable"), - tag="user_access_control_window", - width=400, - height=200, - on_close=_on_close - ): - users: list = await Client.req_get_data("get_all_users", None) - - with dpg.group(horizontal=True): - with dpg.child_window(width=200, autosize_y=True): - dpg.add_text(loc.get_string("users_control_logins"), wrap=0) - for user in users: - dpg.add_button( - label=user, callback=load_user_access, user_data=user - ) - - with dpg.child_window( - width=200, tag="access_rights_admin", autosize_y=True, autosize_x=True - ): - dpg.add_text(loc.get_string("user_control_access_control"), wrap=0) - with dpg.group(tag="access_group"): - dpg.add_text(loc.get_string("user_control_not_load_user"), wrap=0) - - -async def load_user_access(sender, app_data, user_data): - if dpg.does_item_exist("access_group"): - dpg.delete_item("access_group") - - if user_data is None: - logging.error("user_data is None!") - return - - user: dict[str, bool] = await Client.req_get_data( - "get_access", None, login=user_data - ) - - if user is None: - logging.error(f"User '{user_data}' not found.") - return - - with dpg.group(tag="access_group", parent="access_rights_admin"): - if "full_access" in user: - dpg.add_text(loc.get_string("full_access_warning"), wrap=0) - return - - for access_key, access_value in user.items(): - with dpg.group(horizontal=True, parent="access_group"): - uuid_text = dpg.generate_uuid() - dpg.add_text( - loc.get_string(f"text-{access_key}"), wrap=0, tag=uuid_text - ) - - dpg.add_checkbox( - default_value=access_value, - callback=toggle_access, - user_data=(user_data, access_key), - ) - - with dpg.tooltip(uuid_text): - dpg.add_text(loc.get_string(f"desc-{access_key}"), wrap=300) - - dpg.add_spacer(width=0, height=10) - - -async def toggle_access(sender, app_data, user_data): - user_id = user_data[0] - access_key = user_data[1] - new_value = app_data - - changes = {access_key: new_value} - - try: - await Client.req_net_func("change_access", login=user_id, changes=changes) - logging.info(f"Access change for {user_id}: {access_key} -> {new_value}") - - except Exception as e: - logging.error(f"Failed to update access for {user_id}: {e}") - - -def _on_close(): - if dpg.does_item_exist("user_access_control_window"): - dpg.delete_item("user_access_control_window") diff --git a/Content/Client/loc/rus/admin.loc b/Content/Client/loc/rus/admin.loc index a1d0875..bdc8914 100644 --- a/Content/Client/loc/rus/admin.loc +++ b/Content/Client/loc/rus/admin.loc @@ -1,12 +1,23 @@ # For main admin_control_menu = Админ панель -user_access_control_lable = Управление правами -manage_server_settings_lable = Управление настройками сервера -manage_users_lable = Управление пользователями -# For access control -full_access_warning = У этого пользователя полный доступ. Вы не можете поменять права доступа. -user_control = Управление правами пользователей -users_control_logins = Пользователи: -user_control_access_control = Права доступа -user_control_not_load_user = Пользователь не выбран... +# For user managment +confirm_deletion_text = Вы уверены что хотите удалить пользователя? Это действие не обратимо +create_new_user_button = Создать пользователя +delete_confirmation_window = Удалить пользователя +delete_user_button = Удалить пользователя +enter_new_user_login = Введите login нового пользователя +enter_new_user_password = Введите пароль для пользователя +full_access_warning_message = У пользователя нельзя изменить права доступа +new_user_window_title = Создание нового пользователя +user_management_label = Управление игроками +user_management_search_hint = Введите login для поиска +user_management_user_logins = Logins +user_not_loaded = Пользователь не выбран + + +# For server settings +allow_registration_text = Разрешить регестрацию +manage_server_settings_lable = Управление настройками сервера +max_players_text = Максимальное колличество игроков на сервере +timeout_text = Таймаут для подключения