Fix/alpha/int tests (#5311)
* chore: converts dynamic imports to esm require * chore: adjusts require and import usage * chore: reverts bin script change * chore: adjust dataloaded tests to use slate editor * fix: converts custom auth strategy * chore: fixes to form builder int test config * chore: adjusts plugin-stripe and int tests --------- Co-authored-by: Jarrod Flesch <jarrodmflesch@gmail.com>
This commit is contained in:
@@ -1,32 +0,0 @@
|
||||
import type { Config } from 'payload/config'
|
||||
import type { Configuration as WebpackConfig } from 'webpack'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
export const extendWebpackConfig =
|
||||
(config: Config): ((webpackConfig: WebpackConfig) => WebpackConfig) =>
|
||||
(webpackConfig) => {
|
||||
const existingWebpackConfig =
|
||||
typeof config.admin?.webpack === 'function'
|
||||
? config.admin.webpack(webpackConfig)
|
||||
: webpackConfig
|
||||
|
||||
const mockModulePath = path.resolve(__dirname, './mocks/mockFile.js')
|
||||
|
||||
return {
|
||||
...existingWebpackConfig,
|
||||
resolve: {
|
||||
...(existingWebpackConfig.resolve || {}),
|
||||
alias: {
|
||||
...(existingWebpackConfig.resolve?.alias ? existingWebpackConfig.resolve.alias : {}),
|
||||
'@payloadcms/plugin-stripe': path.resolve(__dirname, './admin.js'),
|
||||
express: mockModulePath,
|
||||
[path.resolve(__dirname, './hooks/createNewInStripe')]: mockModulePath,
|
||||
[path.resolve(__dirname, './hooks/deleteFromStripe')]: mockModulePath,
|
||||
[path.resolve(__dirname, './hooks/syncExistingWithStripe')]: mockModulePath,
|
||||
[path.resolve(__dirname, './routes/rest')]: mockModulePath,
|
||||
[path.resolve(__dirname, './routes/webhooks')]: mockModulePath,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,13 @@
|
||||
import type { NextFunction, Response } from 'express'
|
||||
import type { Config, Endpoint } from 'payload/config'
|
||||
import type { PayloadRequest } from 'payload/types'
|
||||
|
||||
import express from 'express'
|
||||
import type { SanitizedStripeConfig, StripeConfig } from './types.js'
|
||||
|
||||
import type { SanitizedStripeConfig, StripeConfig } from './types'
|
||||
|
||||
import { extendWebpackConfig } from './extendWebpackConfig'
|
||||
import { getFields } from './fields/getFields'
|
||||
import { createNewInStripe } from './hooks/createNewInStripe'
|
||||
import { deleteFromStripe } from './hooks/deleteFromStripe'
|
||||
import { syncExistingWithStripe } from './hooks/syncExistingWithStripe'
|
||||
import { stripeREST } from './routes/rest'
|
||||
import { stripeWebhooks } from './routes/webhooks'
|
||||
import { getFields } from './fields/getFields.js'
|
||||
import { createNewInStripe } from './hooks/createNewInStripe.js'
|
||||
import { deleteFromStripe } from './hooks/deleteFromStripe.js'
|
||||
import { syncExistingWithStripe } from './hooks/syncExistingWithStripe.js'
|
||||
import { stripeREST } from './routes/rest.js'
|
||||
import { stripeWebhooks } from './routes/webhooks.js'
|
||||
|
||||
const stripePlugin =
|
||||
(incomingStripeConfig: StripeConfig) =>
|
||||
@@ -31,12 +26,40 @@ const stripePlugin =
|
||||
// unfortunately we must set the 'isTestKey' property on the config instead of using the following code:
|
||||
// const isTestKey = stripeConfig.stripeSecretKey?.startsWith('sk_test_');
|
||||
|
||||
const endpoints: Endpoint[] = [
|
||||
...(config?.endpoints || []),
|
||||
{
|
||||
handler: async (req) => {
|
||||
const res = await stripeWebhooks({
|
||||
config,
|
||||
req,
|
||||
stripeConfig,
|
||||
})
|
||||
|
||||
return res
|
||||
},
|
||||
method: 'post',
|
||||
path: '/stripe/webhooks',
|
||||
},
|
||||
]
|
||||
|
||||
if (incomingStripeConfig?.rest) {
|
||||
endpoints.push({
|
||||
handler: async (req) => {
|
||||
const res = await stripeREST({
|
||||
req,
|
||||
stripeConfig,
|
||||
})
|
||||
|
||||
return res
|
||||
},
|
||||
method: 'post' as Endpoint['method'],
|
||||
path: '/stripe/rest',
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
...config,
|
||||
admin: {
|
||||
...config.admin,
|
||||
webpack: extendWebpackConfig(config),
|
||||
},
|
||||
collections: collections?.map((collection) => {
|
||||
const { hooks: existingHooks } = collection
|
||||
|
||||
@@ -86,42 +109,7 @@ const stripePlugin =
|
||||
|
||||
return collection
|
||||
}),
|
||||
endpoints: [
|
||||
...(config?.endpoints || []),
|
||||
{
|
||||
handler: [
|
||||
express.raw({ type: 'application/json' }),
|
||||
async (req, res, next) => {
|
||||
await stripeWebhooks({
|
||||
config,
|
||||
next,
|
||||
req,
|
||||
res,
|
||||
stripeConfig,
|
||||
})
|
||||
},
|
||||
],
|
||||
method: 'post',
|
||||
path: '/stripe/webhooks',
|
||||
root: true,
|
||||
},
|
||||
...(incomingStripeConfig?.rest
|
||||
? [
|
||||
{
|
||||
handler: async (req: PayloadRequest, res: Response, next: NextFunction) => {
|
||||
await stripeREST({
|
||||
next,
|
||||
req,
|
||||
res,
|
||||
stripeConfig,
|
||||
})
|
||||
},
|
||||
method: 'post' as Endpoint['method'],
|
||||
path: '/stripe/rest',
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
endpoints,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import type { Response } from 'express'
|
||||
import type { PayloadRequest } from 'payload/types'
|
||||
|
||||
import { Forbidden } from 'payload/errors'
|
||||
|
||||
import type { StripeConfig } from '../types'
|
||||
import type { StripeConfig } from '../types.js'
|
||||
|
||||
import { stripeProxy } from '../utilities/stripeProxy'
|
||||
import { stripeProxy } from '../utilities/stripeProxy.js'
|
||||
|
||||
export const stripeREST = async (args: {
|
||||
next: any
|
||||
req: PayloadRequest
|
||||
res: Response
|
||||
stripeConfig: StripeConfig
|
||||
}): Promise<any> => {
|
||||
const { req, res, stripeConfig } = args
|
||||
let responseStatus = 200
|
||||
let responseJSON
|
||||
|
||||
const { req, stripeConfig } = args
|
||||
|
||||
const {
|
||||
body: {
|
||||
data: {
|
||||
stripeArgs, // example: ['cus_MGgt3Tuj3D66f2'] or [{ limit: 100 }, { stripeAccount: 'acct_1J9Z4pKZ4Z4Z4Z4Z' }]
|
||||
stripeMethod, // example: 'subscriptions.list',
|
||||
},
|
||||
@@ -32,20 +32,26 @@ export const stripeREST = async (args: {
|
||||
throw new Forbidden(req.t)
|
||||
}
|
||||
|
||||
const pluginRes = await stripeProxy({
|
||||
responseJSON = await stripeProxy({
|
||||
stripeArgs,
|
||||
stripeMethod,
|
||||
stripeSecretKey,
|
||||
})
|
||||
|
||||
const { status } = pluginRes
|
||||
|
||||
res.status(status).json(pluginRes)
|
||||
const { status } = responseJSON
|
||||
responseStatus = status
|
||||
} catch (error: unknown) {
|
||||
const message = `An error has occurred in the Stripe plugin REST handler: '${error}'`
|
||||
const message = `An error has occurred in the Stripe plugin REST handler: '${JSON.stringify(
|
||||
error,
|
||||
)}'`
|
||||
payload.logger.error(message)
|
||||
return res.status(500).json({
|
||||
responseStatus = 500
|
||||
responseJSON = {
|
||||
message,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return Response.json(responseJSON, {
|
||||
status: responseStatus,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
import type { Response } from 'express'
|
||||
import type { Config as PayloadConfig } from 'payload/config'
|
||||
import type { PayloadRequest } from 'payload/types'
|
||||
|
||||
import Stripe from 'stripe'
|
||||
|
||||
import type { StripeConfig } from '../types'
|
||||
import type { StripeConfig } from '../types.js'
|
||||
|
||||
import { handleWebhooks } from '../webhooks'
|
||||
import { handleWebhooks } from '../webhooks/index.js'
|
||||
|
||||
export const stripeWebhooks = async (args: {
|
||||
config: PayloadConfig
|
||||
next: any
|
||||
req: PayloadRequest
|
||||
res: Response
|
||||
stripeConfig: StripeConfig
|
||||
}): Promise<any> => {
|
||||
const { config, req, res, stripeConfig } = args
|
||||
const { config, req, stripeConfig } = args
|
||||
let returnStatus = 200
|
||||
|
||||
const { stripeSecretKey, stripeWebhooksEndpointSecret, webhooks } = stripeConfig
|
||||
|
||||
@@ -28,21 +26,21 @@ export const stripeWebhooks = async (args: {
|
||||
},
|
||||
})
|
||||
|
||||
const stripeSignature = req.headers['stripe-signature']
|
||||
const stripeSignature = req.headers.get('stripe-signature')
|
||||
|
||||
if (stripeSignature) {
|
||||
let event: Stripe.Event | undefined
|
||||
|
||||
try {
|
||||
event = stripe.webhooks.constructEvent(
|
||||
req.body,
|
||||
await req.text(),
|
||||
stripeSignature,
|
||||
stripeWebhooksEndpointSecret,
|
||||
)
|
||||
} catch (err: unknown) {
|
||||
const msg = err instanceof Error ? err.message : err
|
||||
const msg: string = err instanceof Error ? err.message : JSON.stringify(err)
|
||||
req.payload.logger.error(`Error constructing Stripe event: ${msg}`)
|
||||
res.status(400)
|
||||
returnStatus = 400
|
||||
}
|
||||
|
||||
if (event) {
|
||||
@@ -81,5 +79,10 @@ export const stripeWebhooks = async (args: {
|
||||
}
|
||||
}
|
||||
|
||||
res.json({ received: true })
|
||||
return Response.json(
|
||||
{ received: true },
|
||||
{
|
||||
status: returnStatus,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,46 +1,30 @@
|
||||
import { Strategy } from 'passport-strategy'
|
||||
|
||||
import type { Payload } from '../../../packages/payload/src/index.js'
|
||||
import type { AuthStrategyFunction } from 'payload/auth.js'
|
||||
|
||||
import { buildConfigWithDefaults } from '../../buildConfigWithDefaults.js'
|
||||
import { usersSlug } from './shared.js'
|
||||
|
||||
export const strategyName = 'test-local'
|
||||
|
||||
export class CustomStrategy extends Strategy {
|
||||
ctx: Payload
|
||||
const customAuthenticationStrategy: AuthStrategyFunction = async ({ headers, payload }) => {
|
||||
const usersQuery = await payload.find({
|
||||
collection: usersSlug,
|
||||
where: {
|
||||
code: {
|
||||
equals: headers.get('code'),
|
||||
},
|
||||
secret: {
|
||||
equals: headers.get('secret'),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
constructor(ctx: Payload) {
|
||||
super()
|
||||
this.ctx = ctx
|
||||
}
|
||||
const user = usersQuery.docs[0] || null
|
||||
if (!user) return null
|
||||
|
||||
authenticate(req: Request, options?: any): void {
|
||||
if (!req.headers.code && !req.headers.secret) {
|
||||
return this.success(null)
|
||||
}
|
||||
this.ctx
|
||||
.find({
|
||||
collection: usersSlug,
|
||||
where: {
|
||||
code: {
|
||||
equals: req.headers.code,
|
||||
},
|
||||
secret: {
|
||||
equals: req.headers.secret,
|
||||
},
|
||||
},
|
||||
})
|
||||
.then((users) => {
|
||||
if (users.docs && users.docs.length) {
|
||||
const user = users.docs[0]
|
||||
user.collection = usersSlug
|
||||
user._strategy = `${usersSlug}-${strategyName}`
|
||||
this.success(user)
|
||||
} else {
|
||||
this.error(null)
|
||||
}
|
||||
})
|
||||
return {
|
||||
...user,
|
||||
_strategy: `${usersSlug}-${strategyName}`,
|
||||
collection: usersSlug,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,45 +35,45 @@ export default buildConfigWithDefaults({
|
||||
collections: [
|
||||
{
|
||||
slug: usersSlug,
|
||||
access: {
|
||||
create: () => true,
|
||||
},
|
||||
auth: {
|
||||
disableLocalStrategy: true,
|
||||
strategies: [
|
||||
{
|
||||
name: strategyName,
|
||||
strategy: (ctx) => new CustomStrategy(ctx),
|
||||
authenticate: customAuthenticationStrategy,
|
||||
},
|
||||
],
|
||||
},
|
||||
access: {
|
||||
create: () => true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'code',
|
||||
label: 'Code',
|
||||
type: 'text',
|
||||
unique: true,
|
||||
index: true,
|
||||
label: 'Code',
|
||||
unique: true,
|
||||
},
|
||||
{
|
||||
name: 'secret',
|
||||
label: 'Secret',
|
||||
type: 'text',
|
||||
label: 'Secret',
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
type: 'text',
|
||||
label: 'Name',
|
||||
},
|
||||
{
|
||||
name: 'roles',
|
||||
label: 'Role',
|
||||
type: 'select',
|
||||
options: ['admin', 'editor', 'moderator', 'user', 'viewer'],
|
||||
defaultValue: 'user',
|
||||
hasMany: true,
|
||||
label: 'Role',
|
||||
options: ['admin', 'editor', 'moderator', 'user', 'viewer'],
|
||||
required: true,
|
||||
saveToJWT: true,
|
||||
hasMany: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
UploadFeature,
|
||||
lexicalEditor,
|
||||
} from '../packages/richtext-lexical/src/index.js'
|
||||
//import { slateEditor } from '../packages/richtext-slate/src/index.js'
|
||||
// import { slateEditor } from '../packages/richtext-slate/src/index.js'
|
||||
// process.env.PAYLOAD_DATABASE = 'postgres'
|
||||
|
||||
const databaseAdapters = {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { slateEditor } from '../../packages/richtext-slate/src/index.js'
|
||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
|
||||
import { devUser } from '../credentials.js'
|
||||
|
||||
@@ -14,19 +15,15 @@ export default buildConfigWithDefaults({
|
||||
{
|
||||
name: 'owner',
|
||||
type: 'relationship',
|
||||
relationTo: 'users',
|
||||
hooks: {
|
||||
beforeChange: [({ req: { user } }) => user?.id],
|
||||
},
|
||||
relationTo: 'users',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'relation-a',
|
||||
labels: {
|
||||
singular: 'Relation A',
|
||||
plural: 'Relation As',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'relationship',
|
||||
@@ -36,15 +33,16 @@ export default buildConfigWithDefaults({
|
||||
{
|
||||
name: 'richText',
|
||||
type: 'richText',
|
||||
editor: slateEditor({}),
|
||||
},
|
||||
],
|
||||
labels: {
|
||||
plural: 'Relation As',
|
||||
singular: 'Relation A',
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: 'relation-b',
|
||||
labels: {
|
||||
singular: 'Relation B',
|
||||
plural: 'Relation Bs',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'relationship',
|
||||
@@ -54,8 +52,13 @@ export default buildConfigWithDefaults({
|
||||
{
|
||||
name: 'richText',
|
||||
type: 'richText',
|
||||
editor: slateEditor({}),
|
||||
},
|
||||
],
|
||||
labels: {
|
||||
plural: 'Relation Bs',
|
||||
singular: 'Relation B',
|
||||
},
|
||||
},
|
||||
],
|
||||
onInit: async (payload) => {
|
||||
@@ -68,9 +71,9 @@ export default buildConfigWithDefaults({
|
||||
})
|
||||
|
||||
await payload.create({
|
||||
user,
|
||||
collection: 'posts',
|
||||
data: postDoc,
|
||||
user,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Block } from '../../packages/payload/src/fields/config/types.js'
|
||||
|
||||
import formBuilder, { fields as formFields } from '../../packages/plugin-form-builder/src/index.js'
|
||||
import { slateEditor } from '../../packages/richtext-slate/src/index.js'
|
||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
|
||||
import { devUser } from '../credentials.js'
|
||||
import { Pages } from './collections/Pages.js'
|
||||
@@ -9,20 +10,21 @@ import { seed } from './seed/index.js'
|
||||
|
||||
const colorField: Block = {
|
||||
slug: 'color',
|
||||
labels: {
|
||||
singular: 'Color',
|
||||
plural: 'Colors',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'value',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
labels: {
|
||||
plural: 'Colors',
|
||||
singular: 'Color',
|
||||
},
|
||||
}
|
||||
|
||||
export default buildConfigWithDefaults({
|
||||
collections: [Pages, Users],
|
||||
editor: slateEditor({}),
|
||||
localization: {
|
||||
defaultLocale: 'en',
|
||||
fallback: true,
|
||||
@@ -43,27 +45,14 @@ export default buildConfigWithDefaults({
|
||||
formBuilder({
|
||||
// handlePayment: handleFormPayments,
|
||||
// beforeEmail: prepareFormEmails,
|
||||
redirectRelationships: ['pages'],
|
||||
formOverrides: {
|
||||
// labels: {
|
||||
// singular: 'Contact Form',
|
||||
// plural: 'Contact Forms'
|
||||
// },
|
||||
fields: [
|
||||
{
|
||||
name: 'custom',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
fields: {
|
||||
payment: true,
|
||||
colorField,
|
||||
payment: true,
|
||||
text: {
|
||||
...formFields.text,
|
||||
labels: {
|
||||
singular: 'Custom Text Field',
|
||||
plural: 'Custom Text Fields',
|
||||
singular: 'Custom Text Field',
|
||||
},
|
||||
},
|
||||
// payment: {
|
||||
@@ -78,6 +67,19 @@ export default buildConfigWithDefaults({
|
||||
// },
|
||||
// },
|
||||
},
|
||||
formOverrides: {
|
||||
// labels: {
|
||||
// singular: 'Contact Form',
|
||||
// plural: 'Contact Forms'
|
||||
// },
|
||||
fields: [
|
||||
{
|
||||
name: 'custom',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
redirectRelationships: ['pages'],
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
@@ -18,19 +18,19 @@ describe('@payloadcms/plugin-form-builder', () => {
|
||||
payload = await getPayload({ config })
|
||||
|
||||
const formConfig: Omit<Form, 'createdAt' | 'id' | 'updatedAt'> = {
|
||||
title: 'Test Form',
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
blockType: 'text',
|
||||
},
|
||||
],
|
||||
confirmationMessage: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Confirmed.',
|
||||
},
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
blockType: 'text',
|
||||
},
|
||||
],
|
||||
title: 'Test Form',
|
||||
}
|
||||
|
||||
form = (await payload.create({
|
||||
@@ -54,19 +54,19 @@ describe('@payloadcms/plugin-form-builder', () => {
|
||||
describe('form building', () => {
|
||||
it('can create a simple form', async () => {
|
||||
const formConfig: Omit<Form, 'createdAt' | 'id' | 'updatedAt'> = {
|
||||
title: 'Test Form',
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
blockType: 'text',
|
||||
},
|
||||
],
|
||||
confirmationMessage: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Confirmed.',
|
||||
},
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
blockType: 'text',
|
||||
},
|
||||
],
|
||||
title: 'Test Form',
|
||||
}
|
||||
|
||||
const testForm = await payload.create({
|
||||
@@ -81,14 +81,14 @@ describe('@payloadcms/plugin-form-builder', () => {
|
||||
|
||||
it('can use form overrides', async () => {
|
||||
const formConfig: Omit<Form, 'createdAt' | 'id' | 'updatedAt'> = {
|
||||
custom: 'custom',
|
||||
title: 'Test Form',
|
||||
confirmationMessage: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Confirmed.',
|
||||
},
|
||||
],
|
||||
custom: 'custom',
|
||||
title: 'Test Form',
|
||||
}
|
||||
|
||||
const testForm = await payload.create({
|
||||
@@ -142,7 +142,7 @@ describe('@payloadcms/plugin-form-builder', () => {
|
||||
await expect(req).rejects.toThrow(ValidationError)
|
||||
})
|
||||
|
||||
it('replaces curly braces with data when using slate serializer', async () => {
|
||||
it('replaces curly braces with data when using slate serializer', () => {
|
||||
const mockName = 'Test Submission'
|
||||
const mockEmail = 'dev@payloadcms.com'
|
||||
|
||||
@@ -150,12 +150,12 @@ describe('@payloadcms/plugin-form-builder', () => {
|
||||
[
|
||||
{ text: 'Welcome {{name}}. Here is a dynamic ' },
|
||||
{
|
||||
type: 'link',
|
||||
children: [
|
||||
{
|
||||
text: 'link',
|
||||
},
|
||||
],
|
||||
type: 'link',
|
||||
url: 'www.test.com?email={{email}}',
|
||||
},
|
||||
],
|
||||
@@ -177,24 +177,17 @@ describe('@payloadcms/plugin-form-builder', () => {
|
||||
{
|
||||
root: {
|
||||
type: 'root',
|
||||
format: '',
|
||||
indent: 0,
|
||||
version: 1,
|
||||
children: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
version: 1,
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: 'Name: {{name}}',
|
||||
type: 'text',
|
||||
version: 1,
|
||||
},
|
||||
{
|
||||
@@ -202,18 +195,25 @@ describe('@payloadcms/plugin-form-builder', () => {
|
||||
version: 1,
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: 'Email: {{email}}',
|
||||
type: 'text',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
version: 1,
|
||||
},
|
||||
},
|
||||
[
|
||||
|
||||
@@ -5,10 +5,9 @@ import { customersSlug } from '../shared.js'
|
||||
|
||||
export const Customers: CollectionConfig = {
|
||||
slug: customersSlug,
|
||||
timestamps: true,
|
||||
admin: {
|
||||
useAsTitle: 'email',
|
||||
defaultColumns: ['email', 'name'],
|
||||
useAsTitle: 'email',
|
||||
},
|
||||
auth: {
|
||||
useAPIKey: true,
|
||||
@@ -16,12 +15,11 @@ export const Customers: CollectionConfig = {
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
type: 'text',
|
||||
label: 'Name',
|
||||
},
|
||||
{
|
||||
name: 'subscriptions',
|
||||
label: 'Subscriptions',
|
||||
type: 'array',
|
||||
admin: {
|
||||
description:
|
||||
@@ -30,7 +28,6 @@ export const Customers: CollectionConfig = {
|
||||
fields: [
|
||||
{
|
||||
name: 'link',
|
||||
label: 'Link',
|
||||
type: 'ui',
|
||||
admin: {
|
||||
components: {
|
||||
@@ -38,43 +35,44 @@ export const Customers: CollectionConfig = {
|
||||
LinkToDoc({
|
||||
...args,
|
||||
isTestKey: process.env.PAYLOAD_PUBLIC_IS_STRIPE_TEST_KEY === 'true',
|
||||
stripeResourceType: 'subscriptions',
|
||||
nameOfIDField: `${args.path}.stripeSubscriptionID`,
|
||||
stripeResourceType: 'subscriptions',
|
||||
}),
|
||||
},
|
||||
},
|
||||
label: 'Link',
|
||||
},
|
||||
{
|
||||
name: 'stripeSubscriptionID',
|
||||
label: 'Stripe ID',
|
||||
type: 'text',
|
||||
admin: {
|
||||
readOnly: true,
|
||||
},
|
||||
label: 'Stripe ID',
|
||||
},
|
||||
{
|
||||
name: 'stripeProductID',
|
||||
label: 'Product ID',
|
||||
type: 'text',
|
||||
admin: {
|
||||
readOnly: true,
|
||||
},
|
||||
label: 'Product ID',
|
||||
},
|
||||
{
|
||||
name: 'product',
|
||||
type: 'relationship',
|
||||
relationTo: 'products',
|
||||
admin: {
|
||||
readOnly: true,
|
||||
},
|
||||
relationTo: 'products',
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
label: 'Status',
|
||||
type: 'select',
|
||||
admin: {
|
||||
readOnly: true,
|
||||
},
|
||||
label: 'Status',
|
||||
options: [
|
||||
{
|
||||
label: 'Active',
|
||||
@@ -107,6 +105,8 @@ export const Customers: CollectionConfig = {
|
||||
],
|
||||
},
|
||||
],
|
||||
label: 'Subscriptions',
|
||||
},
|
||||
],
|
||||
timestamps: true,
|
||||
}
|
||||
|
||||
@@ -4,36 +4,36 @@ import { productsSlug } from '../shared.js'
|
||||
|
||||
export const Products: CollectionConfig = {
|
||||
slug: productsSlug,
|
||||
timestamps: true,
|
||||
admin: {
|
||||
defaultColumns: ['name'],
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
type: 'text',
|
||||
label: 'Name',
|
||||
},
|
||||
{
|
||||
name: 'price',
|
||||
label: 'Price',
|
||||
type: 'group',
|
||||
admin: {
|
||||
readOnly: true,
|
||||
description: 'All pricing information is managed in Stripe and will be reflected here.',
|
||||
readOnly: true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'stripePriceID',
|
||||
label: 'Stripe Price ID',
|
||||
type: 'text',
|
||||
label: 'Stripe Price ID',
|
||||
},
|
||||
{
|
||||
name: 'stripeJSON',
|
||||
label: 'Stripe JSON',
|
||||
type: 'textarea',
|
||||
label: 'Stripe JSON',
|
||||
},
|
||||
],
|
||||
label: 'Price',
|
||||
},
|
||||
],
|
||||
timestamps: true,
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@ import type { CollectionConfig } from '../../../packages/payload/src/collections
|
||||
|
||||
export const Users: CollectionConfig = {
|
||||
slug: 'users',
|
||||
auth: true,
|
||||
admin: {
|
||||
useAsTitle: 'email',
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
},
|
||||
admin: {
|
||||
useAsTitle: 'email',
|
||||
},
|
||||
auth: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
|
||||
@@ -32,14 +32,14 @@ export default buildConfigWithDefaults({
|
||||
},
|
||||
plugins: [
|
||||
stripePlugin({
|
||||
stripeSecretKey: process.env.STRIPE_SECRET_KEY,
|
||||
isTestKey: true,
|
||||
logs: true,
|
||||
rest: false,
|
||||
stripeSecretKey: process.env.STRIPE_SECRET_KEY,
|
||||
stripeWebhooksEndpointSecret: process.env.STRIPE_WEBHOOKS_ENDPOINT_SECRET,
|
||||
sync: [
|
||||
{
|
||||
collection: 'customers',
|
||||
stripeResourceType: 'customers',
|
||||
stripeResourceTypeSingular: 'customer',
|
||||
fields: [
|
||||
{
|
||||
fieldPath: 'name',
|
||||
@@ -57,11 +57,11 @@ export default buildConfigWithDefaults({
|
||||
// property: 'plan.name',
|
||||
// }
|
||||
],
|
||||
stripeResourceType: 'customers',
|
||||
stripeResourceTypeSingular: 'customer',
|
||||
},
|
||||
{
|
||||
collection: 'products',
|
||||
stripeResourceType: 'products',
|
||||
stripeResourceTypeSingular: 'product',
|
||||
fields: [
|
||||
{
|
||||
fieldPath: 'name',
|
||||
@@ -72,17 +72,17 @@ export default buildConfigWithDefaults({
|
||||
stripeProperty: 'default_price',
|
||||
},
|
||||
],
|
||||
stripeResourceType: 'products',
|
||||
stripeResourceTypeSingular: 'product',
|
||||
},
|
||||
],
|
||||
rest: false,
|
||||
webhooks: {
|
||||
'customer.subscription.created': subscriptionCreatedOrUpdated,
|
||||
'customer.subscription.updated': subscriptionCreatedOrUpdated,
|
||||
'customer.subscription.deleted': subscriptionDeleted,
|
||||
'customer.subscription.updated': subscriptionCreatedOrUpdated,
|
||||
'product.created': syncPriceJSON,
|
||||
'product.updated': syncPriceJSON,
|
||||
},
|
||||
stripeWebhooksEndpointSecret: process.env.STRIPE_WEBHOOKS_ENDPOINT_SECRET,
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
module.exports = {
|
||||
raw: () => {},
|
||||
url: () => {},
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = {}
|
||||
@@ -72,28 +72,28 @@ export const subscriptionCreatedOrUpdated = async (args) => {
|
||||
payload.logger.info(`- Subscription already exists, now updating.`)
|
||||
// update existing subscription
|
||||
subscriptions[indexOfSubscription] = {
|
||||
stripeProductID: plan.product,
|
||||
product: payloadProductID,
|
||||
status: subscriptionStatus,
|
||||
stripeProductID: plan.product,
|
||||
}
|
||||
} else {
|
||||
payload.logger.info(`- This is a new subscription, now adding.`)
|
||||
// create new subscription
|
||||
subscriptions.push({
|
||||
stripeSubscriptionID: eventID,
|
||||
stripeProductID: plan.product,
|
||||
product: payloadProductID,
|
||||
status: subscriptionStatus,
|
||||
stripeProductID: plan.product,
|
||||
stripeSubscriptionID: eventID,
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
await payload.update({
|
||||
collection: 'customers',
|
||||
id: foundCustomer.id,
|
||||
collection: 'customers',
|
||||
data: {
|
||||
subscriptions,
|
||||
skipSync: true,
|
||||
subscriptions,
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -49,11 +49,11 @@ export const subscriptionDeleted = async (args) => {
|
||||
|
||||
try {
|
||||
await payload.update({
|
||||
collection: 'customers',
|
||||
id: foundCustomer.id,
|
||||
collection: 'customers',
|
||||
data: {
|
||||
subscriptions,
|
||||
skipSync: true,
|
||||
subscriptions,
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -41,8 +41,8 @@ export const syncPriceJSON = async (args) => {
|
||||
const stripePrice = await stripe.prices.retrieve(default_price)
|
||||
|
||||
await payload.update({
|
||||
collection: 'products',
|
||||
id: payloadProductID,
|
||||
collection: 'products',
|
||||
data: {
|
||||
price: {
|
||||
stripeJSON: JSON.stringify(stripePrice),
|
||||
|
||||
Reference in New Issue
Block a user