Move from using parentPages to backlinks
This commit is contained in:
		
							parent
							
								
									8cd8a67778
								
							
						
					
					
						commit
						5acaf65ade
					
				
							
								
								
									
										24
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										24
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -10,7 +10,7 @@ | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@fontsource/vollkorn": "5.0.20", | ||||
|         "@iconify-json/material-symbols": "^1.1.84", | ||||
|         "@iconify-json/material-symbols": "^1.1.85", | ||||
|         "@payloadcms/bundler-webpack": "1.0.7", | ||||
|         "@payloadcms/db-mongodb": "1.6.0", | ||||
|         "@payloadcms/richtext-lexical": "0.11.2", | ||||
| @ -19,9 +19,10 @@ | ||||
|         "language-tags": "1.0.9", | ||||
|         "luxon": "3.4.4", | ||||
|         "payload": "2.24.0", | ||||
|         "payloadcms-relationships": "github:DrMint/payloadcms-relationships", | ||||
|         "payloadcms-sftp-storage": "1.0.1", | ||||
|         "sharp": "0.33.4", | ||||
|         "styled-components": "6.1.11" | ||||
|         "styled-components": "6.1.12" | ||||
|       }, | ||||
|       "devDependencies": { | ||||
|         "@types/express": "4.17.21", | ||||
| @ -1962,9 +1963,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@iconify-json/material-symbols": { | ||||
|       "version": "1.1.84", | ||||
|       "resolved": "https://registry.npmjs.org/@iconify-json/material-symbols/-/material-symbols-1.1.84.tgz", | ||||
|       "integrity": "sha512-Vio0Ns2rzdTsushHGBiyAcIIbGNWXI6nTNsrVqcq1EEPkfNkuchufBMvErs9vdc1vN1Fj7Ul3uWA3r988TIvfQ==", | ||||
|       "version": "1.1.85", | ||||
|       "resolved": "https://registry.npmjs.org/@iconify-json/material-symbols/-/material-symbols-1.1.85.tgz", | ||||
|       "integrity": "sha512-GJXTScAIdaxxMPcp6GCd4qbntvHpG9UrF/2V03PMUuD7+1fMU5vHG5w0IGDdvqOnI9HpEcUFa7CFDVQHOpBeDA==", | ||||
|       "dependencies": { | ||||
|         "@iconify/types": "*" | ||||
|       } | ||||
| @ -9055,6 +9056,13 @@ | ||||
|         "uuid": "dist/bin/uuid" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/payloadcms-relationships": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "git+ssh://git@github.com/DrMint/payloadcms-relationships.git#aa65c94f14fa36abe1b482a56fd82d4df3cbfb3e", | ||||
|       "dependencies": { | ||||
|         "payload": "^2.24.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/payloadcms-sftp-storage": { | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/payloadcms-sftp-storage/-/payloadcms-sftp-storage-1.0.1.tgz", | ||||
| @ -11545,9 +11553,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/styled-components": { | ||||
|       "version": "6.1.11", | ||||
|       "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.11.tgz", | ||||
|       "integrity": "sha512-Ui0jXPzbp1phYij90h12ksljKGqF8ncGx+pjrNPsSPhbUUjWT2tD1FwGo2LF6USCnbrsIhNngDfodhxbegfEOA==", | ||||
|       "version": "6.1.12", | ||||
|       "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.12.tgz", | ||||
|       "integrity": "sha512-n/O4PzRPhbYI0k1vKKayfti3C/IGcPf+DqcrOB7O/ab9x4u/zjqraneT5N45+sIe87cxrCApXM8Bna7NYxwoTA==", | ||||
|       "dependencies": { | ||||
|         "@emotion/is-prop-valid": "1.2.2", | ||||
|         "@emotion/unitless": "0.8.1", | ||||
|  | ||||
| @ -22,7 +22,7 @@ | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@fontsource/vollkorn": "5.0.20", | ||||
|     "@iconify-json/material-symbols": "^1.1.84", | ||||
|     "@iconify-json/material-symbols": "^1.1.85", | ||||
|     "@payloadcms/bundler-webpack": "1.0.7", | ||||
|     "@payloadcms/db-mongodb": "1.6.0", | ||||
|     "@payloadcms/richtext-lexical": "0.11.2", | ||||
| @ -31,9 +31,10 @@ | ||||
|     "language-tags": "1.0.9", | ||||
|     "luxon": "3.4.4", | ||||
|     "payload": "2.24.0", | ||||
|     "payloadcms-relationships": "github:DrMint/payloadcms-relationships", | ||||
|     "payloadcms-sftp-storage": "1.0.1", | ||||
|     "sharp": "0.33.4", | ||||
|     "styled-components": "6.1.11" | ||||
|     "styled-components": "6.1.12" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@types/express": "4.17.21", | ||||
|  | ||||
| @ -7,6 +7,7 @@ import { | ||||
|   convertCreditsToEndpointCredits, | ||||
|   convertMediaThumbnailToEndpointPayloadImage, | ||||
|   convertRTCToEndpointRTC, | ||||
|   convertRelationshipsToEndpointRelations, | ||||
|   getLanguageId, | ||||
| } from "../../../utils/endpoints"; | ||||
| import { Collections } from "../../../shared/payload/constants"; | ||||
| @ -15,6 +16,7 @@ import { | ||||
|   EndpointAudioPreview, | ||||
|   EndpointAudio, | ||||
| } from "../../../shared/payload/endpoint-types"; | ||||
| import { findIncomingRelationships } from "payloadcms-relationships"; | ||||
| 
 | ||||
| export const getByID: CollectionEndpoint = { | ||||
|   method: "get", | ||||
| @ -44,7 +46,7 @@ export const getByID: CollectionEndpoint = { | ||||
|         return res.sendStatus(404); | ||||
|       } | ||||
| 
 | ||||
|       return res.status(200).json(convertAudioToEndpointAudio(result)); | ||||
|       return res.status(200).json(await convertAudioToEndpointAudio(result)); | ||||
|     } catch { | ||||
|       return res.sendStatus(404); | ||||
|     } | ||||
| @ -79,8 +81,8 @@ export const convertAudioToEndpointAudioPreview = ({ | ||||
|     : {}), | ||||
| }); | ||||
| 
 | ||||
| const convertAudioToEndpointAudio = (audio: Audio & PayloadMedia): EndpointAudio => { | ||||
|   const { translations, createdAt, updatedAt, filesize, credits } = audio; | ||||
| const convertAudioToEndpointAudio = async (audio: Audio & PayloadMedia): Promise<EndpointAudio> => { | ||||
|   const { translations, createdAt, updatedAt, filesize, credits, id } = audio; | ||||
|   return { | ||||
|     ...convertAudioToEndpointAudioPreview(audio), | ||||
|     createdAt, | ||||
| @ -95,5 +97,8 @@ const convertAudioToEndpointAudio = (audio: Audio & PayloadMedia): EndpointAudio | ||||
|         ...(isNotEmpty(description) ? { description: convertRTCToEndpointRTC(description) } : {}), | ||||
|       })) ?? [], | ||||
|     credits: convertCreditsToEndpointCredits(credits), | ||||
|     backlinks: convertRelationshipsToEndpointRelations( | ||||
|       await findIncomingRelationships(Collections.Audios, id) | ||||
|     ), | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @ -6,7 +6,11 @@ import { convertCreditsToEndpointCredits, getDomainFromUrl } from "../../../util | ||||
| import { convertCollectibleToEndpointCollectiblePreview } from "../../Collectibles/endpoints/getBySlugEndpoint"; | ||||
| import { convertPageToEndpointPagePreview } from "../../Pages/endpoints/getBySlugEndpoint"; | ||||
| import { Collections } from "../../../shared/payload/constants"; | ||||
| import { EndpointChronologyEvent, EndpointSource } from "../../../shared/payload/endpoint-types"; | ||||
| import { | ||||
|   EndpointChronologyEvent, | ||||
|   EndpointCollectibleRelationRange, | ||||
|   EndpointRelation, | ||||
| } from "../../../shared/payload/endpoint-types"; | ||||
| 
 | ||||
| export const getAllEndpoint: CollectionEndpoint = { | ||||
|   method: "get", | ||||
| @ -48,13 +52,13 @@ export const getAllEndpoint: CollectionEndpoint = { | ||||
|         if (aDay !== bDay) return aDay - bDay; | ||||
|         return 0; | ||||
|       }) | ||||
|       .map<EndpointChronologyEvent>(eventToEndpointEvent); | ||||
|       .map<EndpointChronologyEvent>(convertEventToEndpointEvent); | ||||
| 
 | ||||
|     res.status(200).json(events); | ||||
|   }, | ||||
| }; | ||||
| 
 | ||||
| export const eventToEndpointEvent = ({ | ||||
| export const convertEventToEndpointEvent = ({ | ||||
|   date: { year, day, month }, | ||||
|   events, | ||||
|   id, | ||||
| @ -80,24 +84,26 @@ export const eventToEndpointEvent = ({ | ||||
|   })), | ||||
| }); | ||||
| 
 | ||||
| const handleSources = (sources: ChronologyEvent["events"][number]["sources"]): EndpointSource[] => { | ||||
| const handleSources = ( | ||||
|   sources: ChronologyEvent["events"][number]["sources"] | ||||
| ): EndpointRelation[] => { | ||||
|   return ( | ||||
|     sources?.flatMap<EndpointSource>((source) => { | ||||
|     sources?.flatMap<EndpointRelation>((source) => { | ||||
|       switch (source.blockType) { | ||||
|         case "collectibleBlock": | ||||
|           const range = handleRange(source.range); | ||||
|           if (!isPayloadType(source.collectible)) return []; | ||||
|           return { | ||||
|             type: "collectible", | ||||
|             collectible: convertCollectibleToEndpointCollectiblePreview(source.collectible), | ||||
|             type: Collections.Collectibles, | ||||
|             value: convertCollectibleToEndpointCollectiblePreview(source.collectible), | ||||
|             ...(isDefined(range) ? { range } : {}), | ||||
|           }; | ||||
| 
 | ||||
|         case "pageBlock": | ||||
|           if (!isPayloadType(source.page)) return []; | ||||
|           return { | ||||
|             type: "page", | ||||
|             page: convertPageToEndpointPagePreview(source.page), | ||||
|             type: Collections.Pages, | ||||
|             value: convertPageToEndpointPagePreview(source.page), | ||||
|           }; | ||||
| 
 | ||||
|         case "urlBlock": | ||||
| @ -113,7 +119,7 @@ const handleSources = (sources: ChronologyEvent["events"][number]["sources"]): E | ||||
| 
 | ||||
| const handleRange = ( | ||||
|   rawRange: CollectibleBlock["range"] | ||||
| ): Extract<EndpointSource, { type: "collectible" }>["range"] => { | ||||
| ): EndpointCollectibleRelationRange | undefined => { | ||||
|   const range = rawRange?.[0]; | ||||
| 
 | ||||
|   switch (range?.blockType) { | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| import payload from "payload"; | ||||
| import { CollectionEndpoint } from "../../../types/payload"; | ||||
| import { eventToEndpointEvent } from "./getAllEndpoint"; | ||||
| import { convertEventToEndpointEvent } from "./getAllEndpoint"; | ||||
| import { Collections } from "../../../shared/payload/constants"; | ||||
| 
 | ||||
| export const getByID: CollectionEndpoint = { | ||||
| @ -27,7 +27,7 @@ export const getByID: CollectionEndpoint = { | ||||
|         id: req.params.id, | ||||
|       }); | ||||
| 
 | ||||
|       return res.status(200).json(eventToEndpointEvent(result)); | ||||
|       return res.status(200).json(convertEventToEndpointEvent(result)); | ||||
|     } catch { | ||||
|       return res.sendStatus(404); | ||||
|     } | ||||
|  | ||||
| @ -1,7 +1,5 @@ | ||||
| import { RowLabelArgs } from "payload/dist/admin/components/forms/RowLabel/types"; | ||||
| import { Where } from "payload/types"; | ||||
| import { attributesField } from "../../fields/attributesField/attributesField"; | ||||
| import { backPropagationField } from "../../fields/backPropagationField/backPropagationField"; | ||||
| import { componentField } from "../../fields/componentField/componentField"; | ||||
| import { creditsField } from "../../fields/creditsField/creditsField"; | ||||
| import { imageField } from "../../fields/imageField/imageField"; | ||||
| @ -11,8 +9,6 @@ import { translatedFields } from "../../fields/translatedFields/translatedFields | ||||
| import { beforeDuplicateAddCopyTo } from "../../hooks/beforeDuplicateAddCopyTo"; | ||||
| import { beforeDuplicatePiping } from "../../hooks/beforeDuplicatePiping"; | ||||
| import { beforeDuplicateUnpublish } from "../../hooks/beforeDuplicateUnpublish"; | ||||
| import { Collectible } from "../../types/collections"; | ||||
| import { isPayloadType } from "../../utils/asserts"; | ||||
| import { createEditor } from "../../utils/editor"; | ||||
| import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig"; | ||||
| import { RowLabel } from "./components/RowLabel"; | ||||
| @ -695,42 +691,9 @@ export const Collectibles = buildVersionedCollectionConfig({ | ||||
|                 }, | ||||
|               ], | ||||
|             }, | ||||
| 
 | ||||
|             rowField([ | ||||
|               backPropagationField({ | ||||
|                 name: fields.folders, | ||||
|                 relationTo: Collections.Folders, | ||||
|                 hasMany: true, | ||||
|                 where: ({ id }) => ({ | ||||
|                   and: [ | ||||
|                     { "files.value": { equals: id } }, | ||||
|                     { "files.relationTo": { equals: Collections.Collectibles } }, | ||||
|                   ] as Where[], | ||||
|                 }), | ||||
|                 admin: { | ||||
|                   description: `You can go to the "Folders" collection to include this collectible in a folder.`, | ||||
|                 }, | ||||
|               }), | ||||
|               backPropagationField({ | ||||
|                 name: fields.parentItems, | ||||
|                 relationTo: Collections.Collectibles, | ||||
|                 hasMany: true, | ||||
|                 where: ({ id }) => ({ [fields.subitems]: { equals: id } }), | ||||
|               }), | ||||
|             ]), | ||||
|           ], | ||||
|         }, | ||||
|       ], | ||||
|     }, | ||||
|   ], | ||||
|   custom: { | ||||
|     getBackPropagatedRelationships: ({ subitems, contents }: Collectible) => { | ||||
|       const result: string[] = []; | ||||
|       subitems?.forEach((subitem) => result.push(isPayloadType(subitem) ? subitem.id : subitem)); | ||||
|       contents?.forEach(({ content: { relationTo, value } }) => { | ||||
|         if (relationTo === "pages") result.push(isPayloadType(value) ? value.id : value); | ||||
|       }); | ||||
|       return result; | ||||
|     }, | ||||
|   }, | ||||
| }); | ||||
|  | ||||
| @ -20,8 +20,8 @@ import { | ||||
| import { | ||||
|   convertAttributesToEndpointAttributes, | ||||
|   convertImageToEndpointPayloadImage, | ||||
|   convertRelationshipsToEndpointRelations, | ||||
|   convertScanToEndpointScanImage, | ||||
|   convertSourceToEndpointSource, | ||||
|   getDomainFromUrl, | ||||
| } from "../../../utils/endpoints"; | ||||
| import { convertAudioToEndpointAudioPreview } from "../../Audios/endpoints/getByID"; | ||||
| @ -29,12 +29,13 @@ import { convertFileToEndpointFilePreview } from "../../Files/endpoints/getByID" | ||||
| import { convertPageToEndpointPagePreview } from "../../Pages/endpoints/getBySlugEndpoint"; | ||||
| import { convertRecorderToEndpointRecorderPreview } from "../../Recorders/endpoints/getByID"; | ||||
| import { convertVideoToEndpointVideoPreview } from "../../Videos/endpoints/getByID"; | ||||
| import { findIncomingRelationships } from "payloadcms-relationships"; | ||||
| 
 | ||||
| export const getBySlugEndpoint = createGetByEndpoint({ | ||||
|   collection: Collections.Collectibles, | ||||
|   attribute: "slug", | ||||
|   depth: 3, | ||||
|   handler: (collectible) => convertCollectibleToEndpointCollectible(collectible), | ||||
|   handler: async (collectible) => await convertCollectibleToEndpointCollectible(collectible), | ||||
| }); | ||||
| 
 | ||||
| export const convertCollectibleToEndpointCollectiblePreview = ({ | ||||
| @ -64,8 +65,11 @@ export const convertCollectibleToEndpointCollectiblePreview = ({ | ||||
|   ...handlePrice(price, priceEnabled), | ||||
| }); | ||||
| 
 | ||||
| const convertCollectibleToEndpointCollectible = (collectible: Collectible): EndpointCollectible => { | ||||
| const convertCollectibleToEndpointCollectible = async ( | ||||
|   collectible: Collectible | ||||
| ): Promise<EndpointCollectible> => { | ||||
|   const { | ||||
|     id, | ||||
|     nature, | ||||
|     urls, | ||||
|     subitems, | ||||
| @ -80,8 +84,6 @@ const convertCollectibleToEndpointCollectible = (collectible: Collectible): Endp | ||||
|     weightEnabled, | ||||
|     pageInfo, | ||||
|     pageInfoEnabled, | ||||
|     parentItems, | ||||
|     folders, | ||||
|     backgroundImage, | ||||
|     translations, | ||||
|     scans: rawScans, | ||||
| @ -128,7 +130,9 @@ const convertCollectibleToEndpointCollectible = (collectible: Collectible): Endp | ||||
|     ...(isPayloadType(updatedBy) | ||||
|       ? { updatedBy: convertRecorderToEndpointRecorderPreview(updatedBy) } | ||||
|       : {}), | ||||
|     parentPages: convertSourceToEndpointSource({ collectibles: parentItems, folders }), | ||||
|     backlinks: convertRelationshipsToEndpointRelations( | ||||
|       await findIncomingRelationships(Collections.Collectibles, id) | ||||
|     ), | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -2,10 +2,8 @@ import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint"; | ||||
| import { Collections } from "../../../shared/payload/constants"; | ||||
| import { EndpointCollectibleGallery } from "../../../shared/payload/endpoint-types"; | ||||
| import { isImage, isNotEmpty, isPayloadType } from "../../../utils/asserts"; | ||||
| import { | ||||
|   convertImageToEndpointPayloadImage, | ||||
|   convertSourceToEndpointSource, | ||||
| } from "../../../utils/endpoints"; | ||||
| import { convertImageToEndpointPayloadImage } from "../../../utils/endpoints"; | ||||
| import { convertCollectibleToEndpointCollectiblePreview } from "./getBySlugEndpoint"; | ||||
| 
 | ||||
| export const getBySlugEndpointGallery = createGetByEndpoint({ | ||||
|   collection: Collections.Collectibles, | ||||
| @ -29,7 +27,12 @@ export const getBySlugEndpointGallery = createGetByEndpoint({ | ||||
|         gallery?.flatMap(({ image }) => | ||||
|           isImage(image) ? convertImageToEndpointPayloadImage(image) : [] | ||||
|         ) ?? [], | ||||
|       parentPages: convertSourceToEndpointSource({ collectibles: [collectible] }), | ||||
|       backlinks: [ | ||||
|         { | ||||
|           type: Collections.Collectibles, | ||||
|           value: convertCollectibleToEndpointCollectiblePreview(collectible), | ||||
|         }, | ||||
|       ], | ||||
|     }; | ||||
|   }, | ||||
| }); | ||||
|  | ||||
| @ -2,10 +2,10 @@ import payload from "payload"; | ||||
| import { Collectible, Image } from "../../../types/collections"; | ||||
| import { CollectionEndpoint } from "../../../types/payload"; | ||||
| import { isDefined, isImage, isNotEmpty, isPayloadType } from "../../../utils/asserts"; | ||||
| import { convertSourceToEndpointSource } from "../../../utils/endpoints"; | ||||
| import { convertImageToEndpointImage } from "../../Images/endpoints/getByID"; | ||||
| import { Collections } from "../../../shared/payload/constants"; | ||||
| import { EndpointCollectibleGalleryImage } from "../../../shared/payload/endpoint-types"; | ||||
| import { convertCollectibleToEndpointCollectiblePreview } from "./getBySlugEndpoint"; | ||||
| 
 | ||||
| export const getBySlugEndpointGalleryImage: CollectionEndpoint = { | ||||
|   path: "/slug/:slug/gallery/:index", | ||||
| @ -51,8 +51,7 @@ export const getBySlugEndpointGalleryImage: CollectionEndpoint = { | ||||
|     const nextIndex = getNextIndex(index, collectible.gallery); | ||||
| 
 | ||||
|     const scanPage: EndpointCollectibleGalleryImage = { | ||||
|       image: convertImageToEndpointImage(image), | ||||
|       parentPages: convertSourceToEndpointSource({ gallery: [collectible] }), | ||||
|       image: await convertImageToEndpointImage(image), | ||||
|       slug, | ||||
|       translations: | ||||
|         collectible.translations?.map(({ language, title, description, pretitle, subtitle }) => ({ | ||||
| @ -64,6 +63,12 @@ export const getBySlugEndpointGalleryImage: CollectionEndpoint = { | ||||
|         })) ?? [], | ||||
|       ...(isDefined(previousIndex) ? { previousIndex } : {}), | ||||
|       ...(isDefined(nextIndex) ? { nextIndex } : {}), | ||||
|       backlinks: [ | ||||
|         { | ||||
|           type: Collections.Collectibles, | ||||
|           value: convertCollectibleToEndpointCollectiblePreview(collectible), | ||||
|         }, | ||||
|       ], | ||||
|     }; | ||||
| 
 | ||||
|     res.status(200).send(scanPage); | ||||
|  | ||||
| @ -2,12 +2,10 @@ import payload from "payload"; | ||||
| import { Collectible, Scan } from "../../../types/collections"; | ||||
| import { CollectionEndpoint } from "../../../types/payload"; | ||||
| import { isDefined, isNotEmpty, isPayloadType, isScan } from "../../../utils/asserts"; | ||||
| import { | ||||
|   convertScanToEndpointScanImage, | ||||
|   convertSourceToEndpointSource, | ||||
| } from "../../../utils/endpoints"; | ||||
| import { convertScanToEndpointScanImage } from "../../../utils/endpoints"; | ||||
| import { Collections } from "../../../shared/payload/constants"; | ||||
| import { EndpointCollectibleScanPage } from "../../../shared/payload/endpoint-types"; | ||||
| import { convertCollectibleToEndpointCollectiblePreview } from "./getBySlugEndpoint"; | ||||
| 
 | ||||
| export const getBySlugEndpointScanPage: CollectionEndpoint = { | ||||
|   path: "/slug/:slug/scans/:index", | ||||
| @ -54,7 +52,6 @@ export const getBySlugEndpointScanPage: CollectionEndpoint = { | ||||
| 
 | ||||
|     const scanPage: EndpointCollectibleScanPage = { | ||||
|       image: convertScanToEndpointScanImage(scan, index), | ||||
|       parentPages: convertSourceToEndpointSource({ scans: [collectible] }), | ||||
|       slug, | ||||
|       translations: | ||||
|         collectible.translations?.map(({ language, title, description, pretitle, subtitle }) => ({ | ||||
| @ -66,6 +63,12 @@ export const getBySlugEndpointScanPage: CollectionEndpoint = { | ||||
|         })) ?? [], | ||||
|       ...(isDefined(previousIndex) ? { previousIndex } : {}), | ||||
|       ...(isDefined(nextIndex) ? { nextIndex } : {}), | ||||
|       backlinks: [ | ||||
|         { | ||||
|           type: Collections.Collectibles, | ||||
|           value: convertCollectibleToEndpointCollectiblePreview(collectible), | ||||
|         }, | ||||
|       ], | ||||
|     }; | ||||
| 
 | ||||
|     res.status(200).send(scanPage); | ||||
|  | ||||
| @ -7,8 +7,8 @@ import { | ||||
|   convertCreditsToEndpointCredits, | ||||
|   convertImageToEndpointPayloadImage, | ||||
|   convertScanToEndpointScanImage, | ||||
|   convertSourceToEndpointSource, | ||||
| } from "../../../utils/endpoints"; | ||||
| import { convertCollectibleToEndpointCollectiblePreview } from "./getBySlugEndpoint"; | ||||
| 
 | ||||
| export const getBySlugEndpointScans = createGetByEndpoint({ | ||||
|   collection: Collections.Collectibles, | ||||
| @ -29,7 +29,12 @@ export const getBySlugEndpointScans = createGetByEndpoint({ | ||||
|         })) ?? [], | ||||
|       ...(isImage(thumbnail) ? { thumbnail: convertImageToEndpointPayloadImage(thumbnail) } : {}), | ||||
|       ...(scansEnabled && scans ? handleScans(scans) : { credits: [], pages: [] }), | ||||
|       parentPages: convertSourceToEndpointSource({ collectibles: [collectible] }), | ||||
|       backlinks: [ | ||||
|         { | ||||
|           type: Collections.Collectibles, | ||||
|           value: convertCollectibleToEndpointCollectiblePreview(collectible), | ||||
|         }, | ||||
|       ], | ||||
|     }; | ||||
|   }, | ||||
| }); | ||||
|  | ||||
| @ -7,6 +7,7 @@ import { | ||||
|   convertCreditsToEndpointCredits, | ||||
|   convertMediaThumbnailToEndpointPayloadImage, | ||||
|   convertRTCToEndpointRTC, | ||||
|   convertRelationshipsToEndpointRelations, | ||||
|   getLanguageId, | ||||
| } from "../../../utils/endpoints"; | ||||
| import { Collections } from "../../../shared/payload/constants"; | ||||
| @ -15,6 +16,7 @@ import { | ||||
|   EndpointFilePreview, | ||||
|   EndpointFile, | ||||
| } from "../../../shared/payload/endpoint-types"; | ||||
| import { findIncomingRelationships } from "payloadcms-relationships"; | ||||
| 
 | ||||
| export const getByID: CollectionEndpoint = { | ||||
|   method: "get", | ||||
| @ -44,7 +46,7 @@ export const getByID: CollectionEndpoint = { | ||||
|         return res.sendStatus(404); | ||||
|       } | ||||
| 
 | ||||
|       return res.status(200).json(convertFileToEndpointFile(result)); | ||||
|       return res.status(200).json(await convertFileToEndpointFile(result)); | ||||
|     } catch { | ||||
|       return res.sendStatus(404); | ||||
|     } | ||||
| @ -79,8 +81,8 @@ export const convertFileToEndpointFilePreview = ({ | ||||
|     : {}), | ||||
| }); | ||||
| 
 | ||||
| const convertFileToEndpointFile = (file: File & PayloadMedia): EndpointFile => { | ||||
|   const { translations, createdAt, updatedAt, filesize, credits } = file; | ||||
| const convertFileToEndpointFile = async (file: File & PayloadMedia): Promise<EndpointFile> => { | ||||
|   const { translations, createdAt, updatedAt, filesize, credits, id } = file; | ||||
| 
 | ||||
|   return { | ||||
|     ...convertFileToEndpointFilePreview(file), | ||||
| @ -96,5 +98,8 @@ const convertFileToEndpointFile = (file: File & PayloadMedia): EndpointFile => { | ||||
|         ...(isNotEmpty(description) ? { description: convertRTCToEndpointRTC(description) } : {}), | ||||
|       })) ?? [], | ||||
|     credits: convertCreditsToEndpointCredits(credits), | ||||
|     backlinks: convertRelationshipsToEndpointRelations( | ||||
|       await findIncomingRelationships(Collections.Files, id) | ||||
|     ), | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @ -1,11 +1,8 @@ | ||||
| import { backPropagationField } from "../../fields/backPropagationField/backPropagationField"; | ||||
| import { iconField } from "../../fields/iconField/iconField"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| import { slugField } from "../../fields/slugField/slugField"; | ||||
| import { translatedFields } from "../../fields/translatedFields/translatedFields"; | ||||
| import { Collections, CollectionGroups } from "../../shared/payload/constants"; | ||||
| import { Folder } from "../../types/collections"; | ||||
| import { isPayloadType } from "../../utils/asserts"; | ||||
| import { buildCollectionConfig } from "../../utils/collectionConfig"; | ||||
| import { createEditor } from "../../utils/editor"; | ||||
| import { getBySlugEndpoint } from "./endpoints/getBySlugEndpoint"; | ||||
| @ -44,16 +41,7 @@ export const Folders = buildCollectionConfig({ | ||||
|   }, | ||||
|   endpoints: [getBySlugEndpoint], | ||||
|   fields: [ | ||||
|     rowField([ | ||||
|       slugField({ name: fields.slug }), | ||||
|       iconField({ name: fields.icon }), | ||||
|       backPropagationField({ | ||||
|         name: fields.parentFolders, | ||||
|         relationTo: Collections.Folders, | ||||
|         hasMany: true, | ||||
|         where: ({ id }) => ({ "sections.subfolders": { equals: id } }), | ||||
|       }), | ||||
|     ]), | ||||
|     rowField([slugField({ name: fields.slug }), iconField({ name: fields.icon })]), | ||||
|     translatedFields({ | ||||
|       name: fields.translations, | ||||
|       admin: { useAsTitle: fields.translationsName }, | ||||
| @ -112,21 +100,4 @@ export const Folders = buildCollectionConfig({ | ||||
|       hasMany: true, | ||||
|     }, | ||||
|   ], | ||||
| 
 | ||||
|   custom: { | ||||
|     getBackPropagatedRelationships: ({ files, sections }: Folder) => { | ||||
|       const result: string[] = []; | ||||
|       files?.forEach(({ relationTo, value }) => { | ||||
|         if (relationTo === "collectibles" || relationTo === "pages") { | ||||
|           result.push(isPayloadType(value) ? value.id : value); | ||||
|         } | ||||
|       }); | ||||
|       sections?.forEach(({ subfolders }) => | ||||
|         subfolders?.forEach((folder) => { | ||||
|           result.push(isPayloadType(folder) ? folder.id : folder); | ||||
|         }) | ||||
|       ); | ||||
|       return result; | ||||
|     }, | ||||
|   }, | ||||
| }); | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint"; | ||||
| import { findIncomingRelationships } from "payloadcms-relationships"; | ||||
| import { Collections } from "../../../shared/payload/constants"; | ||||
| import { EndpointFolderPreview, EndpointFolder } from "../../../shared/payload/endpoint-types"; | ||||
| import { Folder, Language } from "../../../types/collections"; | ||||
| @ -12,7 +13,7 @@ import { | ||||
|   isPublished, | ||||
|   isVideo, | ||||
| } from "../../../utils/asserts"; | ||||
| import { convertSourceToEndpointSource, getLanguageId } from "../../../utils/endpoints"; | ||||
| import { convertRelationshipsToEndpointRelations, getLanguageId } from "../../../utils/endpoints"; | ||||
| import { convertAudioToEndpointAudioPreview } from "../../Audios/endpoints/getByID"; | ||||
| import { convertCollectibleToEndpointCollectiblePreview } from "../../Collectibles/endpoints/getBySlugEndpoint"; | ||||
| import { convertFileToEndpointFilePreview } from "../../Files/endpoints/getByID"; | ||||
| @ -43,8 +44,8 @@ export const convertFolderToEndpointFolderPreview = ({ | ||||
|     })) ?? [], | ||||
| }); | ||||
| 
 | ||||
| const convertFolderToEndpointFolder = (folder: Folder): EndpointFolder => { | ||||
|   const { translations, sections, files, parentFolders } = folder; | ||||
| const convertFolderToEndpointFolder = async (folder: Folder): Promise<EndpointFolder> => { | ||||
|   const { translations, sections, files, id } = folder; | ||||
| 
 | ||||
|   return { | ||||
|     ...convertFolderToEndpointFolderPreview(folder), | ||||
| @ -116,7 +117,9 @@ const convertFolderToEndpointFolder = (folder: Folder): EndpointFolder => { | ||||
|             return []; | ||||
|         } | ||||
|       }) ?? [], | ||||
|     parentPages: convertSourceToEndpointSource({ folders: parentFolders }), | ||||
|     backlinks: convertRelationshipsToEndpointRelations( | ||||
|       await findIncomingRelationships(Collections.Folders, id) | ||||
|     ), | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -6,6 +6,7 @@ import { | ||||
|   convertAttributesToEndpointAttributes, | ||||
|   convertCreditsToEndpointCredits, | ||||
|   convertRTCToEndpointRTC, | ||||
|   convertRelationshipsToEndpointRelations, | ||||
|   convertSizesToPayloadImages, | ||||
|   getLanguageId, | ||||
| } from "../../../utils/endpoints"; | ||||
| @ -15,6 +16,7 @@ import { | ||||
|   EndpointImagePreview, | ||||
|   EndpointImage, | ||||
| } from "../../../shared/payload/endpoint-types"; | ||||
| import { findIncomingRelationships } from "payloadcms-relationships"; | ||||
| 
 | ||||
| export const getByID: CollectionEndpoint = { | ||||
|   method: "get", | ||||
| @ -44,7 +46,7 @@ export const getByID: CollectionEndpoint = { | ||||
|         return res.sendStatus(404); | ||||
|       } | ||||
| 
 | ||||
|       return res.status(200).json(convertImageToEndpointImage(result)); | ||||
|       return res.status(200).json(await convertImageToEndpointImage(result)); | ||||
|     } catch { | ||||
|       return res.sendStatus(404); | ||||
|     } | ||||
| @ -93,8 +95,10 @@ export const convertImageToEndpointImagePreview = ({ | ||||
|   ...(isPayloadImage(sizes?.og) ? { openGraph: sizes.og } : {}), | ||||
| }); | ||||
| 
 | ||||
| export const convertImageToEndpointImage = (image: Image & PayloadImage): EndpointImage => { | ||||
|   const { translations, createdAt, updatedAt, filesize, credits } = image; | ||||
| export const convertImageToEndpointImage = async ( | ||||
|   image: Image & PayloadImage | ||||
| ): Promise<EndpointImage> => { | ||||
|   const { translations, createdAt, updatedAt, filesize, credits, id } = image; | ||||
|   return { | ||||
|     ...convertImageToEndpointImagePreview(image), | ||||
|     createdAt, | ||||
| @ -109,5 +113,8 @@ export const convertImageToEndpointImage = (image: Image & PayloadImage): Endpoi | ||||
|         ...(isNotEmpty(description) ? { description: convertRTCToEndpointRTC(description) } : {}), | ||||
|       })) ?? [], | ||||
|     credits: convertCreditsToEndpointCredits(credits), | ||||
|     backlinks: convertRelationshipsToEndpointRelations( | ||||
|       await findIncomingRelationships(Collections.Images, id) | ||||
|     ), | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @ -1,10 +1,8 @@ | ||||
| import { Where } from "payload/types"; | ||||
| import { breakBlock } from "../../blocks/breakBlock"; | ||||
| import { sectionBlock } from "../../blocks/sectionBlock"; | ||||
| import { transcriptBlock } from "../../blocks/transcriptBlock"; | ||||
| import { QuickFilters, publishStatusFilters } from "../../components/QuickFilters"; | ||||
| import { attributesField } from "../../fields/attributesField/attributesField"; | ||||
| import { backPropagationField } from "../../fields/backPropagationField/backPropagationField"; | ||||
| import { creditsField } from "../../fields/creditsField/creditsField"; | ||||
| import { imageField } from "../../fields/imageField/imageField"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| @ -125,29 +123,5 @@ export const Pages = buildVersionedCollectionConfig({ | ||||
|         creditsField({ name: fields.credits }), | ||||
|       ], | ||||
|     }), | ||||
|     rowField([ | ||||
|       backPropagationField({ | ||||
|         name: fields.folders, | ||||
|         relationTo: Collections.Folders, | ||||
|         hasMany: true, | ||||
|         where: ({ id }) => ({ | ||||
|           and: [ | ||||
|             { "files.value": { equals: id } }, | ||||
|             { "files.relationTo": { equals: Collections.Pages } }, | ||||
|           ] as Where[], | ||||
|         }), | ||||
|       }), | ||||
|       backPropagationField({ | ||||
|         name: fields.collectibles, | ||||
|         hasMany: true, | ||||
|         relationTo: Collections.Collectibles, | ||||
|         where: ({ id }) => ({ | ||||
|           and: [ | ||||
|             { "contents.content.value": { equals: id } }, | ||||
|             { "contents.content.relationTo": { equals: Collections.Pages } }, | ||||
|           ] as Where[], | ||||
|         }), | ||||
|       }), | ||||
|     ]), | ||||
|   ], | ||||
| }); | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint"; | ||||
| import { findIncomingRelationships } from "payloadcms-relationships"; | ||||
| import { Collections, BreakBlockType } from "../../../shared/payload/constants"; | ||||
| import { | ||||
|   EndpointPagePreview, | ||||
| @ -18,7 +19,7 @@ import { | ||||
|   convertCreditsToEndpointCredits, | ||||
|   convertImageToEndpointPayloadImage, | ||||
|   convertRTCToEndpointRTC, | ||||
|   convertSourceToEndpointSource, | ||||
|   convertRelationshipsToEndpointRelations, | ||||
| } from "../../../utils/endpoints"; | ||||
| import { convertRecorderToEndpointRecorderPreview } from "../../Recorders/endpoints/getByID"; | ||||
| 
 | ||||
| @ -49,8 +50,8 @@ export const convertPageToEndpointPagePreview = ({ | ||||
|   updatedAt, | ||||
| }); | ||||
| 
 | ||||
| const convertPageToEndpointPage = (page: Page): EndpointPage => { | ||||
|   const { translations, collectibles, folders, backgroundImage, createdAt, updatedBy } = page; | ||||
| const convertPageToEndpointPage = async (page: Page): Promise<EndpointPage> => { | ||||
|   const { translations, backgroundImage, createdAt, updatedBy, id } = page; | ||||
| 
 | ||||
|   return { | ||||
|     ...convertPageToEndpointPagePreview(page), | ||||
| @ -74,7 +75,9 @@ const convertPageToEndpointPage = (page: Page): EndpointPage => { | ||||
|     ...(isPayloadType(updatedBy) | ||||
|       ? { updatedBy: convertRecorderToEndpointRecorderPreview(updatedBy) } | ||||
|       : {}), | ||||
|     parentPages: convertSourceToEndpointSource({ collectibles, folders }), | ||||
|     backlinks: convertRelationshipsToEndpointRelations( | ||||
|       await findIncomingRelationships(Collections.Pages, id) | ||||
|     ), | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -5,8 +5,6 @@ import { imageField } from "../../fields/imageField/imageField"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| import { translatedFields } from "../../fields/translatedFields/translatedFields"; | ||||
| import { Collections, CollectionGroups } from "../../shared/payload/constants"; | ||||
| import { Video } from "../../types/collections"; | ||||
| import { isPayloadType } from "../../utils/asserts"; | ||||
| import { buildCollectionConfig } from "../../utils/collectionConfig"; | ||||
| import { createEditor } from "../../utils/editor"; | ||||
| import { getByID } from "./endpoints/getByID"; | ||||
| @ -130,12 +128,4 @@ export const Videos = buildCollectionConfig({ | ||||
|       ], | ||||
|     }), | ||||
|   ], | ||||
|   custom: { | ||||
|     getBackPropagatedRelationships: ({ platform, platformEnabled }: Video) => { | ||||
|       if (!platform || !platformEnabled) { | ||||
|         return []; | ||||
|       } | ||||
|       return [isPayloadType(platform.channel) ? platform.channel.id : platform.channel]; | ||||
|     }, | ||||
|   }, | ||||
| }); | ||||
|  | ||||
| @ -15,6 +15,7 @@ import { | ||||
|   convertCreditsToEndpointCredits, | ||||
|   convertMediaThumbnailToEndpointPayloadImage, | ||||
|   convertRTCToEndpointRTC, | ||||
|   convertRelationshipsToEndpointRelations, | ||||
|   getLanguageId, | ||||
| } from "../../../utils/endpoints"; | ||||
| import { Collections } from "../../../shared/payload/constants"; | ||||
| @ -23,6 +24,7 @@ import { | ||||
|   EndpointVideoPreview, | ||||
|   EndpointVideo, | ||||
| } from "../../../shared/payload/endpoint-types"; | ||||
| import { findIncomingRelationships } from "payloadcms-relationships"; | ||||
| 
 | ||||
| export const getByID: CollectionEndpoint = { | ||||
|   method: "get", | ||||
| @ -52,7 +54,7 @@ export const getByID: CollectionEndpoint = { | ||||
|         return res.sendStatus(404); | ||||
|       } | ||||
| 
 | ||||
|       return res.status(200).json(convertVideoToEndpointVideo(result)); | ||||
|       return res.status(200).json(await convertVideoToEndpointVideo(result)); | ||||
|     } catch { | ||||
|       return res.sendStatus(404); | ||||
|     } | ||||
| @ -98,8 +100,8 @@ export const convertVideoToEndpointVideoPreview = ({ | ||||
|     }) ?? [], | ||||
| }); | ||||
| 
 | ||||
| const convertVideoToEndpointVideo = (video: Video & PayloadMedia): EndpointVideo => { | ||||
|   const { translations, createdAt, updatedAt, filesize, platform, platformEnabled, credits } = | ||||
| const convertVideoToEndpointVideo = async (video: Video & PayloadMedia): Promise<EndpointVideo> => { | ||||
|   const { translations, createdAt, updatedAt, filesize, platform, platformEnabled, credits, id } = | ||||
|     video; | ||||
| 
 | ||||
|   return { | ||||
| @ -125,5 +127,8 @@ const convertVideoToEndpointVideo = (video: Video & PayloadMedia): EndpointVideo | ||||
|         } | ||||
|       : {}), | ||||
|     credits: convertCreditsToEndpointCredits(credits), | ||||
|     backlinks: convertRelationshipsToEndpointRelations( | ||||
|       await findIncomingRelationships(Collections.Videos, id) | ||||
|     ), | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| import { CollectionConfig } from "payload/types"; | ||||
| import { backPropagationField } from "../../fields/backPropagationField/backPropagationField"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| import { buildCollectionConfig } from "../../utils/collectionConfig"; | ||||
| import { Collections, CollectionGroups } from "../../shared/payload/constants"; | ||||
| @ -31,11 +30,5 @@ export const VideosChannels: CollectionConfig = buildCollectionConfig({ | ||||
|       { name: fields.title, type: "text", required: true }, | ||||
|       { name: fields.subscribers, type: "number", required: true }, | ||||
|     ]), | ||||
|     backPropagationField({ | ||||
|       name: fields.videos, | ||||
|       relationTo: Collections.Videos, | ||||
|       hasMany: true, | ||||
|       where: ({ id }) => ({ "platform.channel": { equals: id } }), | ||||
|     }), | ||||
|   ], | ||||
| }); | ||||
|  | ||||
| @ -2,7 +2,6 @@ import { GlobalConfig } from "payload/types"; | ||||
| import { mustBeAdmin } from "../../accesses/collections/mustBeAdmin"; | ||||
| import { imageField } from "../../fields/imageField/imageField"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| import { globalAfterChangeWebhook } from "../../hooks/afterOperationWebhook"; | ||||
| import { getConfigEndpoint } from "./endpoints/getConfigEndpoint"; | ||||
| import { Collections, CollectionGroups } from "../../shared/payload/constants"; | ||||
| 
 | ||||
| @ -31,9 +30,6 @@ export const WebsiteConfig: GlobalConfig = { | ||||
|   }, | ||||
|   access: { update: mustBeAdmin, read: mustBeAdmin }, | ||||
|   endpoints: [getConfigEndpoint], | ||||
|   hooks: { | ||||
|     afterChange: [globalAfterChangeWebhook], | ||||
|   }, | ||||
|   fields: [ | ||||
|     rowField([ | ||||
|       { | ||||
|  | ||||
| @ -124,7 +124,7 @@ export const getAllSDKUrlsEndpoint: Endpoint = { | ||||
|   }, | ||||
| }; | ||||
| 
 | ||||
| export const getSDKUrlsForDocument = (collection: Collections, doc: any): string[] => { | ||||
| const getSDKUrlsForDocument = (collection: Collections, doc: any): string[] => { | ||||
|   switch (collection) { | ||||
|     case Collections.WebsiteConfig: | ||||
|       return [getSDKEndpoint.getConfigEndpoint()]; | ||||
|  | ||||
| @ -1,51 +0,0 @@ | ||||
| import payload, { GeneratedTypes } from "payload"; | ||||
| import { FieldBase, SingleRelationshipField } from "payload/dist/fields/config/types"; | ||||
| import { Where } from "payload/types"; | ||||
| import { isEmpty } from "../../utils/asserts"; | ||||
| 
 | ||||
| type BackPropagationField = FieldBase & { | ||||
|   where: (data: any) => Where; | ||||
|   relationTo: keyof GeneratedTypes["collections"]; | ||||
|   hasMany?: boolean; | ||||
| }; | ||||
| export const backPropagationField = ({ | ||||
|   admin, | ||||
|   hooks: { beforeChange = [], afterRead = [], ...otherHooks } = {}, | ||||
|   where, | ||||
|   hasMany = false, | ||||
|   ...params | ||||
| }: BackPropagationField): SingleRelationshipField => ({ | ||||
|   ...params, | ||||
|   type: "relationship", | ||||
|   hasMany: hasMany, | ||||
|   admin: { ...admin, readOnly: true }, | ||||
|   hooks: { | ||||
|     ...otherHooks, | ||||
|     beforeChange: [ | ||||
|       ...beforeChange, | ||||
|       ({ siblingData }) => { | ||||
|         delete siblingData[params.name]; | ||||
|       }, | ||||
|     ], | ||||
|     afterRead: [ | ||||
|       ...afterRead, | ||||
|       async ({ data, context }) => { | ||||
|         if (isEmpty(data?.id) || context.stopPropagation) { | ||||
|           return hasMany ? [] : undefined; | ||||
|         } | ||||
|         const result = await payload.find({ | ||||
|           collection: params.relationTo, | ||||
|           where: where(data), | ||||
|           limit: 100, | ||||
|           depth: 0, | ||||
|           context: { stopPropagation: true }, | ||||
|         }); | ||||
|         if (hasMany) { | ||||
|           return result.docs.map((doc) => doc.id); | ||||
|         } else { | ||||
|           return result.docs[0]?.id; | ||||
|         } | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
| }); | ||||
| @ -1,47 +0,0 @@ | ||||
| import payload, { GeneratedTypes } from "payload"; | ||||
| import { SanitizedCollectionConfig, SanitizedGlobalConfig } from "payload/types"; | ||||
| 
 | ||||
| export const getAddedBackPropagationRelationships = async ( | ||||
|   config: SanitizedCollectionConfig | SanitizedGlobalConfig, | ||||
|   doc: any, | ||||
|   previousDoc?: any | ||||
| ): Promise<string[]> => { | ||||
|   if (!("getBackPropagatedRelationships" in config.custom)) { | ||||
|     return []; | ||||
|   } | ||||
| 
 | ||||
|   const getBackPropagatedRelationships: (doc: any) => string[] = | ||||
|     config.custom.getBackPropagatedRelationships; | ||||
| 
 | ||||
|   if (!previousDoc) { | ||||
|     return getBackPropagatedRelationships(doc); | ||||
|   } | ||||
| 
 | ||||
|   let currentIds: string[]; | ||||
|   let previousIds: string[]; | ||||
| 
 | ||||
|   if (config.versions.drafts) { | ||||
|     const versions = await payload.findVersions({ | ||||
|       collection: config.slug as keyof GeneratedTypes["collections"], | ||||
|       sort: "-updatedAt", | ||||
|       limit: 2, | ||||
|       where: { | ||||
|         and: [{ parent: { equals: doc.id } }, { "version._status": { equals: "published" } }], | ||||
|       }, | ||||
|     }); | ||||
| 
 | ||||
|     const currentVersion = versions.docs[0]?.version; | ||||
|     const previousVersion = versions.docs[1]?.version; | ||||
| 
 | ||||
|     if (!currentVersion) return []; | ||||
|     if (!previousVersion) return getBackPropagatedRelationships(currentVersion); | ||||
| 
 | ||||
|     currentIds = getBackPropagatedRelationships(currentVersion); | ||||
|     previousIds = getBackPropagatedRelationships(previousVersion); | ||||
|   } else { | ||||
|     currentIds = getBackPropagatedRelationships(doc); | ||||
|     previousIds = getBackPropagatedRelationships(previousDoc); | ||||
|   } | ||||
| 
 | ||||
|   return currentIds.filter((id) => !previousIds.includes(id)); | ||||
| }; | ||||
| @ -1,99 +0,0 @@ | ||||
| import { | ||||
|   AfterDeleteHook, | ||||
|   AfterChangeHook as CollectionAfterChangeHook, | ||||
| } from "payload/dist/collections/config/types"; | ||||
| import { AfterChangeHook as GlobalAfterChangeHook } from "payload/dist/globals/config/types"; | ||||
| import { getSDKUrlsForDocument } from "../endpoints/getAllSDKUrlsEndpoint"; | ||||
| import { getAddedBackPropagationRelationships } from "../fields/backPropagationField/backPropagationUtils"; | ||||
| import { Collections } from "../shared/payload/constants"; | ||||
| import { AfterOperationWebHookMessage } from "../shared/payload/webhooks"; | ||||
| 
 | ||||
| export const globalAfterChangeWebhook: GlobalAfterChangeHook = async ({ | ||||
|   global, | ||||
|   doc, | ||||
|   previousDoc, | ||||
| }) => { | ||||
|   const collection = global.slug as Collections; | ||||
|   await sendWebhookMessage({ | ||||
|     collection, | ||||
|     addedDependantIds: await getAddedBackPropagationRelationships(global, doc, previousDoc), | ||||
|     urls: getSDKUrlsForDocument(collection, doc), | ||||
|   }); | ||||
|   return doc; | ||||
| }; | ||||
| 
 | ||||
| export const collectionAfterChangeWebhook: CollectionAfterChangeHook = async ({ | ||||
|   collection, | ||||
|   doc, | ||||
|   previousDoc, | ||||
|   operation, | ||||
| }) => { | ||||
|   const collectionSlug = collection.slug as Collections; | ||||
|   console.log("afterChange", operation, collectionSlug, doc.id); | ||||
| 
 | ||||
|   if ("_status" in doc && doc._status === "draft") { | ||||
|     return doc; | ||||
|   } | ||||
| 
 | ||||
|   if (!("id" in doc)) { | ||||
|     return doc; | ||||
|   } | ||||
| 
 | ||||
|   await sendWebhookMessage({ | ||||
|     collection: collectionSlug, | ||||
|     id: doc.id, | ||||
|     addedDependantIds: await getAddedBackPropagationRelationships(collection, doc, previousDoc), | ||||
|     urls: getSDKUrlsForDocument(collectionSlug, doc), | ||||
|   }); | ||||
| 
 | ||||
|   return doc; | ||||
| }; | ||||
| 
 | ||||
| export const afterDeleteWebhook: AfterDeleteHook = async ({ collection, doc }) => { | ||||
|   const collectionSlug = collection.slug as Collections; | ||||
|   console.log("afterDelete", collection.slug, doc.id); | ||||
| 
 | ||||
|   if (!("id" in doc)) { | ||||
|     return doc; | ||||
|   } | ||||
| 
 | ||||
|   await sendWebhookMessage({ | ||||
|     collection: collectionSlug, | ||||
|     id: doc.id, | ||||
|     addedDependantIds: [], | ||||
|     urls: getSDKUrlsForDocument(collectionSlug, doc), | ||||
|   }); | ||||
| 
 | ||||
|   return doc; | ||||
| }; | ||||
| 
 | ||||
| const webhookTargets: { url: string; token: string }[] = [ | ||||
|   { | ||||
|     url: process.env.WEB_SERVER_HOOK_URL ?? "", | ||||
|     token: process.env.WEB_SERVER_HOOK_TOKEN ?? "", | ||||
|   }, | ||||
|   { | ||||
|     url: process.env.MEILISEARCH_HOOK_URL ?? "", | ||||
|     token: process.env.MEILISEARCH_HOOK_TOKEN ?? "", | ||||
|   }, | ||||
| ]; | ||||
| 
 | ||||
| const sendWebhookMessage = async (message: AfterOperationWebHookMessage) => { | ||||
|   try { | ||||
|     await Promise.all( | ||||
|       webhookTargets.flatMap(({ url, token }) => { | ||||
|         if (!url) return; | ||||
|         return fetch(url, { | ||||
|           headers: { | ||||
|             Authorization: `Bearer ${token}`, | ||||
|             "Content-Type": "application/json", | ||||
|           }, | ||||
|           body: JSON.stringify(message), | ||||
|           method: "POST", | ||||
|         }); | ||||
|       }) | ||||
|     ); | ||||
|   } catch (e) { | ||||
|     console.warn("Error while sending webhook", e); | ||||
|   } | ||||
| }; | ||||
| @ -31,6 +31,9 @@ import { getAllIds } from "./endpoints/getAllIdsEndpoint"; | ||||
| import { getAllSDKUrlsEndpoint } from "./endpoints/getAllSDKUrlsEndpoint"; | ||||
| import { createEditor } from "./utils/editor"; | ||||
| import { Collections } from "./shared/payload/constants"; | ||||
| import { relationshipsPlugin } from "payloadcms-relationships"; | ||||
| import { shownOnlyToAdmin } from "./accesses/collections/shownOnlyToAdmin"; | ||||
| import { mustBeAdmin } from "./accesses/fields/mustBeAdmin"; | ||||
| 
 | ||||
| const configuredSftpAdapter = sftpAdapter({ | ||||
|   connectOptions: { | ||||
| @ -96,6 +99,19 @@ export default buildConfig({ | ||||
|     skip: () => true, | ||||
|   }, | ||||
|   plugins: [ | ||||
|     relationshipsPlugin({ | ||||
|       collectionConfig: { | ||||
|         admin: { | ||||
|           hidden: shownOnlyToAdmin, | ||||
|         }, | ||||
|         access: { | ||||
|           update: mustBeAdmin, | ||||
|           create: mustBeAdmin, | ||||
|           delete: mustBeAdmin, | ||||
|         }, | ||||
|       }, | ||||
|     }), | ||||
| 
 | ||||
|     cloudStorage({ | ||||
|       collections: { | ||||
|         [Collections.Videos]: { | ||||
|  | ||||
| @ -2,7 +2,7 @@ import "dotenv/config"; | ||||
| import express from "express"; | ||||
| import path from "path"; | ||||
| import payload from "payload"; | ||||
| import { isDefined, isUndefined } from "./utils/asserts"; | ||||
| import { isUndefined } from "./utils/asserts"; | ||||
| import { Collections, RecordersRoles } from "./shared/payload/constants"; | ||||
| 
 | ||||
| const app = express(); | ||||
| @ -28,29 +28,30 @@ const start = async () => { | ||||
|     express: app, | ||||
|     onInit: async () => { | ||||
|       payload.logger.info(`Payload Admin URL: ${payload.getAdminURL()}`); | ||||
|       const recorders = await payload.find({ collection: Collections.Recorders }); | ||||
| 
 | ||||
|       // If no recorders, we seed some initial data
 | ||||
|       if ( | ||||
|         isDefined(process.env.SEEDING_ADMIN_EMAIL) && | ||||
|         isDefined(process.env.SEEDING_ADMIN_PASSWORD) && | ||||
|         isDefined(process.env.SEEDING_ADMIN_USERNAME) | ||||
|       ) { | ||||
|         if (recorders.docs.length === 0) { | ||||
|           payload.logger.info("Seeding some initial data"); | ||||
|       const seedFirstUser = async () => { | ||||
|         const recorders = await payload.find({ collection: Collections.Recorders }); | ||||
| 
 | ||||
|           await payload.create({ | ||||
|             collection: Collections.Recorders, | ||||
|             data: { | ||||
|               email: process.env.SEEDING_ADMIN_EMAIL, | ||||
|               password: process.env.SEEDING_ADMIN_PASSWORD, | ||||
|               username: process.env.SEEDING_ADMIN_USERNAME, | ||||
|               role: [RecordersRoles.Admin, RecordersRoles.Api], | ||||
|               anonymize: false, | ||||
|             }, | ||||
|           }); | ||||
|         } | ||||
|       } | ||||
|         if (recorders.docs.length > 0) return; | ||||
|         if (isUndefined(process.env.SEEDING_ADMIN_EMAIL)) return; | ||||
|         if (isUndefined(process.env.SEEDING_ADMIN_PASSWORD)) return; | ||||
|         if (isUndefined(process.env.SEEDING_ADMIN_USERNAME)) return; | ||||
| 
 | ||||
|         payload.logger.info("Seeding your first user"); | ||||
| 
 | ||||
|         await payload.create({ | ||||
|           collection: Collections.Recorders, | ||||
|           data: { | ||||
|             email: process.env.SEEDING_ADMIN_EMAIL, | ||||
|             password: process.env.SEEDING_ADMIN_PASSWORD, | ||||
|             username: process.env.SEEDING_ADMIN_USERNAME, | ||||
|             role: [RecordersRoles.Admin, RecordersRoles.Api], | ||||
|             anonymize: false, | ||||
|           }, | ||||
|         }); | ||||
|       }; | ||||
| 
 | ||||
|       await seedFirstUser(); | ||||
|     }, | ||||
|   }); | ||||
| 
 | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| Subproject commit 824f7085f9e0787f97ef9afd11cb5320a2cd6208 | ||||
| Subproject commit 7d6f5ffb704f4ecddfb0e0982ce9eb79d39d450d | ||||
| @ -40,6 +40,7 @@ export interface Config { | ||||
|     currencies: Currency; | ||||
|     wordings: Wording; | ||||
|     "generic-contents": GenericContent; | ||||
|     relationships: Relationship; | ||||
|     "payload-preferences": PayloadPreference; | ||||
|     "payload-migrations": PayloadMigration; | ||||
|   }; | ||||
| @ -96,8 +97,6 @@ export interface Page { | ||||
|     credits?: Credits; | ||||
|     id?: string | null; | ||||
|   }[]; | ||||
|   folders?: (string | Folder)[] | null; | ||||
|   collectibles?: (string | Collectible)[] | null; | ||||
|   updatedBy: string | Recorder; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
| @ -352,79 +351,6 @@ export interface Recorder { | ||||
|   lockUntil?: string | null; | ||||
|   password?: string | null; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "folders". | ||||
|  */ | ||||
| export interface Folder { | ||||
|   id: string; | ||||
|   slug: string; | ||||
|   icon?: string | null; | ||||
|   parentFolders?: (string | Folder)[] | null; | ||||
|   translations: { | ||||
|     language: string | Language; | ||||
|     name: string; | ||||
|     description?: { | ||||
|       root: { | ||||
|         type: string; | ||||
|         children: { | ||||
|           type: string; | ||||
|           version: number; | ||||
|           [k: string]: unknown; | ||||
|         }[]; | ||||
|         direction: ("ltr" | "rtl") | null; | ||||
|         format: "left" | "start" | "center" | "right" | "end" | "justify" | ""; | ||||
|         indent: number; | ||||
|         version: number; | ||||
|       }; | ||||
|       [k: string]: unknown; | ||||
|     } | null; | ||||
|     id?: string | null; | ||||
|   }[]; | ||||
|   sections?: | ||||
|     | { | ||||
|         translations?: | ||||
|           | { | ||||
|               language: string | Language; | ||||
|               name: string; | ||||
|               id?: string | null; | ||||
|             }[] | ||||
|           | null; | ||||
|         subfolders?: (string | Folder)[] | null; | ||||
|         id?: string | null; | ||||
|       }[] | ||||
|     | null; | ||||
|   files?: | ||||
|     | ( | ||||
|         | { | ||||
|             relationTo: "collectibles"; | ||||
|             value: string | Collectible; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "pages"; | ||||
|             value: string | Page; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "videos"; | ||||
|             value: string | Video; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "images"; | ||||
|             value: string | Image; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "audios"; | ||||
|             value: string | Audio; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "files"; | ||||
|             value: string | File; | ||||
|           } | ||||
|       )[] | ||||
|     | null; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "collectibles". | ||||
| @ -608,8 +534,6 @@ export interface Collectible { | ||||
|         id?: string | null; | ||||
|       }[] | ||||
|     | null; | ||||
|   folders?: (string | Folder)[] | null; | ||||
|   parentItems?: (string | Collectible)[] | null; | ||||
|   updatedBy: string | Recorder; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
| @ -951,7 +875,78 @@ export interface VideosChannel { | ||||
|   url: string; | ||||
|   title: string; | ||||
|   subscribers: number; | ||||
|   videos?: (string | Video)[] | null; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "folders". | ||||
|  */ | ||||
| export interface Folder { | ||||
|   id: string; | ||||
|   slug: string; | ||||
|   icon?: string | null; | ||||
|   translations: { | ||||
|     language: string | Language; | ||||
|     name: string; | ||||
|     description?: { | ||||
|       root: { | ||||
|         type: string; | ||||
|         children: { | ||||
|           type: string; | ||||
|           version: number; | ||||
|           [k: string]: unknown; | ||||
|         }[]; | ||||
|         direction: ("ltr" | "rtl") | null; | ||||
|         format: "left" | "start" | "center" | "right" | "end" | "justify" | ""; | ||||
|         indent: number; | ||||
|         version: number; | ||||
|       }; | ||||
|       [k: string]: unknown; | ||||
|     } | null; | ||||
|     id?: string | null; | ||||
|   }[]; | ||||
|   sections?: | ||||
|     | { | ||||
|         translations?: | ||||
|           | { | ||||
|               language: string | Language; | ||||
|               name: string; | ||||
|               id?: string | null; | ||||
|             }[] | ||||
|           | null; | ||||
|         subfolders?: (string | Folder)[] | null; | ||||
|         id?: string | null; | ||||
|       }[] | ||||
|     | null; | ||||
|   files?: | ||||
|     | ( | ||||
|         | { | ||||
|             relationTo: "collectibles"; | ||||
|             value: string | Collectible; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "pages"; | ||||
|             value: string | Page; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "videos"; | ||||
|             value: string | Video; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "images"; | ||||
|             value: string | Image; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "audios"; | ||||
|             value: string | Audio; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "files"; | ||||
|             value: string | File; | ||||
|           } | ||||
|       )[] | ||||
|     | null; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
| @ -1082,6 +1077,260 @@ export interface Wording { | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "relationships". | ||||
|  */ | ||||
| export interface Relationship { | ||||
|   id: string; | ||||
|   document: | ||||
|     | { | ||||
|         relationTo: "pages"; | ||||
|         value: string | Page; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "collectibles"; | ||||
|         value: string | Collectible; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "folders"; | ||||
|         value: string | Folder; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "chronology-events"; | ||||
|         value: string | ChronologyEvent; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "images"; | ||||
|         value: string | Image; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "audios"; | ||||
|         value: string | Audio; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "media-thumbnails"; | ||||
|         value: string | MediaThumbnail; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "videos"; | ||||
|         value: string | Video; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "videos-subtitles"; | ||||
|         value: string | VideoSubtitle; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "videos-channels"; | ||||
|         value: string | VideosChannel; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "files"; | ||||
|         value: string | File; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "scans"; | ||||
|         value: string | Scan; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "tags"; | ||||
|         value: string | Tag; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "attributes"; | ||||
|         value: string | Attribute; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "credits-roles"; | ||||
|         value: string | CreditsRole; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "recorders"; | ||||
|         value: string | Recorder; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "languages"; | ||||
|         value: string | Language; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "currencies"; | ||||
|         value: string | Currency; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "wordings"; | ||||
|         value: string | Wording; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "generic-contents"; | ||||
|         value: string | GenericContent; | ||||
|       }; | ||||
|   incomingRelations?: | ||||
|     | ( | ||||
|         | { | ||||
|             relationTo: "pages"; | ||||
|             value: string | Page; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "collectibles"; | ||||
|             value: string | Collectible; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "folders"; | ||||
|             value: string | Folder; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "chronology-events"; | ||||
|             value: string | ChronologyEvent; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "images"; | ||||
|             value: string | Image; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "audios"; | ||||
|             value: string | Audio; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "media-thumbnails"; | ||||
|             value: string | MediaThumbnail; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "videos"; | ||||
|             value: string | Video; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "videos-subtitles"; | ||||
|             value: string | VideoSubtitle; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "videos-channels"; | ||||
|             value: string | VideosChannel; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "files"; | ||||
|             value: string | File; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "scans"; | ||||
|             value: string | Scan; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "tags"; | ||||
|             value: string | Tag; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "attributes"; | ||||
|             value: string | Attribute; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "credits-roles"; | ||||
|             value: string | CreditsRole; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "recorders"; | ||||
|             value: string | Recorder; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "languages"; | ||||
|             value: string | Language; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "currencies"; | ||||
|             value: string | Currency; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "wordings"; | ||||
|             value: string | Wording; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: "generic-contents"; | ||||
|             value: string | GenericContent; | ||||
|           } | ||||
|       )[] | ||||
|     | null; | ||||
|   outgoingRelations: ( | ||||
|     | { | ||||
|         relationTo: "pages"; | ||||
|         value: string | Page; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "collectibles"; | ||||
|         value: string | Collectible; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "folders"; | ||||
|         value: string | Folder; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "chronology-events"; | ||||
|         value: string | ChronologyEvent; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "images"; | ||||
|         value: string | Image; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "audios"; | ||||
|         value: string | Audio; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "media-thumbnails"; | ||||
|         value: string | MediaThumbnail; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "videos"; | ||||
|         value: string | Video; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "videos-subtitles"; | ||||
|         value: string | VideoSubtitle; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "videos-channels"; | ||||
|         value: string | VideosChannel; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "files"; | ||||
|         value: string | File; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "scans"; | ||||
|         value: string | Scan; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "tags"; | ||||
|         value: string | Tag; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "attributes"; | ||||
|         value: string | Attribute; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "credits-roles"; | ||||
|         value: string | CreditsRole; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "recorders"; | ||||
|         value: string | Recorder; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "languages"; | ||||
|         value: string | Language; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "currencies"; | ||||
|         value: string | Currency; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "wordings"; | ||||
|         value: string | Wording; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "generic-contents"; | ||||
|         value: string | GenericContent; | ||||
|       } | ||||
|   )[]; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "payload-preferences". | ||||
|  | ||||
| @ -1,6 +1,5 @@ | ||||
| import { GeneratedTypes } from "payload"; | ||||
| import { CollectionConfig } from "payload/types"; | ||||
| import { afterDeleteWebhook, collectionAfterChangeWebhook } from "../hooks/afterOperationWebhook"; | ||||
| import { formatToPascalCase } from "./string"; | ||||
| 
 | ||||
| type CollectionConfigWithPlugins = CollectionConfig; | ||||
| @ -11,18 +10,9 @@ export type BuildCollectionConfig = Omit< | ||||
| > & { | ||||
|   slug: keyof GeneratedTypes["collections"]; | ||||
|   labels: { singular: string; plural: string }; | ||||
|   custom?: { | ||||
|     getBackPropagatedRelationships?: (object: any) => string[]; | ||||
|     [key: string]: unknown; | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| export const buildCollectionConfig = (config: BuildCollectionConfig): CollectionConfig => ({ | ||||
|   ...config, | ||||
|   typescript: { interface: formatToPascalCase(config.labels.singular) }, | ||||
|   hooks: { | ||||
|     ...config.hooks, | ||||
|     afterChange: [...(config.hooks?.afterChange ?? []), collectionAfterChangeWebhook], | ||||
|     afterDelete: [...(config.hooks?.afterDelete ?? []), afterDeleteWebhook], | ||||
|   }, | ||||
| }); | ||||
|  | ||||
| @ -1,18 +1,22 @@ | ||||
| import { convertAudioToEndpointAudioPreview } from "../collections/Audios/endpoints/getByID"; | ||||
| import { convertEventToEndpointEvent } from "../collections/ChronologyEvents/endpoints/getAllEndpoint"; | ||||
| import { convertCollectibleToEndpointCollectiblePreview } from "../collections/Collectibles/endpoints/getBySlugEndpoint"; | ||||
| import { convertFileToEndpointFilePreview } from "../collections/Files/endpoints/getByID"; | ||||
| import { convertFolderToEndpointFolderPreview } from "../collections/Folders/endpoints/getBySlugEndpoint"; | ||||
| import { convertImageToEndpointImagePreview } from "../collections/Images/endpoints/getByID"; | ||||
| import { convertPageToEndpointPagePreview } from "../collections/Pages/endpoints/getBySlugEndpoint"; | ||||
| import { convertRecorderToEndpointRecorderPreview } from "../collections/Recorders/endpoints/getByID"; | ||||
| import { convertVideoToEndpointVideoPreview } from "../collections/Videos/endpoints/getByID"; | ||||
| import { AttributeTypes } from "../shared/payload/constants"; | ||||
| import { AttributeTypes, Collections } from "../shared/payload/constants"; | ||||
| import { | ||||
|   EndpointTag, | ||||
|   EndpointSource, | ||||
|   EndpointSourcePreview, | ||||
|   EndpointRole, | ||||
|   EndpointCredit, | ||||
|   EndpointAttribute, | ||||
|   PayloadImage, | ||||
|   EndpointScanImage, | ||||
|   EndpointPayloadImage, | ||||
|   EndpointRelation, | ||||
| } from "../shared/payload/endpoint-types"; | ||||
| import { | ||||
|   RichTextContent, | ||||
| @ -29,14 +33,13 @@ import { | ||||
| } from "../shared/payload/rich-text"; | ||||
| import { | ||||
|   Audio, | ||||
|   Collectible, | ||||
|   Credits, | ||||
|   CreditsRole, | ||||
|   Folder, | ||||
|   Image, | ||||
|   Language, | ||||
|   MediaThumbnail, | ||||
|   NumberBlock, | ||||
|   Relationship, | ||||
|   Scan, | ||||
|   Tag, | ||||
|   TagsBlock, | ||||
| @ -47,12 +50,11 @@ import { | ||||
|   isAudio, | ||||
|   isDefined, | ||||
|   isEmpty, | ||||
|   isFile, | ||||
|   isImage, | ||||
|   isNotEmpty, | ||||
|   isPayloadArrayType, | ||||
|   isPayloadImage, | ||||
|   isPayloadType, | ||||
|   isPublished, | ||||
|   isVideo, | ||||
| } from "./asserts"; | ||||
| 
 | ||||
| @ -139,86 +141,64 @@ export const convertRTCToEndpointRTC = ( | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| // TODO: Handle URL sources
 | ||||
| export const convertSourceToEndpointSource = ({ | ||||
|   collectibles, | ||||
|   folders, | ||||
|   gallery, | ||||
|   scans, | ||||
| }: { | ||||
|   collectibles?: (string | Collectible)[] | null | undefined; | ||||
|   scans?: (string | Collectible)[] | null | undefined; | ||||
|   gallery?: (string | Collectible)[] | null | undefined; | ||||
|   folders?: (string | Folder)[] | null | undefined; | ||||
| }): EndpointSource[] => { | ||||
|   const result: EndpointSource[] = []; | ||||
| export const convertRelationshipsToEndpointRelations = ( | ||||
|   relationships: Relationship["incomingRelations"] | Relationship["outgoingRelations"] | ||||
| ): EndpointRelation[] => | ||||
|   relationships?.flatMap<EndpointRelation>(({ relationTo, value }) => { | ||||
|     if (!isPayloadType(value)) return []; | ||||
|     switch (relationTo) { | ||||
|       case Collections.Folders: | ||||
|         return { type: Collections.Folders, value: convertFolderToEndpointFolderPreview(value) }; | ||||
| 
 | ||||
|   const convertFolderToEndpointSourcePreview = ({ | ||||
|     id, | ||||
|     slug, | ||||
|     translations, | ||||
|   }: Folder): EndpointSourcePreview => ({ | ||||
|     id, | ||||
|     slug, | ||||
|     translations: translations.map(({ language, name }) => ({ | ||||
|       language: isPayloadType(language) ? language.id : language, | ||||
|       title: name, | ||||
|     })), | ||||
|   }); | ||||
|       case Collections.Pages: | ||||
|         return { type: Collections.Pages, value: convertPageToEndpointPagePreview(value) }; | ||||
| 
 | ||||
|   const convertCollectibleToEndpointSourcePreview = ({ | ||||
|     id, | ||||
|     slug, | ||||
|     translations, | ||||
|   }: Collectible): EndpointSourcePreview => ({ | ||||
|     id, | ||||
|     slug, | ||||
|     translations: translations.map(({ language, title, pretitle, subtitle }) => ({ | ||||
|       language: isPayloadType(language) ? language.id : language, | ||||
|       title, | ||||
|       ...(isNotEmpty(pretitle) ? { pretitle } : {}), | ||||
|       ...(isNotEmpty(subtitle) ? { subtitle } : {}), | ||||
|     })), | ||||
|   }); | ||||
|       case Collections.Collectibles: | ||||
|         return { | ||||
|           type: Collections.Collectibles, | ||||
|           value: convertCollectibleToEndpointCollectiblePreview(value), | ||||
|         }; | ||||
| 
 | ||||
|   if (collectibles && isPayloadArrayType(collectibles)) { | ||||
|     collectibles.filter(isPublished).forEach((collectible) => { | ||||
|       result.push({ | ||||
|         type: "collectible", | ||||
|         collectible: convertCollectibleToEndpointSourcePreview(collectible), | ||||
|       }); | ||||
|     }); | ||||
|   } | ||||
|       case Collections.Images: | ||||
|         if (!isImage(value)) return []; | ||||
|         return { type: Collections.Images, value: convertImageToEndpointImagePreview(value) }; | ||||
| 
 | ||||
|   if (scans && isPayloadArrayType(scans)) { | ||||
|     scans.filter(isPublished).forEach((collectible) => { | ||||
|       result.push({ | ||||
|         type: "scans", | ||||
|         collectible: convertCollectibleToEndpointSourcePreview(collectible), | ||||
|       }); | ||||
|     }); | ||||
|   } | ||||
|       case Collections.Videos: | ||||
|         if (!isVideo(value)) return []; | ||||
|         return { type: Collections.Videos, value: convertVideoToEndpointVideoPreview(value) }; | ||||
| 
 | ||||
|   if (gallery && isPayloadArrayType(gallery)) { | ||||
|     gallery.filter(isPublished).forEach((collectible) => { | ||||
|       result.push({ | ||||
|         type: "gallery", | ||||
|         collectible: convertCollectibleToEndpointSourcePreview(collectible), | ||||
|       }); | ||||
|     }); | ||||
|   } | ||||
|       case Collections.Audios: | ||||
|         if (!isAudio(value)) return []; | ||||
|         return { type: Collections.Audios, value: convertAudioToEndpointAudioPreview(value) }; | ||||
| 
 | ||||
|   if (folders && isPayloadArrayType(folders)) { | ||||
|     folders.forEach((folder) => { | ||||
|       result.push({ | ||||
|         type: "folder", | ||||
|         folder: convertFolderToEndpointSourcePreview(folder), | ||||
|       }); | ||||
|     }); | ||||
|   } | ||||
|       case Collections.Files: | ||||
|         if (!isFile(value)) return []; | ||||
|         return { type: Collections.Files, value: convertFileToEndpointFilePreview(value) }; | ||||
| 
 | ||||
|   return result; | ||||
| }; | ||||
|       case Collections.Recorders: | ||||
|         return { | ||||
|           type: Collections.Recorders, | ||||
|           value: convertRecorderToEndpointRecorderPreview(value), | ||||
|         }; | ||||
| 
 | ||||
|       case Collections.ChronologyEvents: | ||||
|         return { type: Collections.ChronologyEvents, value: convertEventToEndpointEvent(value) }; | ||||
| 
 | ||||
|       case Collections.MediaThumbnails: | ||||
|       case Collections.VideosSubtitles: | ||||
|       case Collections.VideosChannels: | ||||
|       case Collections.Scans: | ||||
|       case Collections.Tags: | ||||
|       case Collections.Attributes: | ||||
|       case Collections.CreditsRole: | ||||
|       case Collections.Languages: | ||||
|       case Collections.Currencies: | ||||
|       case Collections.Wordings: | ||||
|       case Collections.GenericContents: | ||||
|       default: | ||||
|         return []; | ||||
|     } | ||||
|   }) ?? []; | ||||
| 
 | ||||
| export const getDomainFromUrl = (url: string): string => { | ||||
|   const urlObject = new URL(url); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint