mirror of
https://github.com/formbricks/formbricks.git
synced 2026-03-13 12:39:25 -05:00
feat: custom S3 endpoint to use third party storage services (#2133)
Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
committed by
GitHub
parent
47ec19b46d
commit
5acdf018d3
13
.env.example
13
.env.example
@@ -56,6 +56,19 @@ SMTP_PASSWORD=smtpPassword
|
||||
|
||||
# Uncomment the variables you would like to use and customize the values.
|
||||
|
||||
##############
|
||||
# S3 STORAGE #
|
||||
##############
|
||||
|
||||
# S3 Storage is required for the file uplaod in serverless environments like Vercel
|
||||
S3_ACCESS_KEY=
|
||||
S3_SECRET_KEY=
|
||||
S3_REGION=
|
||||
S3_BUCKET_NAME=
|
||||
# Configure a third party S3 compatible storage service endpoint like StorJ leave empty if you use Amazon S3
|
||||
# e.g., https://gateway.storjshare.io
|
||||
S3_ENDPOINT_URL=
|
||||
|
||||
#####################
|
||||
# Disable Features #
|
||||
#####################
|
||||
|
||||
@@ -87,6 +87,7 @@ export const ONBOARDING_DISABLED = env.ONBOARDING_DISABLED;
|
||||
export const S3_ACCESS_KEY = env.S3_ACCESS_KEY;
|
||||
export const S3_SECRET_KEY = env.S3_SECRET_KEY;
|
||||
export const S3_REGION = env.S3_REGION;
|
||||
export const S3_ENDPOINT_URL = env.S3_ENDPOINT_URL;
|
||||
export const S3_BUCKET_NAME = env.S3_BUCKET_NAME;
|
||||
export const UPLOADS_DIR = "./uploads";
|
||||
export const MAX_SIZES = {
|
||||
|
||||
@@ -61,6 +61,7 @@ export const env = createEnv({
|
||||
S3_BUCKET_NAME: z.string().optional(),
|
||||
S3_REGION: z.string().optional(),
|
||||
S3_SECRET_KEY: z.string().optional(),
|
||||
S3_ENDPOINT_URL: z.string().optional(),
|
||||
SHORT_URL_BASE: z.string().url().optional().or(z.string().length(0)),
|
||||
SIGNUP_DISABLED: z.enum(["1", "0"]).optional(),
|
||||
SMTP_HOST: z.string().min(1).optional(),
|
||||
@@ -156,6 +157,7 @@ export const env = createEnv({
|
||||
S3_BUCKET_NAME: process.env.S3_BUCKET_NAME,
|
||||
S3_REGION: process.env.S3_REGION,
|
||||
S3_SECRET_KEY: process.env.S3_SECRET_KEY,
|
||||
S3_ENDPOINT_URL: process.env.S3_ENDPOINT_URL,
|
||||
SHORT_URL_BASE: process.env.SHORT_URL_BASE,
|
||||
SIGNUP_DISABLED: process.env.SIGNUP_DISABLED,
|
||||
SMTP_HOST: process.env.SMTP_HOST,
|
||||
|
||||
@@ -20,8 +20,11 @@ import { TAccessType } from "@formbricks/types/storage";
|
||||
import {
|
||||
IS_S3_CONFIGURED,
|
||||
MAX_SIZES,
|
||||
S3_ACCESS_KEY,
|
||||
S3_BUCKET_NAME,
|
||||
S3_ENDPOINT_URL,
|
||||
S3_REGION,
|
||||
S3_SECRET_KEY,
|
||||
UPLOADS_DIR,
|
||||
WEBAPP_URL,
|
||||
} from "../constants";
|
||||
@@ -30,14 +33,21 @@ import { env } from "../env";
|
||||
import { storageCache } from "./cache";
|
||||
|
||||
// S3Client Singleton
|
||||
let s3ClientInstance: S3Client | null = null;
|
||||
|
||||
export const s3Client = new S3Client({
|
||||
credentials: {
|
||||
accessKeyId: env.S3_ACCESS_KEY!,
|
||||
secretAccessKey: env.S3_SECRET_KEY!,
|
||||
},
|
||||
region: S3_REGION!,
|
||||
});
|
||||
export const getS3Client = () => {
|
||||
if (!s3ClientInstance) {
|
||||
s3ClientInstance = new S3Client({
|
||||
credentials: {
|
||||
accessKeyId: S3_ACCESS_KEY!,
|
||||
secretAccessKey: S3_SECRET_KEY!,
|
||||
},
|
||||
region: S3_REGION,
|
||||
endpoint: S3_ENDPOINT_URL,
|
||||
});
|
||||
}
|
||||
return s3ClientInstance;
|
||||
};
|
||||
|
||||
const ensureDirectoryExists = async (dirPath: string) => {
|
||||
try {
|
||||
@@ -85,6 +95,7 @@ const getS3SignedUrl = async (fileKey: string): Promise<string> => {
|
||||
});
|
||||
|
||||
try {
|
||||
const s3Client = getS3Client();
|
||||
return await getSignedUrl(s3Client, getObjectCommand, { expiresIn });
|
||||
} catch (err) {
|
||||
throw err;
|
||||
@@ -239,6 +250,7 @@ export const getS3UploadSignedUrl = async (
|
||||
const postConditions: PresignedPostOptions["Conditions"] = [["content-length-range", 0, maxSize]];
|
||||
|
||||
try {
|
||||
const s3Client = getS3Client();
|
||||
const { fields, url } = await createPresignedPost(s3Client, {
|
||||
Expires: 10 * 60, // 10 minutes
|
||||
Bucket: env.S3_BUCKET_NAME!,
|
||||
@@ -309,6 +321,7 @@ export const putFile = async (
|
||||
};
|
||||
|
||||
const command = new PutObjectCommand(input);
|
||||
const s3Client = getS3Client();
|
||||
await s3Client.send(command);
|
||||
return { success: true, message: "File uploaded" };
|
||||
}
|
||||
@@ -358,6 +371,7 @@ export const deleteS3File = async (fileKey: string) => {
|
||||
});
|
||||
|
||||
try {
|
||||
const s3Client = getS3Client();
|
||||
await s3Client.send(deleteObjectCommand);
|
||||
} catch (err) {
|
||||
throw err;
|
||||
@@ -367,6 +381,7 @@ export const deleteS3File = async (fileKey: string) => {
|
||||
export const deleteS3FilesByEnvironmentId = async (environmentId: string) => {
|
||||
try {
|
||||
// List all objects in the bucket with the prefix of environmentId
|
||||
const s3Client = getS3Client();
|
||||
const listObjectsOutput = await s3Client.send(
|
||||
new ListObjectsCommand({
|
||||
Bucket: S3_BUCKET_NAME,
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"S3_SECRET_KEY",
|
||||
"S3_REGION",
|
||||
"S3_BUCKET_NAME",
|
||||
"S3_ENDPOINT_URL",
|
||||
"SENTRY_DSN",
|
||||
"SHORT_URL_BASE",
|
||||
"SIGNUP_DISABLED",
|
||||
|
||||
Reference in New Issue
Block a user