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) self.tests_running = False # 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)
def on_user_click(self): """Build system tray menu based on current state.""" menu = self.contextMenu() menu.clear() open_action = menu.addAction(self.tr('Vorta for Borg Backup')) open_action.triggered.connect(self.app.open_main_window_action) menu.addSeparator() status = menu.addAction(self.app.scheduler.next_job) status.setEnabled(False) if BorgThread.is_running(): status.setText(self.tr('Backup in Progress')) cancel_action = menu.addAction(self.tr('Cancel Backup')) cancel_action.triggered.connect(self.app.backup_cancelled_event.emit) else: status.setText(self.tr('Next Task: %s') % self.app.scheduler.next_job) profiles = BackupProfileModel.select() if profiles.count() > 1: profile_menu = menu.addMenu(self.tr('Backup Now')) for profile in profiles: new_item = profile_menu.addAction(profile.name) new_item.triggered.connect(lambda state, i=profile.id: self.app.create_backup_action(i)) else: profile = profiles.first() profile_menu = menu.addAction(self.tr('Backup Now')) profile_menu.triggered.connect(lambda state, i=profile.id: self.app.create_backup_action(i)) menu.addSeparator() exit_action = menu.addAction(self.tr('Quit')) exit_action.triggered.connect(self.app.quit)
def populate_profile_selector(self): self.profileSelector.clear() 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)
def test_import_bootstrap_success(qapp, mocker): mocked_unlink = mocker.MagicMock() mocker.patch.object(Path, 'unlink', mocked_unlink) qapp.bootstrap_profile(Path(VALID_IMPORT_FILE)) assert mocked_unlink.called restored_profile = BackupProfileModel.get_or_none( name="Test Profile Restoration") assert restored_profile is not None restored_repo = restored_profile.repo assert restored_repo is not None assert len(SourceFileModel.select().where( SourceFileModel.profile == restored_profile)) == 3 assert BackupProfileModel.select().count() == 2
def bootstrap_profile(self, bootstrap_file=PROFILE_BOOTSTRAP_FILE): """ Make sure there is at least one profile when first starting Vorta. Will either import a profile placed in ~/.vorta-init.json or add an empty "Default" profile. """ if bootstrap_file.is_file(): profile_export = ProfileExport.from_json(bootstrap_file) profile = profile_export.to_db(overwrite_profile=True, overwrite_settings=True) bootstrap_file.unlink() notifier = VortaNotifications.pick() notifier.deliver(self.tr('Profile import successful!'), self.tr('Profile {} imported.').format( profile.name), level='info') logger.info('Profile {} imported.'.format(profile.name)) if BackupProfileModel.select().count() == 0: default_profile = BackupProfileModel(name='Default') default_profile.save()
def reload(self): for profile in BackupProfileModel.select(): trigger = None job_id = f'{profile.id}' if profile.schedule_mode == 'interval': if profile.schedule_interval_hours >= 24: days = profile.schedule_interval_hours // 24 leftover_hours = profile.schedule_interval_hours % 24 if leftover_hours == 0: cron_hours = '1' else: cron_hours = f'*/{leftover_hours}' trigger = cron.CronTrigger(day=f'*/{days}', hour=cron_hours, minute=profile.schedule_interval_minutes) else: trigger = cron.CronTrigger(hour=f'*/{profile.schedule_interval_hours}', minute=profile.schedule_interval_minutes) elif profile.schedule_mode == 'fixed': trigger = cron.CronTrigger(hour=profile.schedule_fixed_hour, minute=profile.schedule_fixed_minute) if self.get_job(job_id) is not None and trigger is not None: self.reschedule_job(job_id, trigger=trigger) notifier = VortaNotifications.pick() notifier.deliver(self.tr('Vorta Scheduler'), self.tr('Background scheduler was changed.')) logger.debug('Job for profile %s was rescheduled.', profile.name) elif trigger is not None: self.add_job( func=self.create_backup, args=[profile.id], trigger=trigger, id=job_id, misfire_grace_time=180 ) logger.debug('New job for profile %s was added.', profile.name) elif self.get_job(job_id) is not None and trigger is None: self.remove_job(job_id) logger.debug('Job for profile %s was removed.', profile.name)
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()
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)