From 8536692bec03913455a683e062288ea7c96c2f04 Mon Sep 17 00:00:00 2001
From: Kai Reinhard <K.Reinhard@micromata.de>
Date: Sun, 16 Dec 2018 21:35:36 +0000
Subject: [PATCH] Recovery (download) of backup files started.

---
 borgbutler-webapp/src/components/views/archives/FileListEntry.jsx                     |   35 ++++++++++++++++-
 borgbutler-webapp/src/components/views/archives/FileListPanel.jsx                     |    1 
 borgbutler-webapp/src/components/views/archives/FileListTable.jsx                     |    6 ++-
 borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ArchivesRest.java |   21 ++++++++++
 4 files changed, 59 insertions(+), 4 deletions(-)

diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ArchivesRest.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ArchivesRest.java
index 6cfe285..04e69dd 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ArchivesRest.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/ArchivesRest.java
@@ -15,6 +15,7 @@
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
 import java.util.List;
 
 @Path("/archives")
@@ -66,4 +67,24 @@
         }
         return JsonUtils.toJson(items, prettyPrinter);
     }
+
+    @GET
+    @Path("/download")
+    @Produces(MediaType.APPLICATION_OCTET_STREAM)
+    /**
+     * @param archiveId
+     * @param fileNumber The fileNumber of the file in the archive served by BorgButler's
+     * {@link #getArchiveFileLIst(String, String, String, boolean, boolean)}
+     */
+    public Response downloadFilebyPath(@QueryParam("archiveId") String archiveId, @QueryParam("fileNumber") int fileNumber) {
+        log.info("Downloading file #" + fileNumber + " of archive '" + archiveId + "'.");
+        return null;
+/*        byte[] byteArray = result.getAsByteArrayOutputStream().toByteArray();
+        Response.ResponseBuilder builder = Response.ok(byteArray);
+        builder.header("Content-Disposition", "attachment; filename=" + filename);
+        // Needed to get the Content-Disposition by client:
+        builder.header("Access-Control-Expose-Headers", "Content-Disposition");
+        Response response = builder.build();
+        return response;*/
+    }
 }
diff --git a/borgbutler-webapp/src/components/views/archives/FileListEntry.jsx b/borgbutler-webapp/src/components/views/archives/FileListEntry.jsx
index d994b4b..90dfb83 100644
--- a/borgbutler-webapp/src/components/views/archives/FileListEntry.jsx
+++ b/borgbutler-webapp/src/components/views/archives/FileListEntry.jsx
@@ -1,14 +1,45 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import Highlight from 'react-highlighter';
-import {humanFileSize} from '../../../utilities/global';
+import {IconDownload} from '../../general/IconComponents';
+import {getResponseHeaderFilename, getRestServiceUrl, humanFileSize} from '../../../utilities/global';
+import fileDownload from 'js-file-download';
 
-function FileListEntry({entry, search}) {
+function download(archiveId, fileNumber) {
+    let filename;
+    fetch(getRestServiceUrl('archives/download', {
+        archiveId: archiveId,
+        fileNumber: fileNumber
+    }))
+        .then(response => {
+            if (!response.ok) {
+                throw new Error(response.statusText);
+            }
+
+            filename = getResponseHeaderFilename(response.headers.get('Content-Disposition'));
+            return response.blob();
+        })
+        .then(blob => {
+            this.setState({
+                running: false
+            });
+            fileDownload(blob, filename)
+        })
+        .catch(error => {
+            console.log(error.toString());
+        });
+}
+
+function FileListEntry({archiveId, entry, search}) {
     return (
         <tr>
             <td className={'tt'}>{entry.mode}</td>
             <td className={'tt'}>{entry.mtime}</td>
             <td className={'tt'}>{humanFileSize(entry.size, true, true)}</td>
+            <td className={'tt'}>
+                <div className={'btn'} onClick={() => download(archiveId, entry.fileNumber)}>
+                    <IconDownload/></div>
+            </td>
             <td className={'tt'}><Highlight search={search}>{entry.path}</Highlight></td>
         </tr>
     );
diff --git a/borgbutler-webapp/src/components/views/archives/FileListPanel.jsx b/borgbutler-webapp/src/components/views/archives/FileListPanel.jsx
index f015c79..39c7701 100644
--- a/borgbutler-webapp/src/components/views/archives/FileListPanel.jsx
+++ b/borgbutler-webapp/src/components/views/archives/FileListPanel.jsx
@@ -87,6 +87,7 @@
                         }}
                     />
                     <FileListTable
+                        archiveId={this.props.archiveId}
                         entries={this.state.fileList}
                         search={this.state.filter.search}/>
                 </React.Fragment>;
diff --git a/borgbutler-webapp/src/components/views/archives/FileListTable.jsx b/borgbutler-webapp/src/components/views/archives/FileListTable.jsx
index a530328..a10e512 100644
--- a/borgbutler-webapp/src/components/views/archives/FileListTable.jsx
+++ b/borgbutler-webapp/src/components/views/archives/FileListTable.jsx
@@ -3,7 +3,7 @@
 import {Table} from 'reactstrap';
 import FileListEntry from './FileListEntry';
 
-function FileListTable({entries, search}) {
+function FileListTable({archiveId, entries, search}) {
     const lowercaseSearch = search.split(' ')[0].toLowerCase();
     return (
         <Table striped bordered hover size={'sm'} responsive>
@@ -12,13 +12,14 @@
                 <th>Mode</th>
                 <th>Modified time</th>
                 <th>Size</th>
-                <th>Path</th>
                 <th></th>
+                <th>Path</th>
             </tr>
             </thead>
             <tbody>
             {entries
                 .map((entry, index) => <FileListEntry
+                    archiveId={archiveId}
                     entry={entry}
                     search={lowercaseSearch}
                     key={index}
@@ -29,6 +30,7 @@
 }
 
 FileListTable.propTypes = {
+    archiveId: PropTypes.string,
     entries: PropTypes.array,
     search: PropTypes.string
 };

--
Gitblit v1.10.0