feat: provider checks protection

This commit is contained in:
Nevo David 2025-12-28 10:28:09 +07:00
parent 8c1191a093
commit 9c751fb725
13 changed files with 70 additions and 70 deletions

View File

@ -18,14 +18,14 @@ export default withProvider({
dto: undefined,
checkValidity: async (posts) => {
if (
posts.some(
(p) => p.some((a) => a.path.indexOf('mp4') > -1) && p.length > 1
posts?.some(
(p) => p?.some((a) => (a?.path?.indexOf?.('mp4') ?? -1) > -1) && (p?.length ?? 0) > 1
)
) {
return 'You can only upload one video per post.';
}
if (posts.some((p) => p.length > 4)) {
if (posts?.some((p) => (p?.length ?? 0) > 4)) {
return 'There can be maximum 4 pictures in a post.';
}
return true;

View File

@ -24,9 +24,9 @@ export default withProvider({
SettingsComponent: DribbbleSettings,
CustomPreviewComponent: undefined,
dto: DribbbleDto,
checkValidity: async ([firstItem, ...otherItems]) => {
const isMp4 = firstItem?.find((item) => item.path.indexOf('mp4') > -1);
if (firstItem.length !== 1) {
checkValidity: async ([firstItem, ...otherItems] = []) => {
const isMp4 = firstItem?.find((item) => (item?.path?.indexOf?.('mp4') ?? -1) > -1);
if (firstItem?.length !== 1) {
return 'Requires one item';
}
if (isMp4) {
@ -41,7 +41,7 @@ export default withProvider({
// @ts-ignore
resolve({ width: this.width, height: this.height });
};
url.src = firstItem[0].path;
url.src = firstItem?.[0]?.path;
});
if (
(details?.width === 400 && details?.height === 300) ||

View File

@ -167,20 +167,20 @@ export default withProvider({
dto: GmbSettingsDto,
checkValidity: async (items, settings: any) => {
// GMB posts can have text only, or text with one image
if (items.length > 0 && items[0].length > 1) {
if ((items?.length ?? 0) > 0 && (items?.[0]?.length ?? 0) > 1) {
return 'Google My Business posts can only have one image';
}
// Check for video - GMB doesn't support video in local posts
if (items.length > 0 && items[0].length > 0) {
const media = items[0][0];
if (media.path.indexOf('mp4') > -1) {
if ((items?.length ?? 0) > 0 && (items?.[0]?.length ?? 0) > 0) {
const media = items?.[0]?.[0];
if ((media?.path?.indexOf?.('mp4') ?? -1) > -1) {
return 'Google My Business posts do not support video attachments';
}
}
// Event posts require a title
if (settings.topicType === 'EVENT' && !settings.eventTitle) {
if (settings?.topicType === 'EVENT' && !settings?.eventTitle) {
return 'Event posts require an event title';
}

View File

@ -60,18 +60,18 @@ export default withProvider<InstagramDto>({
SettingsComponent: InstagramCollaborators,
CustomPreviewComponent: InstagramPreview,
dto: InstagramDto,
checkValidity: async ([firstPost, ...otherPosts], settings) => {
if (!firstPost.length) {
checkValidity: async ([firstPost, ...otherPosts] = [], settings) => {
if (!firstPost?.length) {
return 'Should have at least one media';
}
if (firstPost.length > 1 && settings.post_type === 'story') {
if ((firstPost?.length ?? 0) > 1 && settings?.post_type === 'story') {
return 'Stories can only have one media';
}
const checkVideosLength = await Promise.all(
firstPost
.filter((f) => f.path.indexOf('mp4') > -1)
.flatMap((p) => p.path)
.map((p) => {
?.filter((f) => (f?.path?.indexOf?.('mp4') ?? -1) > -1)
?.flatMap((p) => p?.path)
?.map((p) => {
return new Promise<number>((res) => {
const video = document.createElement('video');
video.preload = 'metadata';
@ -80,13 +80,13 @@ export default withProvider<InstagramDto>({
res(video.duration);
});
});
})
}) ?? []
);
for (const video of checkVideosLength) {
if (video > 60 && settings.post_type === 'story') {
if (video > 60 && settings?.post_type === 'story') {
return 'Stories should be maximum 60 seconds';
}
if (video > 180 && settings.post_type === 'post') {
if (video > 180 && settings?.post_type === 'post') {
return 'Reel should be maximum 180 seconds';
}
}

View File

@ -73,13 +73,13 @@ export default withProvider({
CustomPreviewComponent: undefined,
dto: LemmySettingsDto,
checkValidity: async (items) => {
const [firstItems] = items;
const [firstItems] = items ?? [];
if (
firstItems.length &&
firstItems[0].path.indexOf('png') === -1 &&
firstItems[0].path.indexOf('jpg') === -1 &&
firstItems[0].path.indexOf('jpef') === -1 &&
firstItems[0].path.indexOf('gif') === -1
firstItems?.length &&
(firstItems?.[0]?.path?.indexOf?.('png') ?? -1) === -1 &&
(firstItems?.[0]?.path?.indexOf?.('jpg') ?? -1) === -1 &&
(firstItems?.[0]?.path?.indexOf?.('jpef') ?? -1) === -1 &&
(firstItems?.[0]?.path?.indexOf?.('gif') ?? -1) === -1
) {
return 'You can set only one picture for a cover';
}

View File

@ -33,23 +33,23 @@ export default withProvider<LinkedinDto>({
CustomPreviewComponent: LinkedinPreview,
dto: LinkedinDto,
checkValidity: async (posts, vals) => {
const [firstPost, ...restPosts] = posts;
const [firstPost, ...restPosts] = posts ?? [];
if (
vals.post_as_images_carousel &&
(firstPost.length < 2 ||
firstPost.some((p) => p.path.indexOf('mp4') > -1))
vals?.post_as_images_carousel &&
((firstPost?.length ?? 0) < 2 ||
firstPost?.some((p) => (p?.path?.indexOf?.('mp4') ?? -1) > -1))
) {
return 'Carousel can only be created with 2 or more images and no videos.';
}
if (
firstPost.length > 1 &&
firstPost.some((p) => p.path.indexOf('mp4') > -1)
(firstPost?.length ?? 0) > 1 &&
firstPost?.some((p) => (p?.path?.indexOf?.('mp4') ?? -1) > -1)
) {
return 'Can have maximum 1 media when selecting a video.';
}
if (restPosts.some((p) => p.length > 0)) {
if (restPosts?.some((p) => (p?.length ?? 0) > 0)) {
return 'Comments can only contain text.';
}
return true;

View File

@ -34,42 +34,42 @@ export default withProvider({
SettingsComponent: PinterestSettings,
CustomPreviewComponent: PinterestPreview,
dto: PinterestSettingsDto,
checkValidity: async ([firstItem, ...otherItems]) => {
const isMp4 = firstItem?.find((item) => item.path.indexOf('mp4') > -1);
checkValidity: async ([firstItem, ...otherItems] = []) => {
const isMp4 = firstItem?.find((item) => (item?.path?.indexOf?.('mp4') ?? -1) > -1);
const isPicture = firstItem?.find(
(item) => item.path.indexOf('mp4') === -1
(item) => (item?.path?.indexOf?.('mp4') ?? -1) === -1
);
if (firstItem.length === 0) {
if ((firstItem?.length ?? 0) === 0) {
return 'Requires at least one media';
}
if (isMp4 && firstItem.length !== 2 && !isPicture) {
if (isMp4 && firstItem?.length !== 2 && !isPicture) {
return 'If posting a video you have to also include a cover image as second media';
}
if (isMp4 && firstItem.length > 2) {
if (isMp4 && (firstItem?.length ?? 0) > 2) {
return 'If posting a video you can only have two media items';
}
if (
firstItem.length > 1 &&
firstItem.every((p) => p.path.indexOf('mp4') == -1)
(firstItem?.length ?? 0) > 1 &&
firstItem?.every((p) => (p?.path?.indexOf?.('mp4') ?? -1) == -1)
) {
const loadAll: Array<{
width: number;
height: number;
}> = (await Promise.all(
firstItem.map((p) => {
firstItem?.map((p) => {
return new Promise((resolve, reject) => {
const url = new Image();
url.onload = function () {
// @ts-ignore
resolve({ width: this.width, height: this.height });
};
url.src = p.path;
url.src = p?.path;
});
})
}) ?? []
)) as any;
const checkAllTheSameWidthHeight = loadAll.every((p, i, arr) => {
return p.width === arr[0].width && p.height === arr[0].height;
const checkAllTheSameWidthHeight = loadAll?.every((p, i, arr) => {
return p?.width === arr?.[0]?.width && p?.height === arr?.[0]?.height;
});
if (!checkAllTheSameWidthHeight) {
return 'Requires all images to have the same width and height';

View File

@ -218,15 +218,15 @@ export default withProvider({
if (
settings?.subreddit?.some(
(p: any, index: number) =>
p?.value?.type === 'media' && posts[0].length !== 1
p?.value?.type === 'media' && posts?.[0]?.length !== 1
)
) {
return 'When posting a media post, you must attached exactly one media file.';
}
if (
posts.some((p) =>
p.some((a) => !a.thumbnail && a.path.indexOf('mp4') > -1)
posts?.some((p) =>
p?.some((a) => !a?.thumbnail && (a?.path?.indexOf?.('mp4') ?? -1) > -1)
)
) {
return 'You must attach a thumbnail to your video post.';

View File

@ -15,12 +15,12 @@ export default withProvider({
SettingsComponent: SettingsComponent,
CustomPreviewComponent: undefined,
dto: undefined,
checkValidity: async ([firstPost, ...otherPosts], settings) => {
checkValidity: async ([firstPost, ...otherPosts] = [], settings) => {
const checkVideosLength = await Promise.all(
firstPost
.filter((f) => f.path.indexOf('mp4') > -1)
.flatMap((p) => p.path)
.map((p) => {
?.filter((f) => (f?.path?.indexOf?.('mp4') ?? -1) > -1)
?.flatMap((p) => p?.path)
?.map((p) => {
return new Promise<number>((res) => {
const video = document.createElement('video');
video.preload = 'metadata';
@ -29,7 +29,7 @@ export default withProvider({
res(video.duration);
});
});
})
}) ?? []
);
for (const video of checkVideosLength) {

View File

@ -26,7 +26,7 @@ const TikTokSettings: FC<{
const t = useT();
const isTitle = useMemo(() => {
return value?.[0].image.some((p) => p.path.indexOf('mp4') === -1);
return value?.[0]?.image?.some((p) => (p?.path?.indexOf?.('mp4') ?? -1) === -1);
}, [value]);
const disclose = watch('disclose');
@ -300,18 +300,18 @@ export default withProvider({
CustomPreviewComponent: TiktokPreview,
dto: TikTokDto,
checkValidity: async (items) => {
const [firstItems] = items;
if (firstItems.length === 0) {
const [firstItems] = items ?? [];
if ((firstItems?.length ?? 0) === 0) {
return 'No video / images selected';
}
if (
firstItems.length > 1 &&
firstItems?.some((p) => p?.path?.indexOf('mp4') > -1)
(firstItems?.length ?? 0) > 1 &&
firstItems?.some((p) => (p?.path?.indexOf?.('mp4') ?? -1) > -1)
) {
return 'Only pictures are supported when selecting multiple items';
} else if (
firstItems?.length !== 1 &&
firstItems?.[0]?.path?.indexOf('mp4') > -1
(firstItems?.[0]?.path?.indexOf?.('mp4') ?? -1) > -1
) {
return 'You need one media';
}

View File

@ -65,7 +65,7 @@ export default withProvider({
dto: undefined,
checkValidity: async (list) => {
if (
list.some((item) => item.some((field) => field.path.indexOf('mp4') > -1))
list?.some((item) => item?.some((field) => (field?.path?.indexOf?.('mp4') ?? -1) > -1))
) {
return 'Can only accept images';
}

View File

@ -80,18 +80,18 @@ export default withProvider({
const premium =
additionalSettings?.find((p: any) => p?.title === 'Verified')?.value ||
false;
if (posts.some((p) => p.length > 4)) {
if (posts?.some((p) => (p?.length ?? 0) > 4)) {
return 'There can be maximum 4 pictures in a post.';
}
if (
posts.some(
(p) => p.some((m) => m.path.indexOf('mp4') > -1) && p.length > 1
posts?.some(
(p) => p?.some((m) => (m?.path?.indexOf?.('mp4') ?? -1) > -1) && (p?.length ?? 0) > 1
)
) {
return 'There can be maximum 1 video in a post.';
}
for (const load of posts.flatMap((p) => p.flatMap((a) => a.path))) {
if (load.indexOf('mp4') > -1) {
for (const load of posts?.flatMap((p) => p?.flatMap((a) => a?.path)) ?? []) {
if ((load?.indexOf?.('mp4') ?? -1) > -1) {
const isValid = await checkVideoDuration(load, premium);
if (!isValid) {
return 'Video duration must be less than or equal to 140 seconds.';

View File

@ -88,11 +88,11 @@ export default withProvider({
CustomPreviewComponent: YoutubePreview,
dto: YoutubeSettingsDto,
checkValidity: async (items) => {
const [firstItems] = items;
if (items[0].length !== 1) {
const [firstItems] = items ?? [];
if (items?.[0]?.length !== 1) {
return 'You need one media';
}
if (firstItems[0].path.indexOf('mp4') === -1) {
if ((firstItems?.[0]?.path?.indexOf?.('mp4') ?? -1) === -1) {
return 'Item must be a video';
}
return true;