Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 30 additions & 21 deletions apps/frontend/src/app/(app)/api/uploads/[[...path]]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,39 @@ function iteratorToStream(iterator: any) {
},
});
}
export const GET = (
export const GET = async (
request: NextRequest,
context: {
params: {
params: Promise<{
path: string[];
};
}>;
}
) => {
const filePath =
process.env.UPLOAD_DIRECTORY + '/' + context.params.path.join('/');
const response = createReadStream(filePath);
const fileStats = statSync(filePath);
const contentType = mime.getType(filePath) || 'application/octet-stream';
const iterator = nodeStreamToIterator(response);
const webStream = iteratorToStream(iterator);
return new Response(webStream, {
headers: {
'Content-Type': contentType,
// Set the appropriate content-type header
'Content-Length': fileStats.size.toString(),
// Set the content-length header
'Last-Modified': fileStats.mtime.toUTCString(),
// Set the last-modified header
'Cache-Control': 'public, max-age=31536000, immutable', // Example cache-control header
},
});
try {
const params = await context.params;
const filePath =
process.env.UPLOAD_DIRECTORY + '/' + params.path.join('/');
const response = createReadStream(filePath);
const fileStats = statSync(filePath);
const contentType = mime.getType(filePath) || 'application/octet-stream';
const iterator = nodeStreamToIterator(response);
const webStream = iteratorToStream(iterator);
return new Response(webStream, {
headers: {
'Content-Type': contentType,
// Set the appropriate content-type header
'Content-Length': fileStats.size.toString(),
// Set the content-length header
'Last-Modified': fileStats.mtime.toUTCString(),
// Set the last-modified header
'Cache-Control': 'public, max-age=31536000, immutable', // Example cache-control header
},
});
} catch (error: any) {
console.error('Error serving upload:', error);
return new NextResponse(
JSON.stringify({ error: 'File not found', message: error.message }),
{ status: 404, headers: { 'Content-Type': 'application/json' } }
);
}
};
2 changes: 1 addition & 1 deletion apps/frontend/src/components/agents/agent.chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ const NewInput: FC<InputProps> = (props) => {
? '\n[--Media--]' +
media
.map((m) =>
m.path.indexOf('mp4') > -1
m.path.toLowerCase().indexOf('mp4') > -1
? `Video: ${m.path}`
: `Image: ${m.path}`
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ export const MediaComponentInner: FC<{
className="w-full px-3 py-2 bg-fifth border border-tableBorder rounded-lg text-textColor placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-forth focus:border-transparent"
/>
</div>
{media?.path.indexOf('mp4') > -1 && (
{media?.path.toLowerCase().indexOf('mp4') > -1 && (
<>
{/* Alt Text Input */}
<div>
Expand Down
13 changes: 10 additions & 3 deletions apps/frontend/src/components/launches/repeat.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,17 @@ export const RepeatComponent: FC<{
label=""
hideErrors={true}
name="repeat"
value={repeat ? repeat : undefined}
onChange={(e) => props.onChange(Number(e.target.value))}
value={repeat ?? 0}
onChange={(e) => {
const value = e.target.value;
if (value === '0') {
props.onChange(0);
return;
}
props.onChange(Number(value));
}}
>
<option>{t('repeat_post_every', 'Repeat Post Every...')}</option>
<option value="0">{t('no_repeat', 'No Repeat (Post Once)')}</option>
{list.map((item) => (
<option key={item.value} value={item.value}>
{item.label}
Expand Down
8 changes: 4 additions & 4 deletions apps/frontend/src/components/media/media.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -475,9 +475,9 @@ export const MediaBox: FC<{
{mediaList
.filter((f) => {
if (type === 'video') {
return f.path.indexOf('mp4') > -1;
return f.path.toLowerCase().indexOf('mp4') > -1;
} else if (type === 'image') {
return f.path.indexOf('mp4') === -1;
return f.path.toLowerCase().indexOf('mp4') === -1;
}
return true;
})
Expand All @@ -499,7 +499,7 @@ export const MediaBox: FC<{
X
</div>

{media.path.indexOf('mp4') > -1 ? (
{media.path.toLowerCase().indexOf('mp4') > -1 ? (
<VideoFrame url={mediaDirectory.set(media.path)} />
) : (
<Image
Expand Down Expand Up @@ -735,7 +735,7 @@ export const MultiMediaComponent: FC<{
/>
</svg>
</div>
{media?.path?.indexOf('mp4') > -1 ? (
{media?.path?.toLowerCase().indexOf('mp4') > -1 ? (
<VideoFrame url={mediaDirectory.set(media?.path)} />
) : (
<img
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default withProvider({
checkValidity: async (posts) => {
if (
posts.some(
(p) => p.some((a) => a.path.indexOf('mp4') > -1) && p.length > 1
(p) => p.some((a) => a.path.toLowerCase().indexOf('mp4') > -1) && p.length > 1
)
) {
return 'You can only upload one video per post.';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default withProvider({
CustomPreviewComponent: undefined,
dto: DribbbleDto,
checkValidity: async ([firstItem, ...otherItems]) => {
const isMp4 = firstItem?.find((item) => item.path.indexOf('mp4') > -1);
const isMp4 = firstItem?.find((item) => item.path.toLowerCase().indexOf('mp4') > -1);
if (firstItem.length !== 1) {
return 'Requires one item';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default withProvider<InstagramDto>({
}
const checkVideosLength = await Promise.all(
firstPost
.filter((f) => f.path.indexOf('mp4') > -1)
.filter((f) => f.path.toLowerCase().indexOf('mp4') > -1)
.flatMap((p) => p.path)
.map((p) => {
return new Promise<number>((res) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ export default withProvider<LinkedinDto>({
if (
vals.post_as_images_carousel &&
(firstPost.length < 2 ||
firstPost.some((p) => p.path.indexOf('mp4') > -1))
firstPost.some((p) => p.path.toLowerCase().indexOf('mp4') > -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.some((p) => p.path.toLowerCase().indexOf('mp4') > -1)
) {
return 'Can have maximum 1 media when selecting a video.';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ export default withProvider({
CustomPreviewComponent: undefined,
dto: PinterestSettingsDto,
checkValidity: async ([firstItem, ...otherItems]) => {
const isMp4 = firstItem?.find((item) => item.path.indexOf('mp4') > -1);
const isMp4 = firstItem?.find((item) => item.path.toLowerCase().indexOf('mp4') > -1);
const isPicture = firstItem?.find(
(item) => item.path.indexOf('mp4') === -1
(item) => item.path.toLowerCase().indexOf('mp4') === -1
);
if (firstItem.length === 0) {
return 'Requires at least one media';
Expand All @@ -51,7 +51,7 @@ export default withProvider({
}
if (
firstItem.length > 1 &&
firstItem.every((p) => p.path.indexOf('mp4') == -1)
firstItem.every((p) => p.path.toLowerCase().indexOf('mp4') == -1)
) {
const loadAll: Array<{
width: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ export default withProvider({

if (
posts.some((p) =>
p.some((a) => !a.thumbnail && a.path.indexOf('mp4') > -1)
p.some((a) => !a.thumbnail && a.path.toLowerCase().indexOf('mp4') > -1)
)
) {
return 'You must attach a thumbnail to your video post.';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default withProvider({
checkValidity: async ([firstPost, ...otherPosts], settings) => {
const checkVideosLength = await Promise.all(
firstPost
.filter((f) => f.path.indexOf('mp4') > -1)
.filter((f) => f.path.toLowerCase().indexOf('mp4') > -1)
.flatMap((p) => p.path)
.map((p) => {
return new Promise<number>((res) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const CheckTikTokValidity: FC<{
},
[maxVideoLength, registerVideo]
);
if (!maxVideoLength || !video || video.indexOf('mp4') === -1) {
if (!maxVideoLength || !video || video.toLowerCase().indexOf('mp4') === -1) {
return null;
}
return (
Expand Down Expand Up @@ -92,7 +92,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.toLowerCase().indexOf('mp4') === -1);
}, [value]);

const disclose = watch('disclose');
Expand Down Expand Up @@ -376,12 +376,12 @@ export default withProvider({
}
if (
firstItems.length > 1 &&
firstItems?.some((p) => p?.path?.indexOf('mp4') > -1)
firstItems?.some((p) => p?.path?.toLowerCase().indexOf('mp4') > -1)
) {
return 'Only pictures are supported when selecting multiple items';
} else if (
firstItems?.length !== 1 &&
firstItems?.[0]?.path?.indexOf('mp4') > -1
firstItems?.[0]?.path?.toLowerCase().indexOf('mp4') > -1
) {
return 'You need one media';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.toLowerCase().indexOf('mp4') > -1))
) {
return 'Can only accept images';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ export default withProvider({
}
if (
posts.some(
(p) => p.some((m) => m.path.indexOf('mp4') > -1) && p.length > 1
(p) => p.some((m) => m.path.toLowerCase().indexOf('mp4') > -1) && p.length > 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) {
if (load.toLowerCase().indexOf('mp4') > -1) {
const isValid = await checkVideoDuration(load, premium);
if (!isValid) {
return 'Video duration must be less than or equal to 140 seconds.';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export default withProvider({
if (items[0].length !== 1) {
return 'You need one media';
}
if (firstItems[0].path.indexOf('mp4') === -1) {
if (firstItems[0].path.toLowerCase().indexOf('mp4') === -1) {
return 'Item must be a video';
}
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const VEO3Settings: FC = () => {
setValue(
'images',
val.target.value
.filter((f) => f.path.indexOf('mp4') === -1)
.filter((f) => f.path.toLowerCase().indexOf('mp4') === -1)
.slice(0, 3)
)
}
Expand Down
14 changes: 8 additions & 6 deletions libraries/helpers/src/utils/valid.url.path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,21 @@ import {
@ValidatorConstraint({ name: 'checkValidExtension', async: false })
export class ValidUrlExtension implements ValidatorConstraintInterface {
validate(text: string, args: ValidationArguments) {
if (!text) return false;
const lowerText = text.toLowerCase();
return (
text?.endsWith('.png') ||
text?.endsWith('.jpg') ||
text?.endsWith('.jpeg') ||
text?.endsWith('.gif') ||
text?.endsWith('.mp4')
lowerText.endsWith('.png') ||
lowerText.endsWith('.jpg') ||
lowerText.endsWith('.jpeg') ||
lowerText.endsWith('.gif') ||
lowerText.endsWith('.mp4')
);
}

defaultMessage(args: ValidationArguments) {
// here you can provide default error message if validation failed
return (
'File must have a valid extension: .png, .jpg, .jpeg, .gif, or .mp4'
'File must have a valid extension: .png, .jpg, .jpeg, .gif, or .mp4 (case-insensitive)'
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export class IntegrationService {
customInstanceDetails?: string
) {
const uploadedPicture = picture
? picture?.indexOf('imagedelivery.net') > -1
? picture?.indexOf('imagedelivery.net') > -1 || picture?.indexOf('/uploads') > -1
? picture
: await this.storage.uploadSimple(picture)
: undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,9 @@ export class BlueskyProvider extends SocialAbstract implements SocialProvider {
for (const post of postDetails) {
// Separate images and videos
const imageMedia =
post.media?.filter((p) => p.path.indexOf('mp4') === -1) || [];
post.media?.filter((p) => p.path.toLowerCase().indexOf('mp4') === -1) || [];
const videoMedia =
post.media?.filter((p) => p.path.indexOf('mp4') !== -1) || [];
post.media?.filter((p) => p.path.toLowerCase().indexOf('mp4') !== -1) || [];

// Upload images
const images = await Promise.all(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ export class FacebookProvider extends SocialAbstract implements SocialProvider {

let finalId = '';
let finalUrl = '';
if ((firstPost?.media?.[0]?.path?.indexOf('mp4') || -2) > -1) {
if ((firstPost?.media?.[0]?.path?.toLowerCase().indexOf('mp4') || -2) > -1) {
const {
id: videoId,
permalink_url,
Expand Down
Loading