All checks were successful
Build and Push Docker Image / build (push) Successful in 8m31s
Add error logging to silent catch blocks in avatar/logo URL generation, show user avatar on admin member detail page, and surface specific error messages for upload failures (CORS/network issues) instead of generic errors. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
37 lines
1.1 KiB
TypeScript
37 lines
1.1 KiB
TypeScript
import { createStorageProvider, type StorageProviderType } from '@/lib/storage'
|
|
|
|
/**
|
|
* Generate a pre-signed download URL for a project logo.
|
|
* Returns null if the project has no logo.
|
|
*/
|
|
export async function getProjectLogoUrl(
|
|
logoKey: string | null | undefined,
|
|
logoProvider: string | null | undefined
|
|
): Promise<string | null> {
|
|
if (!logoKey) return null
|
|
|
|
try {
|
|
const providerType = (logoProvider as StorageProviderType) || 's3'
|
|
const provider = createStorageProvider(providerType)
|
|
return await provider.getDownloadUrl(logoKey)
|
|
} catch (error) {
|
|
console.error('[LogoURL] Failed to generate URL for key:', logoKey, error)
|
|
return null
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Batch-generate logo URLs for multiple projects.
|
|
* Adds `logoUrl` field to each project object.
|
|
*/
|
|
export async function attachProjectLogoUrls<
|
|
T extends { logoKey?: string | null; logoProvider?: string | null }
|
|
>(projects: T[]): Promise<(T & { logoUrl: string | null })[]> {
|
|
return Promise.all(
|
|
projects.map(async (project) => ({
|
|
...project,
|
|
logoUrl: await getProjectLogoUrl(project.logoKey, project.logoProvider),
|
|
}))
|
|
)
|
|
}
|