Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

projectbackup: add validation of duplicate languages #10915

Merged
merged 1 commit into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading