Skip to content

Commit

Permalink
add GitHub storage adapters (#57)
Browse files Browse the repository at this point in the history
Why:
- the deployment was attempting to store/fetch data locally which isn't
a possibility in the current setup, implicating the need to setup cloud
storage;

How:
- to address the issue a new payload-compatible storage adpater has been
created to enable this build as a git-based CMS using
[Octokit](https://octokit.github.io/rest.js/v21/) to manage files;
  • Loading branch information
rccsousa authored Oct 16, 2024
1 parent d0c6fd5 commit 5b1e25d
Show file tree
Hide file tree
Showing 20 changed files with 307 additions and 30 deletions.
4 changes: 2 additions & 2 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { withPayload } from '@payloadcms/next/withPayload'
import redirects from './redirects.js'

const NEXT_PUBLIC_SERVER_URL = process.env.NEXT_PUBLIC_SERVER_URL || 'http://localhost:3000'
const CDN_DOMAIN = process.env.CDN_DOMAIN || 'http://localhost:3000'

/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
...[NEXT_PUBLIC_SERVER_URL /* 'https://example.com' */].map((item) => {
...[CDN_DOMAIN /* 'https://example.com' */].map((item) => {
const url = new URL(item)

return {
hostname: url.hostname,
protocol: url.protocol.replace(':', ''),
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@
"@lexical/selection": "0.18.0",
"@lexical/table": "0.18.0",
"@lexical/utils": "0.18.0",
"@octokit/rest": "^21.0.2",
"@payloadcms/db-mongodb": "beta",
"@payloadcms/live-preview-react": "beta",
"@payloadcms/next": "beta",
"@payloadcms/plugin-cloud": "beta",
"@payloadcms/plugin-cloud-storage": "3.0.0-beta.111",
"@payloadcms/plugin-form-builder": "beta",
"@payloadcms/plugin-nested-docs": "beta",
"@payloadcms/plugin-redirects": "beta",
Expand Down
Empty file.
Empty file removed public/media/john-doe.jpg
Empty file.
Empty file.
Empty file.
Binary file removed public/media/subscribe-card-image.png
Binary file not shown.
2 changes: 0 additions & 2 deletions src/app/(pages)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,3 @@ export const dynamic = 'auto'
export const revalidate = 10

export default PageTemplate

// export { generateMetadata }
3 changes: 1 addition & 2 deletions src/app/_blocks/BlogpostContent/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";

import { Blogpost } from "@/payload-types";
import FeaturedImage from "../../_components/FeaturedImage";
import styles from "./styles.module.css";
import RichText from "@/components/RichText";
Expand All @@ -10,7 +9,7 @@ export default function BlogpostContent({ blogpost }) {
return (
<div className={styles.container}>
<div className={styles.featuredImage}>
{featuredImage && <FeaturedImage src={featuredImage} />}
{featuredImage && <FeaturedImage src={featuredImage.url} />}
</div>
<div className={styles.summary}>{summary}</div>
<RichText content={blogpost.content} />
Expand Down
9 changes: 5 additions & 4 deletions src/app/_blocks/EpisodeHead/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ export default function EpisodeHead({ episode }) {
// TODO: convert into conditional logic based on ContentType

// Initial undefined state
const { audioFileSource, audioFileType } = getAudio(episodeFile)
// const { audioFileSource, audioFileType } = getAudio(episodeFile)

return (
<div className={styles.container}>
{/*{<pre>{JSON.stringify(episode.episodeFile, null, 2)}</pre>}*/}
<BackButton className={styles.backButton} color={'var(--soft-white-100)'} />

<div className={styles.metadataContainer}>
Expand All @@ -40,12 +41,12 @@ export default function EpisodeHead({ episode }) {
{/* TODO Add conditionals later on: render only if it's a podcast episode */}
<div className={styles.audioPlayer}>
{/*// @ts-ignore*/}
<AudioPlayer src={audioFileSource} type={audioFileType} />
<AudioPlayer src={episode.episodeFile.url} type={episode.episodeFile.mimeType} />
</div>

{/* TODO: Second Column displays EpisodeFeaturedImage if ContentType is podcast */}
<div className={styles.featuredImageContainer}>
{featuredImage && <FeaturedImage className={styles.featuredImage} src={featuredImage} />}
<div className={styles.featuredImage}>
{featuredImage && <FeaturedImage className={styles.featuredImage} src={featuredImage.url} />}
</div>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/app/_blocks/EpisodeHead/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
}

.featuredImage {
position: relative;
width: max(120px, 294px);
aspect-ratio: 1 / 1;
border-radius: 10px;
Expand Down
2 changes: 1 addition & 1 deletion src/app/_components/AuthorPill/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const dynamicVars = {
<>
<div className={styles.authorPill}>
<div className={styles.authorImage}>
{featuredImage && <FeaturedImage src={featuredImage} />}
{featuredImage && <FeaturedImage src={featuredImage.url} />}
</div>
{name}
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/app/_components/AuthorSummary/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default function AuthorSummary({ author }) {
return (
<div className={styles.gridContainer}>
<div className={styles.authorInfoCard}>
{featuredImage && <FeaturedImage className={styles.featuredImage} src={featuredImage} />}
{featuredImage && <FeaturedImage className={styles.featuredImage} src={featuredImage.url} />}
<div className={styles.authorInfo}>
<h5>{name}</h5>
<p>{role}</p>
Expand Down
2 changes: 1 addition & 1 deletion src/app/_components/ContentCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export default function ContentCard({ contentType, content }: ContentSummaryProp
<div className={styles.contentMetaContainer}>
<div className={styles.imageContainer}>
{/* @ts-ignore */}
{featuredImage && <FeaturedImage src={featuredImage} />}
{featuredImage && <FeaturedImage src={featuredImage.url} />}
</div>
{/*<ArchiveButton collection={archiveMap[contentType]} />*/}
<h6>{title} </h6>
Expand Down
12 changes: 3 additions & 9 deletions src/app/_components/FeaturedImage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
import Image from "next/image";

import { getImage } from "../../_utilities/getImage";
import styles from "./styles.module.css";

import { Media } from "@/payload-types";
import { fetchMediaByID } from "@/app/_utilities/contentFetchers";

export default function FeaturedImage({ src, className }: { className?: string; src: Media }) {


const imageSource = getImage(src);


return (

<Image fill={true}
className={className ? className : styles.featuredImage}
src={imageSource} alt={"alt info"}
// @ts-ignore
src={src}
alt={"alt info"}

/>

Expand Down
5 changes: 1 addition & 4 deletions src/collections/Media/Media.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,5 @@ export const Media: CollectionConfig = {
}),
},
],
upload: {
// Upload to the public/media directory in Next.js making them publicly accessible even outside of Payload
staticDir: path.resolve(dirname, '../../public/media'),
},
upload: true,
}
69 changes: 69 additions & 0 deletions src/collections/Media/storageAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { GeneratedAdapter } from "@payloadcms/plugin-cloud-storage/types";
import { Octokit } from "@octokit/rest";

const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN,
});

const owner = process.env.GITHUB_REPO_OWNER;
const repo = process.env.GITHUB_REPO;
const comitter = {
name: "payload admin dashboard",
email: "[email protected]",
};


export const testAdapt = ({ collection, prefix }): GeneratedAdapter => {
return {
name: "Test",
handleUpload: async (args) => {
// @ts-ignore
const buffer = Buffer.from(args.file.buffer, "base64");
const base64Buffer = buffer.toString("base64");
await octokit.repos.createOrUpdateFileContents({
// @ts-ignore
owner: owner,
// @ts-ignore
repo: repo,
path: `public/media/${args.file.filename}`,
message: "Uploaded a new file via Octokit",
content: base64Buffer,
committer: comitter,
author: comitter,
});


},
// @ts-ignore
handleDelete: async (args) => {


const { data: fileData } = await octokit.rest.repos.getContent({
// @ts-ignore
owner: owner,
// @ts-ignore
repo: repo,
path: `public/media/${args.filename}`,
});


await octokit.rest.repos.deleteFile({
// @ts-ignore
owner: owner,
// @ts-ignore
repo: repo,
// @ts-ignore
path: `public/media/${args.filename}`,
// @ts-ignore
message: `Deleted file via Octokit`,
// @ts-ignore
sha: fileData.sha,
});
},
// @ts-ignore
staticHandler: async (req) => {
},

};

};
2 changes: 0 additions & 2 deletions src/endpoints/seed/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,6 @@ export const seed = async ({
req,
})

console.log({ pages })

payload.logger.info(`— Seeding demo author and user...`)

await payload.delete({
Expand Down
17 changes: 16 additions & 1 deletion src/payload.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import { CaseStudies } from "@/collections/CaseStudies";
import { Podcasts } from "@/collections/Podcasts/Podcasts";
import { TalksAndRoundtables } from "@/collections/TalksAndRoundtables";
import { HomePageSettings } from "@/Globals/HubHighlights/config";
import { cloudStoragePlugin } from "@payloadcms/plugin-cloud-storage";
import { testAdapt } from "@/collections/Media/storageAdapter";

const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
Expand Down Expand Up @@ -205,7 +207,20 @@ export default buildConfig({
},
},
}),
payloadCloudPlugin(), // storage-adapter-placeholder
cloudStoragePlugin({
enabled: true,
collections: {
media: {
disableLocalStorage: true,
adapter: testAdapt,
generateFileURL: (args) => {
const url = `${process.env.CDN_DOMAIN}/${args.filename}`
return url
}
}
}

}),// storage-adapter-placeholder
],
secret: process.env.PAYLOAD_SECRET!,
sharp,
Expand Down
Loading

0 comments on commit 5b1e25d

Please sign in to comment.