コード例 #1
0
 def profile_select_action(self, index):
     self.current_profile = BackupProfileModel.get(id=self.profileSelector.currentData())
     self.archiveTab.populate_from_profile()
     self.repoTab.populate_from_profile()
     self.sourceTab.populate_from_profile()
     self.scheduleTab.populate_from_profile()
     SettingsModel.update({SettingsModel.str_value: self.current_profile.id})\
         .where(SettingsModel.key == 'previous_profile_id')\
         .execute()
コード例 #2
0
ファイル: notifications.py プロジェクト: wjt/vorta
    def notifications_suppressed(self, level):
        """Decide if notification is sent or not based on settings and level."""
        if not SettingsModel.get(key='enable_notifications').value:
            logger.debug('notifications suppressed')
            return True
        if level == 'info' and not SettingsModel.get(
                key='enable_notifications_success').value:
            logger.debug('success notifications suppressed')
            return True

        logger.debug('notification not suppressed')
        return False
コード例 #3
0
def main():
    args = parse_args()

    frozen_binary = getattr(sys, 'frozen', False)

    # Don't fork if user specifies it or when running from onedir app bundle on macOS.
    if hasattr(args, 'foreground') or (frozen_binary
                                       and sys.platform == 'darwin'):
        pass
    else:
        print('Forking to background (see system tray).')
        if os.fork():
            sys.exit()

    # Init database
    sqlite_db = peewee.SqliteDatabase(os.path.join(SETTINGS_DIR,
                                                   'settings.db'))
    init_db(sqlite_db)

    # Send crashes to Sentry.
    if SettingsModel.get(key='send_sentry_reports').value:
        vorta.sentry.init()

    app = VortaApp(sys.argv, single_app=True)
    app.updater = get_updater()

    sys.exit(app.exec_())
コード例 #4
0
ファイル: application.py プロジェクト: sten0/vorta
    def __init__(self, args_raw, single_app=False):

        super().__init__(APP_ID, args_raw)
        if self.isRunning() and single_app:
            self.sendMessage("open main window")
            print('An instance of Vorta is already running. Opening main window.')
            sys.exit()

        init_translations(self)

        self.setQuitOnLastWindowClosed(False)
        self.scheduler = VortaScheduler(self)

        # Prepare system tray icon
        self.tray = TrayMenu(self)

        args = parse_args()
        if getattr(args, 'daemonize', False):
            pass
        elif SettingsModel.get(key='foreground').value:
            self.open_main_window_action()

        self.backup_started_event.connect(self.backup_started_event_response)
        self.backup_finished_event.connect(self.backup_finished_event_response)
        self.backup_cancelled_event.connect(self.backup_cancelled_event_response)
        self.message_received_event.connect(self.message_received_event_response)
        self.set_borg_details_action()
        self.installEventFilter(self)
コード例 #5
0
    def save_setting(self, key, new_value):
        setting = SettingsModel.get(key=key)
        setting.value = bool(new_value)
        setting.save()

        if key == 'autostart':
            open_app_at_startup(new_value)
コード例 #6
0
    def closeEvent(self, event):
        # Save window state in SettingsModel
        SettingsModel.update({SettingsModel.str_value: str(self.width())})\
            .where(SettingsModel.key == 'previous_window_width')\
            .execute()
        SettingsModel.update({SettingsModel.str_value: str(self.height())})\
            .where(SettingsModel.key == 'previous_window_height')\
            .execute()

        if not is_system_tray_available():
            run_in_background = QMessageBox.question(
                self, trans_late("MainWindow QMessagebox", "Quit"),
                trans_late("MainWindow QMessagebox",
                           "Should Vorta continue to run in the background?"),
                QMessageBox.Yes | QMessageBox.No)
            if run_in_background == QMessageBox.No:
                self.app.quit()
        event.accept()
