diff --git a/plinth/modules/backups/__init__.py b/plinth/modules/backups/__init__.py index 1fae39a16..d4c710a1c 100644 --- a/plinth/modules/backups/__init__.py +++ b/plinth/modules/backups/__init__.py @@ -24,9 +24,10 @@ import os from django.utils.text import get_valid_filename from django.utils.translation import ugettext_lazy as _ -from plinth import actions -from plinth.menu import main_menu +from plinth import actions, cfg from plinth.errors import ActionError +from plinth.menu import main_menu +from plinth.utils import format_lazy from .errors import BorgError, BorgRepositoryDoesNotExistError from . import api @@ -97,6 +98,19 @@ def list_archives(repository, access_params=None): return json.loads(output)['archives'] +def get_root_location_content(): + """ + Get information about the root backup location in the same format + that the remote repositories use + """ + return { + 'name': format_lazy(_('{box_name} storage'), box_name=cfg.box_name), + 'mounted': True, + 'archives': list_archives(REPOSITORY), + 'type': 'rootfs', + } + + def get_archive(name): # TODO: can't we get this archive directly? for archive in list_archives(): diff --git a/plinth/modules/backups/location.py b/plinth/modules/backups/location.py new file mode 100644 index 000000000..6c637c607 --- /dev/null +++ b/plinth/modules/backups/location.py @@ -0,0 +1,24 @@ +# +# 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 . +# +""" +Manage borg backup locations +""" + + +class Location(object): + def __init__(self, uuid): + pass diff --git a/plinth/modules/backups/remote_locations.py b/plinth/modules/backups/remote_locations.py index c4c26ec4a..8261c41d6 100644 --- a/plinth/modules/backups/remote_locations.py +++ b/plinth/modules/backups/remote_locations.py @@ -73,7 +73,7 @@ def delete(uuid): logger.error(err) -def get_archives(uuid=None): +def get_locations_content(uuid=None): """ Get archives of one or all locations. returns: { @@ -81,7 +81,7 @@ def get_archives(uuid=None): 'path': path, 'type': type, 'archives': [], - 'error': error_message + 'error': error_message, } } """ @@ -89,7 +89,7 @@ def get_archives(uuid=None): for location in get_locations(): mountpoint = os.path.join(MOUNTPOINT, location['uuid']) new_location = { - 'path': location['path'], + 'name': location['path'], 'mounted': uuid_is_mounted(location['uuid']), } if new_location['mounted']: diff --git a/plinth/modules/backups/templates/backups.html b/plinth/modules/backups/templates/backups.html index 6379a3584..58387a92b 100644 --- a/plinth/modules/backups/templates/backups.html +++ b/plinth/modules/backups/templates/backups.html @@ -52,45 +52,10 @@

{% trans 'Existing backups' %}

- {% if not archives %} -

{% trans 'No archives currently exist.' %}

- {% else %} - - - - - - - + {% include "backups_location.inc" with location=root_location uuid='root' editable=False %} - - {% for archive in archives %} - - - - - {% endfor %} - -
{{ box_name }} storage
{{ archive.name }} - - {% trans "Download" %} - - - {% trans "Restore" %} - - - - -
- {% endif %} - - {% for uuid,location in remote_archives.items %} - {% include "backups_location.inc" %} + {% for uuid,location in remote_locations.items %} + {% include "backups_location.inc" with editable=True %} {% endfor %}
diff --git a/plinth/modules/backups/templates/backups_location.inc b/plinth/modules/backups/templates/backups_location.inc index 08153c98b..0e4f191ea 100644 --- a/plinth/modules/backups/templates/backups_location.inc +++ b/plinth/modules/backups/templates/backups_location.inc @@ -24,34 +24,46 @@ - {{ location.path }} - {% if location.mounted %} -
- {% csrf_token %} - -
- {% else %} - -
- {% csrf_token %} - -
+ + {{ location.name }} + + {% if editable %} + + {% if location.mounted %} + + +
+ {% csrf_token %} + +
+ + {% else %} + +
+ {% csrf_token %} + +
+ + {% endif %} + + + + {% endif %} - - + @@ -59,25 +71,33 @@ - {% for archive in location.archives %} - - {{ archive.name }} - - - {% trans "Download" %} - - - {% trans "Restore" %} - - - - - - - {% endfor %} + {% if location.mounted %} + + {% for archive in location.archives %} + + {{ archive.name }} + + + {% trans "Download" %} + + + {% trans "Restore" %} + + + + + + + {% endfor %} + + {% if not location.archives %} +

{% trans 'No archives currently exist.' %}

+ {% endif %} + + {% endif %} diff --git a/plinth/modules/backups/urls.py b/plinth/modules/backups/urls.py index 83dab4251..342f0ce89 100644 --- a/plinth/modules/backups/urls.py +++ b/plinth/modules/backups/urls.py @@ -28,7 +28,7 @@ from .views import IndexView, CreateArchiveView, AddLocationView, \ urlpatterns = [ url(r'^sys/backups/$', IndexView.as_view(), name='index'), url(r'^sys/backups/create/$', CreateArchiveView.as_view(), name='create'), - url(r'^sys/backups/export-and-download/(?P[^/]+)/$', + url(r'^sys/backups/export-and-download/(?P[^/]+)/(?P[^/]+)/$', ExportAndDownloadView.as_view(), name='export-and-download'), url(r'^sys/backups/delete/(?P[^/]+)/$', DeleteArchiveView.as_view(), name='delete'), diff --git a/plinth/modules/backups/views.py b/plinth/modules/backups/views.py index 9235566cf..9b327d8a2 100644 --- a/plinth/modules/backups/views.py +++ b/plinth/modules/backups/views.py @@ -73,8 +73,8 @@ class IndexView(TemplateView): context['title'] = backups.name context['description'] = backups.description context['info'] = backups.get_info(REPOSITORY) - context['archives'] = backups.list_archives(REPOSITORY) - context['remote_archives'] = remote_locations.get_archives() + context['root_location'] = backups.get_root_location_content() + context['remote_locations'] = remote_locations.get_locations_content() context['subsubmenu'] = subsubmenu return context @@ -275,7 +275,8 @@ class ZipStream(object): class ExportAndDownloadView(View): """View to export and download an archive as stream.""" - def get(self, request, name): + def get(self, request, uuid, name): + # The uuid is 'root' for the root repository name = unquote(name) filename = "%s.tar.gz" % name args = ['export-tar', '--name', name]