Skip to content

Commit

Permalink
Copy & Move API calls + Updated Commands Path in Release Workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
Saifullah-dev committed Aug 30, 2024
1 parent 45c63ab commit 0e87d3f
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 71 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- run: npm ci
- run: npm run build
- run: npm audit signatures
- run: cd frontend && npm ci
- run: cd frontend && npm run build
- run: cd frontend && npm audit signatures
- name: Release
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
NPM_TOKEN: ${{secrets.NPM_TOKEN}}
run: npx semantic-release
run: cd frontend && npx semantic-release
131 changes: 131 additions & 0 deletions backend/controllers/fileSystemController.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,134 @@ exports.rename = async (req, res) => {
}
};
//

// Copy File/Folder
const recursiveCopy = async (sourceItem, destinationFolder) => {
const copyItem = new FileSystem({
name: sourceItem.name,
isDirectory: sourceItem.isDirectory,
path: `${destinationFolder?.path ?? ""}/${sourceItem.name}`,
parentId: destinationFolder?._id || null,
size: sourceItem.size,
mimeType: sourceItem.mimeType,
});

await copyItem.save();

const children = await FileSystem.find({ parentId: sourceItem._id });

for (const child of children) {
await recursiveCopy(child, copyItem);
}
};

exports.copyItem = async (req, res) => {
try {
const { sourceId, destinationId } = req.body;
const isRootDestination = !destinationId;

if (!sourceId) {
return res.status(400).json({ error: "sourceId is required!" });
}

const sourceItem = await FileSystem.findById(sourceId);
if (!sourceItem) {
return res.status(404).json({ error: "Source File/Folder not found!" });
}

const srcFullPath = path.join(__dirname, "../uploads", sourceItem.path);

if (isRootDestination) {
const destFullPath = path.join(__dirname, "../uploads", sourceItem.name);
await fs.promises.cp(srcFullPath, destFullPath, { recursive: true });
await recursiveCopy(sourceItem, null); // Destination Folder -> Root Folder
} else {
const destinationFolder = await FileSystem.findById(destinationId);
if (!destinationFolder || !destinationFolder.isDirectory) {
return res.status(400).json({ error: "Invalid destinationId!" });
}
const destFullPath = path.join(
__dirname,
"../uploads",
destinationFolder.path,
sourceItem.name
);
await fs.promises.cp(srcFullPath, destFullPath, { recursive: true });
await recursiveCopy(sourceItem, destinationFolder);
}

res.status(200).json({ message: "Item(s) copied successfully!" });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
//

// Move File/Folder
// We want the source file / folder to copy in the destination directory.
// And move from its original location.
const recursiveMove = async (sourceItem, destinationFolder) => {
const moveItem = new FileSystem({
name: sourceItem.name,
isDirectory: sourceItem.isDirectory,
path: `${destinationFolder?.path ?? ""}/${sourceItem.name}`,
parentId: destinationFolder?._id || null,
size: sourceItem.size,
mimeType: sourceItem.mimeType,
});

await moveItem.save();
await FileSystem.findByIdAndDelete(sourceItem._id);

const children = await FileSystem.find({ parentId: sourceItem._id });
for (const child of children) {
await recursiveMove(child, moveItem);
}
};

exports.moveItem = async (req, res) => {
try {
const { sourceId, destinationId } = req.body;
const isRootDestination = !destinationId;

if (!sourceId) {
return res.status(400).json({ error: "sourceId is required!" });
}

const sourceItem = await FileSystem.findById(sourceId);
if (!sourceItem) {
return res.status(404), json({ error: "Source File/Folder not found!" });
}

const srcFullPath = path.join(__dirname, "../uploads", sourceItem.path);

if (isRootDestination) {
const destFullPath = path.join(__dirname, "../uploads", sourceItem.name);
await fs.promises.cp(srcFullPath, destFullPath, { recursive: true });
await fs.promises.rm(srcFullPath, { recursive: true });

await recursiveMove(sourceItem, null);
} else {
const destinationFolder = await FileSystem.findById(destinationId);
if (!destinationFolder || !destinationFolder.isDirectory) {
return res.status(400).json({ error: "Invalid destinationId!" });
}

const destFullPath = path.join(
__dirname,
"../uploads",
destinationFolder.path,
sourceItem.name
);
await fs.promises.cp(srcFullPath, destFullPath, { recursive: true });
await fs.promises.rm(srcFullPath, { recursive: true });

await recursiveMove(sourceItem, destinationFolder);
}

res.status(200).json({ message: "Item(s) moved successfully!" });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
//
2 changes: 2 additions & 0 deletions backend/routes/fileSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ router.post("/folder", fileSystemController.createFolder);
router.post("/upload", upload.single("file"), fileSystemController.uploadFile);
router.delete("/:id", fileSystemController.delete);
router.patch("/rename", fileSystemController.rename);
router.post("/copy", fileSystemController.copyItem);
router.put("/move", fileSystemController.moveItem);

module.exports = router;
15 changes: 9 additions & 6 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import FileManager from "./File Manager/FileManager";
import { createFolderAPI } from "./Mock APIs/createFolderAPI";
import { renameAPI } from "./Mock APIs/renameAPI";
import { deleteAPI } from "./Mock APIs/deleteAPI";
import { fileTransferAPI } from "./Mock APIs/fileTransferAPI";
import { copyItemAPI, moveItemAPI } from "./Mock APIs/fileTransferAPI";
import { getAllFilesAPI } from "./Mock APIs/getAllFilesAPI";

function App() {
Expand Down Expand Up @@ -44,7 +44,7 @@ function App() {

// File Upload Handlers
const handleFileUploading = (file, parentFolder) => {
return { parentId: parentFolder._id };
return { parentId: parentFolder?._id };
};

const handleFileUploaded = (response) => {
Expand Down Expand Up @@ -80,11 +80,14 @@ function App() {
//

// Paste File/Folder
const handlePaste = async (files, pastePath, clipBoard, filesCopied) => {
const handlePaste = async (sourceItem, destinationFolder, operationType) => {
setIsLoading(true);
const response = await fileTransferAPI(files, pastePath, clipBoard, filesCopied);
setFiles(response);
setIsLoading(false);
if (operationType === "copy") {
const response = await copyItemAPI(sourceItem._id, destinationFolder?._id);
} else {
const response = await moveItemAPI(sourceItem._id, destinationFolder?._id);
}
await getFiles();
};
//

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const UploadItem = ({ index, fileData, setIsUploading, fileUploadConfig, handleF
const formData = new FormData();
const appendData = fileData?.appendData;
for (let key in appendData) {
formData.append(key, appendData[key]);
appendData[key] && formData.append(key, appendData[key]);
}
formData.append("file", fileData.file);

Expand Down
8 changes: 6 additions & 2 deletions frontend/src/File Manager/Files/FileItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const FileItem = ({
const handleFilePasting = (e) => {
e.stopPropagation();
if (clipBoard) {
const pastePath = file.path + "/" + file.name;
const pastePath = file.path;
const selectedCopiedFile = clipBoard.files[0];
const copiedFiles = files.filter((f) => {
const folderToCopy =
Expand All @@ -61,7 +61,11 @@ const FileItem = ({
);
return folderToCopy || folderChildren;
});
handlePaste(files, pastePath, clipBoard, copiedFiles);

const destinationFolder = files.find((f) => f.path === pastePath);
const operationType = clipBoard.isMoving ? "move" : "copy";

handlePaste(selectedCopiedFile, destinationFolder, operationType);
clipBoard.isMoving && setClipBoard(null);
setIsItemSelection(false);
setSelectedFile(null);
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/File Manager/Toolbar/Toolbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ const Toolbar = ({
return folderToCopy || folderChildren;
});

handlePaste(files, pastePath, clipBoard, copiedFiles);
const destinationFolder = files.find((file) => file.path === pastePath);
const operationType = clipBoard.isMoving ? "move" : "copy";

handlePaste(selectedCopiedFile, destinationFolder, operationType);
clipBoard.isMoving && setClipBoard(null);
setIsItemSelection(false);
setSelectedFile(null);
Expand Down Expand Up @@ -100,7 +103,7 @@ const Toolbar = ({

// Selected File/Folder Actions
if (isItemSelection) {
const pastePath = selectedFile.path + "/" + selectedFile.name;
const pastePath = selectedFile.path;

return (
<div className="toolbar file-selected">
Expand Down
63 changes: 7 additions & 56 deletions frontend/src/Mock APIs/fileTransferAPI.js
Original file line number Diff line number Diff line change
@@ -1,60 +1,11 @@
const getCopiedFiles = (file, pastePath) => {
const children = file.children ?? [];
return [
{ name: file.name, isDirectory: file.isDirectory, path: pastePath },
...children.flatMap((child) => getCopiedFiles(child, pastePath + "/" + file.name)),
];
};

const handleDuplicateFile = (file, pastePath, pastePathFiles) => {
if (file.path === pastePath || pastePathFiles.find((f) => f.name === file.name)) {
const fileExtension = file.isDirectory ? "" : "." + file.name.split(".").pop();
const fileName = file.isDirectory ? file.name : file.name.split(".").slice(0, -1).join(".");

// Generating new file name for duplicate file
let maxFileNum = 0;
// If there exists a file with name fileName (1), fileName (2), etc.
// Check if the number is greater than the maxFileNum, then set it to that greater number
const fileNameRegex = new RegExp(`${fileName} \\(\\d+\\)`);
pastePathFiles.forEach((f) => {
const fName = f.isDirectory ? f.name : f.name.split(".").slice(0, -1).join(".");
if (fileNameRegex.test(fName)) {
const fileNumStr = fName.split(`${fileName} (`).pop().slice(0, -1);
const fileNum = parseInt(fileNumStr);
if (!isNaN(fileNum) && fileNum > maxFileNum) {
maxFileNum = fileNum;
}
}
});
const appendNum = ` (${++maxFileNum})`;
const newFileName = fileName + appendNum + fileExtension;
//
import { api } from "./api";

return { ...file, name: newFileName };
} else {
return file;
}
export const copyItemAPI = async (sourceId, destinationId) => {
const response = await api.post("/copy", { sourceId, destinationId });
return response;
};

export const fileTransferAPI = (files, pastePath, clipBoard, filesCopied) => {
return new Promise((resolve) => {
setTimeout(() => {
if (clipBoard.isMoving) {
files = files.filter((f) => {
return !filesCopied.find((cf) => cf.name === f.name && cf.path === f.path);
});
}

const response = [
...files,
...clipBoard.files.flatMap((file) => {
const pastePathFiles = files.filter((f) => f.path === pastePath);
const nonDuplicateFile = handleDuplicateFile(file, pastePath, pastePathFiles);
return getCopiedFiles(nonDuplicateFile, pastePath);
}),
];

resolve(response);
}, 700);
});
export const moveItemAPI = async (sourceId, destinationId) => {
const response = await api.put("/move", { sourceId, destinationId });
return response;
};

0 comments on commit 0e87d3f

Please sign in to comment.