コード例 #7
0
    def deliver(self, title, text):
        if SettingsModel.get(key='enable_notifications').value:
            from Foundation import NSUserNotification
            from Foundation import NSUserNotificationCenter

            notification = NSUserNotification.alloc().init()
            notification.setTitle_(title)
            notification.setInformativeText_(text)
            center = NSUserNotificationCenter.defaultUserNotificationCenter()
            if center is not None:  # Only works when run from app bundle.
                center.deliverNotification_(notification)
コード例 #8
0
    def closeEvent(self, event):
        # Save window state in SettingsModel
        SettingsModel.update({SettingsModel.str_value: str(self.width())})\
            .where(SettingsModel.key == 'previous_window_width')\
            .execute()
        SettingsModel.update({SettingsModel.str_value: str(self.height())})\
            .where(SettingsModel.key == 'previous_window_height')\
            .execute()

        if not is_system_tray_available():
            if SettingsModel.get(key="enable_background_question").value:
                msg = QMessageBox()
                msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
                msg.setParent(self, QtCore.Qt.Sheet)
                msg.setText(
                    self.tr("Should Vorta continue to run in the background?"))
                msg.button(QMessageBox.Yes).clicked.connect(
                    lambda: self.miscTab.save_setting(
                        "disable_background_state", True))
                msg.button(QMessageBox.No).clicked.connect(
                    lambda: (self.miscTab.save_setting(
                        "disable_background_state", False), self.app.quit()))
                msg.setWindowTitle(self.tr("Quit"))
                dont_show_box = QCheckBox(self.tr("Don't show this again"))
                dont_show_box.clicked.connect(
                    lambda x: self.miscTab.save_setting(
                        "enable_background_question", not x))
                dont_show_box.setTristate(False)
                msg.setCheckBox(dont_show_box)
                msg.exec()
            elif not SettingsModel.get(key="disable_background_state").value:
                self.app.quit()
        event.accept()
コード例 #9
0
ファイル: updater.py プロジェクト: wjt/vorta
def get_updater():
    if sys.platform == 'darwin' and getattr(sys, 'frozen', False):
        """
        Use Sparkle framework on macOS.

        Settings: https://sparkle-project.org/documentation/customization/
        Examples: https://programtalk.com/python-examples/objc.loadBundle/

        To debug:
        $ defaults read com.borgbase.client.macos
        """

        import objc
        import Cocoa
        bundle_path = os.path.join(os.path.dirname(sys.executable), os.pardir,
                                   'Frameworks', 'Sparkle.framework')
        objc.loadBundle('Sparkle', globals(), bundle_path)
        sparkle = SUUpdater.sharedUpdater()  # noqa: F821

        # A default Appcast URL is set in vorta.spec, when setting it here it's saved to defaults,
        # so we need both cases.
        if SettingsModel.get(key='updates_include_beta').value:
            appcast_nsurl = Cocoa.NSURL.URLWithString_(
                'https://borgbase.github.io/vorta/appcast-pre.xml')
        else:
            appcast_nsurl = Cocoa.NSURL.URLWithString_(
                'https://borgbase.github.io/vorta/appcast.xml')

        sparkle.setFeedURL_(appcast_nsurl)

        if SettingsModel.get(key='check_for_updates').value:
            sparkle.setAutomaticallyChecksForUpdates_(True)
            sparkle.checkForUpdatesInBackground()

        sparkle.setAutomaticallyDownloadsUpdates_(False)
        return sparkle

    else:  # TODO: implement for Linux
        return None
コード例 #10
0
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(parent)
        self.versionLabel.setText(__version__)

        for setting in SettingsModel.select().where(
                SettingsModel.type == 'checkbox'):
            b = QCheckBox(setting.label)
            b.setCheckState(setting.value)
            b.setTristate(False)
            b.stateChanged.connect(
                lambda v, key=setting.key: self.save_setting(key, v))
            self.checkboxLayout.addWidget(b)
