async def test_workspace_button_shared_with(qtbot, workspace_fs, core_config, bob): switch_language(core_config, "en") roles = { bob.user_id: WorkspaceRole.READER, workspace_fs.device.user_id: WorkspaceRole.OWNER } w = WorkspaceButton( workspace_name="Workspace", workspace_fs=workspace_fs, users_roles=roles, is_mounted=True, files=[], ) qtbot.addWidget(w) w.show() assert w.widget_empty.isVisible() is True assert w.widget_files.isVisible() is False assert w.label_owner.isVisible() is True assert w.label_shared.isVisible() is True assert w.name == "Workspace" assert w.label_title.text().startswith("Workspace") assert w.label_title.toolTip() == "Workspace (shared with bob)"
async def test_workspace_button_owned_by(qtbot, workspace_fs, core_config, bob, alice_user_info, bob_user_info): switch_language(core_config, "en") roles = { bob.user_id: (WorkspaceRole.OWNER, bob_user_info), alice_user_info.user_id: (WorkspaceRole.READER, alice_user_info), } w = WorkspaceButton( workspace_name="Workspace", workspace_fs=workspace_fs, users_roles=roles, is_mounted=True, files=[], ) qtbot.addWidget(w) w.show() assert w.widget_empty.isVisible() is True assert w.widget_files.isVisible() is False assert w.label_owner.isVisible() is False assert w.label_shared.isVisible() is True assert w.name == "Workspace" assert w.label_title.text().startswith("Workspace") assert w.label_title.toolTip() == "Workspace (owned by Boby McBobFace)" assert w.label_role.text() == _("TEXT_WORKSPACE_ROLE_READER")
async def test_workspace_button_reencrypt_clicked(qtbot, workspace_fs, core_config, alice_user_info): switch_language(core_config, "en") roles = { workspace_fs.device.user_id: (WorkspaceRole.OWNER, alice_user_info) } w = WorkspaceButton( workspace_name="Workspace", workspace_fs=workspace_fs, users_roles=roles, is_mounted=True, files=[], ) w.reencryption_needs = ReencryptionNeed( user_revoked=True, role_revoked=False, reencryption_already_in_progress=False) qtbot.addWidget(w) assert not w.button_reencrypt.isHidden() w.reencrypting = (8, 4) assert w.widget_actions.isHidden() assert not w.widget_reencryption.isHidden() assert w.progress_reencryption.value() == 50 assert w.progress_reencryption.text() == "Reencrypting... 50%" w.reencrypting = None assert not w.widget_actions.isHidden() assert w.widget_reencryption.isHidden()
async def test_workspace_button_files(qtbot, workspace_fs, core_config, alice_user_info): switch_language(core_config, "en") roles = {alice_user_info.user_id: (WorkspaceRole.OWNER, alice_user_info)} w = WorkspaceButton.create( workspace_name=EntryName("Workspace"), workspace_fs=workspace_fs, users_roles=roles, is_mounted=True, files=[ EntryName("File1.txt"), EntryName("File2.txt"), EntryName("Dir1") ], ) qtbot.add_widget(w) w.show() assert w.widget_empty.isVisible() is False assert w.widget_files.isVisible() is True assert w.label_owner.isVisible() is True assert w.label_shared.isVisible() is False assert w.name == EntryName("Workspace") assert w.file1_name.text() == "File1.txt" assert w.file2_name.text() == "File2.txt" assert w.file3_name.text() == "Dir1" assert w.file4_name.text() == ""
async def test_workspace_button_shared_by(qtbot, workspace_fs, core_config): switch_language(core_config, "en") w = WorkspaceButton( workspace_name="Workspace", workspace_fs=workspace_fs, is_shared=True, is_creator=False, files=[], ) qtbot.addWidget(w) w.show() assert w.widget_empty.isVisible() is True assert w.widget_files.isVisible() is False assert w.label_owner.isVisible() is False assert w.label_shared.isVisible() is True assert w.name == "Workspace" assert w.label_title.text() == "Workspace"
def add_workspace(self, workspace_fs, ws_entry, users_roles, files, timestamped, reencryption_needs): # The Qt thread should never hit the core directly. # Synchronous calls can run directly in the job system # as they won't block the Qt loop for long workspace_name = self.jobs_ctx.run_sync( workspace_fs.get_workspace_name) # Temporary code to fix the workspace names edited by # the previous naming policy (the userfs used to add # `(shared by <device>)` at the end of the workspace name) token = " (shared by " if token in workspace_name: workspace_name, *_ = workspace_name.split(token) self.jobs_ctx.submit_job( ThreadSafeQtSignal(self, "ignore_success", QtToTrioJob), ThreadSafeQtSignal(self, "ignore_error", QtToTrioJob), _do_workspace_rename, core=self.core, workspace_id=workspace_fs.workspace_id, new_name=workspace_name, button=None, ) if self.filter_user_info is not None and self.filter_user_info.user_id not in users_roles: return button = WorkspaceButton( workspace_name=workspace_name, workspace_fs=workspace_fs, users_roles=users_roles, is_mounted=self.is_workspace_mounted(workspace_fs.workspace_id, None), files=files[:4], timestamped=timestamped, reencryption_needs=reencryption_needs, ) self.layout_workspaces.addWidget(button) button.clicked.connect(self.load_workspace) button.share_clicked.connect(self.share_workspace) button.reencrypt_clicked.connect(self.reencrypt_workspace) button.delete_clicked.connect(self.delete_workspace) button.rename_clicked.connect(self.rename_workspace) button.remount_ts_clicked.connect(self.remount_workspace_ts) button.open_clicked.connect(self.open_workspace) button.switch_clicked.connect(self._on_switch_clicked) self.jobs_ctx.submit_job( ThreadSafeQtSignal(self, "reencryption_needs_success", QtToTrioJob), ThreadSafeQtSignal(self, "reencryption_needs_error", QtToTrioJob), _get_reencryption_needs, workspace_fs=workspace_fs, )
async def test_workspace_button_files(qtbot, workspace_fs, core_config): switch_language(core_config, "en") roles = {workspace_fs.device.user_id: WorkspaceRole.OWNER} w = WorkspaceButton( workspace_name="Workspace", workspace_fs=workspace_fs, users_roles=roles, is_mounted=True, files=["File1.txt", "File2.txt", "Dir1"], ) qtbot.addWidget(w) w.show() assert w.widget_empty.isVisible() is False assert w.widget_files.isVisible() is True assert w.label_owner.isVisible() is True assert w.label_shared.isVisible() is False assert w.name == "Workspace" assert w.file1_name.text() == "File1.txt" assert w.file2_name.text() == "File2.txt" assert w.file3_name.text() == "Dir1" assert w.file4_name.text() == ""
async def test_workspace_button_files(qtbot, workspace_fs, core_config): switch_language(core_config, "en") w = WorkspaceButton( workspace_name="Workspace", workspace_fs=workspace_fs, is_shared=True, is_creator=True, files=["File1.txt", "File2.txt", "Dir1"], ) qtbot.addWidget(w) w.show() assert w.widget_empty.isVisible() is False assert w.widget_files.isVisible() is True assert w.label_owner.isVisible() is True assert w.label_shared.isVisible() is True assert w.name == "Workspace" assert w.label_title.text() == "Workspace (shared wi..." assert w.label_title.toolTip() assert w.file1_name.text() == "File1.txt" assert w.file2_name.text() == "File2.txt" assert w.file3_name.text() == "Dir1" assert w.file4_name.text() == ""
async def test_workspace_button_delete_clicked(qtbot, workspace_fs, core_config): switch_language(core_config, "en") w = WorkspaceButton( workspace_name="Workspace", workspace_fs=workspace_fs, is_shared=False, is_creator=True, files=[], ) qtbot.addWidget(w) with qtbot.waitSignal(w.delete_clicked, timeout=500) as blocker: qtbot.mouseClick(w.button_delete, QtCore.Qt.LeftButton) assert blocker.args == [workspace_fs]
async def test_workspace_button_timestamped(qtbot, workspace_fs, core_config, alice_user_info): switch_language(core_config, "en") timestamp = pendulum.now().add(seconds=10) roles = {alice_user_info.user_id: (WorkspaceRole.OWNER, alice_user_info)} ts_workspace_fs = WorkspaceFSTimestamped(workspace_fs, timestamp) w = WorkspaceButton.create( workspace_name=EntryName("Workspace"), workspace_fs=ts_workspace_fs, users_roles=roles, is_mounted=True, timestamped=True, ) assert w.timestamp == timestamp label = w.widget_empty.layout().itemAt(0).widget().label_timestamp assert label.text() == format_datetime(timestamp)
async def test_workspace_button_delete_clicked(qtbot, workspace_fs, core_config, alice_user_info): switch_language(core_config, "en") roles = {alice_user_info.user_id: (WorkspaceRole.OWNER, alice_user_info)} w = WorkspaceButton.create( workspace_name=EntryName("Workspace"), workspace_fs=workspace_fs, users_roles=roles, is_mounted=True, files=[], ) qtbot.add_widget(w) with qtbot.waitSignal(w.delete_clicked, timeout=500) as blocker: qtbot.mouseClick(w.button_delete, QtCore.Qt.LeftButton) assert blocker.args == [workspace_fs]
async def test_workspace_button_delete_clicked(qtbot, workspace_fs, core_config): switch_language(core_config, "en") roles = {workspace_fs.device.user_id: WorkspaceRole.OWNER} w = WorkspaceButton( workspace_name="Workspace", workspace_fs=workspace_fs, users_roles=roles, is_mounted=True, files=[], ) qtbot.addWidget(w) with qtbot.waitSignal(w.delete_clicked, timeout=500) as blocker: qtbot.mouseClick(w.button_delete, QtCore.Qt.LeftButton) assert blocker.args == [workspace_fs]
def add_workspace(self, workspace_name, is_owner, creator, files, shared_with=None): button = WorkspaceButton(workspace_name, is_owner, creator, shared_with=shared_with, files=files) button.clicked.connect(self.load_workspace) self.layout_workspaces.addWidget( button, int(self.workspaces_count / self.COLUMNS_NUMBER), int(self.workspaces_count % self.COLUMNS_NUMBER), ) self.workspaces_count += 1 button.share_clicked.connect(self.share_workspace) button.details_clicked.connect(self.show_workspace_details) button.delete_clicked.connect(self.delete_workspace) button.rename_clicked.connect(self.rename_workspace)
def add_workspace(self, workspace_fs, ws_entry, users_roles, files, timestamped): # The Qt thread should never hit the core directly. # Synchronous calls can run directly in the job system # as they won't block the Qt loop for long workspace_name = self.jobs_ctx.run_sync( workspace_fs.get_workspace_name) button = WorkspaceButton( workspace_name=workspace_name, workspace_fs=workspace_fs, is_shared=len(users_roles) > 1, is_creator=ws_entry.role == WorkspaceRole.OWNER, files=files[:4], timestamped=timestamped, ) self.layout_workspaces.addWidget(button) button.clicked.connect(self.load_workspace) button.share_clicked.connect(self.share_workspace) button.reencrypt_clicked.connect(self.reencrypt_workspace) button.delete_clicked.connect(self.delete_workspace) button.rename_clicked.connect(self.rename_workspace) button.remount_ts_clicked.connect(self.remount_workspace_ts) button.open_clicked.connect(self.open_workspace) self.jobs_ctx.submit_job( ThreadSafeQtSignal(self, "mount_success", QtToTrioJob), ThreadSafeQtSignal(self, "mount_error", QtToTrioJob), _do_workspace_mount, core=self.core, workspace_id=workspace_fs.workspace_id, ) self.jobs_ctx.submit_job( ThreadSafeQtSignal(self, "reencryption_needs_success", QtToTrioJob), ThreadSafeQtSignal(self, "reencryption_needs_error", QtToTrioJob), _get_reencryption_needs, workspace_fs=workspace_fs, )
async def test_workspace_button(qtbot, workspace_fs, core_config, alice_user_info): switch_language(core_config, "en") roles = {alice_user_info.user_id: (WorkspaceRole.OWNER, alice_user_info)} w = WorkspaceButton.create( workspace_name=EntryName("Workspace"), workspace_fs=workspace_fs, users_roles=roles, is_mounted=True, files=[], ) qtbot.add_widget(w) w.show() assert w.widget_empty.isVisible() is True assert w.widget_files.isVisible() is False assert w.label_owner.isVisible() is True assert w.label_shared.isVisible() is False assert w.name == EntryName("Workspace") assert w.label_title.text().startswith("Workspace") assert w.label_title.toolTip() == "Workspace (private)" assert w.label_role.text() == _("TEXT_WORKSPACE_ROLE_OWNER")
def on_list_success(self, job): # Hide the spinner in case it was visible self.spinner.hide() workspaces = job.ret # Use temporary dict to update the workspace mapping new_mapping = {} old_mapping = dict(self.workspace_button_mapping) # Loop over the resulting workspaces for workspace_fs, workspace_name, ws_entry, users_roles, files, timestamped in workspaces: # Pop button from existing mapping key = (workspace_fs.workspace_id, getattr(workspace_fs, "timestamp", None)) button = old_mapping.pop(key, None) # Create and bind button if it doesn't exist if button is None: button = WorkspaceButton(workspace_fs) button.clicked.connect(self.load_workspace) if self.core.device.is_outsider: button.button_share.hide() else: button.share_clicked.connect(self.share_workspace) button.reencrypt_clicked.connect(self.reencrypt_workspace) button.delete_clicked.connect(self.delete_workspace) button.rename_clicked.connect(self.rename_workspace) button.remount_ts_clicked.connect(self.remount_workspace_ts) button.open_clicked.connect(self.open_workspace) button.switch_clicked.connect(self._on_switch_clicked) # Apply new state button.apply_state( workspace_name=workspace_name, workspace_fs=workspace_fs, users_roles=users_roles, is_mounted=self.is_workspace_mounted(workspace_fs.workspace_id, None), files=files[:4], timestamped=timestamped, ) # Use this opportunity to trigger the `get_reencryption_needs` routine if button.is_owner: try: self.jobs_ctx.submit_job( ThreadSafeQtSignal(self, "reencryption_needs_success", QtToTrioJob), ThreadSafeQtSignal(self, "reencryption_needs_error", QtToTrioJob), _get_reencryption_needs, workspace_fs=workspace_fs, ) except JobSchedulerNotAvailable: pass # Add the button to the new mapping # Note that the order of insertion matters as it corresponds to the order in which # the workspaces are displayed. new_mapping[key] = button # Set the new mapping self.workspace_button_mapping = new_mapping # Refresh the layout, taking the filtering into account self.refresh_workspace_layout() # Dereference the old buttons for button in old_mapping.values(): button.setParent(None)