Add EventLog

This commit is contained in:
Manu 2018-10-29 21:23:42 +08:00
parent 015b25f34b
commit b9d4d57f33
16 changed files with 468 additions and 170 deletions

View File

@ -2,11 +2,18 @@ import sys
from PyQt5.QtWidgets import QApplication
from vorta.tray_menu import TrayMenu
from vorta.scheduler import init_scheduler
from vorta.models import BackupProfileModel
app = QApplication(sys.argv)
app.thread = None
app.setQuitOnLastWindowClosed(False)
TrayMenu(app)
app.scheduler = init_scheduler()
app.profile = BackupProfileModel.get(id=1)
if not getattr(sys, 'frozen', False):
from .views.main_window import MainWindow
ex = MainWindow()
ex.show()
sys.exit(app.exec_())

View File

@ -54,7 +54,10 @@
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>2</number>
<number>0</number>
</property>
<property name="tabsClosable">
<bool>false</bool>
</property>
<widget class="QWidget" name="repoTabSlot">
<property name="sizePolicy">

View File

@ -100,8 +100,11 @@
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
<bool>false</bool>
</property>
</widget>
</item>
@ -122,7 +125,7 @@
</property>
</widget>
</item>
<item row="6" column="1">
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="saveButton">

View File

@ -22,8 +22,14 @@
<bold>false</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">QToolBox::tab {
color: black;
font-weight: bold;
}</string>
</property>
<property name="currentIndex">
<number>1</number>
<number>2</number>
</property>
<widget class="QWidget" name="schedule">
<property name="geometry">
@ -31,7 +37,7 @@
<x>0</x>
<y>0</y>
<width>663</width>
<height>415</height>
<height>381</height>
</rect>
</property>
<property name="font">
@ -40,140 +46,205 @@
<bold>false</bold>
</font>
</property>
<attribute name="icon">
<iconset>
<normaloff>../icons/clock-o.svg</normaloff>../icons/clock-o.svg</iconset>
</attribute>
<attribute name="label">
<string>Schedule</string>
</attribute>
<widget class="QWidget" name="verticalLayoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>661</width>
<height>101</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>10</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<item>
<widget class="QRadioButton" name="radioButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Backup Manually</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QRadioButton" name="radioButton_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Backup every </string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_2"/>
</item>
<item alignment="Qt::AlignLeft">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>hours at</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>minutes past the hour.</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QRadioButton" name="radioButton_3">
<property name="text">
<string>Backup daily at</string>
</property>
</widget>
</item>
<item>
<widget class="QTimeEdit" name="timeEdit"/>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<item>
<widget class="QRadioButton" name="scheduleOffRadio">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Backup Manually</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QRadioButton" name="scheduleIntervalRadio">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Backup every </string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="scheduleIntervalHours">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>48</number>
</property>
</widget>
</item>
<item alignment="Qt::AlignLeft">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>hours at</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="scheduleIntervalMinutes">
<property name="maximum">
<number>59</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>minutes past the hour.</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QRadioButton" name="scheduleFixedRadio">
<property name="text">
<string>Backup daily at</string>
</property>
</widget>
</item>
<item>
<widget class="QTimeEdit" name="scheduleFixedTime"/>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="scheduleApplyButton">
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Next Backup:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="nextBackupDateTimeLabel">
<property name="text">
<string>Off</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2">
<property name="geometry">
@ -181,22 +252,82 @@
<x>0</x>
<y>0</y>
<width>663</width>
<height>415</height>
<height>381</height>
</rect>
</property>
<attribute name="label">
<string>Rules</string>
<attribute name="icon">
<iconset>
<normaloff>../icons/wifi.svg</normaloff>../icons/wifi.svg</iconset>
</attribute>
<widget class="QListWidget" name="wifiListWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>30</y>
<width>256</width>
<height>192</height>
</rect>
</property>
</widget>
<attribute name="label">
<string>Networks</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<widget class="QListWidget" name="wifiListWidget"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Allowed Networks:</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page">
<attribute name="icon">
<iconset>
<normaloff>../icons/tasks.svg</normaloff>../icons/tasks.svg</iconset>
</attribute>
<attribute name="label">
<string>Log</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QTableWidget" name="logTableWidget">
<property name="font">
<font>
<pointsize>11</pointsize>
</font>
</property>
<property name="showGrid">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>Time</string>
</property>
</column>
<column>
<property name="text">
<string>Category</string>
</property>
</column>
<column>
<property name="text">
<string>Subcommand</string>
</property>
</column>
<column>
<property name="text">
<string>Message</string>
</property>
</column>
<column>
<property name="text">
<string>Returncode</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</widget>
</item>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1024 544v448q0 14-9 23t-23 9h-320q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h224v-352q0-14 9-23t23-9h64q14 0 23 9t9 23zm416 352q0-148-73-273t-198-198-273-73-273 73-198 198-73 273 73 273 198 198 273 73 273-73 198-198 73-273zm224 0q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/></svg>

