mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-03-11 09:04:54 +00:00
Backups, remote repositories: re-use template for root location
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
parent
e3817a1a31
commit
27fbc982c7
@ -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():
|
||||
|
||||
24
plinth/modules/backups/location.py
Normal file
24
plinth/modules/backups/location.py
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
"""
|
||||
Manage borg backup locations
|
||||
"""
|
||||
|
||||
|
||||
class Location(object):
|
||||
def __init__(self, uuid):
|
||||
pass
|
||||
@ -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']:
|
||||
|
||||
@ -52,45 +52,10 @@
|
||||
|
||||
<h3>{% trans 'Existing backups' %}</h3>
|
||||
|
||||
{% if not archives %}
|
||||
<p>{% trans 'No archives currently exist.' %}</p>
|
||||
{% else %}
|
||||
<table class="table table-bordered table-condensed table-striped"
|
||||
id="archives-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ box_name }} storage</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% include "backups_location.inc" with location=root_location uuid='root' editable=False %}
|
||||
|
||||
<tbody>
|
||||
{% for archive in archives %}
|
||||
<tr id="archive-{{ archive.name }}" class="archive">
|
||||
<td class="archive-name">{{ archive.name }}</td>
|
||||
<td class="archive-operations">
|
||||
<a class="archive-export btn btn-sm btn-default" target="_blank"
|
||||
href="{% url 'backups:export-and-download' archive.name %}">
|
||||
{% trans "Download" %}
|
||||
</a>
|
||||
<a class="archive-export btn btn-sm btn-default"
|
||||
href="{% url 'backups:restore-archive' archive.name %}">
|
||||
{% trans "Restore" %}
|
||||
</a>
|
||||
<a class="archive-delete btn btn-sm btn-default"
|
||||
href="{% url 'backups:delete' archive.name %}">
|
||||
<span class="glyphicon glyphicon-trash" aria-hidden="true">
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% 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 %}
|
||||
|
||||
<br />
|
||||
|
||||
@ -24,34 +24,46 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
{{ location.path }}
|
||||
{% if location.mounted %}
|
||||
<form action="{% url 'backups:location-umount' uuid %}" method="POST"
|
||||
class="inline-block" >
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-sm btn-default"
|
||||
title="{% trans 'Unount Location' %}">
|
||||
<span class="glyphicon glyphicon-eject" aria-hidden="true">
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<!-- With GET redirects the browser URL would be pointing to the
|
||||
redirected page - use POST instead.
|
||||
-->
|
||||
<form action="{% url 'backups:location-mount' uuid %}" method="POST"
|
||||
class="inline-block" >
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-sm btn-default"
|
||||
title="{% trans 'Mount Location' %}">
|
||||
<span class="glyphicon glyphicon-eye-open" aria-hidden="true">
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{{ location.name }}
|
||||
|
||||
{% if editable %}
|
||||
|
||||
{% if location.mounted %}
|
||||
|
||||
<!-- With GET redirects the browser URL would be pointing to the
|
||||
redirected page - use POST instead.
|
||||
-->
|
||||
<form action="{% url 'backups:location-umount' uuid %}" method="POST"
|
||||
class="inline-block" >
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-sm btn-default"
|
||||
title="{% trans 'Unount Location' %}">
|
||||
<span class="glyphicon glyphicon-eject" aria-hidden="true">
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{% else %}
|
||||
|
||||
<form action="{% url 'backups:location-mount' uuid %}" method="POST"
|
||||
class="inline-block" >
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-sm btn-default"
|
||||
title="{% trans 'Mount Location' %}">
|
||||
<span class="glyphicon glyphicon-eye-open" aria-hidden="true">
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{% endif %}
|
||||
|
||||
<a title="{% trans 'Remove Location. This will not delete the remote backup.' %}"
|
||||
role="button" class="location-remove btn btn-sm btn-default"
|
||||
href="{% url 'backups:location-remove' uuid %}">
|
||||
<span class="glyphicon glyphicon-trash" aria-hidden="true">
|
||||
</a>
|
||||
|
||||
{% endif %}
|
||||
<a title="{% trans 'Remove Location. This will not delete the remote backup.' %}"
|
||||
role="button" class="location-remove btn btn-sm btn-default"
|
||||
href="{% url 'backups:location-remove' uuid %}">
|
||||
<span class="glyphicon glyphicon-trash" aria-hidden="true">
|
||||
</a>
|
||||
|
||||
</th>
|
||||
<th>
|
||||
</th>
|
||||
@ -59,25 +71,33 @@
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for archive in location.archives %}
|
||||
<tr id="archive-{{ archive.name }}" class="archive">
|
||||
<td class="archive-name">{{ archive.name }}</td>
|
||||
<td class="archive-operations">
|
||||
<a class="archive-export btn btn-sm btn-default" target="_blank"
|
||||
href="{% url 'backups:export-and-download' archive.name %}">
|
||||
{% trans "Download" %}
|
||||
</a>
|
||||
<a class="archive-export btn btn-sm btn-default"
|
||||
href="{% url 'backups:restore-archive' archive.name %}">
|
||||
{% trans "Restore" %}
|
||||
</a>
|
||||
<a class="archive-delete btn btn-sm btn-default"
|
||||
href="{% url 'backups:delete' archive.name %}">
|
||||
<span class="glyphicon glyphicon-trash" aria-hidden="true">
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% if location.mounted %}
|
||||
|
||||
{% for archive in location.archives %}
|
||||
<tr id="archive-{{ archive.name }}" class="archive">
|
||||
<td class="archive-name">{{ archive.name }}</td>
|
||||
<td class="archive-operations">
|
||||
<a class="archive-export btn btn-sm btn-default" target="_blank"
|
||||
href="{% url 'backups:export-and-download' uuid archive.name %}">
|
||||
{% trans "Download" %}
|
||||
</a>
|
||||
<a class="archive-export btn btn-sm btn-default"
|
||||
href="{% url 'backups:restore-archive' archive.name %}">
|
||||
{% trans "Restore" %}
|
||||
</a>
|
||||
<a class="archive-delete btn btn-sm btn-default"
|
||||
href="{% url 'backups:delete' archive.name %}">
|
||||
<span class="glyphicon glyphicon-trash" aria-hidden="true">
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
{% if not location.archives %}
|
||||
<p>{% trans 'No archives currently exist.' %}</p>
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -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<name>[^/]+)/$',
|
||||
url(r'^sys/backups/export-and-download/(?P<uuid>[^/]+)/(?P<name>[^/]+)/$',
|
||||
ExportAndDownloadView.as_view(), name='export-and-download'),
|
||||
url(r'^sys/backups/delete/(?P<name>[^/]+)/$',
|
||||
DeleteArchiveView.as_view(), name='delete'),
|
||||
|
||||
@ -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]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user