diff --git a/src/utils/helpers/fileHelpers.js b/src/utils/helpers/fileHelpers.js index e43f0eb..b541741 100644 --- a/src/utils/helpers/fileHelpers.js +++ b/src/utils/helpers/fileHelpers.js @@ -1,35 +1,83 @@ +import ffprobe from "ffprobe"; +import ffprobeStatic from "ffprobe-static"; import path from "path"; +import UserModel from "src/models/UserModel"; import { FILE_STORAGE_LOCATION } from "../../consts/filePaths"; import FileModel from "../../models/FileModel"; -import { createFileIO } from "./ioHelpers"; +import { createFileIO, readFileIO } from "./ioHelpers"; import { connectMongo } from "./mongoHelpers"; import { randomString } from "./stringHelpers"; connectMongo(); +const BASE_STORAGE = `${FILE_STORAGE_LOCATION}${path.sep}`; + /** * Returns the the files object in mongo for the given id * * @param {string} fileId The files id + * @param {boolean} isInternal If true, will return more data * @return The file object or null if not found */ -export async function getFile(fileId) { - return await FileModel.findOne({ fileId: fileId }); +export async function getFileInfo(fileId, isInternal = false) { + // Todo: Implement cache? + let file = await FileModel.aggregate([ + { + $match: { + fileId: fileId, + }, + }, + { + $lookup: { + from: UserModel.collection.name, + localField: "uploader", + foreignField: "_id", + as: "uploader", + }, + }, + ]).exec(); + if (file.length < 1) { + return null; + } + file = file[0]; + const uploader = file.uploader[0]; + uploader._id = undefined; + if (!isInternal) { + uploader.uploadKey = undefined; + } + uploader.password = undefined; + uploader.salt = undefined; + uploader.lastLoginDate = undefined; + uploader.__v = undefined; + file.uploader = uploader; + file._id = undefined; + file.__v = undefined; + file.fileUrl = process.env.NEXT_PUBLIC_SITE_URL + "/api/files/" + file.fileId; + return file; } /** * Creates the file object in mongo and stores it to the storage location * * @param {UserModel} uploader The user who uploaded the file - * @param {[]} fileData The file data for the upload + * @param {string} fileName The original files name + * @param {Buffer} buffer The buffer of the file + * @param {string} contentType The content type of the file + * @param {Number} size The size of the file */ -export async function createFile(uploader, fileName, buffer, contentType) { +export async function createFile( + uploader, + fileName, + buffer, + contentType, + size +) { const fileId = randomString(process.env.FILE_ID_LENGTH); - const extention = fileName.split(".")[1].toLowerCase(); + const extention = fileName.split(".").at(-1).toLowerCase(); // Todo: Check if the file was actually saved to // disk and create a return type so we can notify the user what happened await createFileIO( - `${FILE_STORAGE_LOCATION}${path.sep}${uploader.uploadKey}`, + `${BASE_STORAGE}${uploader.uploadKey}`, `${fileId}.${extention}`, buffer ); @@ -38,7 +86,32 @@ export async function createFile(uploader, fileName, buffer, contentType) { fileId: fileId, uploadDate: new Date(), contentType: contentType, + ext: extention, + size: size, }); + + contentType = contentType.toLowerCase(); + if (contentType.includes("image") || contentType.includes("video")) { + const fileMetaData = await ffprobe( + `${BASE_STORAGE}${uploader.uploadKey}${path.sep}${fileId}.${extention}`, + { path: ffprobeStatic.path } + ); + const dimensions = fileMetaData.streams[0]; + file.width = dimensions.width; + file.height = dimensions.height; + } + await file.save(); return `${fileId}.${extention}`; } + +export async function getFileRaw(fileId) { + const fileInfo = await getFileInfo(fileId, true); + if (fileInfo == null) { + return null; + } + + const filePath = `${BASE_STORAGE}${fileInfo.uploader.uploadKey}${path.sep}${fileInfo.fileId}.${fileInfo.ext}`; + const buffer = await readFileIO(filePath); + return { file: fileInfo, buffer: buffer }; +}