fix: uploads (#1449)

Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
Anshuman Pandey
2023-10-25 20:20:48 +05:30
committed by GitHub
parent e21f82e1fc
commit 21fe7080ef
10 changed files with 323 additions and 89 deletions
@@ -1,8 +1,5 @@
import { env } from "@/env.mjs";
import { responses } from "@/app/lib/api/response";
import { WEBAPP_URL } from "@formbricks/lib/constants";
import { getSignedUrlForS3Upload } from "@formbricks/lib/storage/service";
import { generateLocalSignedUrl } from "@formbricks/lib/crypto";
import { getUploadSignedUrl } from "@formbricks/lib/storage/service";
const uploadPrivateFile = async (
fileName: string,
@@ -13,40 +10,14 @@ const uploadPrivateFile = async (
const accessType = "private"; // private files are only accessible by the user who has access to the environment
// if s3 is not configured, we'll upload to a local folder named uploads
if (!env.S3_ACCESS_KEY || !env.S3_SECRET_KEY || !env.S3_REGION || !env.S3_BUCKET_NAME) {
try {
const { signature, timestamp, uuid } = generateLocalSignedUrl(fileName, environmentId, fileType);
return responses.successResponse({
signedUrl: `${WEBAPP_URL}/api/v1/client/storage/local`,
signingData: {
signature,
timestamp,
uuid,
},
fileUrl: new URL(`${WEBAPP_URL}/storage/${environmentId}/${accessType}/${fileName}`).href,
});
} catch (err) {
return responses.internalServerErrorResponse(err.message);
}
}
try {
const signedUrl = await getSignedUrlForS3Upload(
fileName,
fileType,
accessType,
environmentId,
false,
plan
);
const signedUrlResponse = await getUploadSignedUrl(fileName, environmentId, fileType, accessType, plan);
return responses.successResponse({
signedUrl,
fileUrl: new URL(`${WEBAPP_URL}/storage/${environmentId}/${accessType}/${fileName}`).href,
...signedUrlResponse,
});
} catch (err) {
return responses.internalServerErrorResponse(err.message);
return responses.internalServerErrorResponse("Internal server error");
}
};
@@ -1,7 +1,4 @@
import { env } from "@/env.mjs";
import { getSignedUrlForS3Upload } from "@formbricks/lib/storage/service";
import { WEBAPP_URL } from "@formbricks/lib/constants";
import { generateLocalSignedUrl } from "@formbricks/lib/crypto";
import { getUploadSignedUrl } from "@formbricks/lib/storage/service";
import { responses } from "@/app/lib/api/response";
const getSignedUrlForPublicFile = async (fileName: string, environmentId: string, fileType: string) => {
@@ -9,41 +6,11 @@ const getSignedUrlForPublicFile = async (fileName: string, environmentId: string
// if s3 is not configured, we'll upload to a local folder named uploads
if (!env.S3_ACCESS_KEY || !env.S3_SECRET_KEY || !env.S3_REGION || !env.S3_BUCKET_NAME) {
try {
const { signature, timestamp, uuid } = generateLocalSignedUrl(fileName, environmentId, fileType);
return responses.successResponse({
signedUrl: new URL(`${WEBAPP_URL}/api/v1/management/storage/local`).href,
signingData: {
signature,
timestamp,
uuid,
},
fileUrl: new URL(`${WEBAPP_URL}/storage/${environmentId}/${accessType}/${fileName}`).href,
});
} catch (err) {
if (err.name === "FileTooLargeError") {
return responses.badRequestResponse(err.message);
}
return responses.internalServerErrorResponse("Internal server error");
}
}
try {
const { presignedFields, signedUrl } = await getSignedUrlForS3Upload(
fileName,
fileType,
accessType,
environmentId,
true
);
const signedUrlResponse = await getUploadSignedUrl(fileName, environmentId, fileType, accessType);
return responses.successResponse({
signedUrl,
presignedFields,
fileUrl: new URL(`${WEBAPP_URL}/storage/${environmentId}/${accessType}/${fileName}`).href,
...signedUrlResponse,
});
} catch (err) {
return responses.internalServerErrorResponse("Internal server error");
@@ -0,0 +1,24 @@
import { responses } from "@/app/lib/api/response";
import { storageCache } from "@formbricks/lib/storage/cache";
import { deleteFile } from "@formbricks/lib/storage/service";
import { TAccessType } from "@formbricks/types/storage";
export const handleDeleteFile = async (environmentId: string, accessType: TAccessType, fileName: string) => {
try {
const { message, success, code } = await deleteFile(environmentId, accessType, fileName);
if (success) {
// revalidate cache
storageCache.revalidate({ fileKey: `${environmentId}/${accessType}/${fileName}` });
return responses.successResponse(message);
}
if (code === 404) {
return responses.notFoundResponse("File", "File not found");
}
return responses.internalServerErrorResponse(message);
} catch (err) {
return responses.internalServerErrorResponse("Something went wrong");
}
};
@@ -1,14 +1,14 @@
import { env } from "@/env.mjs";
import { responses } from "@/app/lib/api/response";
import { UPLOADS_DIR } from "@formbricks/lib/constants";
import { getFileFromLocalStorage, getFileFromS3 } from "@formbricks/lib/storage/service";
import { getLocalFile, getS3File } from "@formbricks/lib/storage/service";
import { notFound } from "next/navigation";
import path from "path";
const getFile = async (environmentId: string, accessType: string, fileName: string) => {
if (!env.S3_ACCESS_KEY || !env.S3_SECRET_KEY || !env.S3_REGION || !env.S3_BUCKET_NAME) {
try {
const { fileBuffer, metaData } = await getFileFromLocalStorage(
const { fileBuffer, metaData } = await getLocalFile(
path.join(UPLOADS_DIR, environmentId, accessType, fileName)
);
@@ -24,7 +24,7 @@ const getFile = async (environmentId: string, accessType: string, fileName: stri
}
try {
const signedUrl = await getFileFromS3(`${environmentId}/${accessType}/${fileName}`);
const signedUrl = await getS3File(`${environmentId}/${accessType}/${fileName}`);
return new Response(null, {
status: 302,
@@ -6,6 +6,7 @@ import { ZStorageRetrievalParams } from "@formbricks/types/storage";
import { getServerSession } from "next-auth";
import { NextRequest } from "next/server";
import getFile from "./lib/getFile";
import { handleDeleteFile } from "@/app/storage/[environmentId]/[accessType]/[fileName]/lib/deleteFile";
export async function GET(
_: NextRequest,
@@ -43,3 +44,44 @@ export async function GET(
return await getFile(environmentId, accessType, fileName);
}
export async function DELETE(_: NextRequest, { params }: { params: { fileName: string } }) {
if (!params.fileName) {
return responses.badRequestResponse("Fields are missing or incorrectly formatted", {
fileName: "fileName is required",
});
}
const [environmentId, accessType, file] = params.fileName.split("/");
const paramValidation = ZStorageRetrievalParams.safeParse({ fileName: file, environmentId, accessType });
if (!paramValidation.success) {
return responses.badRequestResponse(
"Fields are missing or incorrectly formatted",
transformErrorToDetails(paramValidation.error),
true
);
}
// check if user is authenticated
const session = await getServerSession(authOptions);
if (!session || !session.user) {
return responses.notAuthenticatedResponse();
}
// check if the user has access to the environment
const isUserAuthorized = await hasUserEnvironmentAccess(session.user.id, environmentId);
if (!isUserAuthorized) {
return responses.unauthorizedResponse();
}
return await handleDeleteFile(
paramValidation.data.environmentId,
paramValidation.data.accessType,
paramValidation.data.fileName
);
}