Skip to content

Commit

Permalink
projectbackup: add validation of duplicate languages
Browse files Browse the repository at this point in the history
This can happen with different set of languages.

Fixes #10912
  • Loading branch information
nijel committed Jan 31, 2024
1 parent c0875aa commit 893e21d
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 0 deletions.
8 changes: 8 additions & 0 deletions docs/admin/backup.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ The generated backups are kept on the server as configured by
:setting:`PROJECT_BACKUP_KEEP_DAYS` and :setting:`PROJECT_BACKUP_KEEP_COUNT`
(it defaults to keep at most 3 backups for 30 days).

.. note::

Restoring of the backup might fail if the restoring server has different set
of :ref:`languages` or different configuration of
:setting:`SIMPLIFY_LANGUAGES`. The restore will tell you which language
codes could not be processed and you can then add missing langage
definitions manually.

Automated backup using BorgBackup
---------------------------------

Expand Down
13 changes: 13 additions & 0 deletions weblate/trans/backups.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import json
import os
from collections import defaultdict
from datetime import datetime
from itertools import chain
from shutil import copyfileobj
Expand Down Expand Up @@ -329,6 +330,18 @@ def load_components(self, zipfile, callback: Callable | None = None):
raise ValueError(
f'Component {data["component"]["name"]} uses unsupported VCS: {data["component"]["vcs"]}'
)
# Validate translations have unique languages
languages = defaultdict(list)
for item in data["translations"]:
language = self.import_language(item["language_code"])
languages[language.code].append(item["language_code"])

for code, values in languages.items():
if len(values) > 1:
raise ValueError(
f"Several languages from backup map to single language on this server {values} -> {code}"
)

if callback is not None:
callback(zipfile, data)

Expand Down
Binary file not shown.
8 changes: 8 additions & 0 deletions weblate/trans/tests/test_backups.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

TEST_SCREENSHOT = get_test_file("screenshot.png")
TEST_BACKUP = get_test_file("projectbackup-4.14.zip")
TEST_BACKUP_DUPLICATE = get_test_file("projectbackup-duplicate.zip")


class BackupsTest(ViewTestCase):
Expand Down Expand Up @@ -154,6 +155,13 @@ def test_restore_4_14(self):
set(restored.label_set.values_list("name", "color")),
)

def test_restore_duplicate(self):
if not connection.features.can_return_rows_from_bulk_insert:
raise SkipTest("Not supported")
restore = ProjectBackup(TEST_BACKUP_DUPLICATE)
with self.assertRaises(ValueError):
restore.validate()

def test_cleanup(self):
cleanup_project_backups()
self.assertLessEqual(len(self.project.list_backups()), 3)
Expand Down

0 comments on commit 893e21d

Please sign in to comment.