Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
233 lines
10 KiB
Plaintext
233 lines
10 KiB
Plaintext
import { authCollectionEndpoints } from '../../auth/endpoints/index.js';
|
|
import { getBaseAuthFields } from '../../auth/getAuthFields.js';
|
|
import { TimestampsRequired } from '../../errors/TimestampsRequired.js';
|
|
import { sanitizeFields } from '../../fields/config/sanitize.js';
|
|
import { fieldAffectsData } from '../../fields/config/types.js';
|
|
import { mergeBaseFields } from '../../fields/mergeBaseFields.js';
|
|
import { uploadCollectionEndpoints } from '../../uploads/endpoints/index.js';
|
|
import { getBaseUploadFields } from '../../uploads/getBaseFields.js';
|
|
import { flattenAllFields } from '../../utilities/flattenAllFields.js';
|
|
import { formatLabels } from '../../utilities/formatLabels.js';
|
|
import { miniChalk } from '../../utilities/miniChalk.js';
|
|
import { traverseForLocalizedFields } from '../../utilities/traverseForLocalizedFields.js';
|
|
import { baseVersionFields } from '../../versions/baseFields.js';
|
|
import { versionDefaults } from '../../versions/defaults.js';
|
|
import { defaultCollectionEndpoints } from '../endpoints/index.js';
|
|
import { addDefaultsToAuthConfig, addDefaultsToCollectionConfig, addDefaultsToLoginWithUsernameConfig } from './defaults.js';
|
|
import { sanitizeCompoundIndexes } from './sanitizeCompoundIndexes.js';
|
|
import { validateUseAsTitle } from './useAsTitle.js';
|
|
export const sanitizeCollection = async (config, collection, /**
|
|
* If this property is set, RichText fields won't be sanitized immediately. Instead, they will be added to this array as promises
|
|
* so that you can sanitize them together, after the config has been sanitized.
|
|
*/ richTextSanitizationPromises, _validRelationships)=>{
|
|
if (collection._sanitized) {
|
|
return collection;
|
|
}
|
|
collection._sanitized = true;
|
|
// /////////////////////////////////
|
|
// Make copy of collection config
|
|
// /////////////////////////////////
|
|
const sanitized = addDefaultsToCollectionConfig(collection);
|
|
// /////////////////////////////////
|
|
// Sanitize fields
|
|
// /////////////////////////////////
|
|
const validRelationships = _validRelationships ?? config.collections.map((c)=>c.slug) ?? [];
|
|
const joins = {};
|
|
const polymorphicJoins = [];
|
|
sanitized.fields = await sanitizeFields({
|
|
collectionConfig: sanitized,
|
|
config,
|
|
fields: sanitized.fields,
|
|
joinPath: '',
|
|
joins,
|
|
parentIsLocalized: false,
|
|
polymorphicJoins,
|
|
richTextSanitizationPromises,
|
|
validRelationships
|
|
});
|
|
if (sanitized.endpoints !== false) {
|
|
if (!sanitized.endpoints) {
|
|
sanitized.endpoints = [];
|
|
}
|
|
if (sanitized.auth) {
|
|
for (const endpoint of authCollectionEndpoints){
|
|
sanitized.endpoints.push(endpoint);
|
|
}
|
|
}
|
|
if (sanitized.upload) {
|
|
for (const endpoint of uploadCollectionEndpoints){
|
|
sanitized.endpoints.push(endpoint);
|
|
}
|
|
}
|
|
for (const endpoint of defaultCollectionEndpoints){
|
|
sanitized.endpoints.push(endpoint);
|
|
}
|
|
}
|
|
if (sanitized.timestamps !== false) {
|
|
// add default timestamps fields only as needed
|
|
let hasUpdatedAt = null;
|
|
let hasCreatedAt = null;
|
|
let hasDeletedAt = null;
|
|
sanitized.fields.some((field)=>{
|
|
if (fieldAffectsData(field)) {
|
|
if (field.name === 'updatedAt') {
|
|
hasUpdatedAt = true;
|
|
}
|
|
if (field.name === 'createdAt') {
|
|
hasCreatedAt = true;
|
|
}
|
|
if (field.name === 'deletedAt') {
|
|
hasDeletedAt = true;
|
|
}
|
|
}
|
|
return hasCreatedAt && hasUpdatedAt && (!sanitized.trash || hasDeletedAt);
|
|
});
|
|
if (!hasUpdatedAt) {
|
|
sanitized.fields.push({
|
|
name: 'updatedAt',
|
|
type: 'date',
|
|
admin: {
|
|
disableBulkEdit: true,
|
|
hidden: true
|
|
},
|
|
index: true,
|
|
label: ({ t })=>t('general:updatedAt')
|
|
});
|
|
}
|
|
if (!hasCreatedAt) {
|
|
sanitized.fields.push({
|
|
name: 'createdAt',
|
|
admin: {
|
|
disableBulkEdit: true,
|
|
hidden: true
|
|
},
|
|
// The default sort for list view is createdAt. Thus, enabling indexing by default, is a major performance improvement, especially for large or a large amount of collections.
|
|
type: 'date',
|
|
index: true,
|
|
label: ({ t })=>t('general:createdAt')
|
|
});
|
|
}
|
|
if (sanitized.trash && !hasDeletedAt) {
|
|
sanitized.fields.push({
|
|
name: 'deletedAt',
|
|
type: 'date',
|
|
admin: {
|
|
disableBulkEdit: true,
|
|
hidden: true
|
|
},
|
|
index: true,
|
|
label: ({ t })=>t('general:deletedAt')
|
|
});
|
|
}
|
|
}
|
|
const defaultLabels = formatLabels(sanitized.slug);
|
|
sanitized.labels = {
|
|
plural: sanitized.labels?.plural || defaultLabels.plural,
|
|
singular: sanitized.labels?.singular || defaultLabels.singular
|
|
};
|
|
if (sanitized.versions) {
|
|
if (sanitized.timestamps === false) {
|
|
throw new TimestampsRequired(collection);
|
|
}
|
|
if (sanitized.versions === true) {
|
|
sanitized.versions = {
|
|
drafts: false,
|
|
maxPerDoc: 100
|
|
};
|
|
}
|
|
sanitized.versions.maxPerDoc = typeof sanitized.versions.maxPerDoc === 'number' ? sanitized.versions.maxPerDoc : 100;
|
|
if (sanitized.versions.drafts) {
|
|
if (sanitized.versions.drafts === true) {
|
|
sanitized.versions.drafts = {
|
|
autosave: false,
|
|
validate: false
|
|
};
|
|
}
|
|
const hasLocalizedFields = traverseForLocalizedFields(sanitized.fields);
|
|
if (config.localization) {
|
|
if (hasLocalizedFields && sanitized.versions.drafts.localizeStatus === undefined) {
|
|
sanitized.versions.drafts.localizeStatus = false;
|
|
}
|
|
}
|
|
// TODO v4: remove this sanitization check, should not need to enable the experimental flag
|
|
if (sanitized.versions.drafts.localizeStatus && !config.experimental?.localizeStatus) {
|
|
sanitized.versions.drafts.localizeStatus = false;
|
|
console.log(miniChalk.yellowBold(`Warning: "localizeStatus" for drafts is an experimental feature. To enable, set "experimental.localizeStatus" to true in your Payload config.`));
|
|
}
|
|
if (sanitized.versions.drafts.autosave === true) {
|
|
sanitized.versions.drafts.autosave = {
|
|
interval: versionDefaults.autosaveInterval
|
|
};
|
|
}
|
|
if (sanitized.versions.drafts.validate === undefined) {
|
|
sanitized.versions.drafts.validate = false;
|
|
}
|
|
sanitized.fields = mergeBaseFields(sanitized.fields, baseVersionFields({
|
|
localized: sanitized.versions.drafts.localizeStatus ?? false
|
|
}));
|
|
}
|
|
} else {
|
|
delete sanitized.versions;
|
|
}
|
|
if (sanitized.folders === true) {
|
|
sanitized.folders = {
|
|
browseByFolder: true
|
|
};
|
|
} else if (sanitized.folders) {
|
|
sanitized.folders.browseByFolder = sanitized.folders.browseByFolder ?? true;
|
|
}
|
|
if (sanitized.upload) {
|
|
if (sanitized.upload === true) {
|
|
sanitized.upload = {};
|
|
}
|
|
sanitized.upload.cacheTags = sanitized.upload?.cacheTags ?? true;
|
|
sanitized.upload.bulkUpload = sanitized.upload?.bulkUpload ?? true;
|
|
sanitized.upload.staticDir = sanitized.upload.staticDir || sanitized.slug;
|
|
sanitized.admin.useAsTitle = sanitized.admin?.useAsTitle && sanitized.admin.useAsTitle !== 'id' ? sanitized.admin.useAsTitle : 'filename';
|
|
const uploadFields = getBaseUploadFields({
|
|
collection: sanitized,
|
|
config
|
|
});
|
|
sanitized.fields = mergeBaseFields(sanitized.fields, uploadFields);
|
|
}
|
|
if (sanitized.auth) {
|
|
sanitized.auth = addDefaultsToAuthConfig(typeof sanitized.auth === 'boolean' ? {} : sanitized.auth);
|
|
// disable duplicate for auth enabled collections by default
|
|
sanitized.disableDuplicate = sanitized.disableDuplicate ?? true;
|
|
if (sanitized.auth.loginWithUsername) {
|
|
if (sanitized.auth.loginWithUsername === true) {
|
|
sanitized.auth.loginWithUsername = addDefaultsToLoginWithUsernameConfig({});
|
|
} else {
|
|
const loginWithUsernameWithDefaults = addDefaultsToLoginWithUsernameConfig(sanitized.auth.loginWithUsername);
|
|
// if allowEmailLogin is false, requireUsername must be true
|
|
if (loginWithUsernameWithDefaults.allowEmailLogin === false) {
|
|
loginWithUsernameWithDefaults.requireUsername = true;
|
|
}
|
|
sanitized.auth.loginWithUsername = loginWithUsernameWithDefaults;
|
|
}
|
|
} else {
|
|
sanitized.auth.loginWithUsername = false;
|
|
}
|
|
if (!collection?.admin?.useAsTitle) {
|
|
sanitized.admin.useAsTitle = sanitized.auth.loginWithUsername ? 'username' : 'email';
|
|
}
|
|
sanitized.fields = mergeBaseFields(sanitized.fields, getBaseAuthFields(sanitized.auth));
|
|
}
|
|
if (collection?.admin?.pagination?.limits?.length) {
|
|
sanitized.admin.pagination.limits = collection.admin.pagination.limits;
|
|
}
|
|
validateUseAsTitle(sanitized);
|
|
const sanitizedConfig = sanitized;
|
|
sanitizedConfig.joins = joins;
|
|
sanitizedConfig.polymorphicJoins = polymorphicJoins;
|
|
sanitizedConfig.flattenedFields = flattenAllFields({
|
|
fields: sanitizedConfig.fields
|
|
});
|
|
sanitizedConfig.sanitizedIndexes = sanitizeCompoundIndexes({
|
|
fields: sanitizedConfig.flattenedFields,
|
|
indexes: sanitizedConfig.indexes
|
|
});
|
|
return sanitizedConfig;
|
|
};
|
|
|
|
//# sourceMappingURL=sanitize.js.map |