Esempio n. 1
0
def test_login_ensure_errors_displayed(qtbot, mocker):
    """
    We see an error if incomplete credentials are supplied to the login dialog.
    """
    w = Window()
    login_dialog = LoginDialog(w)
    login_dialog.show()
    assert login_dialog.error_bar.error_status_bar.text() == ""
    qtbot.keyClicks(login_dialog.username_field, "journalist")
    qtbot.mouseClick(login_dialog.submit, Qt.LeftButton)
    expected = "Please enter a username, passphrase and two-factor code."
    actual = login_dialog.error_bar.error_status_bar.text()
    assert actual == expected
Esempio n. 2
0
class Window(QMainWindow):
    """
    Represents the application's main window that will contain the UI widgets.
    All interactions with the UI go through the object created by this class.
    """

    icon = "icon.png"

    def __init__(self) -> None:
        """
        Create the default start state. The window contains a root widget into
        which is placed:

        * A status bar widget at the top, containing curent user / status
          information.
        * A main-view widget, itself containing a list view for sources and a
          place for details / message contents / forms.
        """
        super().__init__()

        load_font("Montserrat")
        load_font("Source_Sans_Pro")
        self.setStyleSheet(load_css("sdclient.css"))
        self.setWindowTitle(_("SecureDrop Client {}").format(__version__))
        self.setWindowIcon(load_icon(self.icon))

        # Top Pane to display activity and error messages
        self.top_pane = TopPane()

        # Main Pane to display everything else
        self.main_pane = QWidget()
        layout = QHBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        self.main_pane.setLayout(layout)
        self.left_pane = LeftPane()
        self.main_view = MainView(self.main_pane)
        layout.addWidget(self.left_pane)
        layout.addWidget(self.main_view)

        # Set the main window's central widget to show Top Pane and Main Pane
        self.central_widget = QWidget()
        central_widget_layout = QVBoxLayout()
        central_widget_layout.setContentsMargins(0, 0, 0, 0)
        central_widget_layout.setSpacing(0)
        self.central_widget.setLayout(central_widget_layout)
        self.setCentralWidget(self.central_widget)
        central_widget_layout.addWidget(self.top_pane)
        central_widget_layout.addWidget(self.main_pane)

    def setup(self, controller):
        """
        Create references to the controller logic and instantiate the various
        views used in the UI.
        """
        self.controller = controller  # Reference the Controller logic instance.
        self.top_pane.setup(self.controller)
        self.left_pane.setup(self, self.controller)
        self.main_view.setup(self.controller)
        self.show_login()

    def show_main_window(self, db_user: User = None) -> None:
        """
        Show main application window.
        """
        self.autosize_window()
        self.show()

        if db_user:
            self.set_logged_in_as(db_user)

    def autosize_window(self):
        """
        Ensure the application window takes up 100% of the available screen
        (i.e. the whole of the virtualised desktop in Qubes dom)
        """
        screen = QDesktopWidget().screenGeometry()
        self.resize(screen.width(), screen.height())

    def show_login(self, error: str = ""):
        """
        Show the login form.
        """
        self.login_dialog = LoginDialog(self)

        # Always display the login dialog centered in the screen.
        screen_size = QDesktopWidget().screenGeometry()
        login_dialog_size = self.login_dialog.geometry()
        x_center = (screen_size.width() - login_dialog_size.width()) / 2
        y_center = (screen_size.height() - login_dialog_size.height()) / 2
        self.login_dialog.move(x_center, y_center)
        self.login_dialog.setup(self.controller)
        self.login_dialog.reset()
        if error:
            self.login_dialog.error(error)
        self.login_dialog.show()

    def show_login_error(self, error):
        """
        Display an error in the login dialog.
        """
        if self.login_dialog and error:
            self.login_dialog.error(error)

    def hide_login(self):
        """
        Kill the login dialog.
        """
        self.login_dialog.accept()
        self.login_dialog = None

    def refresh_current_source_conversation(self):
        """
        Update the current conversation if the source collection has changed.
        """
        self.main_view.on_source_changed()

    def show_sources(self, sources: List[Source]):
        """
        Update the left hand sources list in the UI with the passed in list of
        sources.
        """
        self.main_view.show_sources(sources)

    def show_last_sync(self, updated_on):
        """
        Display a message indicating the time of last sync with the server.
        """
        if updated_on:
            self.update_activity_status(
                _("Last Refresh: {}").format(updated_on.humanize()))
        else:
            self.update_activity_status(_("Last Refresh: never"))

    def set_logged_in_as(self, db_user: User):
        """
        Update the UI to show user logged in with username.
        """
        self.left_pane.set_logged_in_as(db_user)
        self.top_pane.set_logged_in()

    def logout(self):
        """
        Update the UI to show the user is logged out.
        """
        self.left_pane.set_logged_out()
        self.top_pane.set_logged_out()

    def update_activity_status(self, message: str, duration=0):
        """
        Display an activity status message to the user. Optionally, supply a duration
        (in milliseconds), the default will continuously show the message.
        """
        self.top_pane.update_activity_status(message, duration)

    def update_error_status(self, message: str, duration=10000) -> None:
        """
        Display an error status message to the user. Optionally, supply a duration
        (in milliseconds), the default will continuously show the message.
        """
        self.top_pane.update_error_status(message, duration)

    def clear_error_status(self):
        """
        Clear any message currently in the error status bar.
        """
        self.top_pane.clear_error_status()

    def clear_clipboard(self):
        """
        Purge any clipboard contents.
        """
        cb = QApplication.clipboard()
        cb.clear()