After

Width:  |  Height:  |  Size: 507 B

View File

@ -0,0 +1,9 @@
<RCC>
<qresource prefix="/icons">
<file>wifi.svg</file>
<file>tasks.svg</file>
<file>clock-o.svg</file>
<file>server.svg</file>
<file>window-restore.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M128 1408h1024v-128h-1024v128zm0-512h1024v-128h-1024v128zm1568 448q0-40-28-68t-68-28-68 28-28 68 28 68 68 28 68-28 28-68zm-1568-960h1024v-128h-1024v128zm1568 448q0-40-28-68t-68-28-68 28-28 68 28 68 68 28 68-28 28-68zm0-512q0-40-28-68t-68-28-68 28-28 68 28 68 68 28 68-28 28-68zm96 832v384h-1792v-384h1792zm0-512v384h-1792v-384h1792zm0-512v384h-1792v-384h1792z"/></svg>

After

Width:  |  Height:  |  Size: 507 B

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1024 1408h640v-128h-640v128zm-384-512h1024v-128h-1024v128zm640-512h384v-128h-384v128zm512 832v256q0 26-19 45t-45 19h-1664q-26 0-45-19t-19-45v-256q0-26 19-45t45-19h1664q26 0 45 19t19 45zm0-512v256q0 26-19 45t-45 19h-1664q-26 0-45-19t-19-45v-256q0-26 19-45t45-19h1664q26 0 45 19t19 45zm0-512v256q0 26-19 45t-45 19h-1664q-26 0-45-19t-19-45v-256q0-26 19-45t45-19h1664q26 0 45 19t19 45z"/></svg>

After

Width:  |  Height:  |  Size: 530 B

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="2048" height="1792" viewBox="0 0 2048 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1024 1523q-20 0-93-73.5t-73-93.5q0-32 62.5-54t103.5-22 103.5 22 62.5 54q0 20-73 93.5t-93 73.5zm270-271q-2 0-40-25t-101.5-50-128.5-25-128.5 25-101 50-40.5 25q-18 0-93.5-75t-75.5-93q0-13 10-23 78-77 196-121t233-44 233 44 196 121q10 10 10 23 0 18-75.5 93t-93.5 75zm273-272q-11 0-23-8-136-105-252-154.5t-268-49.5q-85 0-170.5 22t-149 53-113.5 62-79 53-31 22q-17 0-92-75t-75-93q0-12 10-22 132-132 320-205t380-73 380 73 320 205q10 10 10 22 0 18-75 93t-92 75zm271-271q-11 0-22-9-179-157-371.5-236.5t-420.5-79.5-420.5 79.5-371.5 236.5q-11 9-22 9-17 0-92.5-75t-75.5-93q0-13 10-23 187-186 445-288t527-102 527 102 445 288q10 10 10 23 0 18-75.5 93t-92.5 75z"/></svg>

After

Width:  |  Height:  |  Size: 793 B

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="2048" height="1792" viewBox="0 0 2048 1792" xmlns="http://www.w3.org/2000/svg"><path d="M256 1536h768v-512h-768v512zm1024-512h512v-768h-768v256h96q66 0 113 47t47 113v352zm768-864v960q0 66-47 113t-113 47h-608v352q0 66-47 113t-113 47h-960q-66 0-113-47t-47-113v-960q0-66 47-113t113-47h608v-352q0-66 47-113t113-47h960q66 0 113 47t47 113z"/></svg>

After

Width:  |  Height:  |  Size: 393 B

View File

@ -10,7 +10,7 @@ from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication
from subprocess import Popen, PIPE
from .models import SourceDirModel, BackupProfileModel
from .models import SourceDirModel, BackupProfileModel, EventLogModel
class BorgThread(QtCore.QThread):
@ -31,18 +31,22 @@ class BorgThread(QtCore.QThread):
env['BORG_HOSTNAME_IS_UNIQUE'] = '1'
if params.get('password') and params['password']:
env['BORG_PASSPHRASE'] = params['password']
params['password'] = '***'
env['BORG_RSH'] = 'ssh -oStrictHostKeyChecking=no'
if params.get('ssh_key') and params['ssh_key']:
env['BORG_RSH'] += f' -i ~/.ssh/{params["ssh_key"]}'
self.env = env
self.profile = BackupProfileModel.get(id=1)
self.params = params
self.process = None
def run(self):
log_entry = EventLogModel(category='borg-run', subcommand=self.cmd[1], params=self.params)
log_entry.save()
self.process = Popen(self.cmd, stdout=PIPE, stderr=PIPE, bufsize=1, universal_newlines=True, env=self.env)
for line in iter(self.process.stderr.readline, b''):
for line in iter(self.process.stderr.readline, ''):
try:
parsed = json.loads(line)
if parsed['type'] == 'log_message':
@ -57,12 +61,15 @@ class BorgThread(QtCore.QThread):
result = {
'params': self.params,
'returncode': self.process.returncode,
'cmd': self.cmd
}
try:
result['data'] = json.loads(stdout)
except:
result['data'] = {}
log_entry.returncode = self.process.returncode
log_entry.save()
self.result.emit(result)
@classmethod
@ -80,9 +87,6 @@ class BorgThread(QtCore.QThread):
params = {'password': keyring.get_password("vorta-repo", profile.repo.url)}
print(params)
if app.thread and app.thread.isRunning():
ret['message'] = 'Backup is already in progress.'
return ret

