[FEATURE] Move Files Protocol
This commit is contained in:
parent
39369fe41a
commit
c9361e6771
7 changed files with 52 additions and 79 deletions
|
@ -4,6 +4,7 @@ import {
|
||||||
listServerFiles,
|
listServerFiles,
|
||||||
removeServerItem,
|
removeServerItem,
|
||||||
uploadServerItem,
|
uploadServerItem,
|
||||||
|
moveServerItems,
|
||||||
} from "../k8s/server-files.js";
|
} from "../k8s/server-files.js";
|
||||||
import { sendError } from "../util/ExpressClientError.js";
|
import { sendError } from "../util/ExpressClientError.js";
|
||||||
import { checkAuthorization } from "../database/queries/server-queries.js";
|
import { checkAuthorization } from "../database/queries/server-queries.js";
|
||||||
|
@ -79,3 +80,18 @@ export async function getItem(req, res) {
|
||||||
})
|
})
|
||||||
.catch(sendError(res));
|
.catch(sendError(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function moveItems(req, res) {
|
||||||
|
const serverSpec = req.body;
|
||||||
|
if (!serverSpec.id) return res.status(400).send("Server id missing!");
|
||||||
|
if (!serverSpec.destination)
|
||||||
|
return res.status(400).send("Destination required!");
|
||||||
|
if (!serverSpec.origin) return res.status(400).send("Origin required!");
|
||||||
|
if (!serverSpec.files || !Array.isArray(serverSpec.files))
|
||||||
|
return res.status(400).send("Files required!");
|
||||||
|
const authorized = await checkAuthorization(serverSpec.id, req.cairoId);
|
||||||
|
if (!authorized) return res.sendStatus(403);
|
||||||
|
moveServerItems(serverSpec)
|
||||||
|
.then(() => res.sendStatus(200))
|
||||||
|
.catch(sendError(res));
|
||||||
|
}
|
||||||
|
|
|
@ -86,12 +86,22 @@ export async function uploadServerItem(serverSpec, file) {
|
||||||
}).catch(handleError);
|
}).catch(handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getServerItem(serverSpec, writableStream) {
|
export async function getServerItem(serverSpec) {
|
||||||
const { path } = serverSpec;
|
const { path } = serverSpec;
|
||||||
const ds = new Transform({ transform: (c, e, cb) => cb(null, c) });
|
const ds = new Transform({ transform: (c, _e, cb) => cb(null, c) });
|
||||||
pathSecurityCheck(path);
|
pathSecurityCheck(path);
|
||||||
const ftpTransfer = useServerFtp(serverSpec, async (c) => {
|
const ftpTransfer = useServerFtp(serverSpec, async (c) => {
|
||||||
await c.downloadTo(ds, path);
|
await c.downloadTo(ds, path);
|
||||||
}).catch(handleError);
|
}).catch(handleError);
|
||||||
return { ds, ftpTransfer };
|
return { ds, ftpTransfer };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function moveServerItems(serverSpec) {
|
||||||
|
const { destination, origin, files } = serverSpec;
|
||||||
|
useServerFtp(serverSpec, async (c) =>
|
||||||
|
Promise.all(
|
||||||
|
files.map((f) => c.rename(`${origin}/${f}`, `${destination}/${f}`)),
|
||||||
|
),
|
||||||
|
).catch(handleError);
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
listFiles,
|
listFiles,
|
||||||
uploadItem,
|
uploadItem,
|
||||||
getItem,
|
getItem,
|
||||||
|
moveItems,
|
||||||
} from "../controllers/file-controller.js";
|
} from "../controllers/file-controller.js";
|
||||||
|
|
||||||
import cairoAuthMiddleware from "./middlewares/auth-middleware.js";
|
import cairoAuthMiddleware from "./middlewares/auth-middleware.js";
|
||||||
|
@ -18,6 +19,7 @@ router.post("/list", listFiles);
|
||||||
router.post("/folder", createFolder);
|
router.post("/folder", createFolder);
|
||||||
router.delete("/item", deleteItem);
|
router.delete("/item", deleteItem);
|
||||||
router.post("/item", getItem);
|
router.post("/item", getItem);
|
||||||
|
router.post("/move", moveItems);
|
||||||
router.post("/upload", multerMiddleware.single("file"), uploadItem);
|
router.post("/upload", multerMiddleware.single("file"), uploadItem);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
import multer from "multer";
|
|
||||||
import multerS3 from "multer-s3";
|
|
||||||
import AWS from "aws-sdk";
|
|
||||||
|
|
||||||
// Environment Variables
|
|
||||||
const {
|
|
||||||
MCL_S3_ENDPOINT: s3Endpoint,
|
|
||||||
MCL_S3_ACCESS_KEY_ID: s3KeyId,
|
|
||||||
MCL_S3_ACCESS_KEY: s3Key,
|
|
||||||
} = process.env;
|
|
||||||
|
|
||||||
export const mcl = "mcl";
|
|
||||||
|
|
||||||
export const s3 = new AWS.S3({
|
|
||||||
endpoint: s3Endpoint,
|
|
||||||
accessKeyId: s3KeyId,
|
|
||||||
secretAccessKey: s3Key,
|
|
||||||
sslEnabled: true,
|
|
||||||
s3ForcePathStyle: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const storage = multerS3({
|
|
||||||
s3,
|
|
||||||
bucket,
|
|
||||||
contentType: multerS3.AUTO_CONTENT_TYPE,
|
|
||||||
metadata: (req, file, cb) => {
|
|
||||||
cb(null, { fieldName: file.fieldname });
|
|
||||||
},
|
|
||||||
key: (req, file, cb) => {
|
|
||||||
cb(null, Date.now().toString());
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const upload = multer({ storage });
|
|
|
@ -1,42 +0,0 @@
|
||||||
// ChonkyFullFileBrowser.tsx
|
|
||||||
import { forwardRef, memo } from "react";
|
|
||||||
import {
|
|
||||||
StylesProvider,
|
|
||||||
createGenerateClassName,
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
|
|
||||||
import {
|
|
||||||
FileBrowser,
|
|
||||||
FileList,
|
|
||||||
FileContextMenu,
|
|
||||||
FileNavbar,
|
|
||||||
FileToolbar,
|
|
||||||
setChonkyDefaults,
|
|
||||||
FileBrowserHandle,
|
|
||||||
FileBrowserProps,
|
|
||||||
} from "chonky";
|
|
||||||
|
|
||||||
import { ChonkyIconFA } from "chonky-icon-fontawesome";
|
|
||||||
|
|
||||||
setChonkyDefaults({ iconComponent: ChonkyIconFA });
|
|
||||||
|
|
||||||
const muiJSSClassNameGenerator = createGenerateClassName({
|
|
||||||
// Seed property is used to add a prefix classes generated by material ui.
|
|
||||||
seed: "chonky",
|
|
||||||
});
|
|
||||||
|
|
||||||
export default memo(
|
|
||||||
forwardRef((props, ref) => {
|
|
||||||
const { onScroll } = props;
|
|
||||||
return (
|
|
||||||
<StylesProvider generateClassName={muiJSSClassNameGenerator}>
|
|
||||||
<FileBrowser ref={ref} {...props}>
|
|
||||||
<FileNavbar />
|
|
||||||
<FileToolbar />
|
|
||||||
<FileList onScroll={onScroll} />
|
|
||||||
<FileContextMenu />
|
|
||||||
</FileBrowser>
|
|
||||||
</StylesProvider>
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
|
@ -1,5 +1,8 @@
|
||||||
import { useState, useEffect, useMemo, useRef } from "react";
|
import { useState, useEffect, useMemo, useRef } from "react";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
|
import { DndProvider } from "react-dnd";
|
||||||
|
import { HTML5Backend } from "react-dnd-html5-backend";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FileBrowser,
|
FileBrowser,
|
||||||
FileContextMenu,
|
FileContextMenu,
|
||||||
|
@ -17,7 +20,7 @@ import {
|
||||||
deleteServerItem,
|
deleteServerItem,
|
||||||
getServerItem,
|
getServerItem,
|
||||||
} from "@mcl/queries";
|
} from "@mcl/queries";
|
||||||
import { previewServerItem } from "../../util/queries";
|
import { moveServerItems, previewServerItem } from "../../util/queries";
|
||||||
import { cairoAuthHeader } from "@mcl/util/auth.js";
|
import { cairoAuthHeader } from "@mcl/util/auth.js";
|
||||||
|
|
||||||
import { supportedFileTypes } from "./FilePreview.jsx";
|
import { supportedFileTypes } from "./FilePreview.jsx";
|
||||||
|
@ -32,6 +35,7 @@ export default function MineclusterFiles(props) {
|
||||||
ChonkyActions.DownloadFiles,
|
ChonkyActions.DownloadFiles,
|
||||||
ChonkyActions.CopyFiles,
|
ChonkyActions.CopyFiles,
|
||||||
ChonkyActions.DeleteFiles,
|
ChonkyActions.DeleteFiles,
|
||||||
|
ChonkyActions.MoveFiles,
|
||||||
],
|
],
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
@ -132,6 +136,15 @@ export default function MineclusterFiles(props) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function moveFile(movePayload) {
|
||||||
|
const { files: filePayload, destination: destinationPayload } = movePayload;
|
||||||
|
if (!destinationPayload.isDir || filePayload.length === 0) return;
|
||||||
|
const files = filePayload.map((f) => f.name);
|
||||||
|
const dest = destinationPayload.id;
|
||||||
|
const origin = dirStack.join("/");
|
||||||
|
moveServerItems(serverId, files, dest, origin).then(updateFiles);
|
||||||
|
}
|
||||||
|
|
||||||
function fileClick(chonkyEvent) {
|
function fileClick(chonkyEvent) {
|
||||||
const { id: clickEvent, payload } = chonkyEvent;
|
const { id: clickEvent, payload } = chonkyEvent;
|
||||||
if (clickEvent === "open_parent_folder") return openParentFolder();
|
if (clickEvent === "open_parent_folder") return openParentFolder();
|
||||||
|
@ -141,6 +154,7 @@ export default function MineclusterFiles(props) {
|
||||||
return downloadFiles(chonkyEvent.state.selectedFilesForAction);
|
return downloadFiles(chonkyEvent.state.selectedFilesForAction);
|
||||||
if (clickEvent === "delete_files")
|
if (clickEvent === "delete_files")
|
||||||
return deleteItems(chonkyEvent.state.selectedFilesForAction);
|
return deleteItems(chonkyEvent.state.selectedFilesForAction);
|
||||||
|
if (clickEvent === "move_files") return moveFile(payload);
|
||||||
if (clickEvent !== "open_files") return; // console.log(clickEvent);
|
if (clickEvent !== "open_files") return; // console.log(clickEvent);
|
||||||
openItem(payload);
|
openItem(payload);
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,13 @@ export const createServerFolder = async (serverId, path) =>
|
||||||
export const deleteServerItem = async (serverId, path, isDir) =>
|
export const deleteServerItem = async (serverId, path, isDir) =>
|
||||||
fetchApiCore("/files/item", { id: serverId, path, isDir }, "DELETE");
|
fetchApiCore("/files/item", { id: serverId, path, isDir }, "DELETE");
|
||||||
|
|
||||||
|
export const moveServerItems = async (serverId, files, destination, origin) =>
|
||||||
|
fetchApiCore(
|
||||||
|
"/files/move",
|
||||||
|
{ id: serverId, files, destination, origin },
|
||||||
|
"POST",
|
||||||
|
);
|
||||||
|
|
||||||
export async function previewServerItem(serverId, path) {
|
export async function previewServerItem(serverId, path) {
|
||||||
const resp = await fetchApiCore("/files/item", { id: serverId, path });
|
const resp = await fetchApiCore("/files/item", { id: serverId, path });
|
||||||
if (resp.status !== 200) return console.log("AHHHH");
|
if (resp.status !== 200) return console.log("AHHHH");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue