Beispiel #1
0
    def on_verify_token_finished(self, res):

        if res == OAuth2Session.Success:
            self.auth_session.save_creds()

            # switch to next page
            self.stackedWidget.slideInIdx(2)
            self.pushButtonDropboxPathSelect.setFocus()
            self.lineEditAuthCode.clear()  # clear since we might come back on unlink

            # start Maestral after linking to Dropbox account
            start_maestral_daemon_thread(self._config_name, run=False)
            self.mdbx = get_maestral_proxy(self._config_name)
            self.mdbx.reset_sync_state()
            self.mdbx.get_account_info()
        elif res == OAuth2Session.InvalidToken:
            msg = 'Please make sure that you entered the correct authentication token.'
            msg_box = UserDialog('Authentication failed.', msg, parent=self)
            msg_box.open()
        elif res == OAuth2Session.ConnectionFailed:
            msg = 'Please make sure that you are connected to the internet and try again.'
            msg_box = UserDialog('Connection failed.', msg, parent=self)
            msg_box.open()

        self.progressIndicator.stopAnimation()
        self.pushButtonAuthPageLink.setEnabled(True)
        self.lineEditAuthCode.setEnabled(True)
Beispiel #2
0
def rebuild_index(config_name: str):
    """Rebuilds Maestral's index. May take several minutes."""

    if not pending_link_cli(config_name):

        import textwrap

        width, height = click.get_terminal_size()

        message1 = textwrap.wrap(
            'If you encounter sync issues, please run \'maestral status\' to check for '
            'sync issues which can should be resolved manually, e.g., incompatible file '
            'names or insufficient permissions. After resolving them, please pause and '
            'resume syncing. Only rebuild the index if you continue to have problems '
            'after taking those steps.',
            width=width,
        )

        message2 = textwrap.wrap(
            'Rebuilding the index may take several minutes, depending on the size of '
            'your Dropbox. Please do not modify any items in your local Dropbox folder '
            'during this process. Any changes to local files while rebuilding may be '
            'lost.',
            width=width)

        click.echo('\n'.join(message1) + '\n')
        click.echo('\n'.join(message2) + '\n')
        click.confirm('Do you want to continue?', abort=True)

        import time
        import Pyro5.client
        from concurrent.futures import ThreadPoolExecutor
        from maestral.daemon import MaestralProxy, get_maestral_proxy

        m0 = get_maestral_proxy(config_name, fallback=True)

        def rebuild_in_thread():
            if isinstance(m0, Pyro5.client.Proxy):
                # rebuild index from separate proxy
                with MaestralProxy(config_name) as m1:
                    m1.rebuild_index()
            else:
                # rebuild index with main instance
                m0.rebuild_index()

        with ThreadPoolExecutor(max_workers=1) as executor:
            future = executor.submit(rebuild_in_thread)
            while future.running():  # get status updates while rebuilding
                msg = ('\r' + m0.status).ljust(width)
                click.echo(msg, nl=False)
                time.sleep(1.0)

        future.result()  # this will raise any errors during rebuilding
        click.echo('\rRebuilding complete.'.ljust(width))

        del m0  # delete while still in scope

    else:
        click.echo('Maestral does not appear to be linked.')
Beispiel #3
0
    def load_maestral(self):

        not_linked = pending_link(self.config_name)

        if not_linked or pending_dropbox_folder(self.config_name):
            from maestral_qt.setup_dialog import SetupDialog
            logger.info('Setting up Maestral...')
            done = SetupDialog.configureMaestral(self.config_name, not_linked)
            self._started = True
            if done:
                logger.info('Successfully set up Maestral')
                self.mdbx = get_maestral_proxy(self.config_name)
                self.mdbx.run()
                self.setup_ui_linked()
            else:
                logger.info('Setup aborted.')
                self.quit()
        else:
            self.mdbx = self._get_or_start_maestral_daemon()
            self.setup_ui_linked()
Beispiel #4
0
    def _get_or_start_maestral_daemon(self):

        pid = get_maestral_pid(self.config_name)
        if pid:
            self._started = False
        else:
            if IS_MACOS_BUNDLE:
                res = start_maestral_daemon_thread(self.config_name)
            else:
                res = start_maestral_daemon_process(self.config_name)
            if res == Start.Failed:
                title = 'Could not start Maestral'
                message = ('Could not start or connect to sync daemon. Please try again '
                           'and contact the developer if this issue persists.')
                show_dialog(title, message, level='error')
                self.quit()
            elif res == Start.AlreadyRunning:
                self._started = False
            elif res == Start.Ok:
                self._started = True

        return get_maestral_proxy(self.config_name)
