Make storage reporting more granular

This commit is contained in:
Sam Becker 2023-11-28 17:53:02 -06:00
parent 5cdb726566
commit 2b9c0cbbe2
4 changed files with 44 additions and 23 deletions

View File

@ -18,16 +18,10 @@ const S3_ADMIN_ACCESS_KEY =
const S3_ADMIN_SECRET_ACCESS_KEY =
process.env.S3_ADMIN_SECRET_ACCESS_KEY;
export const HAS_AWS_S3_STORAGE =
S3_BUCKET.length > 0 &&
S3_REGION.length > 0 &&
S3_UPLOAD_ACCESS_KEY.length > 0 &&
S3_UPLOAD_SECRET_ACCESS_KEY.length > 0;
const client = () => new S3Client({
region: S3_REGION,
credentials: {
// Fall back on upload credentials if admin credentials are not available
// Fall back on upload credentials when admin credentials aren't available
accessKeyId: S3_ADMIN_ACCESS_KEY ?? S3_UPLOAD_ACCESS_KEY,
secretAccessKey: S3_ADMIN_SECRET_ACCESS_KEY ?? S3_UPLOAD_SECRET_ACCESS_KEY,
},

View File

@ -7,13 +7,13 @@ import {
} from './vercel-blob';
import {
AWS_S3_BASE_URL,
HAS_AWS_S3_STORAGE,
awsS3Copy,
awsS3Delete,
awsS3List,
awsS3UploadFromClient,
isUrlFromAwsS3,
} from './aws-s3';
import { HAS_AWS_S3_STORAGE_CLIENT, HAS_AWS_S3_STORAGE } from '@/site/config';
const PREFIX_UPLOAD = 'upload';
const PREFIX_PHOTO = 'photo';
@ -47,7 +47,7 @@ const getFileNameFromBlobUrl = (url: string) =>
export const uploadPhotoFromClient = async (
file: File | Blob,
extension = 'jpg',
) => HAS_AWS_S3_STORAGE
) => HAS_AWS_S3_STORAGE_CLIENT
? awsS3UploadFromClient(file, PREFIX_UPLOAD, extension, true)
: vercelBlobUploadFromClient(file, `${PREFIX_UPLOAD}.${extension}`);
@ -59,12 +59,14 @@ export const convertUploadToPhoto = async (
const fileExtension = getExtensionFromBlobUrl(uploadUrl);
const photoUrl = `${fileName}.${fileExtension ?? 'jpg'}`;
const url = await (HAS_AWS_S3_STORAGE
const useAwsS3 = HAS_AWS_S3_STORAGE && isUrlFromAwsS3(uploadUrl);
const url = await (useAwsS3
? awsS3Copy(uploadUrl, photoUrl, photoId === undefined)
: vercelBlobCopy(uploadUrl, photoUrl, photoId === undefined));
if (url) {
await (HAS_AWS_S3_STORAGE
await (useAwsS3
? awsS3Delete(getFileNameFromBlobUrl(uploadUrl))
: vercelBlobDelete(uploadUrl));
}

View File

@ -1,6 +1,6 @@
'use client';
import { useTransition } from 'react';
import { ComponentProps, ReactNode, useTransition } from 'react';
import { useRouter } from 'next/navigation';
import { cc } from '@/utility/css';
import ChecklistRow from '../components/ChecklistRow';
@ -18,10 +18,13 @@ import InfoBlock from '@/components/InfoBlock';
import Checklist from '@/components/Checklist';
import { toastSuccess } from '@/toast';
import { ConfigChecklistStatus } from './config';
import StatusIcon from '@/components/StatusIcon';
export default function SiteChecklistClient({
hasPostgres,
hasBlob,
hasVercelBlob,
hasAwsS3Storage,
hasAuth,
hasAdminUser,
hasTitle,
@ -102,6 +105,17 @@ export default function SiteChecklistClient({
{variables.map(renderEnvVar)}
</div>;
const renderSubStatus = (
type: ComponentProps<typeof StatusIcon>['type'],
label: ReactNode,
) =>
<div className="flex gap-1.5">
<StatusIcon {...{ type }} />
<span>
{label}
</span>
</div>;
return (
<div className="text-sm max-w-xl space-y-6 w-full">
<Checklist
@ -125,8 +139,9 @@ export default function SiteChecklistClient({
status={hasBlob}
isPending={isPendingPage}
>
<ol className="list-decimal list-inside">
<li>
{renderSubStatus(
hasVercelBlob ? 'checked' : 'optional',
<>
Vercel Blob:
{' '}
{renderLink(
@ -135,16 +150,19 @@ export default function SiteChecklistClient({
)}
{' '}
and connect to project
</li>
<li>
</>,
)}
{renderSubStatus(
hasAwsS3Storage ? 'checked' : 'optional',
<>
AWS S3:
{' '}
{renderLink(
'https://github.com/sambecker/exif-photo-blog#aws-s3',
'create/configure bucket',
)}
</li>
</ol>
</>
)}
</ChecklistRow>
</Checklist>
<Checklist

View File

@ -30,14 +30,19 @@ export const BASE_URL = process.env.NODE_ENV === 'production'
? makeUrlAbsolute(SITE_DOMAIN).toLowerCase()
: 'http://localhost:3000';
// STORAGE
// STORAGE: VERCEL BLOB
export const HAS_VERCEL_BLOB =
(process.env.BLOB_READ_WRITE_TOKEN ?? '').length > 0;
const hasVercelBlob = (process.env.BLOB_READ_WRITE_TOKEN ?? '').length > 0;
const hasAwsS3Storage =
// STORAGE: AWS S3
// Includes separate check for client-side usage, i.e., uploading,
export const HAS_AWS_S3_STORAGE_CLIENT =
(process.env.NEXT_PUBLIC_S3_BUCKET ?? '').length > 0 &&
(process.env.NEXT_PUBLIC_S3_REGION ?? '').length > 0 &&
(process.env.NEXT_PUBLIC_S3_UPLOAD_ACCESS_KEY ?? '').length > 0 &&
(process.env.NEXT_PUBLIC_S3_UPLOAD_SECRET_ACCESS_KEY ?? '').length > 0 &&
(process.env.NEXT_PUBLIC_S3_UPLOAD_SECRET_ACCESS_KEY ?? '').length > 0;
export const HAS_AWS_S3_STORAGE =
HAS_AWS_S3_STORAGE_CLIENT &&
(process.env.S3_ADMIN_ACCESS_KEY ?? '').length > 0 &&
(process.env.S3_ADMIN_SECRET_ACCESS_KEY ?? '').length > 0;
@ -54,7 +59,9 @@ export const OG_TEXT_BOTTOM_ALIGNMENT =
export const CONFIG_CHECKLIST_STATUS = {
hasPostgres: (process.env.POSTGRES_HOST ?? '').length > 0,
hasBlob: hasVercelBlob || hasAwsS3Storage,
hasBlob: HAS_VERCEL_BLOB || HAS_AWS_S3_STORAGE,
hasVercelBlob: HAS_VERCEL_BLOB,
hasAwsS3Storage: HAS_AWS_S3_STORAGE,
hasAuth: (process.env.AUTH_SECRET ?? '').length > 0,
hasAdminUser: (
(process.env.ADMIN_EMAIL ?? '').length > 0 &&