diff --git a/plinth/modules/backups/__init__.py b/plinth/modules/backups/__init__.py
index e1cc6b4b1..ab8bb0023 100644
--- a/plinth/modules/backups/__init__.py
+++ b/plinth/modules/backups/__init__.py
@@ -40,6 +40,8 @@ managed_packages = ['borgbackup', 'sshfs']
name = _('Backups')
+depends = ['storage']
+
description = [
_('Backups allows creating and managing backup archives.'),
]
@@ -48,8 +50,8 @@ manual_page = 'Backups'
MANIFESTS_FOLDER = '/var/lib/plinth/backups-manifests/'
ROOT_REPOSITORY = '/var/lib/freedombox/borgbackup'
-ROOT_REPOSITORY_NAME = format_lazy(
- _('{box_name} storage'), box_name=cfg.box_name)
+ROOT_REPOSITORY_NAME = format_lazy(_('{box_name} storage'),
+ box_name=cfg.box_name)
ROOT_REPOSITORY_UUID = 'root'
# session variable name that stores when a backup file should be deleted
SESSION_PATH_VARIABLE = 'fbx-backups-upload-path'
@@ -110,9 +112,8 @@ def _backup_handler(packet, encryption_passphrase=None):
arguments = ['create-archive', '--path', packet.path, '--paths'] + paths
input_data = ''
if encryption_passphrase:
- input_data = json.dumps({
- 'encryption_passphrase': encryption_passphrase
- })
+ input_data = json.dumps(
+ {'encryption_passphrase': encryption_passphrase})
actions.superuser_run('backups', arguments, input=input_data.encode())
diff --git a/plinth/modules/backups/forms.py b/plinth/modules/backups/forms.py
index 431082589..0fe391fc3 100644
--- a/plinth/modules/backups/forms.py
+++ b/plinth/modules/backups/forms.py
@@ -29,6 +29,7 @@ from django.core.validators import (FileExtensionValidator,
from django.utils.translation import ugettext
from django.utils.translation import ugettext_lazy as _
+from plinth.modules.storage import get_disks
from plinth.utils import format_lazy
from . import ROOT_REPOSITORY_NAME, api, network_storage, split_path
@@ -124,18 +125,8 @@ def repository_validator(path):
raise ValidationError(_(f'Invalid directory path: {dir_path}'))
-class AddRepositoryForm(forms.Form):
- """Form to add new SSH remote repository."""
- repository = forms.CharField(
- label=_('SSH Repository Path'), strip=True,
- help_text=_('Path of a new or existing repository. Example: '
- 'user@host:~/path/to/repo/'),
- validators=[repository_validator])
- ssh_password = forms.CharField(
- label=_('SSH server password'), strip=True,
- help_text=_('Password of the SSH Server.
'
- 'SSH key-based authentication is not yet possible.'),
- widget=forms.PasswordInput(), required=False)
+class EncryptedBackupsMixin(forms.Form):
+ """Form to add a new backup repository."""
encryption = forms.ChoiceField(
label=_('Encryption'), help_text=format_lazy(
_('"Key in Repository" means that a '
@@ -150,7 +141,7 @@ class AddRepositoryForm(forms.Form):
widget=forms.PasswordInput(), required=False)
def clean(self):
- super(AddRepositoryForm, self).clean()
+ super().clean()
passphrase = self.cleaned_data.get('encryption_passphrase')
confirm_passphrase = self.cleaned_data.get(
'confirm_encryption_passphrase')
@@ -165,6 +156,44 @@ class AddRepositoryForm(forms.Form):
return self.cleaned_data
+
+encryption_fields = [
+ 'encryption', 'encryption_passphrase', 'confirm_encryption_passphrase'
+]
+
+
+def get_disk_choices():
+ """Returns a list of all available partitions except the root partition."""
+ return [(device['mount_point'],
+ device['label'] if device['label'] else device['mount_point'])
+ for device in get_disks() if device['mount_point'] != '/']
+
+
+class AddRepositoryForm(EncryptedBackupsMixin, forms.Form):
+ """Form to create a new backups repository on a disk."""
+ disk = forms.ChoiceField(
+ label=_('Select Disk or Partition'), help_text=format_lazy(
+ _('Backups will be stored in the directory FreedomBoxBackups')),
+ choices=get_disk_choices)
+
+ field_order = ['disk'] + encryption_fields
+
+
+class AddRemoteRepositoryForm(EncryptedBackupsMixin, forms.Form):
+ """Form to add new SSH remote repository."""
+ repository = forms.CharField(
+ label=_('SSH Repository Path'), strip=True,
+ help_text=_('Path of a new or existing repository. Example: '
+ 'user@host:~/path/to/repo/'),
+ validators=[repository_validator])
+ ssh_password = forms.CharField(
+ label=_('SSH server password'), strip=True,
+ help_text=_('Password of the SSH Server.
'
+ 'SSH key-based authentication is not yet possible.'),
+ widget=forms.PasswordInput(), required=False)
+
+ field_order = ['repository', 'ssh_password'] + encryption_fields
+
def clean_repository(self):
"""Validate repository form field."""
path = self.cleaned_data.get('repository')
@@ -202,10 +231,8 @@ class VerifySshHostkeyForm(forms.Form):
stderr=subprocess.DEVNULL)
keys = keyscan.stdout.decode().splitlines()
# Generate user-friendly fingerprints of public keys
- keygen = subprocess.run(
- ['ssh-keygen', '-l', '-f', '-'],
- input=keyscan.stdout,
- stdout=subprocess.PIPE)
+ keygen = subprocess.run(['ssh-keygen', '-l', '-f', '-'],
+ input=keyscan.stdout, stdout=subprocess.PIPE)
fingerprints = keygen.stdout.decode().splitlines()
return zip(keys, fingerprints)
diff --git a/plinth/modules/backups/templates/backups.html b/plinth/modules/backups/templates/backups.html
index e67fb0042..39c851792 100644
--- a/plinth/modules/backups/templates/backups.html
+++ b/plinth/modules/backups/templates/backups.html
@@ -66,13 +66,18 @@
{% include "backups_repository.inc" with editable=True %}
{% endfor %}
-
+
+
+ {% trans 'Add Backup Location' %}
+
+ href="{% url 'backups:add-remote-repository' %}">
- {% trans 'Add Remote Location' %}
+ {% trans 'Add Remote Backup Location' %}
{% endblock %}
diff --git a/plinth/modules/backups/templates/backups_repository_add.html b/plinth/modules/backups/templates/backups_add_remote_repository.html
similarity index 100%
rename from plinth/modules/backups/templates/backups_repository_add.html
rename to plinth/modules/backups/templates/backups_add_remote_repository.html
diff --git a/plinth/modules/backups/templates/backups_add_repository.html b/plinth/modules/backups/templates/backups_add_repository.html
new file mode 100644
index 000000000..2aab6fa3c
--- /dev/null
+++ b/plinth/modules/backups/templates/backups_add_repository.html
@@ -0,0 +1,40 @@
+{% extends "base.html" %}
+{% comment %}
+#
+# This file is part of FreedomBox.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see