コード例 #11
0
def get_theme_class():
    """
    Choose a package to import collection_rc from.

    light = white icons, dark = black icons.

    Defaults to dark icons (light theme) if DB isn't initialized yet.
    """
    if SettingsModel._meta.database.obj is None:
        return 'vorta.views.dark'
    else:
        use_light_icon = SettingsModel.get(key='use_dark_theme').value
        return 'vorta.views.light' if use_light_icon else 'vorta.views.dark'
コード例 #12
0
ファイル: application.py プロジェクト: srgvg/vorta
    def __init__(self, args_raw, single_app=False):
        super().__init__(APP_ID, args_raw)
        args = parse_args()
        if self.isRunning():
            if single_app:
                self.sendMessage("open main window")
                print(
                    'An instance of Vorta is already running. Opening main window.'
                )
                sys.exit()
            elif args.profile:
                self.sendMessage(f"create {args.profile}")
                print('Creating backup using existing Vorta instance.')
                sys.exit()
        elif args.profile:
            sys.exit('Vorta must already be running for --create to work')

        init_translations(self)

        self.setQuitOnLastWindowClosed(False)
        self.scheduler = VortaScheduler(self)
        self.setApplicationName("Vorta")

        # Import profile from ~/.vorta-init.json or add empty "Default" profile.
        self.bootstrap_profile()

        # Prepare tray and main window
        self.tray = TrayMenu(self)
        self.main_window = MainWindow(self)

        if getattr(args, 'daemonize', False):
            pass
        elif SettingsModel.get(key='foreground').value:
            self.open_main_window_action()

        self.backup_started_event.connect(self.backup_started_event_response)
        self.backup_finished_event.connect(self.backup_finished_event_response)
        self.backup_cancelled_event.connect(
            self.backup_cancelled_event_response)
        self.message_received_event.connect(
            self.message_received_event_response)
        self.backup_log_event.connect(self.react_to_log)
        self.aboutToQuit.connect(self.quit_app_action)
        self.set_borg_details_action()
        if sys.platform == 'darwin':
            self.check_darwin_permissions()

        self.installEventFilter(self)
コード例 #13
0
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(parent)
        self.versionLabel.setText(__version__)
        self.logLink.setText(f'<a href="file://{LOG_DIR}"><span style="text-decoration:'
                             'underline; color:#0984e3;">Log</span></a>')

        for setting in SettingsModel.select().where(SettingsModel.type == 'checkbox'):
            x = filter(lambda s: s['key'] == setting.key, get_misc_settings())
            if not list(x):  # Skip settings that aren't specified in vorta.models.
                continue
            b = QCheckBox(translate('settings', setting.label))
            b.setCheckState(setting.value)
            b.setTristate(False)
            b.stateChanged.connect(lambda v, key=setting.key: self.save_setting(key, v))
            self.checkboxLayout.addWidget(b)
コード例 #14
0
ファイル: misc_tab.py プロジェクト: ipwog/vorta
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(parent)
        self.versionLabel.setText(__version__)

        for setting in SettingsModel.select().where(
                SettingsModel.type == 'checkbox'):
            x = filter(lambda s: s['key'] == setting.key, get_misc_settings())
            if not list(
                    x):  # Skip settings that aren't specified in vorta.models.
                continue
            b = QCheckBox(translate('settings', setting.label))
            b.setCheckState(setting.value)
            b.setTristate(False)
            b.stateChanged.connect(
                lambda v, key=setting.key: self.save_setting(key, v))
            self.checkboxLayout.addWidget(b)
コード例 #15
0
ファイル: misc_tab.py プロジェクト: srgvg/vorta
 def populate(self):
     # clear layout
     while self.checkboxLayout.count():
         child = self.checkboxLayout.takeAt(0)
         if child.widget():
             child.widget().deleteLater()
     # dynamically add widgets for settings
     for setting in SettingsModel.select().where(
             SettingsModel.type == 'checkbox'):
         x = filter(lambda s: s['key'] == setting.key, get_misc_settings())
         if not list(
                 x):  # Skip settings that aren't specified in vorta.models.
             continue
         b = QCheckBox(translate('settings', setting.label))
         b.setCheckState(setting.value)
         b.setTristate(False)
         b.stateChanged.connect(
             lambda v, key=setting.key: self.save_setting(key, v))
         self.checkboxLayout.addWidget(b)