View File

@ -1,8 +1,23 @@
import peewee
import os
import json
from datetime import datetime
from .config import SETTINGS_DIR
class JSONField(peewee.TextField):
"""
Class to "fake" a JSON field with a text field. Not efficient but works nicely
From: https://gist.github.com/rosscdh/f4f26758b0228f475b132c688f15af2b
"""
def db_value(self, value):
"""Convert the python value for storage in the database."""
return value if value is None else json.dumps(value)
def python_value(self, value):
"""Convert the database value to a pythonic value."""
return value if value is None else json.loads(value)
db = peewee.SqliteDatabase(os.path.join(SETTINGS_DIR, 'settings.db'))
@ -29,6 +44,11 @@ class BackupProfileModel(peewee.Model):
compression = peewee.CharField(default='lz4')
exclude_patterns = peewee.TextField(null=True)
exclude_if_present = peewee.TextField(null=True)
schedule_mode = peewee.CharField(default='off')
schedule_interval_hours = peewee.IntegerField(default=3)
schedule_interval_minutes = peewee.IntegerField(default=42)
schedule_fixed_hour = peewee.IntegerField(default=3)
schedule_fixed_minute = peewee.IntegerField(default=42)
class Meta:
database = db
@ -58,7 +78,33 @@ class SnapshotModel(peewee.Model):
database = db
class WifiSettingModel(peewee.Model):
"""Save Wifi Settings"""
ssid = peewee.CharField()
last_connected = peewee.DateTimeField()
allowed = peewee.BooleanField(default=True)
profile = peewee.ForeignKeyField(BackupProfileModel, default=1)
class Meta:
database = db
class EventLogModel(peewee.Model):
"""Keep a log of background jobs."""
start_time = peewee.DateTimeField(default=datetime.utcnow)
category = peewee.CharField()
subcommand = peewee.CharField(null=True)
message = peewee.CharField(null=True)
returncode = peewee.IntegerField(default=1)
params = JSONField(null=True)
profile = peewee.ForeignKeyField(BackupProfileModel, default=1)
class Meta:
database = db
db.connect()
db.create_tables([RepoModel, BackupProfileModel, SourceDirModel, SnapshotModel])
db.create_tables([RepoModel, BackupProfileModel, SourceDirModel,
SnapshotModel, WifiSettingModel, EventLogModel])
BackupProfileModel.get_or_create(id=1, name='Default')

View File

@ -1,12 +1,31 @@
from apscheduler.schedulers.qt import QtScheduler
from apscheduler.triggers import cron
from PyQt5.QtWidgets import QApplication
from .models import BackupProfileModel
def tick():
print('scheduler')
print('scheduler running')
def init_scheduler():
app = QApplication.instance()
if hasattr(app, 'scheduler') and app.scheduler is not None:
app.scheduler.shutdown()
s = QtScheduler()
trigger = cron.CronTrigger(second='*/3')
profile = BackupProfileModel.get(id=1)
if profile.schedule_mode == 'off':
return None
elif profile.schedule_mode == 'interval':
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)
s.add_job(tick, trigger, id='create-backup')
s.start()
return s

View File

@ -5,7 +5,9 @@ from paramiko.rsakey import RSAKey
from paramiko.ecdsakey import ECDSAKey
from paramiko.ed25519key import Ed25519Key
from paramiko import SSHException
from PyQt5.QtWidgets import QApplication
from .models import WifiSettingModel
def get_private_keys():
"""Find SSH keys in standard folder."""
@ -41,7 +43,7 @@ def prettyBytes(size):
n = 0
Dic_powerN = {0: '', 1: 'K', 2: 'M', 3: 'G', 4: 'T'}
while size > power:
size /= power
size /= power
n += 1
return str(round(size))+Dic_powerN[n]+'B'
@ -58,12 +60,16 @@ def get_asset(path):
def get_sorted_wifis():
"""Get SSIDs from OS and merge with settings in DB."""
app = QApplication.instance()
wifis = plistlib.load(open('/Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist', 'rb'))['KnownNetworks']
out = []
plist_file = open('/Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist', 'rb')
wifis = plistlib.load(plist_file)['KnownNetworks']
if wifis:
for wifi in wifis.values():
timestamp = wifi['LastConnected']
ssid = wifi['SSIDString']
out.append({'ssid': ssid, 'last_connected': timestamp, 'allowed': True})
return out
WifiSettingModel.get_or_create(ssid=ssid, profile=app.profile,
defaults={'last_connected': timestamp,
'allowed': True})
return WifiSettingModel.select().order_by(-WifiSettingModel.last_connected)

