Use public get urls for hack cover images

This commit is contained in:
Jared Schoeny
2025-12-15 16:30:24 -10:00
parent 3888e9e26d
commit 0b355fd93c
7 changed files with 40 additions and 31 deletions

View File

@@ -3,7 +3,7 @@ import HackForm from "@/components/Hack/HackForm";
import { createClient } from "@/utils/supabase/server";
import { FaChevronLeft, FaChevronRight } from "react-icons/fa6";
import Link from "next/link";
import { getCoverSignedUrls } from "@/app/hack/actions";
import { getCoverUrls } from "@/utils/format";
import { checkEditPermission } from "@/utils/hack";
interface EditPageProps {
@@ -42,7 +42,7 @@ export default async function EditHackPage({ params }: EditPageProps) {
.order("position", { ascending: true });
if (covers && covers.length > 0) {
coverKeys = covers.map((c: any) => c.url);
signedCoverUrls = await getCoverSignedUrls(coverKeys);
signedCoverUrls = getCoverUrls(coverKeys);
}
const { data: tagRows } = await supabase

View File

@@ -18,9 +18,8 @@ import serialize from "serialize-javascript";
import { headers } from "next/headers";
import { MenuItem } from "@headlessui/react";
import { FaCircleCheck } from "react-icons/fa6";
import { sortOrderedTags } from "@/utils/format";
import { sortOrderedTags, getCoverUrls } from "@/utils/format";
import { RiArchiveStackFill } from "react-icons/ri";
import { getCoverSignedUrls } from "@/app/hack/actions";
import { isInformationalArchiveHack, isDownloadableArchiveHack, isArchiveHack, checkEditPermission } from "@/utils/hack";
import Avatar from "@/components/Account/Avatar";
@@ -132,7 +131,7 @@ export default async function HackDetail({ params }: HackDetailProps) {
.eq("hack_slug", slug)
.order("position", { ascending: true });
if (covers && covers.length > 0) {
images = await getCoverSignedUrls(covers.map(c => c.url));
images = getCoverUrls(covers.map(c => c.url));
}
const { data: tagRows } = await supabase

View File

@@ -265,21 +265,6 @@ export async function presignCoverUpload(args: { slug: string; objectKey: string
return { ok: true, presignedUrl: url } as const;
}
export async function getCoverSignedUrl(objectKey: string) {
const client = getMinioClient();
// 5 minutes expiry for viewing
const url = await client.presignedGetObject(COVERS_BUCKET, objectKey, 60 * 5);
return url;
}
export async function getCoverSignedUrls(objectKeys: string[]) {
const client = getMinioClient();
// 5 minutes expiry for viewing
const urls = await Promise.all(
objectKeys.map(key => client.presignedGetObject(COVERS_BUCKET, key, 60 * 5))
);
return urls;
}
export async function approveHack(slug: string) {
const supabase = await createClient();

View File

@@ -4,8 +4,7 @@ import { FaArrowRightLong } from "react-icons/fa6";
import { createClient } from "@/utils/supabase/server";
import HackCard from "@/components/HackCard";
import Button from "@/components/Button";
import { sortOrderedTags } from "@/utils/format";
import { getCoverSignedUrls } from "@/app/hack/actions";
import { sortOrderedTags, getCoverUrls } from "@/utils/format";
import { HackCardAttributes } from "@/components/HackCard";
export const metadata: Metadata = {
@@ -42,7 +41,7 @@ export default async function Home() {
const coversBySlug = new Map<string, string[]>();
if (coverRows && coverRows.length > 0) { const coverKeys = coverRows.map((c) => c.url);
const signedUrls = await getCoverSignedUrls(coverKeys);
const signedUrls = getCoverUrls(coverKeys);
const urlToSignedUrl = new Map<string, string>();
coverKeys.forEach((key, idx) => {
urlToSignedUrl.set(key, signedUrls[idx]);

View File

@@ -11,8 +11,7 @@ import { MdTune } from "react-icons/md";
import { BsSdCardFill } from "react-icons/bs";
import { CATEGORY_ICONS } from "@/components/Icons/tagCategories";
import { useBaseRoms } from "@/contexts/BaseRomContext";
import { sortOrderedTags, OrderedTag } from "@/utils/format";
import { getCoverSignedUrls } from "@/app/hack/actions";
import { sortOrderedTags, OrderedTag, getCoverUrls } from "@/utils/format";
import { HackCardAttributes } from "@/components/HackCard";
const HACKS_PER_PAGE = 9;
@@ -82,7 +81,7 @@ export default function DiscoverBrowser() {
const coversBySlug = new Map<string, string[]>();
if (coverRows && coverRows.length > 0) {
const coverKeys = coverRows.map(c => c.url);
const urls = await getCoverSignedUrls(coverKeys);
const urls = getCoverUrls(coverKeys);
// Map: storage object url -> signedUrl
const urlToSignedUrl = new Map<string, string>();
coverKeys.forEach((key, idx) => {

View File

@@ -31,3 +31,25 @@ export function slugify(text: string) {
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "");
}
/**
* Get the public URL for a single cover image
*/
export function getCoverUrl(objectKey: string): string {
const domain = process.env.NEXT_PUBLIC_HACK_COVERS_DOMAIN;
if (!domain) {
throw new Error("NEXT_PUBLIC_HACK_COVERS_DOMAIN environment variable is not set");
}
return `${domain}/${objectKey}`;
}
/**
* Get public URLs for multiple cover images
*/
export function getCoverUrls(objectKeys: string[]): string[] {
const domain = process.env.NEXT_PUBLIC_HACK_COVERS_DOMAIN;
if (!domain) {
throw new Error("NEXT_PUBLIC_HACK_COVERS_DOMAIN environment variable is not set");
}
return objectKeys.map(key => `${domain}/${key}`);
}