コード例 #16
0
ファイル: mount.py プロジェクト: srgvg/vorta
    def prepare(cls, profile):
        ret = super().prepare(profile)
        if not ret['ok']:
            return ret
        else:
            ret['ok'] = False  # Set back to false, so we can do our own checks here.

        cmd = ['borg', '--log-json', 'mount']

        # Try to override existing permissions when mounting an archive. May help to read
        # files that come from a different system, like a restrictive NAS.
        override_mount_permissions = SettingsModel.get(key='override_mount_permissions').value
        if override_mount_permissions:
            cmd += ['-o', f"umask=0277,uid={os.getuid()}"]

        cmd += [f"{profile.repo.url}"]

        ret['ok'] = True
        ret['cmd'] = cmd

        return ret
コード例 #17
0
    def __init__(self, parent=None):
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle('Vorta for Borg Backup')
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
        self.app = parent
        self.setWindowFlags(QtCore.Qt.WindowCloseButtonHint | QtCore.Qt.WindowMinimizeButtonHint)
        self.createStartBtn = LoadingButton(self.tr("Start Backup"))
        self.gridLayout.addWidget(self.createStartBtn, 0, 0, 1, 1)
        self.createStartBtn.setGif(get_asset("icons/loading"))

        # Use previous window state
        previous_window_width = SettingsModel.get(key='previous_window_width')
        previous_window_height = SettingsModel.get(key='previous_window_height')
        self.resize(int(previous_window_width.str_value), int(previous_window_height.str_value))

        # Select previously used profile, if available
        prev_profile_id = SettingsModel.get(key='previous_profile_id')
        self.current_profile = BackupProfileModel.get_or_none(id=prev_profile_id.str_value)
        if self.current_profile is None:
            self.current_profile = BackupProfileModel.select().order_by('name').first()

        # Load tab models
        self.repoTab = RepoTab(self.repoTabSlot)
        self.sourceTab = SourceTab(self.sourceTabSlot)
        self.archiveTab = ArchiveTab(self.archiveTabSlot)
        self.scheduleTab = ScheduleTab(self.scheduleTabSlot)
        self.miscTab = MiscTab(self.miscTabSlot)
        self.miscTab.set_borg_details(borg_compat.version, borg_compat.path)
        self.tabWidget.setCurrentIndex(0)

        self.repoTab.repo_changed.connect(self.archiveTab.populate_from_profile)
        self.repoTab.repo_added.connect(self.archiveTab.list_action)
        self.tabWidget.currentChanged.connect(self.scheduleTab._draw_next_scheduled_backup)

        self.createStartBtn.clicked.connect(self.app.create_backup_action)
        self.cancelButton.clicked.connect(self.app.backup_cancelled_event.emit)

        QShortcut(QKeySequence("Ctrl+W"), self).activated.connect(self.on_close_window)
        QShortcut(QKeySequence("Ctrl+Q"), self).activated.connect(self.on_close_window)

        self.app.backup_started_event.connect(self.backup_started_event)
        self.app.backup_finished_event.connect(self.backup_finished_event)
        self.app.backup_log_event.connect(self.set_log)
        self.app.backup_progress_event.connect(self.set_progress)
        self.app.backup_cancelled_event.connect(self.backup_cancelled_event)

        # Init profile list
        for profile in BackupProfileModel.select().order_by(BackupProfileModel.name):
            self.profileSelector.addItem(profile.name, profile.id)
        current_profile_index = self.profileSelector.findData(self.current_profile.id)
        self.profileSelector.setCurrentIndex(current_profile_index)
        self.profileSelector.currentIndexChanged.connect(self.profile_select_action)
        self.profileRenameButton.clicked.connect(self.profile_rename_action)
        self.profileDeleteButton.clicked.connect(self.profile_delete_action)
        self.profileAddButton.clicked.connect(self.profile_add_action)

        # OS-specific startup options:
        if not get_network_status_monitor().is_network_status_available():
            # Hide Wifi-rule section in schedule tab.
            self.scheduleTab.wifiListLabel.hide()
            self.scheduleTab.wifiListWidget.hide()
            self.scheduleTab.page_2.hide()
            self.scheduleTab.toolBox.removeItem(1)

        # Connect to existing thread.
        if BorgThread.is_running():
            self.createStartBtn.setEnabled(False)
            self.createStartBtn.start()
            self.cancelButton.setEnabled(True)

        self.set_icons()
