diff --git a/newsfragments/1270.bugfix.rst b/newsfragments/1270.bugfix.rst new file mode 100644 index 00000000000..96960448633 --- /dev/null +++ b/newsfragments/1270.bugfix.rst @@ -0,0 +1 @@ +Display author name in file history instead of DeviceID diff --git a/parsec/core/gui/file_history_widget.py b/parsec/core/gui/file_history_widget.py index ce0964143c7..15529b59d68 100644 --- a/parsec/core/gui/file_history_widget.py +++ b/parsec/core/gui/file_history_widget.py @@ -3,7 +3,6 @@ from PyQt5.QtCore import Qt, pyqtSignal from PyQt5.QtWidgets import QWidget from PyQt5.QtSvg import QSvgWidget - from parsec.core.gui.lang import translate as _, format_datetime from parsec.core.gui.custom_dialogs import show_error, GreyedDialog from parsec.core.gui.trio_thread import ThreadSafeQtSignal @@ -12,8 +11,20 @@ from parsec.core.gui.ui.file_history_button import Ui_FileHistoryButton -async def _do_workspace_version(version_lister, path): - return await version_lister.list(path, max_manifest_queries=100) +async def _do_workspace_version(version_lister, path, core): + versions_list, download_limit_reached = await version_lister.list( + path, max_manifest_queries=100 + ) + + _cache = {} + + async def get_user_info(user_id): + return _cache.setdefault(user_id, await core.get_user_info(user_id)) + + return ( + [(await get_user_info(v.creator.user_id), v) for v in versions_list], + download_limit_reached, + ) # TODO : check no exception raised, create tests... @@ -47,11 +58,13 @@ def __init__( reload_timestamped_signal, update_version_list, close_version_list, + core, ): super().__init__() self.setupUi(self) self.jobs_ctx = jobs_ctx self.dialog = None + self.core = core update_version_list.connect(self.reset_dialog) self.get_versions_success.connect(self.on_get_version_success) self.get_versions_error.connect(self.on_get_version_error) @@ -98,6 +111,7 @@ def reset_list(self): _do_workspace_version, version_lister=self.version_lister, path=self.path, + core=self.core, ) def add_history_item(self, version, path, creator, size, timestamp, src_path, dst_path): @@ -118,15 +132,15 @@ def on_get_version_success(self): if download_limit_reached: self.button_load_more_entries.setVisible(False) self.versions_job = None - for v in versions_list: + for author, version in versions_list: self.add_history_item( - version=v.version, + version=version.version, path=self.path, - creator=v.creator, - size=v.size, - timestamp=v.early, - src_path=v.source, - dst_path=v.destination, + creator=author.short_user_display, + size=version.size, + timestamp=version.early, + src_path=version.source, + dst_path=version.destination, ) self.set_loading_in_progress(False) @@ -149,6 +163,7 @@ def exec_modal( reload_timestamped_signal, update_version_list, close_version_list, + core, parent, ): w = cls( @@ -158,6 +173,7 @@ def exec_modal( reload_timestamped_signal=reload_timestamped_signal, update_version_list=update_version_list, close_version_list=close_version_list, + core=core, ) d = GreyedDialog( w, title=_("TEXT_FILE_HISTORY_TITLE_name").format(name=path.name), parent=parent diff --git a/parsec/core/gui/files_widget.py b/parsec/core/gui/files_widget.py index 0baaab628ba..8425afe5dde 100644 --- a/parsec/core/gui/files_widget.py +++ b/parsec/core/gui/files_widget.py @@ -392,6 +392,7 @@ def show_history(self): reload_timestamped_signal=self.reload_timestamped_requested, update_version_list=self.update_version_list, close_version_list=self.close_version_list, + core=self.core, parent=self, ) diff --git a/tests/core/gui/conftest.py b/tests/core/gui/conftest.py index 01dba697a26..3de131f0be1 100644 --- a/tests/core/gui/conftest.py +++ b/tests/core/gui/conftest.py @@ -362,8 +362,17 @@ async def test_switch_to_users_widget(error=False): await aqtbot.mouse_click(central_widget.menu.button_users, QtCore.Qt.LeftButton) return u_w + async def test_switch_to_workspaces_widget(error=False): + central_widget = gui.test_get_central_widget() + f_w = gui.test_get_workspaces_widget() + signal = f_w.list_error if error else f_w.list_success + async with aqtbot.wait_exposed(f_w), aqtbot.wait_signal(signal): + await aqtbot.mouse_click(central_widget.menu.button_files, QtCore.Qt.LeftButton) + return f_w + gui.test_switch_to_devices_widget = test_switch_to_devices_widget gui.test_switch_to_users_widget = test_switch_to_users_widget + gui.test_switch_to_workspaces_widget = test_switch_to_workspaces_widget return gui diff --git a/tests/core/gui/test_file_history.py b/tests/core/gui/test_file_history.py new file mode 100644 index 00000000000..dd01a34781b --- /dev/null +++ b/tests/core/gui/test_file_history.py @@ -0,0 +1,101 @@ +# Parsec Cloud (https://parsec.cloud) Copyright (c) AGPLv3 2019 Scille SAS + +import pytest +from PyQt5 import QtCore, QtWidgets + +from tests.common import customize_fixtures + + +@pytest.fixture +def catch_file_history_widget(widget_catcher_factory): + return widget_catcher_factory("parsec.core.gui.file_history_widget.FileHistoryWidget") + + +async def create_workspace(aqtbot, logged_gui, monkeypatch): + w_w = await logged_gui.test_switch_to_workspaces_widget() + add_button = w_w.button_add_workspace + assert add_button is not None + + monkeypatch.setattr( + "parsec.core.gui.workspaces_widget.get_text_input", lambda *args, **kwargs: ("Workspace") + ) + async with aqtbot.wait_signals( + [w_w.create_success, w_w.list_success, w_w.mountpoint_started], timeout=2000 + ): + await aqtbot.mouse_click(add_button, QtCore.Qt.LeftButton) + + def _workspace_button_ready(): + assert w_w.layout_workspaces.count() == 1 + wk_button = w_w.layout_workspaces.itemAt(0).widget() + assert not isinstance(wk_button, QtWidgets.QLabel) + + await aqtbot.wait_until(_workspace_button_ready, timeout=2000) + wk_button = w_w.layout_workspaces.itemAt(0).widget() + assert wk_button.name == "Workspace" + + async with aqtbot.wait_signal(w_w.load_workspace_clicked): + await aqtbot.mouse_click(wk_button, QtCore.Qt.LeftButton) + + return w_w + + +async def create_directories(logged_gui, aqtbot, monkeypatch, dir_names): + central_widget = logged_gui.test_get_central_widget() + assert central_widget is not None + + f_w = logged_gui.test_get_files_widget() + assert f_w is not None + + add_button = f_w.button_create_folder + + for dir_name in dir_names: + monkeypatch.setattr( + "parsec.core.gui.files_widget.get_text_input", lambda *args, **kwargs: (dir_name) + ) + async with aqtbot.wait_signal(f_w.folder_create_success): + await aqtbot.mouse_click(add_button, QtCore.Qt.LeftButton) + + async with aqtbot.wait_signals([f_w.folder_stat_success, f_w.fs_synced_qt], timeout=3000): + pass + + f_w.table_files.rowCount() == 1 + + def _folder_synced(): + item = f_w.table_files.item(1, 0) + assert item.is_synced + + await aqtbot.wait_until(_folder_synced, timeout=3000) + return f_w + + +@pytest.mark.gui +@pytest.mark.trio +@customize_fixtures(logged_gui_as_admin=True) +async def test_file_history( + aqtbot, + running_backend, + logged_gui, + monkeypatch, + autoclose_dialog, + qt_thread_gateway, + catch_file_history_widget, + alice, +): + await create_workspace(aqtbot, logged_gui, monkeypatch) + f_w = await create_directories(logged_gui, aqtbot, monkeypatch, ["dir1"]) + + await aqtbot.run( + f_w.table_files.setRangeSelected, QtWidgets.QTableWidgetSelectionRange(1, 0, 1, 0), True + ) + + await qt_thread_gateway.send_action(f_w.show_history) + hf_w = await catch_file_history_widget() + + def _history_filled(): + assert hf_w.layout_history.count() == 1 + assert hf_w.layout_history.itemAt(0).widget() + + await aqtbot.wait_until(_history_filled, timeout=5000) + history_button = hf_w.layout_history.itemAt(0).widget() + assert history_button.label_user.text() == alice.human_handle.label + assert history_button.label_version.text() == "1"