Beispiel #5
0
    def __init__(self, config_name='maestral', pending_link=True, parent=None):
        super().__init__(parent=parent)
        # load user interface layout from .ui file
        uic.loadUi(SETUP_DIALOG_PATH, self)
        self.setWindowFlags(Qt.WindowStaysOnTopHint)

        self._config_name = config_name
        self._conf = MaestralConfig(config_name)
        self._state = MaestralState(config_name)

        self.app_icon = QtGui.QIcon(APP_ICON_PATH)

        self.labelIcon_0.setPixmap(icon_to_pixmap(self.app_icon, 150))
        self.labelIcon_1.setPixmap(icon_to_pixmap(self.app_icon, 70))
        self.labelIcon_2.setPixmap(icon_to_pixmap(self.app_icon, 70))
        self.labelIcon_3.setPixmap(icon_to_pixmap(self.app_icon, 120))

        self.mdbx = None
        self.dbx_model = None
        self.excluded_items = []

        # resize dialog buttons
        width = self.pushButtonAuthPageCancel.width()*1.1
        for b in (self.pushButtonAuthPageLink, self.pushButtonDropboxPathUnlink,
                  self.pushButtonDropboxPathSelect, self.pushButtonFolderSelectionBack,
                  self.pushButtonFolderSelectionSelect, self.pushButtonAuthPageCancel,
                  self.pushButtonDropboxPathCalcel, self.pushButtonClose):
            b.setMinimumWidth(width)
            b.setMaximumWidth(width)

        # set up combobox
        self.dropbox_location = osp.dirname(self._conf.get('main', 'path')) or get_home_dir()
        relative_path = self.rel_path(self.dropbox_location)

        folder_icon = get_native_item_icon(self.dropbox_location)
        self.comboBoxDropboxPath.addItem(folder_icon, relative_path)

        self.comboBoxDropboxPath.insertSeparator(1)
        self.comboBoxDropboxPath.addItem(QtGui.QIcon(), 'Other...')
        self.comboBoxDropboxPath.currentIndexChanged.connect(self.on_combobox)
        self.dropbox_folder_dialog = QtWidgets.QFileDialog(self)
        self.dropbox_folder_dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptOpen)
        self.dropbox_folder_dialog.setFileMode(QtWidgets.QFileDialog.Directory)
        self.dropbox_folder_dialog.setOption(QtWidgets.QFileDialog.ShowDirsOnly, True)
        self.dropbox_folder_dialog.fileSelected.connect(self.on_new_dbx_folder)
        self.dropbox_folder_dialog.rejected.connect(
                lambda: self.comboBoxDropboxPath.setCurrentIndex(0))

        # connect buttons to callbacks
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.pushButtonLink.clicked.connect(self.on_link)
        self.pushButtonAuthPageCancel.clicked.connect(self.on_reject_requested)
        self.pushButtonAuthPageLink.clicked.connect(self.on_auth_clicked)
        self.pushButtonDropboxPathCalcel.clicked.connect(self.on_reject_requested)
        self.pushButtonDropboxPathSelect.clicked.connect(self.on_dropbox_location_selected)
        self.pushButtonDropboxPathUnlink.clicked.connect(self.unlink_and_go_to_start)
        self.pushButtonFolderSelectionBack.clicked.connect(self.stackedWidget.slideInPrev)
        self.pushButtonFolderSelectionSelect.clicked.connect(self.on_folders_selected)
        self.pushButtonClose.clicked.connect(self.on_accept_requested)
        self.selectAllCheckBox.clicked.connect(self.on_select_all_clicked)

        default_dir_name = self._conf.get('main', 'default_dir_name')

        self.labelDropboxPath.setText(self.labelDropboxPath.text().format(default_dir_name))

        # check if we are already authenticated, skip authentication if yes
        if not pending_link:
            start_maestral_daemon_thread(self._config_name, run=False)
            self.mdbx = get_maestral_proxy(self._config_name)
            self.mdbx.get_account_info()
            self.labelDropboxPath.setText("""
            <html><head/><body>
            <p align="left">
            Your Dropbox folder has been moved or deleted from its original location.
            Maestral will not work properly until you move it back. It used to be located
            at: </p><p align="left">{0}</p>
            <p align="left">
            To move it back, click "Quit" below, move the Dropbox folder back to its
            original location, and launch Maestral again.
            </p>
            <p align="left">
            To re-download your Dropbox, please select a location for your Dropbox
            folder below. Maestral will create a new folder named "{1}" in the
            selected location.</p>
            <p align="left">
            To unlink your Dropbox account from Maestral, click "Unlink" below.</p>
            </body></html>
            """.format(self._conf.get('main', 'path'), default_dir_name))
            self.pushButtonDropboxPathCalcel.setText('Quit')
            self.stackedWidget.setCurrentIndex(2)
            self.stackedWidgetButtons.setCurrentIndex(2)
        else:
            self.stackedWidget.setCurrentIndex(0)
            self.stackedWidgetButtons.setCurrentIndex(0)