1
- import type { BuildFormStateArgs } from '@payloadcms/ui/forms/buildStateFromSchema'
2
- import type { DocumentPreferences , Field , PayloadRequestWithData , TypeWithID } from 'payload/types'
1
+ import type { PayloadRequestWithData } from 'payload/types'
3
2
4
- import { buildStateFromSchema } from '@payloadcms/ui/forms/buildStateFromSchema'
5
- import { reduceFieldsToValues } from '@payloadcms/ui/utilities/reduceFieldsToValues'
3
+ import { buildFormState as buildFormStateFn } from '@payloadcms/ui/utilities/buildFormState'
6
4
import httpStatus from 'http-status'
7
5
8
- import type { FieldSchemaMap } from '../../utilities/buildFieldSchemaMap/types.js'
9
-
10
- import { buildFieldSchemaMap } from '../../utilities/buildFieldSchemaMap/index.js'
11
6
import { headersWithCors } from '../../utilities/headersWithCors.js'
12
7
import { routeError } from './routeError.js'
13
8
14
- let cached = global . _payload_fieldSchemaMap
15
-
16
- if ( ! cached ) {
17
- // eslint-disable-next-line no-multi-assign
18
- cached = global . _payload_fieldSchemaMap = null
19
- }
20
-
21
- export const getFieldSchemaMap = ( req : PayloadRequestWithData ) : FieldSchemaMap => {
22
- if ( cached && process . env . NODE_ENV !== 'development' ) {
23
- return cached
24
- }
25
-
26
- cached = buildFieldSchemaMap ( req )
27
-
28
- return cached
29
- }
30
-
31
9
export const buildFormState = async ( { req } : { req : PayloadRequestWithData } ) => {
32
10
const headers = headersWithCors ( {
33
11
headers : new Headers ( ) ,
34
12
req,
35
13
} )
36
14
37
15
try {
38
- const reqData : BuildFormStateArgs = req . data as BuildFormStateArgs
39
- const { collectionSlug, formState, globalSlug, locale, operation, schemaPath } = reqData
40
-
41
- const incomingUserSlug = req . user ?. collection
42
- const adminUserSlug = req . payload . config . admin . user
43
-
44
- // If we have a user slug, test it against the functions
45
- if ( incomingUserSlug ) {
46
- const adminAccessFunction = req . payload . collections [ incomingUserSlug ] . config . access ?. admin
47
-
48
- // Run the admin access function from the config if it exists
49
- if ( adminAccessFunction ) {
50
- const canAccessAdmin = await adminAccessFunction ( { req } )
51
-
52
- if ( ! canAccessAdmin ) {
53
- return Response . json ( null , {
54
- headers,
55
- status : httpStatus . UNAUTHORIZED ,
56
- } )
57
- }
58
- // Match the user collection to the global admin config
59
- } else if ( adminUserSlug !== incomingUserSlug ) {
60
- return Response . json ( null , {
61
- headers,
62
- status : httpStatus . UNAUTHORIZED ,
63
- } )
64
- }
65
- } else {
66
- const hasUsers = await req . payload . find ( {
67
- collection : adminUserSlug ,
68
- depth : 0 ,
69
- limit : 1 ,
70
- pagination : false ,
71
- } )
72
- // If there are users, we should not allow access because of /create-first-user
73
- if ( hasUsers . docs . length ) {
74
- return Response . json ( null , {
75
- headers,
76
- status : httpStatus . UNAUTHORIZED ,
77
- } )
78
- }
79
- }
80
-
81
- const fieldSchemaMap = getFieldSchemaMap ( req )
82
-
83
- const id = collectionSlug ? reqData . id : undefined
84
- const schemaPathSegments = schemaPath . split ( '.' )
85
-
86
- let fieldSchema : Field [ ]
87
-
88
- if ( schemaPathSegments . length === 1 ) {
89
- if ( req . payload . collections [ schemaPath ] ) {
90
- fieldSchema = req . payload . collections [ schemaPath ] . config . fields
91
- } else {
92
- fieldSchema = req . payload . config . globals . find (
93
- ( global ) => global . slug === schemaPath ,
94
- ) ?. fields
95
- }
96
- } else if ( fieldSchemaMap . has ( schemaPath ) ) {
97
- fieldSchema = fieldSchemaMap . get ( schemaPath )
98
- }
16
+ const result = await buildFormStateFn ( { req } )
99
17
100
- if ( ! fieldSchema ) {
18
+ return Response . json ( result , {
19
+ headers,
20
+ status : httpStatus . OK ,
21
+ } )
22
+ } catch ( err ) {
23
+ if ( err . message === 'Could not find field schema for given path' ) {
101
24
return Response . json (
102
25
{
103
- message : 'Could not find field schema for given path' ,
26
+ message : err . message ,
104
27
} ,
105
28
{
106
29
headers,
@@ -109,126 +32,13 @@ export const buildFormState = async ({ req }: { req: PayloadRequestWithData }) =
109
32
)
110
33
}
111
34
112
- let docPreferences = reqData . docPreferences
113
- let data = reqData . data
114
-
115
- const promises : {
116
- data ?: Promise < void >
117
- preferences ?: Promise < void >
118
- } = { }
119
-
120
- // If the request does not include doc preferences,
121
- // we should fetch them. This is useful for DocumentInfoProvider
122
- // as it reduces the amount of client-side fetches necessary
123
- // when we fetch data for the Edit view
124
- if ( ! docPreferences ) {
125
- let preferencesKey
126
-
127
- if ( collectionSlug && id ) {
128
- preferencesKey = `collection-${ collectionSlug } -${ id } `
129
- }
130
-
131
- if ( globalSlug ) {
132
- preferencesKey = `global-${ globalSlug } `
133
- }
134
-
135
- if ( preferencesKey ) {
136
- const fetchPreferences = async ( ) => {
137
- const preferencesResult = ( await req . payload . find ( {
138
- collection : 'payload-preferences' ,
139
- depth : 0 ,
140
- limit : 1 ,
141
- where : {
142
- key : {
143
- equals : preferencesKey ,
144
- } ,
145
- } ,
146
- } ) ) as unknown as { docs : { value : DocumentPreferences } [ ] }
147
-
148
- if ( preferencesResult ?. docs ?. [ 0 ] ?. value ) docPreferences = preferencesResult . docs [ 0 ] . value
149
- }
150
-
151
- promises . preferences = fetchPreferences ( )
152
- }
153
- }
154
-
155
- // If there is a form state,
156
- // then we can deduce data from that form state
157
- if ( formState ) data = reduceFieldsToValues ( formState , true )
158
-
159
- // If we do not have data at this point,
160
- // we can fetch it. This is useful for DocumentInfoProvider
161
- // to reduce the amount of fetches required
162
- if ( ! data ) {
163
- const fetchData = async ( ) => {
164
- let resolvedData : TypeWithID
165
-
166
- if ( collectionSlug && id ) {
167
- resolvedData = await req . payload . findByID ( {
168
- id,
169
- collection : collectionSlug ,
170
- depth : 0 ,
171
- draft : true ,
172
- fallbackLocale : null ,
173
- locale,
174
- overrideAccess : false ,
175
- user : req . user ,
176
- } )
177
- }
178
-
179
- if ( globalSlug && schemaPath === globalSlug ) {
180
- resolvedData = await req . payload . findGlobal ( {
181
- slug : globalSlug ,
182
- depth : 0 ,
183
- draft : true ,
184
- fallbackLocale : null ,
185
- locale,
186
- overrideAccess : false ,
187
- user : req . user ,
188
- } )
189
- }
190
-
191
- data = resolvedData
192
- }
193
-
194
- promises . data = fetchData ( )
195
- }
196
-
197
- if ( Object . keys ( promises ) . length > 0 ) {
198
- await Promise . all ( Object . values ( promises ) )
199
- }
200
-
201
- const result = await buildStateFromSchema ( {
202
- id,
203
- data,
204
- fieldSchema,
205
- operation,
206
- preferences : docPreferences || { fields : { } } ,
207
- req,
208
- } )
209
-
210
- // Maintain form state of auth / upload fields
211
- if ( collectionSlug && formState ) {
212
- if ( req . payload . collections [ collectionSlug ] ?. config ?. upload && formState . file ) {
213
- result . file = formState . file
214
- }
215
-
216
- if (
217
- req . payload . collections [ collectionSlug ] ?. config ?. auth &&
218
- ! req . payload . collections [ collectionSlug ] . config . auth . disableLocalStrategy
219
- ) {
220
- if ( formState . password ) result . password = formState . password
221
- if ( formState [ 'confirm-password' ] )
222
- result [ 'confirm-password' ] = formState [ 'confirm-password' ]
223
- if ( formState . email ) result . email = formState . email
224
- }
35
+ if ( err . message === 'Unauthorized' ) {
36
+ return Response . json ( null , {
37
+ headers,
38
+ status : httpStatus . UNAUTHORIZED ,
39
+ } )
225
40
}
226
41
227
- return Response . json ( result , {
228
- headers,
229
- status : httpStatus . OK ,
230
- } )
231
- } catch ( err ) {
232
42
req . payload . logger . error ( { err, msg : `There was an error building form state` } )
233
43
234
44
return routeError ( {
0 commit comments