Fix object download (#466)

If an object is within a folder the object downloaded now only has the object's name.
Also, it now supports object version downloading.
This commit is contained in:
Cesar N
2020-12-03 11:37:53 -06:00
committed by GitHub
parent 726bfe623c
commit d15472f417
9 changed files with 43 additions and 42 deletions

View File

@@ -153,12 +153,9 @@ const ListObjects = ({
setLastAsFile,
}: IListObjectsProps) => {
const [records, setRecords] = useState<BucketObject[]>([]);
const [totalRecords, setTotalRecords] = useState<number>(0);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string>("");
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
const [createFolderOpen, setCreateFolderOpen] = useState<boolean>(false);
const [deleteError, setDeleteError] = useState<string>("");
const [selectedObject, setSelectedObject] = useState<string>("");
const [selectedBucket, setSelectedBucket] = useState<string>("");
const [filterObjects, setFilterObjects] = useState<string>("");
@@ -179,8 +176,6 @@ const ListObjects = ({
.then((res: BucketObjectsList) => {
setSelectedBucket(bucketName);
setRecords(res.objects || []);
setTotalRecords(!res.objects ? 0 : res.total);
setError("");
// In case no objects were retrieved, We check if item is a file
if (!res.objects && extraPath !== "") {
verifyIfIsFile();
@@ -190,7 +185,6 @@ const ListObjects = ({
})
.catch((err: any) => {
setLoading(false);
setError(err);
});
}, [loading, match]);
@@ -221,7 +215,6 @@ const ListObjects = ({
})
.catch((err: any) => {
setLoading(false);
setError(err);
});
};
@@ -263,7 +256,7 @@ const ListObjects = ({
xhr.open("POST", uploadUrl, true);
xhr.withCredentials = false;
xhr.onload = function (event) {
xhr.onload = function(event) {
// TODO: handle status
if (xhr.status === 401 || xhr.status === 403) {
showSnackBarMessage("An error occurred while uploading the file.");
@@ -307,8 +300,8 @@ const ListObjects = ({
setSelectedObject(object);
};
const downloadObject = (object: string) => {
download(selectedBucket, object);
const downloadObject = (object: BucketObject) => {
download(selectedBucket, object.name, object.version_id);
};
const openPath = (idElement: string) => {
@@ -366,7 +359,7 @@ const ListObjects = ({
const tableActions = [
{ type: "view", onClick: openPath, sendOnlyId: true },
{ type: "download", onClick: downloadObject, sendOnlyId: true },
{ type: "download", onClick: downloadObject },
{ type: "delete", onClick: confirmDeleteObject, sendOnlyId: true },
];

View File

@@ -19,6 +19,7 @@ export interface BucketObject {
size: number;
last_modified: Date;
content_type: string;
version_id: string;
}
export interface BucketObjectsList {

View File

@@ -223,13 +223,13 @@ const ObjectDetails = ({
setDeleteTagModalOpen(true);
};
const downloadObject = (path: string) => {
download(bucketName, path);
const downloadObject = (object: IFileInfo) => {
download(bucketName, pathInBucket, object.version_id);
};
const tableActions = [
{ type: "share", onClick: shareObject, sendOnlyId: true },
{ type: "download", onClick: downloadObject, sendOnlyId: true },
{ type: "download", onClick: downloadObject },
];
const filteredRecords = versions.filter((version) =>
@@ -408,7 +408,7 @@ const ObjectDetails = ({
size="small"
className={classes.actionsIcon}
onClick={() => {
downloadObject(pathInBucket);
downloadObject(actualInfo);
}}
>
<DownloadIcon />

View File

@@ -14,22 +14,28 @@
// 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/>.
import storage from "local-storage-fallback";
import { isNullOrUndefined } from "util";
export const download = (bucketName: string, objectName: string) => {
export const download = (
bucketName: string,
objectPath: string,
versionID: any
) => {
const anchor = document.createElement("a");
document.body.appendChild(anchor);
const token: string = storage.getItem("token")!;
const xhr = new XMLHttpRequest();
const allPathData = objectPath.split("/");
const objectName = allPathData[allPathData.length - 1];
xhr.open(
"GET",
`/api/v1/buckets/${bucketName}/objects/download?prefix=${objectName}`,
true
);
let path = `/api/v1/buckets/${bucketName}/objects/download?prefix=${objectPath}`;
if (!isNullOrUndefined(versionID) && versionID !== "null") {
path = path.concat(`&version_id=${versionID}`);
}
xhr.open("GET", path, true);
xhr.responseType = "blob";
xhr.onload = function (e) {
xhr.onload = function(e) {
if (this.status === 200) {
const blob = new Blob([this.response], {
type: "octet/stream",

View File

@@ -550,8 +550,7 @@ func init() {
{
"type": "string",
"name": "version_id",
"in": "query",
"required": true
"in": "query"
}
],
"responses": {
@@ -5510,8 +5509,7 @@ func init() {
{
"type": "string",
"name": "version_id",
"in": "query",
"required": true
"in": "query"
}
],
"responses": {

View File

@@ -59,10 +59,9 @@ type DownloadObjectParams struct {
*/
Prefix string
/*
Required: true
In: query
*/
VersionID string
VersionID *string
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
@@ -135,21 +134,18 @@ func (o *DownloadObjectParams) bindPrefix(rawData []string, hasKey bool, formats
// bindVersionID binds and validates parameter VersionID from query.
func (o *DownloadObjectParams) bindVersionID(rawData []string, hasKey bool, formats strfmt.Registry) error {
if !hasKey {
return errors.Required("version_id", "query", rawData)
}
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// Required: false
// AllowEmptyValue: false
if err := validate.RequiredString("version_id", "query", raw); err != nil {
return err
if raw == "" { // empty values pass all other validations
return nil
}
o.VersionID = raw
o.VersionID = &raw
return nil
}

View File

@@ -34,7 +34,7 @@ type DownloadObjectURL struct {
BucketName string
Prefix string
VersionID string
VersionID *string
_basePath string
// avoid unkeyed usage
@@ -82,7 +82,10 @@ func (o *DownloadObjectURL) Build() (*url.URL, error) {
qs.Set("prefix", prefixQ)
}
versionIDQ := o.VersionID
var versionIDQ string
if o.VersionID != nil {
versionIDQ = *o.VersionID
}
if versionIDQ != "" {
qs.Set("version_id", versionIDQ)
}

View File

@@ -228,10 +228,14 @@ func getDownloadObjectResponse(session *models.Principal, params user_api.Downlo
return object, nil
}
func downloadObject(ctx context.Context, client MCClient, versionID string) (io.ReadCloser, error) {
func downloadObject(ctx context.Context, client MCClient, versionID *string) (io.ReadCloser, error) {
// TODO: handle encripted files
var reader io.ReadCloser
reader, pErr := client.get(ctx, mc.GetOptions{VersionID: versionID})
var version string
if versionID != nil {
version = *versionID
}
reader, pErr := client.get(ctx, mc.GetOptions{VersionID: version})
if pErr != nil {
return nil, pErr.Cause
}

View File

@@ -330,7 +330,7 @@ paths:
type: string
- name: version_id
in: query
required: true
required: false
type: string
responses:
200: