Recovery (download) of backup files started.
| | |
| | | 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") |
| | |
| | | } |
| | | 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;*/ |
| | | } |
| | | } |
| | |
| | | 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> |
| | | ); |
| | |
| | | }} |
| | | /> |
| | | <FileListTable |
| | | archiveId={this.props.archiveId} |
| | | entries={this.state.fileList} |
| | | search={this.state.filter.search}/> |
| | | </React.Fragment>; |
| | |
| | | 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> |
| | |
| | | <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} |
| | |
| | | } |
| | | |
| | | FileListTable.propTypes = { |
| | | archiveId: PropTypes.string, |
| | | entries: PropTypes.array, |
| | | search: PropTypes.string |
| | | }; |