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, dto: undefined,
checkValidity: async (posts) => { checkValidity: async (posts) => {
if ( if (
posts.some( posts?.some(
(p) => p.some((a) => a.path.indexOf('mp4') > -1) && p.length > 1 (p) => p?.some((a) => (a?.path?.indexOf?.('mp4') ?? -1) > -1) && (p?.length ?? 0) > 1
) )
) { ) {
return 'You can only upload one video per post.'; 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 'There can be maximum 4 pictures in a post.';
} }
return true; return true;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -65,7 +65,7 @@ export default withProvider({
dto: undefined, dto: undefined,
checkValidity: async (list) => { checkValidity: async (list) => {
if ( 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'; return 'Can only accept images';
} }

View File

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

View File

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