View File

@ -63,7 +63,6 @@ class RepoTab(RepoBase, RepoUI):
else:
self.profile.ssh_key = self.sshComboBox.itemData(index)
self.profile.save()
print('set ssh key to', self.profile.ssh_key)
def compression_select_action(self, index):

View File

@ -1,27 +1,88 @@
import plistlib
from PyQt5 import uic, QtCore
from PyQt5.QtWidgets import QFileDialog, QListWidgetItem
from ..models import SourceDirModel
from PyQt5.QtWidgets import QListWidgetItem, QApplication, QTableView, QHeaderView, QTableWidgetItem
from ..utils import get_asset, get_sorted_wifis
from ..scheduler import init_scheduler
from ..models import EventLogModel
uifile = get_asset('UI/scheduletab.ui')
ScheduleUI, ScheduleBase = uic.loadUiType(uifile)
class ScheduleTab(ScheduleBase, ScheduleUI):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(parent)
self.profile = self.window().profile
self.app = QApplication.instance()
self.schedulerRadioMapping = {
'off': self.scheduleOffRadio,
'interval': self.scheduleIntervalRadio,
'fixed': self.scheduleFixedRadio
}
self.schedulerRadioMapping[self.profile.schedule_mode].setChecked(True)
self.scheduleIntervalHours.setValue(self.profile.schedule_interval_hours)
self.scheduleIntervalMinutes.setValue(self.profile.schedule_interval_minutes)
self.scheduleFixedTime.setTime(
QtCore.QTime(self.profile.schedule_fixed_hour, self.profile.schedule_fixed_minute))
self.scheduleApplyButton.clicked.connect(self.on_scheduler_apply)
self.set_next_backup_datetime()
self.init_wifi()
self.init_logs()
def init_wifi(self):
for wifi in get_sorted_wifis():
item = QListWidgetItem()
item.setText(wifi['ssid'])
item.setText(wifi.ssid)
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
if wifi['allowed']:
if wifi.allowed:
item.setCheckState(QtCore.Qt.Checked)
self.wifiListWidget.addItem(item)
def init_logs(self):
header = self.logTableWidget.horizontalHeader()
header.setVisible(True)
[header.setSectionResizeMode(i, QHeaderView.ResizeToContents) for i in range(5)]
header.setSectionResizeMode(3, QHeaderView.Stretch)
self.logTableWidget.setSelectionBehavior(QTableView.SelectRows)
self.logTableWidget.setEditTriggers(QTableView.NoEditTriggers)
event_logs = [s for s in EventLogModel.select()]
for row, log_line in enumerate(event_logs):
self.logTableWidget.insertRow(row)
formatted_time = log_line.start_time.strftime('%Y-%m-%d %H:%M')
self.logTableWidget.setItem(row, 0, QTableWidgetItem(formatted_time))
self.logTableWidget.setItem(row, 1, QTableWidgetItem(log_line.category))
self.logTableWidget.setItem(row, 2, QTableWidgetItem(log_line.subcommand))
self.logTableWidget.setItem(row, 3, QTableWidgetItem(log_line.message))
self.logTableWidget.setItem(row, 4, QTableWidgetItem(str(log_line.returncode)))
self.logTableWidget.setRowCount(len(event_logs))
def set_next_backup_datetime(self):
if self.app.scheduler is not None:
job = self.app.scheduler.get_job('create-backup')
self.nextBackupDateTimeLabel.setText(job.next_run_time.strftime('%Y-%m-%d %H:%M'))
else:
self.nextBackupDateTimeLabel.setText('Off')
self.nextBackupDateTimeLabel.repaint()
def on_scheduler_apply(self):
for label, obj in self.schedulerRadioMapping.items():
if obj.isChecked():
self.profile.schedule_mode = label
self.profile.schedule_interval_hours = self.scheduleIntervalHours.value()
self.profile.schedule_interval_minutes = self.scheduleIntervalMinutes.value()
qtime = self.scheduleFixedTime.time()
self.profile.schedule_fixed_hour, self.profile.schedule_fixed_minute = qtime.hour(), qtime.minute()
self.profile.save()
self.app.scheduler = init_scheduler()
self.set_next_backup_datetime()
def init_log(self):
pass