コード例 #18
0
    def __init__(self, parent=None):
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle('Vorta for Borg Backup')
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
        self.app = parent
        self.current_profile = BackupProfileModel.select().order_by(
            'id').first()
        self.setWindowFlags(QtCore.Qt.WindowCloseButtonHint
                            | QtCore.Qt.WindowMinimizeButtonHint)

        # Temporary fix for QT Darkstyle dropdown issue.
        # See https://github.com/ColinDuquesnoy/QDarkStyleSheet/issues/200
        if SettingsModel.get(key='use_dark_theme').value:
            self.setStyleSheet("""
            QComboBox::item:checked {
            height: 12px;
            border: 1px solid #32414B;
            margin-top: 0px;
            margin-bottom: 0px;
            padding: 4px;
            padding-left: 0px;
            }
            """)

        # Load tab models
        self.repoTab = RepoTab(self.repoTabSlot)
        self.sourceTab = SourceTab(self.sourceTabSlot)
        self.archiveTab = ArchiveTab(self.archiveTabSlot)
        self.scheduleTab = ScheduleTab(self.scheduleTabSlot)
        self.miscTab = MiscTab(self.miscTabSlot)
        self.miscTab.set_borg_details(borg_compat.version, borg_compat.path)
        self.tabWidget.setCurrentIndex(0)

        self.repoTab.repo_changed.connect(
            self.archiveTab.populate_from_profile)
        self.repoTab.repo_added.connect(self.archiveTab.list_action)
        self.tabWidget.currentChanged.connect(
            self.scheduleTab._draw_next_scheduled_backup)

        self.createStartBtn.clicked.connect(self.app.create_backup_action)
        self.cancelButton.clicked.connect(self.app.backup_cancelled_event.emit)

        QShortcut(QKeySequence("Ctrl+W"),
                  self).activated.connect(self.on_close_window)
        QShortcut(QKeySequence("Ctrl+Q"),
                  self).activated.connect(self.on_close_window)

        self.app.backup_started_event.connect(self.backup_started_event)
        self.app.backup_finished_event.connect(self.backup_finished_event)
        self.app.backup_log_event.connect(self.set_status)
        self.app.backup_cancelled_event.connect(self.backup_cancelled_event)

        # Init profile list
        for profile in BackupProfileModel.select():
            self.profileSelector.addItem(profile.name, profile.id)
        self.profileSelector.setCurrentIndex(0)
        self.profileSelector.currentIndexChanged.connect(
            self.profile_select_action)
        self.profileRenameButton.clicked.connect(self.profile_rename_action)
        self.profileDeleteButton.clicked.connect(self.profile_delete_action)
        self.profileAddButton.clicked.connect(self.profile_add_action)

        # OS-specific startup options:
        if sys.platform != 'darwin':
            # Hide Wifi-rule section in schedule tab.
            self.scheduleTab.wifiListLabel.hide()
            self.scheduleTab.wifiListWidget.hide()
            self.scheduleTab.page_2.hide()
            self.scheduleTab.toolBox.removeItem(1)

        # Connect to existing thread.
        if BorgThread.is_running():
            self.createStartBtn.setEnabled(False)
            self.cancelButton.setEnabled(True)
            self.set_status(self.tr('Backup in progress.'), progress_max=0)
