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:
@@ -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 },
|
||||
];
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ export interface BucketObject {
|
||||
size: number;
|
||||
last_modified: Date;
|
||||
content_type: string;
|
||||
version_id: string;
|
||||
}
|
||||
|
||||
export interface BucketObjectsList {
|
||||
|
||||
@@ -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 />
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -330,7 +330,7 @@ paths:
|
||||
type: string
|
||||
- name: version_id
|
||||
in: query
|
||||
required: true
|
||||
required: false
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
|
||||
Reference in New Issue
Block a user