Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"date-and-time": "^2.4.2",
"file-saver": "^2.0.5",
"filepond": "^4.30.4",
"filepond-plugin-file-validate-type": "^1.2.9",
"js-cookie": "^3.0.1",
"jszip": "^3.10.1",
"react": "^18.2.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const currentDate = new Date();
const currentMonth = currentDate.getMonth() + 1;
const acadYear = (currentMonth >= 1 && currentMonth <= 5) ? currentDate.getFullYear() - 1 : currentDate.getFullYear();
const acadYear = currentDate.getFullYear();

const Yroptions = ({
course,
Expand Down
64 changes: 45 additions & 19 deletions client/src/screens/contributions/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Wrapper from "./components/wrapper";
import SectionC from "./components/sectionC";
import axios from "axios";
import { FilePond, registerPlugin } from "react-filepond";
import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type';
import "filepond/dist/filepond.min.css";
import { useEffect, useRef, useState } from "react";
import "./styles.scss";
Expand All @@ -18,6 +19,9 @@ import {
RefreshCurrentFolder,
ChangeCurrentYearData,
} from "../../actions/filebrowser_actions";

registerPlugin(FilePondPluginFileValidateType);

const Contributions = () => {
const uploadedBy = useSelector((state) => state.user.user._id);
const userName = useSelector((state) => state.user.user.name);
Expand All @@ -27,6 +31,15 @@ const Contributions = () => {
const code = currentFolder?.course;
const [contributionId, setContributionId] = useState("");
const dispatch = useDispatch();
const allowed_file_types = [
'application/pdf',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'video/mp4',
'video/x-matroska', // mkv
'image/png',
'image/jpeg'
]

useEffect(() => {
setContributionId(uuidv4());
}, []);
Expand All @@ -35,26 +48,25 @@ const Contributions = () => {
const [isUploading, setIsUploading] = useState(false);

// const [contributionId, setContributionId] = useState("");

const [files, setFiles] = useState([]);
let pond = useRef();

const handleUpdateFiles = (fileItems) => {
setFiles(fileItems);
if (fileItems.length > 0) setSubmitEnabled(true);
else setSubmitEnabled(false);
};

async function handleSubmit() {
if (isUploading) return;
if (isUploading || files.length === 0) return;

const collection = document.getElementsByClassName("contri");
const contributionSection = collection[0];
// console.log(toggle);
// console.log(isAnoynmous);

try {
setIsUploading(true);
setSubmitEnabled(false);
// console.log(resp);

let resp = await CreateNewContribution({
parentFolder: currentFolder._id,
courseCode: currentFolder.course,
Expand All @@ -63,22 +75,37 @@ const Contributions = () => {
contributionId,
uploadedBy,
});
// console.log(resp);
await pond.current.processFiles();

const formData = new FormData();
files.forEach((fileItem, index) => {
formData.append(`files`, fileItem.file);
});

pond.current.processFiles();

await fetch(`${server}/api/contribution/upload`, {
method: 'POST',
headers: {
"contribution-id": contributionId,
username: userName,
},
body: formData
});

pond.current.removeFiles();
contributionSection.classList.remove("show");
toast.success("Files uploaded successfully!");
setContributionId(uuidv4());
setSubmitEnabled(true);

} catch (error) {
setSubmitEnabled(true);
contributionSection.classList.remove("show");
toast.error("Upload failed. Please try again!");
// console.log(error);
} finally {
setIsUploading(false);
}


//refresh the course in session storage to include the new file.
try {
let loadingCourseToastId = toast.loading("Loading course data...");
Expand Down Expand Up @@ -114,21 +141,20 @@ const Contributions = () => {
allowMultiple={true}
onupdatefiles={handleUpdateFiles}
maxFiles={40}
server={{
url: `${server}/api/contribution/upload`,
process: {
headers: {
"contribution-id": contributionId,
username: userName,
},
},
}}
instantUpload={false}
allowProcess={false}
acceptedFileTypes={allowed_file_types}
fileValidateTypeLabelExpectedTypes="Expects PDF and PowerPoint files"
allowProcess={true}
allowRevert={false}
ref={(ref) => {
pond.current = ref;
}}
server={{
process: (fieldName, file, metadata, load) => {
load();
},
revert: null,
}}
/>
</div>
<div id="disclaimer-container">
Expand Down
7 changes: 6 additions & 1 deletion client/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,12 @@ file-saver@^2.0.5:
resolved "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz"
integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==

filepond@^4.30.4, "filepond@>=3.7.x < 5.x":
filepond-plugin-file-validate-type@^1.2.9:
version "1.2.9"
resolved "https://registry.npmjs.org/filepond-plugin-file-validate-type/-/filepond-plugin-file-validate-type-1.2.9.tgz"
integrity sha512-Tzv07aNdZvjUXDRA3XL16QMEvh6llDrXlcZ6W0eTHQ+taHaVg/JKJTFs/AViO+6ZcpPCcQStbhYEL2HoS+vldw==

filepond@^4.30.4, "filepond@>=1.x <5.x", "filepond@>=3.7.x < 5.x":
version "4.30.4"
resolved "https://registry.npmjs.org/filepond/-/filepond-4.30.4.tgz"
integrity sha512-FCwsMvG9iiEs6uobdDrTaKsCgsqys0NuLgPPD8n37AYVYBiiDkrPkk9MSIU5rT2FahYcL1bScYI9huIPtlzqyA==
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
72 changes: 45 additions & 27 deletions server/modules/contribution/contribution.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,44 +51,62 @@ async function GetAllContributions(req, res, next) {
async function HandleFileUpload(req, res, next) {
console.log("Handling File Upload");
const contributionId = req.headers["contribution-id"];
const files = req.files; // Changed from req.file to req.files for array handling
const username = req.headers.username;
const files = req.files;

// Check if files were uploaded
if (!files || files.length === 0) {
return res.status(400).json({ error: "No files were uploaded" });
}

// Handle multiple files
const uploadedFiles = [];

for (const file of files) {
// Files names
let initialPath = file.path;
let newFilename = file.filename;
let originalFilename = file.originalname;

let wordArr = originalFilename.split(".");
let fileExtension = wordArr[wordArr.length - 1];
let finalFileName = "";

for (let i = 0; i < wordArr.length - 1; i++) {
finalFileName += wordArr[i];
try {
for (const file of files) {
// Files names
let initialPath = file.path;
let newFilename = file.filename;
let originalFilename = file.originalname;

let wordArr = originalFilename.split(".");
let fileExtension = wordArr[wordArr.length - 1];
let finalFileName = "";

for (let i = 0; i < wordArr.length - 1; i++) {
finalFileName += wordArr[i];
}
finalFileName += "~" + username;
finalFileName += "." + fileExtension;

const finalPath = initialPath.slice(0, initialPath.indexOf(newFilename));

await fs.promises.rename(finalPath + newFilename, finalPath + finalFileName);
const fileId = await UploadFile(contributionId, finalPath, finalFileName);

if (fileId) {
await HandleFileToDB(contributionId, fileId);
uploadedFiles.push({
fileId,
originalName: originalFilename,
finalName: finalFileName
});
}

await fs.promises.unlink(finalPath + finalFileName);
}
finalFileName += "~" + req.headers.username;
finalFileName += "." + fileExtension;

const finalPath = initialPath.slice(0, initialPath.indexOf(newFilename));
console.log(`Successfully uploaded ${uploadedFiles.length} files`);
return res.json({
files: uploadedFiles,
count: uploadedFiles.length
});

await fs.promises.rename(finalPath + newFilename, finalPath + finalFileName);
const fileId = await UploadFile(contributionId, finalPath, finalFileName);
if (fileId) {
await HandleFileToDB(contributionId, fileId);
uploadedFiles.push({ fileId, originalName: originalFilename });
}
await fs.promises.unlink(finalPath + finalFileName);
} catch (error) {
console.error("File upload error:", error);
return res.status(500).json({
error: "File upload failed",
details: error.message
});
}

return res.json({ files: uploadedFiles, count: uploadedFiles.length });
}

async function CreateNewContribution(req, res, next) {
Expand Down
2 changes: 1 addition & 1 deletion server/modules/contribution/contribution.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ router.get("/", isAuthenticated, ContributionController.GetMyContributions);
router.get("/all", ContributionController.GetAllContributions);
router.delete("/:contributionId", ContributionController.DeleteContribution);
router.post("/", catchAsync(ContributionController.CreateNewContribution));
router.post("/upload", upload.array("file"), catchAsync(ContributionController.HandleFileUpload));
router.post("/upload", upload.array("files"), catchAsync(ContributionController.HandleFileUpload));
router.post(
"/upload/mobile",
isAuthenticated,
Expand Down
2 changes: 1 addition & 1 deletion server/onedrive-device-code.token
Original file line number Diff line number Diff line change
@@ -1 +1 @@
SAQABIQEAAABVrSpeuWamRam2jAF1XRQEWGdKsPq8yryqwLbeStuwomr7_ecQpZI0SkTNkLul23HPrGog08llLH4HjavMgc7vHrYEowvnWD3KOJaGcH6aVC2LAH1STKBlfczrzJEPaELD27PsyOboCOUey0JLjYAkrVc5qSuJRvIFOBXHTO1HA9IT4AZeca7utAiXhPO56Pk2rXs45wLr6dAhpt0OUgHpIAA
SAQABIQEAAABVrSpeuWamRam2jAF1XRQEWGdKsPq8yryqwLbeStuwomr7_ecQpZI0SkTNkLul23HPrGog08llLH4HjavMgc7vHrYEowvnWD3KOJaGcH6aVC2LAH1STKBlfczrzJEPaELD27PsyOboCOUey0JLjYAkrVc5qSuJRvIFOBXHTO1HA9IT4AZeca7utAiXhPO56Pk2rXs45wLr6dAhpt0OUgHpIAA
5 changes: 5 additions & 0 deletions server/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2040,6 +2040,11 @@ fs.realpath@^1.0.0:
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==

fsevents@~2.3.2:
version "2.3.2"
resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==

function-bind@^1.1.1, function-bind@^1.1.2:
version "1.1.2"
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
Expand Down