コード例 #19
0
ファイル: db.py プロジェクト: srgvg/vorta
 def get_priority(cls):
     return 1 if SettingsModel.get(key='use_system_keyring').value else 10
コード例 #20
0
ファイル: utils.py プロジェクト: bedros/vorta
def set_tray_icon(tray, active=False):
    from vorta.models import SettingsModel
    use_light_style = SettingsModel.get(key='use_light_icon').value
    icon_name = f"icons/hdd-o{'-active' if active else ''}-{'light' if use_light_style else 'dark'}.png"
    icon = QIcon(get_asset(icon_name))
    tray.setIcon(icon)
コード例 #21
0
ファイル: profile_export.py プロジェクト: srgvg/vorta
    def to_db(self, overwrite_profile=False, overwrite_settings=True):
        profile_schema = self._profile_dict['SchemaVersion']['version']
        keyring = VortaKeyring.get_keyring()
        if SCHEMA_VERSION < profile_schema:
            raise VersionException()
        elif SCHEMA_VERSION > profile_schema:
            # Add model upgrading code here, only needed if not adding columns
            if profile_schema < 16:
                for sourcedir in self._profile_dict['SourceFileModel']:
                    sourcedir['dir_files_count'] = -1
                    sourcedir['dir_size'] = -1
                    sourcedir['path_isdir'] = False

        existing_profile = None
        if overwrite_profile:
            existing_profile = BackupProfileModel.get_or_none(BackupProfileModel.name == self.name)
            if existing_profile:
                self._profile_dict['id'] = existing_profile.id
        if not overwrite_profile or not existing_profile:
            # Guarantee uniqueness of ids
            while BackupProfileModel.get_or_none(BackupProfileModel.id == self.id) is not None:
                self._profile_dict['id'] += 1

            # Add suffix incase names are the same
            if BackupProfileModel.get_or_none(BackupProfileModel.name == self.name) is not None:
                suffix = 1
                while BackupProfileModel.get_or_none(BackupProfileModel.name == f"{self.name}-{suffix}") is not None:
                    suffix += 1
                self._profile_dict['name'] = f"{self.name}-{suffix}"

        # Load existing repo or restore it
        if self._profile_dict['repo']:
            repo = RepoModel.get_or_none(RepoModel.url == self.repo_url)
            if repo is None:
                # Load repo from export
                repo = dict_to_model(RepoModel, self._profile_dict['repo'])
                repo.save(force_insert=True)
            self._profile_dict['repo'] = model_to_dict(repo)

        if self.repo_password:
            keyring.set_password('vorta-repo', self.repo_url, self.repo_password)
            del self._profile_dict['password']

        # Delete and recreate the tables to clear them
        if overwrite_settings:
            db.drop_tables([SettingsModel, WifiSettingModel])
            db.create_tables([SettingsModel, WifiSettingModel])
            SettingsModel.insert_many(self._profile_dict['SettingsModel']).execute()
            WifiSettingModel.insert_many(self._profile_dict['WifiSettingModel']).execute()

        # Set the profile ids to be match new profile
        for source in self._profile_dict['SourceFileModel']:
            source['profile'] = self.id
        SourceFileModel.insert_many(self._profile_dict['SourceFileModel']).execute()

        # Delete added dictionaries to make it match BackupProfileModel
        del self._profile_dict['SettingsModel']
        del self._profile_dict['SourceFileModel']
        del self._profile_dict['WifiSettingModel']
        del self._profile_dict['SchemaVersion']

        # dict to profile
        new_profile = dict_to_model(BackupProfileModel, self._profile_dict)
        if overwrite_profile and existing_profile:
            force_insert = False
        else:
            force_insert = True
        new_profile.save(force_insert=force_insert)
        init_db()  # rerun db init code to perform the same operations on the new as as on application boot
        return new_profile