Removed preview types and added media to RTC, collectibles and folders

This commit is contained in:
DrMint 2024-04-07 02:23:07 +02:00
parent b15fe7a0ce
commit 40e54ea2a0
20 changed files with 764 additions and 318 deletions

View File

@ -5,6 +5,7 @@ import { tagsField } from "../../fields/tagsField/tagsField";
import { translatedFields } from "../../fields/translatedFields/translatedFields"; import { translatedFields } from "../../fields/translatedFields/translatedFields";
import { buildCollectionConfig } from "../../utils/collectionConfig"; import { buildCollectionConfig } from "../../utils/collectionConfig";
import { createEditor } from "../../utils/editor"; import { createEditor } from "../../utils/editor";
import { getByID } from "./endpoints/getByID";
const fields = { const fields = {
filename: "filename", filename: "filename",
@ -38,6 +39,7 @@ export const Audios = buildCollectionConfig({
mimeTypes: ["audio/*"], mimeTypes: ["audio/*"],
disableLocalStorage: true, disableLocalStorage: true,
}, },
endpoints: [getByID],
fields: [ fields: [
rowField([ rowField([
{ name: fields.duration, type: "number", min: 0, required: true }, { name: fields.duration, type: "number", min: 0, required: true },

View File

@ -0,0 +1,77 @@
import payload from "payload";
import { Collections } from "../../../constants";
import { EndpointAudio, PayloadMedia } from "../../../sdk";
import { Audio } from "../../../types/collections";
import { CollectionEndpoint } from "../../../types/payload";
import { isNotEmpty, isValidPayloadImage, isValidPayloadMedia } from "../../../utils/asserts";
import {
convertRTCToEndpointRTC,
convertTagsEndpointTagsGroups,
getLanguageId,
} from "../../../utils/endpoints";
export const getByID: CollectionEndpoint = {
method: "get",
path: "/id/:id",
handler: async (req, res) => {
if (!req.user) {
return res.status(403).send({
errors: [
{
message: "You are not allowed to perform this action.",
},
],
});
}
if (!req.params.id) {
return res.status(400).send({ errors: [{ message: "Missing 'id' query params" }] });
}
try {
const result = await payload.findByID({
collection: Collections.Audios,
id: req.params.id,
});
if (!isValidPayloadMedia(result)) {
return res.sendStatus(404);
}
return res.status(200).json(convertAudioToEndpointAudio(result));
} catch {
return res.sendStatus(404);
}
},
};
export const convertAudioToEndpointAudio = ({
url,
tags,
translations,
mimeType,
createdAt,
updatedAt,
filename,
filesize,
duration,
id,
thumbnail,
}: Audio & PayloadMedia): EndpointAudio => ({
url,
tagGroups: convertTagsEndpointTagsGroups(tags),
createdAt,
filename,
filesize,
id,
mimeType,
updatedAt,
translations:
translations?.map(({ language, title, description }) => ({
language: getLanguageId(language),
title,
...(isNotEmpty(description) ? { description: convertRTCToEndpointRTC(description) } : {}),
})) ?? [],
duration,
...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}),
});

View File

@ -4,9 +4,10 @@ import { EndpointChronologyEvent, EndpointSource } from "../../../sdk";
import { ChronologyEvent, CollectibleBlock } from "../../../types/collections"; import { ChronologyEvent, CollectibleBlock } from "../../../types/collections";
import { CollectionEndpoint } from "../../../types/payload"; import { CollectionEndpoint } from "../../../types/payload";
import { isDefined, isNotEmpty, isPayloadArrayType, isPayloadType } from "../../../utils/asserts"; import { isDefined, isNotEmpty, isPayloadArrayType, isPayloadType } from "../../../utils/asserts";
import { getDomainFromUrl, handleRecorder } from "../../../utils/endpoints"; import { getDomainFromUrl } from "../../../utils/endpoints";
import { convertCollectibleToPreview } from "../../Collectibles/endpoints/getBySlugEndpoint"; import { convertCollectibleToEndpointCollectible } from "../../Collectibles/endpoints/getBySlugEndpoint";
import { convertPageToPreview } from "../../Pages/endpoints/getBySlugEndpoint"; import { convertPageToEndpointPage } from "../../Pages/endpoints/getBySlugEndpoint";
import { convertRecorderToEndpointRecorder } from "../../Recorders/endpoints/getByUsername";
export const getAllEndpoint: CollectionEndpoint = { export const getAllEndpoint: CollectionEndpoint = {
method: "get", method: "get",
@ -82,9 +83,15 @@ export const eventToEndpointEvent = ({
...(isNotEmpty(title) ? { title } : {}), ...(isNotEmpty(title) ? { title } : {}),
...(isNotEmpty(description) ? { description } : {}), ...(isNotEmpty(description) ? { description } : {}),
...(isNotEmpty(notes) ? { notes } : {}), ...(isNotEmpty(notes) ? { notes } : {}),
proofreaders: isPayloadArrayType(proofreaders) ? proofreaders.map(handleRecorder) : [], proofreaders: isPayloadArrayType(proofreaders)
transcribers: isPayloadArrayType(transcribers) ? transcribers.map(handleRecorder) : [], ? proofreaders.map(convertRecorderToEndpointRecorder)
translators: isPayloadArrayType(translators) ? translators.map(handleRecorder) : [], : [],
transcribers: isPayloadArrayType(transcribers)
? transcribers.map(convertRecorderToEndpointRecorder)
: [],
translators: isPayloadArrayType(translators)
? translators.map(convertRecorderToEndpointRecorder)
: [],
}) })
), ),
sources: handleSources(sources), sources: handleSources(sources),
@ -100,7 +107,7 @@ const handleSources = (sources: ChronologyEvent["events"][number]["sources"]): E
if (!isPayloadType(source.collectible)) return []; if (!isPayloadType(source.collectible)) return [];
return { return {
type: "collectible", type: "collectible",
collectible: convertCollectibleToPreview(source.collectible), collectible: convertCollectibleToEndpointCollectible(source.collectible),
...(isDefined(range) ? { range } : {}), ...(isDefined(range) ? { range } : {}),
}; };
@ -108,7 +115,7 @@ const handleSources = (sources: ChronologyEvent["events"][number]["sources"]): E
if (!isPayloadType(source.page)) return []; if (!isPayloadType(source.page)) return [];
return { return {
type: "page", type: "page",
page: convertPageToPreview(source.page), page: convertPageToEndpointPage(source.page),
}; };
case "urlBlock": case "urlBlock":

View File

@ -1,6 +1,6 @@
import { CollectibleNature, Collections } from "../../../constants"; import { CollectibleNature, Collections } from "../../../constants";
import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint"; import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint";
import { EndpointCollectible, EndpointCollectiblePreview, PayloadImage } from "../../../sdk"; import { EndpointCollectible, PayloadImage } from "../../../sdk";
import { Collectible } from "../../../types/collections"; import { Collectible } from "../../../types/collections";
import { import {
isDefined, isDefined,
@ -9,52 +9,76 @@ import {
isPayloadType, isPayloadType,
isPublished, isPublished,
isValidPayloadImage, isValidPayloadImage,
isValidPayloadMedia,
} from "../../../utils/asserts"; } from "../../../utils/asserts";
import { convertTagsToGroups, getDomainFromUrl, handleParentPages } from "../../../utils/endpoints"; import {
import { convertPageToPreview } from "../../Pages/endpoints/getBySlugEndpoint"; convertSourceToEndpointSource,
convertTagsEndpointTagsGroups,
getDomainFromUrl,
} from "../../../utils/endpoints";
import { convertAudioToEndpointAudio } from "../../Audios/endpoints/getByID";
import { convertPageToEndpointPage } from "../../Pages/endpoints/getBySlugEndpoint";
import { convertVideoToEndpointVideo } from "../../Videos/endpoints/getByID";
export const getBySlugEndpoint = createGetByEndpoint({ export const getBySlugEndpoint = createGetByEndpoint({
collection: Collections.Collectibles, collection: Collections.Collectibles,
attribute: "slug", attribute: "slug",
depth: 3, depth: 3,
handler: (collectible: Collectible): EndpointCollectible => { handler: (collectible) => convertCollectibleToEndpointCollectible(collectible),
const { });
nature,
urls,
subitems,
gallery,
contents,
priceEnabled,
price,
size,
sizeEnabled,
weight,
weightEnabled,
pageInfo,
pageInfoEnabled,
parentItems,
folders,
backgroundImage,
} = collectible;
return { export const convertCollectibleToEndpointCollectible = ({
...convertCollectibleToPreview(collectible), nature,
...(isValidPayloadImage(backgroundImage) ? { backgroundImage } : {}), urls,
contents: handleContents(contents), subitems,
gallery: handleGallery(gallery), gallery,
scans: handleScans(collectible.scans), contents,
nature: nature === "Physical" ? CollectibleNature.Physical : CollectibleNature.Digital, priceEnabled,
parentPages: handleParentPages({ collectibles: parentItems, folders }), price,
subitems: isPayloadArrayType(subitems) size,
? subitems.filter(isPublished).map(convertCollectibleToPreview) sizeEnabled,
: [], weight,
urls: urls?.map(({ url }) => ({ url, label: getDomainFromUrl(url) })) ?? [], weightEnabled,
...(weightEnabled && isDefined(weight) ? { weight: weight.amount } : {}), pageInfo,
...handleSize(size, sizeEnabled), pageInfoEnabled,
...handlePageInfo(pageInfo, pageInfoEnabled), parentItems,
...handlePrice(price, priceEnabled), folders,
}; backgroundImage,
}, slug,
thumbnail,
translations,
releaseDate,
languages,
scans,
tags,
}: Collectible): EndpointCollectible => ({
slug,
languages: languages?.map((language) => (isPayloadType(language) ? language.id : language)) ?? [],
...(isDefined(releaseDate) ? { releaseDate } : {}),
...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}),
tagGroups: convertTagsEndpointTagsGroups(tags),
translations:
translations?.map(({ language, title, description, pretitle, subtitle }) => ({
language: isPayloadType(language) ? language.id : language,
title,
...(isNotEmpty(pretitle) ? { pretitle } : {}),
...(isNotEmpty(subtitle) ? { subtitle } : {}),
...(isNotEmpty(description) ? { description } : {}),
})) ?? [],
...(isValidPayloadImage(backgroundImage) ? { backgroundImage } : {}),
contents: handleContents(contents),
gallery: handleGallery(gallery),
scans: handleScans(scans),
nature: nature === "Physical" ? CollectibleNature.Physical : CollectibleNature.Digital,
parentPages: convertSourceToEndpointSource({ collectibles: parentItems, folders }),
subitems: isPayloadArrayType(subitems)
? subitems.filter(isPublished).map(convertCollectibleToEndpointCollectible)
: [],
urls: urls?.map(({ url }) => ({ url, label: getDomainFromUrl(url) })) ?? [],
...(weightEnabled && isDefined(weight) ? { weight: weight.amount } : {}),
...handleSize(size, sizeEnabled),
...handlePageInfo(pageInfo, pageInfoEnabled),
...handlePrice(price, priceEnabled),
}); });
const handlePrice = ( const handlePrice = (
@ -173,10 +197,10 @@ const handleContents = (contents: Collectible["contents"]): EndpointCollectible[
const handleContent = (): EndpointCollectible["contents"][number]["content"] | undefined => { const handleContent = (): EndpointCollectible["contents"][number]["content"] | undefined => {
switch (content.relationTo) { switch (content.relationTo) {
case "generic-contents": case Collections.GenericContents:
return isPayloadType(content.value) return isPayloadType(content.value)
? { ? {
relationTo: "generic-contents", relationTo: Collections.GenericContents,
value: { value: {
translations: content.value.translations.map(({ language, name }) => ({ translations: content.value.translations.map(({ language, name }) => ({
language: isPayloadType(language) ? language.id : language, language: isPayloadType(language) ? language.id : language,
@ -186,9 +210,19 @@ const handleContents = (contents: Collectible["contents"]): EndpointCollectible[
} }
: undefined; : undefined;
case "pages": case Collections.Pages:
return isPayloadType(content.value) && isPublished(content.value) return isPayloadType(content.value) && isPublished(content.value)
? { relationTo: "pages", value: convertPageToPreview(content.value) } ? { relationTo: Collections.Pages, value: convertPageToEndpointPage(content.value) }
: undefined;
case Collections.Audios:
return isPayloadType(content.value) && isValidPayloadMedia(content.value)
? { relationTo: Collections.Audios, value: convertAudioToEndpointAudio(content.value) }
: undefined;
case Collections.Videos:
return isPayloadType(content.value) && isValidPayloadMedia(content.value)
? { relationTo: Collections.Videos, value: convertVideoToEndpointVideo(content.value) }
: undefined; : undefined;
default: default:
@ -203,29 +237,3 @@ const handleContents = (contents: Collectible["contents"]): EndpointCollectible[
return [{ content: newContent, range }]; return [{ content: newContent, range }];
}); });
}; };
export const convertCollectibleToPreview = ({
slug,
thumbnail,
translations,
releaseDate,
languages,
tags,
}: Collectible): EndpointCollectiblePreview => {
return {
slug,
languages:
languages?.map((language) => (isPayloadType(language) ? language.id : language)) ?? [],
...(isDefined(releaseDate) ? { releaseDate } : {}),
...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}),
tagGroups: convertTagsToGroups(tags),
translations:
translations?.map(({ language, title, description, pretitle, subtitle }) => ({
language: isPayloadType(language) ? language.id : language,
title,
...(isNotEmpty(pretitle) ? { pretitle } : {}),
...(isNotEmpty(subtitle) ? { subtitle } : {}),
...(isNotEmpty(description) ? { description } : {}),
})) ?? [],
};
};

View File

@ -1,79 +1,95 @@
import { Collections } from "../../../constants"; import { Collections } from "../../../constants";
import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint"; import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint";
import { EndpointFolder, EndpointFolderPreview } from "../../../sdk"; import { EndpointFolder } from "../../../sdk";
import { Folder, Language } from "../../../types/collections"; import { Folder, Language } from "../../../types/collections";
import { isDefined, isNotEmpty, isPayloadType, isPublished } from "../../../utils/asserts"; import {
import { handleParentPages } from "../../../utils/endpoints"; isDefined,
import { convertCollectibleToPreview } from "../../Collectibles/endpoints/getBySlugEndpoint"; isNotEmpty,
import { convertPageToPreview } from "../../Pages/endpoints/getBySlugEndpoint"; isPayloadType,
isPublished,
isValidPayloadImage,
isValidPayloadMedia,
} from "../../../utils/asserts";
import { convertSourceToEndpointSource, getLanguageId } from "../../../utils/endpoints";
import { convertAudioToEndpointAudio } from "../../Audios/endpoints/getByID";
import { convertCollectibleToEndpointCollectible } from "../../Collectibles/endpoints/getBySlugEndpoint";
import { convertImageToEndpointImage } from "../../Images/endpoints/getByID";
import { convertPageToEndpointPage } from "../../Pages/endpoints/getBySlugEndpoint";
import { convertVideoToEndpointVideo } from "../../Videos/endpoints/getByID";
export const getBySlugEndpoint = createGetByEndpoint({ export const getBySlugEndpoint = createGetByEndpoint({
collection: Collections.Folders, collection: Collections.Folders,
attribute: "slug", attribute: "slug",
depth: 3, depth: 3,
handler: (folder: Folder): EndpointFolder => { handler: (folder) => convertFolderToEndpointFolder(folder),
const { sections, files, parentFolders } = folder;
return {
...convertFolderToPreview(folder),
sections:
sections?.length === 1
? {
type: "single",
subfolders:
sections[0]?.subfolders?.filter(isPayloadType).map(convertFolderToPreview) ?? [],
}
: {
type: "multiple",
sections:
sections?.filter(isValidSection).map(({ translations, subfolders }) => ({
translations: translations.map(({ language, name }) => ({
language: getLanguageId(language),
name,
})),
subfolders: subfolders.map(convertFolderToPreview),
})) ?? [],
},
files:
files?.flatMap<EndpointFolder["files"][number]>(({ relationTo, value }) => {
if (!isPayloadType(value) || ("_status" in value && !isPublished(value))) {
return [];
}
switch (relationTo) {
case "collectibles":
return [{ relationTo, value: convertCollectibleToPreview(value) }];
case "pages":
return [{ relationTo, value: convertPageToPreview(value) }];
// TODO: handle media type files
case "images":
return [];
case "audios":
return [];
case "videos":
return [];
}
}) ?? [],
parentPages: handleParentPages({ folders: parentFolders }),
};
},
}); });
export const convertFolderToPreview = ({ export const convertFolderToEndpointFolder = ({
slug, slug,
translations,
icon, icon,
}: Folder): EndpointFolderPreview => { translations,
return { sections,
slug, files,
...(isDefined(icon) ? { icon } : {}), parentFolders,
translations: }: Folder): EndpointFolder => ({
translations?.map(({ language, name, description }) => ({ slug,
language: getLanguageId(language), ...(isDefined(icon) ? { icon } : {}),
name, translations:
...(isNotEmpty(description) ? { description } : {}), translations?.map(({ language, name, description }) => ({
})) ?? [], language: getLanguageId(language),
}; name,
}; ...(isNotEmpty(description) ? { description } : {}),
})) ?? [],
sections:
sections?.length === 1
? {
type: "single",
subfolders:
sections[0]?.subfolders?.filter(isPayloadType).map(convertFolderToEndpointFolder) ?? [],
}
: {
type: "multiple",
sections:
sections?.filter(isValidSection).map(({ translations, subfolders }) => ({
translations: translations.map(({ language, name }) => ({
language: getLanguageId(language),
name,
})),
subfolders: subfolders.map(convertFolderToEndpointFolder),
})) ?? [],
},
files:
files?.flatMap<EndpointFolder["files"][number]>(({ relationTo, value }) => {
if (!isPayloadType(value) || ("_status" in value && !isPublished(value))) {
return [];
}
switch (relationTo) {
case Collections.Collectibles:
return [
{
relationTo: Collections.Collectibles,
value: convertCollectibleToEndpointCollectible(value),
},
];
case Collections.Pages:
return [{ relationTo: Collections.Pages, value: convertPageToEndpointPage(value) }];
// TODO: handle media type files
case Collections.Images:
if (!isValidPayloadImage(value)) return [];
return [{ relationTo: Collections.Images, value: convertImageToEndpointImage(value) }];
case Collections.Audios:
if (!isValidPayloadMedia(value)) return [];
return [{ relationTo: Collections.Audios, value: convertAudioToEndpointAudio(value) }];
case Collections.Videos:
if (!isValidPayloadMedia(value)) return [];
return [{ relationTo: Collections.Videos, value: convertVideoToEndpointVideo(value) }];
default:
return [];
}
}) ?? [],
parentPages: convertSourceToEndpointSource({ folders: parentFolders }),
});
const isValidSection = (section: { const isValidSection = (section: {
translations?: translations?:
@ -100,6 +116,3 @@ const isValidSection = (section: {
} }
return section.subfolders.every(isPayloadType); return section.subfolders.every(isPayloadType);
}; };
const getLanguageId = (language: string | Language) =>
typeof language === "object" ? language.id : language;

View File

@ -3,6 +3,7 @@ import { tagsField } from "../../fields/tagsField/tagsField";
import { translatedFields } from "../../fields/translatedFields/translatedFields"; import { translatedFields } from "../../fields/translatedFields/translatedFields";
import { createEditor } from "../../utils/editor"; import { createEditor } from "../../utils/editor";
import { buildImageCollectionConfig } from "../../utils/imageCollectionConfig"; import { buildImageCollectionConfig } from "../../utils/imageCollectionConfig";
import { getByID } from "./endpoints/getByID";
const fields = { const fields = {
filename: "filename", filename: "filename",
@ -36,6 +37,7 @@ export const Images = buildImageCollectionConfig({
}, },
], ],
}, },
endpoints: [getByID],
fields: [ fields: [
translatedFields({ translatedFields({
name: fields.translations, name: fields.translations,

View File

@ -0,0 +1,77 @@
import payload from "payload";
import { Collections } from "../../../constants";
import { EndpointImage, PayloadImage } from "../../../sdk";
import { Image } from "../../../types/collections";
import { CollectionEndpoint } from "../../../types/payload";
import { isNotEmpty, isValidPayloadImage } from "../../../utils/asserts";
import {
convertRTCToEndpointRTC,
convertTagsEndpointTagsGroups,
getLanguageId,
} from "../../../utils/endpoints";
export const getByID: CollectionEndpoint = {
method: "get",
path: "/id/:id",
handler: async (req, res) => {
if (!req.user) {
return res.status(403).send({
errors: [
{
message: "You are not allowed to perform this action.",
},
],
});
}
if (!req.params.id) {
return res.status(400).send({ errors: [{ message: "Missing 'id' query params" }] });
}
try {
const result = await payload.findByID({
collection: Collections.Images,
id: req.params.id,
});
if (!isValidPayloadImage(result)) {
return res.sendStatus(404);
}
return res.status(200).json(convertImageToEndpointImage(result));
} catch {
return res.sendStatus(404);
}
},
};
export const convertImageToEndpointImage = ({
url,
width,
height,
tags,
translations,
mimeType,
createdAt,
updatedAt,
filename,
filesize,
id,
}: Image & PayloadImage): EndpointImage => ({
url,
width,
height,
tagGroups: convertTagsEndpointTagsGroups(tags),
createdAt,
filename,
filesize,
id,
mimeType,
updatedAt,
translations:
translations?.map(({ language, title, description }) => ({
language: getLanguageId(language),
title,
...(isNotEmpty(description) ? { description: convertRTCToEndpointRTC(description) } : {}),
})) ?? [],
});

View File

@ -2,15 +2,13 @@ import {
BreakBlockType, BreakBlockType,
Collections, Collections,
PageType, PageType,
RichTextBreakBlock,
RichTextContent, RichTextContent,
RichTextSectionBlock,
isBlockNodeBreakBlock, isBlockNodeBreakBlock,
isBlockNodeSectionBlock, isBlockNodeSectionBlock,
isNodeBlockNode, isNodeBlockNode,
} from "../../../constants"; } from "../../../constants";
import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint"; import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint";
import { EndpointPage, EndpointPagePreview, TableOfContentEntry } from "../../../sdk"; import { EndpointPage, TableOfContentEntry } from "../../../sdk";
import { Page } from "../../../types/collections"; import { Page } from "../../../types/collections";
import { import {
isNotEmpty, isNotEmpty,
@ -18,85 +16,70 @@ import {
isPayloadType, isPayloadType,
isValidPayloadImage, isValidPayloadImage,
} from "../../../utils/asserts"; } from "../../../utils/asserts";
import { convertTagsToGroups, handleParentPages, handleRecorder } from "../../../utils/endpoints"; import {
convertRTCToEndpointRTC,
convertSourceToEndpointSource,
convertTagsEndpointTagsGroups,
} from "../../../utils/endpoints";
import { convertRecorderToEndpointRecorder } from "../../Recorders/endpoints/getByUsername";
export const getBySlugEndpoint = createGetByEndpoint({ export const getBySlugEndpoint = createGetByEndpoint({
collection: Collections.Pages, collection: Collections.Pages,
attribute: "slug", attribute: "slug",
handler: (page: Page): EndpointPage => { handler: (page) => convertPageToEndpointPage(page),
const { translations, collectibles, folders, backgroundImage } = page;
return {
...convertPageToPreview(page),
...(isValidPayloadImage(backgroundImage) ? { backgroundImage } : {}),
translations: translations.map(
({
content,
language,
sourceLanguage,
title,
pretitle,
subtitle,
proofreaders,
summary,
transcribers,
translators,
}) => ({
language: isPayloadType(language) ? language.id : language,
sourceLanguage: isPayloadType(sourceLanguage) ? sourceLanguage.id : sourceLanguage,
...(isNotEmpty(pretitle) ? { pretitle } : {}),
title,
...(isNotEmpty(subtitle) ? { subtitle } : {}),
...(isNotEmpty(summary) ? { summary } : {}),
content: handleContent(content),
toc: handleToc(content),
translators: isPayloadArrayType(translators) ? translators.map(handleRecorder) : [],
transcribers: isPayloadArrayType(transcribers) ? transcribers.map(handleRecorder) : [],
proofreaders: isPayloadArrayType(proofreaders) ? proofreaders.map(handleRecorder) : [],
})
),
parentPages: handleParentPages({ collectibles, folders }),
};
},
}); });
const handleContent = ( export const convertPageToEndpointPage = ({
{ root: { children, ...others } }: RichTextContent, translations,
parentPrefix = "" collectibles,
): RichTextContent => { folders,
let index = 0; backgroundImage,
return { authors,
root: { slug,
...others, tags,
children: children.map((node) => { thumbnail,
if (isNodeBlockNode(node)) { type,
if (isBlockNodeSectionBlock(node)) { }: Page): EndpointPage => ({
index++; slug,
const anchorHash = `${parentPrefix}${index}.`; type: type as PageType,
const newNode: RichTextSectionBlock = { ...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}),
...node, tagGroups: convertTagsEndpointTagsGroups(tags),
fields: { authors: isPayloadArrayType(authors) ? authors.map(convertRecorderToEndpointRecorder) : [],
...node.fields, ...(isValidPayloadImage(backgroundImage) ? { backgroundImage } : {}),
content: handleContent(node.fields.content, anchorHash), translations: translations.map(
}, ({
anchorHash, content,
}; language,
return newNode; sourceLanguage,
} else if (isBlockNodeBreakBlock(node)) { title,
index++; pretitle,
const anchorHash = `${parentPrefix}${index}.`; subtitle,
const newNode: RichTextBreakBlock = { proofreaders,
...node, summary,
anchorHash, transcribers,
}; translators,
return newNode; }) => ({
} language: isPayloadType(language) ? language.id : language,
} sourceLanguage: isPayloadType(sourceLanguage) ? sourceLanguage.id : sourceLanguage,
return node; ...(isNotEmpty(pretitle) ? { pretitle } : {}),
}), title,
}, ...(isNotEmpty(subtitle) ? { subtitle } : {}),
}; ...(isNotEmpty(summary) ? { summary } : {}),
}; content: convertRTCToEndpointRTC(content),
toc: handleToc(content),
translators: isPayloadArrayType(translators)
? translators.map(convertRecorderToEndpointRecorder)
: [],
transcribers: isPayloadArrayType(transcribers)
? transcribers.map(convertRecorderToEndpointRecorder)
: [],
proofreaders: isPayloadArrayType(proofreaders)
? proofreaders.map(convertRecorderToEndpointRecorder)
: [],
})
),
parentPages: convertSourceToEndpointSource({ collectibles, folders }),
});
const handleToc = (content: RichTextContent, parentPrefix = ""): TableOfContentEntry[] => { const handleToc = (content: RichTextContent, parentPrefix = ""): TableOfContentEntry[] => {
let index = 0; let index = 0;
@ -150,24 +133,3 @@ const handleToc = (content: RichTextContent, parentPrefix = ""): TableOfContentE
return []; return [];
}); });
}; };
export const convertPageToPreview = ({
authors,
slug,
translations,
tags,
thumbnail,
type,
}: Page): EndpointPagePreview => ({
slug,
type: type as PageType,
...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}),
tagGroups: convertTagsToGroups(tags),
translations: translations.map(({ language, title, pretitle, subtitle }) => ({
language: isPayloadType(language) ? language.id : language,
...(isNotEmpty(pretitle) ? { pretitle } : {}),
title,
...(isNotEmpty(subtitle) ? { subtitle } : {}),
})),
authors: isPayloadArrayType(authors) ? authors.map(handleRecorder) : [],
});

View File

@ -7,6 +7,7 @@ import { imageField } from "../../fields/imageField/imageField";
import { rowField } from "../../fields/rowField/rowField"; import { rowField } from "../../fields/rowField/rowField";
import { buildCollectionConfig } from "../../utils/collectionConfig"; import { buildCollectionConfig } from "../../utils/collectionConfig";
import { getAllEndpoint } from "./endpoints/getAllEndpoint"; import { getAllEndpoint } from "./endpoints/getAllEndpoint";
import { getByUsernameEndpoint } from "./endpoints/getByUsername";
import { importFromStrapi } from "./endpoints/importFromStrapi"; import { importFromStrapi } from "./endpoints/importFromStrapi";
import { beforeLoginMustHaveAtLeastOneRole } from "./hooks/beforeLoginMustHaveAtLeastOneRole"; import { beforeLoginMustHaveAtLeastOneRole } from "./hooks/beforeLoginMustHaveAtLeastOneRole";
@ -74,7 +75,7 @@ export const Recorders = buildCollectionConfig({
hooks: { hooks: {
beforeLogin: [beforeLoginMustHaveAtLeastOneRole], beforeLogin: [beforeLoginMustHaveAtLeastOneRole],
}, },
endpoints: [importFromStrapi, getAllEndpoint], endpoints: [importFromStrapi, getAllEndpoint, getByUsernameEndpoint],
timestamps: false, timestamps: false,
fields: [ fields: [
rowField([ rowField([

View File

@ -0,0 +1,24 @@
import { Collections } from "../../../constants";
import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint";
import { EndpointRecorder } from "../../../sdk";
import { Recorder } from "../../../types/collections";
import { isPayloadType, isValidPayloadImage } from "../../../utils/asserts";
export const getByUsernameEndpoint = createGetByEndpoint({
collection: Collections.Recorders,
attribute: "username",
handler: (recorder) => convertRecorderToEndpointRecorder(recorder),
});
export const convertRecorderToEndpointRecorder = ({
id,
languages,
username,
avatar,
anonymize,
}: Recorder): EndpointRecorder => ({
id,
languages: languages?.map((language) => (isPayloadType(language) ? language.id : language)) ?? [],
username: anonymize ? `Recorder#${id.substring(0, 5)}` : username,
...(isValidPayloadImage(avatar) ? { avatar } : {}),
});

View File

@ -6,6 +6,7 @@ import { tagsField } from "../../fields/tagsField/tagsField";
import { translatedFields } from "../../fields/translatedFields/translatedFields"; import { translatedFields } from "../../fields/translatedFields/translatedFields";
import { buildCollectionConfig } from "../../utils/collectionConfig"; import { buildCollectionConfig } from "../../utils/collectionConfig";
import { createEditor } from "../../utils/editor"; import { createEditor } from "../../utils/editor";
import { getByID } from "./endpoints/getByID";
const fields = { const fields = {
filename: "filename", filename: "filename",
@ -47,13 +48,13 @@ export const Videos = buildCollectionConfig({
mimeTypes: ["video/*"], mimeTypes: ["video/*"],
disableLocalStorage: true, disableLocalStorage: true,
}, },
endpoints: [getByID],
fields: [ fields: [
rowField([ rowField([
{ name: fields.duration, type: "number", min: 0, required: true }, { name: fields.duration, type: "number", min: 0, required: true },
imageField({ imageField({
name: fields.thumbnail, name: fields.thumbnail,
relationTo: Collections.MediaThumbnails, relationTo: Collections.MediaThumbnails,
required: true,
}), }),
]), ]),
translatedFields({ translatedFields({

View File

@ -0,0 +1,108 @@
import payload from "payload";
import { Collections } from "../../../constants";
import { EndpointVideo, PayloadMedia } from "../../../sdk";
import { Video } from "../../../types/collections";
import { CollectionEndpoint } from "../../../types/payload";
import {
isDefined,
isEmpty,
isNotEmpty,
isPayloadType,
isUndefined,
isValidPayloadImage,
isValidPayloadMedia,
} from "../../../utils/asserts";
import {
convertRTCToEndpointRTC,
convertTagsEndpointTagsGroups,
getLanguageId,
} from "../../../utils/endpoints";
export const getByID: CollectionEndpoint = {
method: "get",
path: "/id/:id",
handler: async (req, res) => {
if (!req.user) {
return res.status(403).send({
errors: [
{
message: "You are not allowed to perform this action.",
},
],
});
}
if (!req.params.id) {
return res.status(400).send({ errors: [{ message: "Missing 'id' query params" }] });
}
try {
const result = await payload.findByID({
collection: Collections.Videos,
id: req.params.id,
});
if (!isValidPayloadMedia(result)) {
return res.sendStatus(404);
}
return res.status(200).json(convertVideoToEndpointVideo(result));
} catch {
return res.sendStatus(404);
}
},
};
export const convertVideoToEndpointVideo = ({
url,
tags,
translations,
mimeType,
createdAt,
updatedAt,
filename,
filesize,
duration,
id,
thumbnail,
platform,
platformEnabled,
}: Video & PayloadMedia): EndpointVideo => ({
url,
tagGroups: convertTagsEndpointTagsGroups(tags),
createdAt,
filename,
filesize,
id,
mimeType,
updatedAt,
translations:
translations?.map(({ language, title, description }) => ({
language: getLanguageId(language),
title,
...(isNotEmpty(description) ? { description: convertRTCToEndpointRTC(description) } : {}),
})) ?? [],
duration,
...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}),
...(platformEnabled && isDefined(platform) && isPayloadType(platform.channel)
? {
platform: {
channel: platform.channel,
publishedDate: platform.publishedDate,
url: platform.url,
},
}
: {}),
subtitles:
translations.flatMap(({ language, subfile }) => {
if (
isUndefined(subfile) ||
!isPayloadType(subfile) ||
isUndefined(subfile.url) ||
isEmpty(subfile.url)
)
return [];
return { language: getLanguageId(language), url: subfile.url };
}) ?? [],
});

View File

@ -29,7 +29,7 @@ export const VideosChannels: CollectionConfig = buildCollectionConfig({
{ name: fields.url, type: "text", required: true, unique: true }, { name: fields.url, type: "text", required: true, unique: true },
rowField([ rowField([
{ name: fields.title, type: "text", required: true }, { name: fields.title, type: "text", required: true },
{ name: fields.subscribers, type: "number" }, { name: fields.subscribers, type: "number", required: true },
]), ]),
backPropagationField({ backPropagationField({
name: fields.videos, name: fields.videos,

View File

@ -3,7 +3,7 @@ import { Collections } from "../../../constants";
import { EndpointWebsiteConfig } from "../../../sdk"; import { EndpointWebsiteConfig } from "../../../sdk";
import { CollectionEndpoint } from "../../../types/payload"; import { CollectionEndpoint } from "../../../types/payload";
import { isPayloadType, isValidPayloadImage } from "../../../utils/asserts"; import { isPayloadType, isValidPayloadImage } from "../../../utils/asserts";
import { convertFolderToPreview } from "../../Folders/endpoints/getBySlugEndpoint"; import { convertFolderToEndpointFolder } from "../../Folders/endpoints/getBySlugEndpoint";
export const getConfigEndpoint: CollectionEndpoint = { export const getConfigEndpoint: CollectionEndpoint = {
method: "get", method: "get",
@ -46,7 +46,7 @@ export const getConfigEndpoint: CollectionEndpoint = {
homeFolders?.flatMap(({ folder, darkThumbnail, lightThumbnail }) => { homeFolders?.flatMap(({ folder, darkThumbnail, lightThumbnail }) => {
if (!isPayloadType(folder)) return []; if (!isPayloadType(folder)) return [];
return { return {
...convertFolderToPreview(folder), ...convertFolderToEndpointFolder(folder),
...(isValidPayloadImage(darkThumbnail) ? { darkThumbnail } : {}), ...(isValidPayloadImage(darkThumbnail) ? { darkThumbnail } : {}),
...(isValidPayloadImage(lightThumbnail) ? { lightThumbnail } : {}), ...(isValidPayloadImage(lightThumbnail) ? { lightThumbnail } : {}),
}; };

View File

@ -1,11 +1,5 @@
import type { import { EndpointAudio, EndpointImage, EndpointVideo } from "./sdk";
Audio, import type { BreakBlock, SectionBlock, TranscriptBlock } from "./types/collections";
BreakBlock,
Image,
SectionBlock,
TranscriptBlock,
Video,
} from "./types/collections";
// END MOCKING SECTION // END MOCKING SECTION
@ -149,17 +143,17 @@ export interface RichTextUploadNode extends RichTextNode {
export interface RichTextUploadImageNode extends RichTextUploadNode { export interface RichTextUploadImageNode extends RichTextUploadNode {
relationTo: Collections.Images; relationTo: Collections.Images;
value: Image; value: EndpointImage;
} }
export interface RichTextUploadVideoNode extends RichTextUploadNode { export interface RichTextUploadVideoNode extends RichTextUploadNode {
relationTo: Collections.Videos; relationTo: Collections.Videos;
value: Video; value: EndpointVideo;
} }
export interface RichTextUploadAudioNode extends RichTextUploadNode { export interface RichTextUploadAudioNode extends RichTextUploadNode {
relationTo: Collections.Audios; relationTo: Collections.Audios;
value: Audio; value: EndpointAudio;
} }
export interface RichTextTextNode extends RichTextNode { export interface RichTextTextNode extends RichTextNode {

View File

@ -35,7 +35,7 @@ const configuredFtpAdapter = sftpAdapter({
privateKey: process.env.SFTP_PRIVATE_KEY, privateKey: process.env.SFTP_PRIVATE_KEY,
}, },
destinationPathRoot: process.env.SFTP_DESTINATION_PATH_ROOT ?? "", destinationPathRoot: process.env.SFTP_DESTINATION_PATH_ROOT ?? "",
publicEndpoint: process.env.FTP_BASE_URL ?? "", publicEndpoint: process.env.SFTP_BASE_URL ?? "",
}); });
export default buildConfig({ export default buildConfig({

View File

@ -96,7 +96,7 @@ const request = async (url: string, init?: RequestInit): Promise<Response> => {
// SDK and Types // SDK and Types
export type EndpointFolderPreview = { export type EndpointFolder = {
slug: string; slug: string;
icon?: string; icon?: string;
translations: { translations: {
@ -104,33 +104,42 @@ export type EndpointFolderPreview = {
name: string; name: string;
description?: RichTextContent; description?: RichTextContent;
}[]; }[];
};
export type EndpointFolder = EndpointFolderPreview & {
sections: sections:
| { type: "single"; subfolders: EndpointFolderPreview[] } | { type: "single"; subfolders: EndpointFolder[] }
| { | {
type: "multiple"; type: "multiple";
sections: { sections: {
translations: { language: string; name: string }[]; translations: { language: string; name: string }[];
subfolders: EndpointFolderPreview[]; subfolders: EndpointFolder[];
}[]; }[];
}; };
files: ( files: (
| { | {
relationTo: "collectibles"; relationTo: Collections.Collectibles;
value: EndpointCollectiblePreview; value: EndpointCollectible;
} }
| { | {
relationTo: "pages"; relationTo: Collections.Pages;
value: EndpointPagePreview; value: EndpointPage;
}
| {
relationTo: Collections.Images;
value: EndpointImage;
}
| {
relationTo: Collections.Audios;
value: EndpointAudio;
}
| {
relationTo: Collections.Videos;
value: EndpointVideo;
} }
)[]; )[];
parentPages: EndpointSource[]; parentPages: EndpointSource[];
}; };
export type EndpointWebsiteConfig = { export type EndpointWebsiteConfig = {
homeFolders: (EndpointFolderPreview & { homeFolders: (EndpointFolder & {
lightThumbnail?: PayloadImage; lightThumbnail?: PayloadImage;
darkThumbnail?: PayloadImage; darkThumbnail?: PayloadImage;
})[]; })[];
@ -178,23 +187,18 @@ export type EndpointTagsGroup = {
tags: EndpointTag[]; tags: EndpointTag[];
}; };
export type EndpointPagePreview = { export type EndpointPage = {
slug: string; slug: string;
type: PageType; type: PageType;
thumbnail?: PayloadImage; thumbnail?: PayloadImage;
authors: EndpointRecorder[]; authors: EndpointRecorder[];
tagGroups: EndpointTagsGroup[]; tagGroups: EndpointTagsGroup[];
backgroundImage?: PayloadImage;
translations: { translations: {
language: string; language: string;
pretitle?: string; pretitle?: string;
title: string; title: string;
subtitle?: string; subtitle?: string;
}[];
};
export type EndpointPage = EndpointPagePreview & {
backgroundImage?: PayloadImage;
translations: (EndpointPagePreview["translations"][number] & {
sourceLanguage: string; sourceLanguage: string;
summary?: RichTextContent; summary?: RichTextContent;
content: RichTextContent; content: RichTextContent;
@ -202,11 +206,11 @@ export type EndpointPage = EndpointPagePreview & {
translators: EndpointRecorder[]; translators: EndpointRecorder[];
proofreaders: EndpointRecorder[]; proofreaders: EndpointRecorder[];
toc: TableOfContentEntry[]; toc: TableOfContentEntry[];
})[]; }[];
parentPages: EndpointSource[]; parentPages: EndpointSource[];
}; };
export type EndpointCollectiblePreview = { export type EndpointCollectible = {
slug: string; slug: string;
thumbnail?: PayloadImage; thumbnail?: PayloadImage;
translations: { translations: {
@ -219,9 +223,6 @@ export type EndpointCollectiblePreview = {
tagGroups: EndpointTagsGroup[]; tagGroups: EndpointTagsGroup[];
releaseDate?: string; releaseDate?: string;
languages: string[]; languages: string[];
};
export type EndpointCollectible = EndpointCollectiblePreview & {
backgroundImage?: PayloadImage; backgroundImage?: PayloadImage;
nature: CollectibleNature; nature: CollectibleNature;
gallery: PayloadImage[]; gallery: PayloadImage[];
@ -242,15 +243,23 @@ export type EndpointCollectible = EndpointCollectiblePreview & {
bindingType?: CollectibleBindingTypes; bindingType?: CollectibleBindingTypes;
pageOrder?: CollectiblePageOrders; pageOrder?: CollectiblePageOrders;
}; };
subitems: EndpointCollectiblePreview[]; subitems: EndpointCollectible[];
contents: { contents: {
content: content:
| { | {
relationTo: "pages"; relationTo: Collections.Pages;
value: EndpointPagePreview; value: EndpointPage;
} }
| { | {
relationTo: "generic-contents"; relationTo: Collections.Audios;
value: EndpointAudio;
}
| {
relationTo: Collections.Videos;
value: EndpointVideo;
}
| {
relationTo: Collections.GenericContents;
value: { value: {
translations: { translations: {
language: string; language: string;
@ -315,21 +324,72 @@ export type EndpointSource =
| { type: "url"; url: string; label: string } | { type: "url"; url: string; label: string }
| { | {
type: "collectible"; type: "collectible";
collectible: EndpointCollectiblePreview; collectible: EndpointCollectible;
range?: range?:
| { type: "page"; page: number } | { type: "page"; page: number }
| { type: "timestamp"; timestamp: string } | { type: "timestamp"; timestamp: string }
| { type: "custom"; translations: { language: string; note: string }[] }; | { type: "custom"; translations: { language: string; note: string }[] };
} }
| { type: "page"; page: EndpointPagePreview } | { type: "page"; page: EndpointPage }
| { type: "folder"; folder: EndpointFolderPreview }; | { type: "folder"; folder: EndpointFolder };
export type PayloadImage = { export type EndpointMedia = {
id: string;
url: string; url: string;
filename: string;
mimeType: string;
filesize: number;
updatedAt: string;
createdAt: string;
tagGroups: EndpointTagsGroup[];
translations: {
language: string;
title: string;
description?: RichTextContent;
}[];
};
export type EndpointImage = EndpointMedia & {
width: number; width: number;
height: number; height: number;
};
export type EndpointAudio = EndpointMedia & {
thumbnail?: PayloadImage;
duration: number;
};
export type EndpointVideo = EndpointMedia & {
thumbnail?: PayloadImage;
subtitles: {
language: string;
url: string;
}[];
platform?: {
channel: {
url: string;
title: string;
subscribers: number;
};
views?: number;
likes?: number;
dislikes?: number;
url: string;
publishedDate: string;
};
duration: number;
};
export type PayloadMedia = {
url: string;
mimeType: string; mimeType: string;
filename: string; filename: string;
filesize: number;
};
export type PayloadImage = PayloadMedia & {
width: number;
height: number;
}; };
export const payload = { export const payload = {
@ -353,4 +413,10 @@ export const payload = {
await (await request(payloadApiUrl(Collections.ChronologyEvents, `all`))).json(), await (await request(payloadApiUrl(Collections.ChronologyEvents, `all`))).json(),
getChronologyEventByID: async (id: string): Promise<EndpointChronologyEvent> => getChronologyEventByID: async (id: string): Promise<EndpointChronologyEvent> =>
await (await request(payloadApiUrl(Collections.ChronologyEvents, `id/${id}`))).json(), await (await request(payloadApiUrl(Collections.ChronologyEvents, `id/${id}`))).json(),
getImageByID: async (id: string): Promise<EndpointImage> =>
await (await request(payloadApiUrl(Collections.Images, `id/${id}`))).json(),
getAudioByID: async (id: string): Promise<EndpointAudio> =>
await (await request(payloadApiUrl(Collections.Audios, `id/${id}`))).json(),
getVideoByID: async (id: string): Promise<EndpointVideo> =>
await (await request(payloadApiUrl(Collections.Videos, `id/${id}`))).json(),
}; };

View File

@ -603,7 +603,7 @@ export interface MediaThumbnail {
export interface Video { export interface Video {
id: string; id: string;
duration: number; duration: number;
thumbnail: string | MediaThumbnail; thumbnail?: string | MediaThumbnail | null;
translations: { translations: {
language: string | Language; language: string | Language;
title: string; title: string;
@ -665,7 +665,7 @@ export interface VideosChannel {
id: string; id: string;
url: string; url: string;
title: string; title: string;
subscribers?: number | null; subscribers: number;
videos?: (string | Video)[] | null; videos?: (string | Video)[] | null;
} }
/** /**

View File

@ -1,5 +1,5 @@
import { RichTextContent, isNodeParagraphNode } from "../constants"; import { RichTextContent, isNodeParagraphNode } from "../constants";
import { PayloadImage } from "../sdk"; import { PayloadImage, PayloadMedia } from "../sdk";
export const isDefined = <T>(value: T | null | undefined): value is T => export const isDefined = <T>(value: T | null | undefined): value is T =>
value !== null && value !== undefined; value !== null && value !== undefined;
@ -7,10 +7,11 @@ export const isDefined = <T>(value: T | null | undefined): value is T =>
export const isUndefined = <T>(value: T | null | undefined): value is null | undefined => export const isUndefined = <T>(value: T | null | undefined): value is null | undefined =>
!isDefined(value); !isDefined(value);
export const isNotEmpty = (value: string | null | undefined | RichTextContent): value is string => export const isNotEmpty = (
!isEmpty(value); value: string | null | undefined | RichTextContent
): value is string | RichTextContent => !isEmpty(value);
export const isEmpty = (value: string | null | undefined | RichTextContent): value is string => export const isEmpty = (value: string | null | undefined | RichTextContent): boolean =>
isUndefined(value) || isUndefined(value) ||
(typeof value === "string" && isEmptyString(value)) || (typeof value === "string" && isEmptyString(value)) ||
(typeof value === "object" && isEmptyRichText(value)); (typeof value === "object" && isEmptyRichText(value));
@ -26,6 +27,7 @@ export const isValidPayloadImage = (
image: image:
| { | {
filename?: string | null; filename?: string | null;
filesize?: number | null;
mimeType?: string | null; mimeType?: string | null;
width?: number | null; width?: number | null;
height?: number | null; height?: number | null;
@ -42,6 +44,28 @@ export const isValidPayloadImage = (
if (isEmpty(image.mimeType)) return false; if (isEmpty(image.mimeType)) return false;
if (isUndefined(image.width)) return false; if (isUndefined(image.width)) return false;
if (isUndefined(image.height)) return false; if (isUndefined(image.height)) return false;
if (isUndefined(image.filesize)) return false;
return true;
};
export const isValidPayloadMedia = (
media:
| {
filename?: string | null;
filesize?: number | null;
mimeType?: string | null;
url?: string | null;
}
| undefined
| null
| string
): media is PayloadMedia => {
if (isUndefined(media)) return false;
if (typeof media === "string") return false;
if (isEmpty(media.filename)) return false;
if (isEmpty(media.url)) return false;
if (isEmpty(media.mimeType)) return false;
if (isUndefined(media.filesize)) return false;
return true; return true;
}; };

View File

@ -1,10 +1,32 @@
import { convertCollectibleToPreview } from "../collections/Collectibles/endpoints/getBySlugEndpoint"; import { convertAudioToEndpointAudio } from "../collections/Audios/endpoints/getByID";
import { convertFolderToPreview } from "../collections/Folders/endpoints/getBySlugEndpoint"; import { convertCollectibleToEndpointCollectible } from "../collections/Collectibles/endpoints/getBySlugEndpoint";
import { EndpointRecorder, EndpointSource, EndpointTag, EndpointTagsGroup } from "../sdk"; import { convertFolderToEndpointFolder } from "../collections/Folders/endpoints/getBySlugEndpoint";
import { Collectible, Folder, Recorder, Tag } from "../types/collections"; import { convertImageToEndpointImage } from "../collections/Images/endpoints/getByID";
import { isPayloadArrayType, isPayloadType, isPublished, isValidPayloadImage } from "./asserts"; import { convertVideoToEndpointVideo } from "../collections/Videos/endpoints/getByID";
import {
RichTextBreakBlock,
RichTextContent,
RichTextSectionBlock,
RichTextUploadNode,
isBlockNodeBreakBlock,
isBlockNodeSectionBlock,
isNodeBlockNode,
isNodeUploadNode,
isUploadNodeAudioNode,
isUploadNodeImageNode,
isUploadNodeVideoNode,
} from "../constants";
import { EndpointSource, EndpointTag, EndpointTagsGroup } from "../sdk";
import { Audio, Collectible, Folder, Image, Language, Tag, Video } from "../types/collections";
import {
isPayloadArrayType,
isPayloadType,
isPublished,
isValidPayloadImage,
isValidPayloadMedia,
} from "./asserts";
export const convertTagsToGroups = ( export const convertTagsEndpointTagsGroups = (
tags: (string | Tag)[] | null | undefined tags: (string | Tag)[] | null | undefined
): EndpointTagsGroup[] => { ): EndpointTagsGroup[] => {
if (!isPayloadArrayType(tags)) { if (!isPayloadArrayType(tags)) {
@ -44,7 +66,75 @@ export const convertTagsToGroups = (
return groups; return groups;
}; };
export const handleParentPages = ({ export const convertRTCToEndpointRTC = (
{ root: { children, ...others } }: RichTextContent,
parentPrefix = ""
): RichTextContent => {
let index = 0;
return {
root: {
...others,
children: children.map((node) => {
if (isNodeBlockNode(node)) {
// Add anchor hash on section block (TOC)
if (isBlockNodeSectionBlock(node)) {
index++;
const anchorHash = `${parentPrefix}${index}.`;
const newNode: RichTextSectionBlock = {
...node,
fields: {
...node.fields,
content: convertRTCToEndpointRTC(node.fields.content, anchorHash),
},
anchorHash,
};
return newNode;
// Add anchor hash on section block (TOC)
} else if (isBlockNodeBreakBlock(node)) {
index++;
const anchorHash = `${parentPrefix}${index}.`;
const newNode: RichTextBreakBlock = {
...node,
anchorHash,
};
return newNode;
}
} else if (isNodeUploadNode(node)) {
const errorUploadNode: RichTextUploadNode = {
type: "upload",
relationTo: "error",
version: 1,
};
if (isUploadNodeImageNode(node)) {
const value = node.value as Image | string;
if (!isPayloadType(value) || !isValidPayloadImage(value)) return errorUploadNode;
return {
...node,
value: convertImageToEndpointImage(value),
};
} else if (isUploadNodeAudioNode(node)) {
const value = node.value as Audio | string;
if (!isPayloadType(value) || !isValidPayloadMedia(value)) return errorUploadNode;
return {
...node,
value: convertAudioToEndpointAudio(value),
};
} else if (isUploadNodeVideoNode(node)) {
const value = node.value as Video | string;
if (!isPayloadType(value) || !isValidPayloadMedia(value)) return errorUploadNode;
return {
...node,
value: convertVideoToEndpointVideo(value),
};
}
}
return node;
}),
},
};
};
export const convertSourceToEndpointSource = ({
collectibles, collectibles,
folders, folders,
}: { }: {
@ -57,7 +147,7 @@ export const handleParentPages = ({
collectibles.filter(isPublished).forEach((collectible) => { collectibles.filter(isPublished).forEach((collectible) => {
result.push({ result.push({
type: "collectible", type: "collectible",
collectible: convertCollectibleToPreview(collectible), collectible: convertCollectibleToEndpointCollectible(collectible),
}); });
}); });
} }
@ -66,7 +156,7 @@ export const handleParentPages = ({
folders.forEach((folder) => { folders.forEach((folder) => {
result.push({ result.push({
type: "folder", type: "folder",
folder: convertFolderToPreview(folder), folder: convertFolderToEndpointFolder(folder),
}); });
}); });
} }
@ -74,19 +164,6 @@ export const handleParentPages = ({
return result; return result;
}; };
export const handleRecorder = ({
id,
languages,
username,
avatar,
anonymize,
}: Recorder): EndpointRecorder => ({
id,
languages: languages?.map((language) => (isPayloadType(language) ? language.id : language)) ?? [],
username: anonymize ? `Recorder#${id.substring(0, 5)}` : username,
...(isValidPayloadImage(avatar) ? { avatar } : {}),
});
export const getDomainFromUrl = (url: string): string => { export const getDomainFromUrl = (url: string): string => {
const urlObject = new URL(url); const urlObject = new URL(url);
let domain = urlObject.hostname; let domain = urlObject.hostname;
@ -95,3 +172,6 @@ export const getDomainFromUrl = (url: string): string => {
} }
return domain; return domain;
}; };
export const getLanguageId = (language: string | Language) =>
typeof language === "object" ? language.id : language;