Skip to content

Commit ab3690f

Browse files
Denay2468Denay2468
andauthored
fix: include ExclusionModel in profile export/import (#2471)
Fix #2414 — ExclusionModel data (custom and preset exclusion rules) was missing from profile export/import. Changes: - Add ExclusionModel serialization in `ProfileExport.from_db()` - Add ExclusionModel restoration in `ProfileExport.to_db()` (with backward compat guard for old exports) - Add test coverage for exclusion round-trip in export/import tests Co-authored-by: Denay2468 <denayaung13@gamil.com>
1 parent 5ef6adb commit ab3690f

3 files changed

Lines changed: 38 additions & 2 deletions

File tree

src/vorta/profile_export.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from vorta.store.connection import DB, SCHEMA_VERSION, init_db
99
from vorta.store.models import (
1010
BackupProfileModel,
11+
ExclusionModel,
1112
RepoModel,
1213
SchemaVersion,
1314
SettingsModel,
@@ -64,6 +65,11 @@ def from_db(cls, profile, store_password=True, include_settings=True):
6465
model_to_dict(source, recurse=False, exclude=[SourceFileModel.id])
6566
for source in SourceFileModel.select().where(SourceFileModel.profile == profile)
6667
]
68+
# Add ExclusionModel
69+
profile_dict['ExclusionModel'] = [
70+
model_to_dict(exclusion, recurse=False, exclude=[ExclusionModel.id])
71+
for exclusion in ExclusionModel.select().where(ExclusionModel.profile == profile)
72+
]
6773
# Add SchemaVersion
6874
profile_dict['SchemaVersion'] = model_to_dict(SchemaVersion.get(id=1))
6975

@@ -127,18 +133,27 @@ def to_db(self, overwrite_profile=False, overwrite_settings=True):
127133
SettingsModel.insert_many(self._profile_dict['SettingsModel']).execute()
128134
WifiSettingModel.insert_many(self._profile_dict['WifiSettingModel']).execute()
129135

130-
# Set the profile ids to be match new profile
136+
# Set the profile ids to match new profile
131137
for source in self._profile_dict['SourceFileModel']:
132138
source['profile'] = self.id
133139
# Delete existing Sources to avoid duplicates
134140
SourceFileModel.delete().where(SourceFileModel.profile == self.id).execute()
135141
SourceFileModel.insert_many(self._profile_dict['SourceFileModel']).execute()
136142

143+
# Restore ExclusionModel entries
144+
if 'ExclusionModel' in self._profile_dict:
145+
for exclusion in self._profile_dict['ExclusionModel']:
146+
exclusion['profile'] = self.id
147+
ExclusionModel.delete().where(ExclusionModel.profile == self.id).execute()
148+
ExclusionModel.insert_many(self._profile_dict['ExclusionModel']).execute()
149+
137150
# Delete added dictionaries to make it match BackupProfileModel
138151
del self._profile_dict['SettingsModel']
139152
del self._profile_dict['SourceFileModel']
140153
del self._profile_dict['WifiSettingModel']
141154
del self._profile_dict['SchemaVersion']
155+
if 'ExclusionModel' in self._profile_dict:
156+
del self._profile_dict['ExclusionModel']
142157

143158
# dict to profile
144159
new_profile = dict_to_model(BackupProfileModel, self._profile_dict)

tests/unit/profile_exports/valid.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,20 @@
5252
"added_at": "2020-07-03 04:37:05.106150"
5353
}
5454
],
55+
"ExclusionModel": [
56+
{
57+
"name": "*.pyc",
58+
"enabled": true,
59+
"source": "custom",
60+
"profile": 1
61+
},
62+
{
63+
"name": "__pycache__",
64+
"enabled": true,
65+
"source": "preset",
66+
"profile": 1
67+
}
68+
],
5569
"WifiSettingModel": [],
5670
"SchemaVersion": {
5771
"id": 1,

tests/unit/test_import_export.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from PyQt6.QtWidgets import QDialogButtonBox, QFileDialog, QMessageBox
77

88
from vorta.profile_export import VersionException
9-
from vorta.store.models import BackupProfileModel, SourceFileModel
9+
from vorta.store.models import BackupProfileModel, ExclusionModel, SourceFileModel
1010
from vorta.views.dialogs.profile.import_window import ImportWindow
1111

1212
VALID_IMPORT_FILE = Path(__file__).parent / 'profile_exports' / 'valid.json'
@@ -32,6 +32,7 @@ def test_import_success(qapp, qtbot, rootdir, monkeypatch):
3232
restored_repo = restored_profile.repo
3333
assert restored_repo is not None
3434
assert len(SourceFileModel.select().where(SourceFileModel.profile == restored_profile)) == 3
35+
assert len(ExclusionModel.select().where(ExclusionModel.profile == restored_profile)) == 2
3536

3637

3738
@pytest.mark.parametrize(
@@ -128,6 +129,12 @@ def getSaveFileName(*args, **kwargs):
128129

129130
assert os.path.isfile(FILE_PATH)
130131

132+
import json
133+
134+
with open(FILE_PATH) as f:
135+
exported = json.load(f)
136+
assert 'ExclusionModel' in exported
137+
131138

132139
def test_export_fail_unwritable(qapp, qtbot, monkeypatch):
133140
FILE_PATH = os.path.join(os.path.abspath(os.sep), "testresult.vortabackup")

0 commit comments

Comments
 (0)