-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #932 from CodeForAfrica/ft/climatemappedafrica-pay…
…load-setup ClimateMapped Payload Setup
- Loading branch information
Showing
22 changed files
with
939 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import { buildConfig } from "payload/config"; | ||
import { loadEnvConfig } from "@next/env"; | ||
import { cloudStorage } from "@payloadcms/plugin-cloud-storage"; | ||
import { s3Adapter } from "@payloadcms/plugin-cloud-storage/s3"; | ||
import { slateEditor } from "@payloadcms/richtext-slate"; | ||
import { mongooseAdapter } from "@payloadcms/db-mongodb"; | ||
import { webpackBundler } from "@payloadcms/bundler-webpack"; | ||
import { CollectionConfig, GlobalConfig } from "payload/types"; | ||
import nestedDocs from "@payloadcms/plugin-nested-docs"; | ||
import seo from "@payloadcms/plugin-seo"; | ||
import { sentry } from "@payloadcms/plugin-sentry"; | ||
import { defaultLocale, locales } from "./src/payload/utils/locales"; | ||
|
||
import Media from "./src/payload/collections/Media"; | ||
import Pages from "./src/payload/collections/Pages"; | ||
import Users from "./src/payload/collections/Users"; | ||
|
||
const projectDir = process.cwd(); | ||
loadEnvConfig(projectDir); | ||
|
||
const appURL = process.env.PAYLOAD_PUBLIC_APP_URL; | ||
|
||
const cors = | ||
process?.env?.PAYLOAD_CORS?.split(",") | ||
?.map((d) => d.trim()) | ||
?.filter(Boolean) ?? []; | ||
|
||
const csrf = | ||
process?.env?.PAYLOAD_CSRF?.split(",") | ||
?.map((d) => d.trim()) | ||
?.filter(Boolean) ?? []; | ||
|
||
const adapter = s3Adapter({ | ||
config: { | ||
region: process?.env?.S3_REGION, | ||
credentials: { | ||
accessKeyId: process?.env?.S3_ACCESS_KEY_ID, | ||
secretAccessKey: process?.env?.S3_SECRET_ACCESS_KEY, | ||
}, | ||
}, | ||
bucket: process?.env?.S3_BUCKET, | ||
} as any); | ||
|
||
export default buildConfig({ | ||
serverURL: appURL, | ||
editor: slateEditor({}), | ||
routes: { | ||
admin: "/admin", | ||
}, | ||
db: mongooseAdapter({ | ||
url: process.env.MONGO_URL, | ||
migrationDir: process.env.MIGRATIONS_DIR, | ||
}), | ||
collections: [Media, Pages, Users] as CollectionConfig[], | ||
globals: [] as GlobalConfig[], | ||
...(locales?.length | ||
? { | ||
localization: { | ||
locales, | ||
defaultLocale, | ||
fallback: true, | ||
}, | ||
} | ||
: undefined), | ||
admin: { | ||
webpack: (config) => ({ | ||
...config, | ||
resolve: { | ||
...config.resolve, | ||
fallback: { | ||
...config?.resolve?.fallback, | ||
fs: false, | ||
os: false, | ||
"process/browser": false, | ||
}, | ||
}, | ||
}), | ||
bundler: webpackBundler(), | ||
}, | ||
cors, | ||
csrf, | ||
i18n: { | ||
fallbackLng: "en", // default | ||
debug: false, // default | ||
resources: { | ||
en: { | ||
"codeforafrica.validation": { | ||
uniquePlatforms: "Please select a unique platform", | ||
}, | ||
}, | ||
}, | ||
}, | ||
plugins: [ | ||
cloudStorage({ | ||
collections: { | ||
media: { | ||
adapter, | ||
prefix: "media", | ||
}, | ||
}, | ||
}), | ||
sentry({ | ||
dsn: process?.env?.NEXT_PUBLIC_SENTRY_DSN, | ||
}), | ||
seo({ | ||
collections: ["pages"], | ||
globals: ["settings"], | ||
uploadsCollection: "media", | ||
generateTitle: ({ doc }: any) => doc?.title?.value as string, | ||
generateURL: ({ doc }: any) => | ||
doc?.slug?.value ? `${appURL}/${doc.slug.value}` : undefined, | ||
}), | ||
nestedDocs({ | ||
collections: ["pages"], | ||
generateLabel: (_, doc) => doc.title as string, | ||
generateURL: (docs) => | ||
docs.reduce((url, doc) => `${url}/${doc.slug}`, ""), | ||
}), | ||
], | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import path from "path"; | ||
import { spawn } from "child_process"; | ||
import express from "express"; | ||
import next from "next"; | ||
import nodemailerSendgrid from "nodemailer-sendgrid"; | ||
import payload from "payload"; | ||
import { Payload } from "payload/dist/payload"; | ||
import { loadEnvConfig } from "@next/env"; | ||
|
||
const projectDir = process.cwd(); | ||
loadEnvConfig(projectDir); | ||
|
||
const dev = process.env.NODE_ENV !== "production"; | ||
const hostname = process.env.NEXT_HOSTNAME || "localhost"; | ||
const port = parseInt(process.env.PORT || "3000", 10); | ||
const sendGridAPIKey = process.env.SENDGRID_API_KEY; | ||
|
||
if (!process.env.NEXT_MANUAL_SIG_HANDLE) { | ||
process.on("SIGTERM", () => process.exit(0)); | ||
process.on("SIGINT", () => process.exit(0)); | ||
} | ||
|
||
const app = express(); | ||
|
||
const start = async (): Promise<void> => { | ||
let localPayload: Payload; | ||
try { | ||
localPayload = await payload.init({ | ||
...(sendGridAPIKey | ||
? { | ||
email: { | ||
transportOptions: nodemailerSendgrid({ | ||
apiKey: sendGridAPIKey, | ||
}), | ||
fromName: | ||
process.env.SENDGRID_FROM_NAME || "ClimateMapped Africa CMS", | ||
fromAddress: | ||
process.env.SENDGRID_FROM_EMAIL || "[email protected]", | ||
}, | ||
} | ||
: undefined), | ||
secret: process.env.PAYLOAD_SECRET, | ||
express: app, | ||
onInit: (initPayload) => { | ||
initPayload.logger.info(`Payload Admin URL: ${payload.getAdminURL()}`); | ||
}, | ||
}); | ||
} catch (e: any) { | ||
console.error(e); | ||
process.exit(); | ||
} | ||
|
||
if (process.env.NEXT_BUILD) { | ||
app.listen(port, async () => { | ||
localPayload.logger.info("NextJS is now building..."); | ||
const nextBuild = spawn( | ||
"pnpm", | ||
["next", "build", path.resolve(projectDir)], | ||
{ | ||
shell: true, | ||
stdio: "inherit", | ||
}, | ||
); | ||
nextBuild.on("close", (code) => { | ||
process.exit(code); | ||
}); | ||
nextBuild.on("error", (err) => { | ||
localPayload.logger.error(err); | ||
process.exit(1); | ||
}); | ||
}); | ||
|
||
return; | ||
} | ||
|
||
const nextApp = next({ dev, hostname, port }); | ||
const nextHandler = nextApp.getRequestHandler(); | ||
nextApp.prepare().then(() => { | ||
localPayload.logger.info("NextJS started"); | ||
|
||
app.get("*", (req: any, res: any) => nextHandler(req, res)); | ||
app.post("*", (req: any, res: any) => nextHandler(req, res)); | ||
app.put("*", (req: any, res: any) => nextHandler(req, res)); | ||
|
||
app.listen(port, async () => { | ||
localPayload.logger.info( | ||
`Next.js App URL: ${process.env.NEXT_PUBLIC_APP_URL}`, | ||
); | ||
}); | ||
}); | ||
}; | ||
|
||
start(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { ROLE_ADMIN } from "./roles"; | ||
|
||
export const isAdmin = ({ req: { user } }) => { | ||
// Return true or false based on if the user has an admin role | ||
return Boolean(user?.roles?.includes(ROLE_ADMIN)); | ||
}; | ||
|
||
export const isAdminFieldLevel = ({ req: { user } }) => { | ||
// Return true or false based on if the user has an admin role | ||
return Boolean(user?.roles?.includes(ROLE_ADMIN)); | ||
}; |
14 changes: 14 additions & 0 deletions
14
apps/climatemappedafrica/src/payload/access/isAdminOrPublished.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { ROLE_ADMIN } from "./roles"; | ||
|
||
export const isAdminOrPublished = ({ req: { user } }) => { | ||
if (user?.roles?.includes(ROLE_ADMIN)) { | ||
return true; | ||
} | ||
return { | ||
_status: { | ||
equals: "published", | ||
}, | ||
}; | ||
}; | ||
|
||
export default undefined; |
24 changes: 24 additions & 0 deletions
24
apps/climatemappedafrica/src/payload/access/isAdminOrSelf.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { ROLE_ADMIN } from "./roles"; | ||
|
||
export const isAdminOrSelf = ({ req: { user } }) => { | ||
// Need to be logged in | ||
if (user) { | ||
// If user has role of 'admin' | ||
if (user.roles?.includes(ROLE_ADMIN)) { | ||
return true; | ||
} | ||
// If any other type of user, only provide access to themselves | ||
return { | ||
id: { | ||
equals: user.id, | ||
}, | ||
}; | ||
} | ||
|
||
// Reject everyone else | ||
return false; | ||
}; | ||
|
||
export const isAdminOrSelfFieldLevel = ({ id, req: { user } }) => { | ||
return user?.roles?.includes(ROLE_ADMIN) || id === user?.id; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export const ROLE_ADMIN = "admin"; | ||
export const ROLE_EDITOR = "editor"; | ||
export const ROLE_DEFAULT = ROLE_EDITOR; | ||
export const ROLE_OPTIONS = [ | ||
{ label: "Admin", value: ROLE_ADMIN }, | ||
{ label: "Editor", value: ROLE_EDITOR }, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
const Media = { | ||
slug: "media", | ||
admin: { | ||
defaultColumns: ["alt", "updatedAt"], | ||
enableRichTextLink: false, | ||
group: "Publication", | ||
useAsTitle: "alt", | ||
}, | ||
access: { | ||
read: () => true, // Everyone can read Media | ||
}, | ||
upload: { | ||
staticURL: "/media", | ||
staticDir: "media", | ||
}, | ||
fields: [ | ||
{ | ||
name: "alt", | ||
label: "Alt Text", | ||
type: "text", | ||
required: true, | ||
}, | ||
], | ||
hooks: { | ||
afterRead: [({ doc }) => ({ ...doc, src: doc.url })], | ||
}, | ||
}; | ||
|
||
export default Media; |
Oops, something went wrong.