feat(media): default to s3 with local upload fallback
This commit is contained in:
@@ -10,11 +10,11 @@ CMS_SUPPORT_EMAIL="support@cms.local"
|
|||||||
CMS_SUPPORT_PASSWORD="change-me-support-password"
|
CMS_SUPPORT_PASSWORD="change-me-support-password"
|
||||||
CMS_SUPPORT_NAME="Technical Support"
|
CMS_SUPPORT_NAME="Technical Support"
|
||||||
CMS_SUPPORT_LOGIN_KEY="support-access-change-me"
|
CMS_SUPPORT_LOGIN_KEY="support-access-change-me"
|
||||||
CMS_MEDIA_STORAGE_PROVIDER="local"
|
CMS_MEDIA_STORAGE_PROVIDER="s3"
|
||||||
CMS_MEDIA_UPLOAD_MAX_BYTES="26214400"
|
CMS_MEDIA_UPLOAD_MAX_BYTES="26214400"
|
||||||
# Optional: override local media storage directory for admin upload adapter.
|
# Optional: override local media storage directory for admin upload adapter.
|
||||||
# CMS_MEDIA_LOCAL_STORAGE_DIR="/absolute/path/to/media-storage"
|
# CMS_MEDIA_LOCAL_STORAGE_DIR="/absolute/path/to/media-storage"
|
||||||
# S3/object-storage config (required when CMS_MEDIA_STORAGE_PROVIDER="s3").
|
# S3/object-storage config (default provider). If unavailable, upload falls back to local storage.
|
||||||
# CMS_MEDIA_S3_BUCKET="cms-media"
|
# CMS_MEDIA_S3_BUCKET="cms-media"
|
||||||
# CMS_MEDIA_S3_REGION="eu-central-1"
|
# CMS_MEDIA_S3_REGION="eu-central-1"
|
||||||
# CMS_MEDIA_S3_ACCESS_KEY_ID=""
|
# CMS_MEDIA_S3_ACCESS_KEY_ID=""
|
||||||
|
|||||||
@@ -81,7 +81,8 @@ export default async function MediaManagementPage({
|
|||||||
<h2 className="text-xl font-medium">Upload Media Asset</h2>
|
<h2 className="text-xl font-medium">Upload Media Asset</h2>
|
||||||
<p className="mt-1 text-sm text-neutral-600">
|
<p className="mt-1 text-sm text-neutral-600">
|
||||||
Upload storage provider: <strong>{activeStorageProvider}</strong>. You can switch via
|
Upload storage provider: <strong>{activeStorageProvider}</strong>. You can switch via
|
||||||
`CMS_MEDIA_STORAGE_PROVIDER` (`local` or `s3`) until the admin settings toggle lands.
|
`CMS_MEDIA_STORAGE_PROVIDER` (`s3` default, `local` fallback) until the admin settings
|
||||||
|
toggle lands.
|
||||||
</p>
|
</p>
|
||||||
<MediaUploadForm />
|
<MediaUploadForm />
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import { describe, expect, it } from "vitest"
|
|||||||
import { resolveMediaStorageProvider } from "@/lib/media/storage"
|
import { resolveMediaStorageProvider } from "@/lib/media/storage"
|
||||||
|
|
||||||
describe("resolveMediaStorageProvider", () => {
|
describe("resolveMediaStorageProvider", () => {
|
||||||
it("defaults to local when unset", () => {
|
it("defaults to s3 when unset", () => {
|
||||||
expect(resolveMediaStorageProvider(undefined)).toBe("local")
|
expect(resolveMediaStorageProvider(undefined)).toBe("s3")
|
||||||
})
|
})
|
||||||
|
|
||||||
it("resolves s3", () => {
|
it("resolves s3", () => {
|
||||||
@@ -12,7 +12,12 @@ describe("resolveMediaStorageProvider", () => {
|
|||||||
expect(resolveMediaStorageProvider("S3")).toBe("s3")
|
expect(resolveMediaStorageProvider("S3")).toBe("s3")
|
||||||
})
|
})
|
||||||
|
|
||||||
it("falls back to local for unknown values", () => {
|
it("resolves local explicitly", () => {
|
||||||
expect(resolveMediaStorageProvider("foo")).toBe("local")
|
expect(resolveMediaStorageProvider("local")).toBe("local")
|
||||||
|
expect(resolveMediaStorageProvider("LOCAL")).toBe("local")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("falls back to s3 for unknown values", () => {
|
||||||
|
expect(resolveMediaStorageProvider("foo")).toBe("s3")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -14,21 +14,29 @@ type StoredUpload = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function resolveMediaStorageProvider(raw: string | undefined): MediaStorageProvider {
|
export function resolveMediaStorageProvider(raw: string | undefined): MediaStorageProvider {
|
||||||
if (raw?.toLowerCase() === "s3") {
|
if (raw?.toLowerCase() === "local") {
|
||||||
return "s3"
|
return "local"
|
||||||
}
|
}
|
||||||
|
|
||||||
return "local"
|
return "s3"
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function storeUpload(params: StoreUploadParams): Promise<StoredUpload> {
|
export async function storeUpload(params: StoreUploadParams): Promise<StoredUpload> {
|
||||||
const provider = resolveMediaStorageProvider(process.env.CMS_MEDIA_STORAGE_PROVIDER)
|
const provider = resolveMediaStorageProvider(process.env.CMS_MEDIA_STORAGE_PROVIDER)
|
||||||
|
|
||||||
if (provider === "s3") {
|
if (provider === "s3") {
|
||||||
const stored = await storeUploadToS3(params)
|
try {
|
||||||
return {
|
const stored = await storeUploadToS3(params)
|
||||||
...stored,
|
return {
|
||||||
provider,
|
...stored,
|
||||||
|
provider,
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
const fallbackStored = await storeUploadLocally(params)
|
||||||
|
return {
|
||||||
|
...fallbackStored,
|
||||||
|
provider: "local",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user