From 5dca2c5a13dda5afc2f2d655e023e587c1444a65 Mon Sep 17 00:00:00 2001 From: MuhammadUmer44 Date: Wed, 18 Sep 2024 20:43:31 +0500 Subject: [PATCH] fix(add-content): extend webpage check for RSS feeds --- src/components/AddContentModal/index.tsx | 8 ++- .../AddContentModal/utils/__tests__/index.ts | 55 ++++++++++++------- src/components/AddContentModal/utils/index.ts | 19 ++++++- 3 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/components/AddContentModal/index.tsx b/src/components/AddContentModal/index.tsx index 5bf005f52b..057b9caca4 100644 --- a/src/components/AddContentModal/index.tsx +++ b/src/components/AddContentModal/index.tsx @@ -172,7 +172,13 @@ export const AddContentModal = () => { const isValidSource = validateSourceURL(sourceValue) useEffect(() => { - setValue('inputType', getInputType(source)) + const updateInputType = async () => { + const inputType = await getInputType(source) + + setValue('inputType', inputType) + } + + updateInputType() }, [source, setValue]) const handleClose = () => { diff --git a/src/components/AddContentModal/utils/__tests__/index.ts b/src/components/AddContentModal/utils/__tests__/index.ts index 39ef6c0683..b7ca88fa83 100644 --- a/src/components/AddContentModal/utils/__tests__/index.ts +++ b/src/components/AddContentModal/utils/__tests__/index.ts @@ -3,63 +3,64 @@ import { extractNameFromLink, getInputType } from '..' describe('youtubeRegex', () => { it('should assert we can check for youtube clip regex', async () => { - expect(getInputType('https://www.youtube.com/watch?v=83eQ9flwVS0&ab_channel=EthanChlebowski')).toBe(LINK) + expect(await getInputType('https://www.youtube.com/watch?v=83eQ9flwVS0&ab_channel=EthanChlebowski')).toBe(LINK) }) it('should assert we can check for youtube live clip regex', async () => { - expect(getInputType('https://youtube.com/live/tkdMgjEFNWs')).toBe(LINK) + expect(await getInputType('https://youtube.com/live/tkdMgjEFNWs')).toBe(LINK) }) it('should assert we can check for twitter spaces regex', async () => { - expect(getInputType('https://twitter.com/i/spaces/1zqKVqwrVzlxB?s=20')).toBe(LINK) + expect(await getInputType('https://twitter.com/i/spaces/1zqKVqwrVzlxB?s=20')).toBe(LINK) }) it('should assert we can check for youtu.be link regex', async () => { - expect(getInputType('https://youtu.be/HfMYOeg79dM')).toBe(LINK) + expect(await getInputType('https://youtu.be/HfMYOeg79dM')).toBe(LINK) }) it('should assert we can check for youtu.be link with parameters regex', async () => { - expect(getInputType('https://youtu.be/HfMYOeg79dM?t=120')).toBe(LINK) + expect(await getInputType('https://youtu.be/HfMYOeg79dM?t=120')).toBe(LINK) }) it('should assert we can check for twitter tweet regex', async () => { - expect(getInputType('https://twitter.com/LarryRuane/status/1720496960489095668')).toBe(TWITTER_SOURCE) + expect(await getInputType('https://twitter.com/LarryRuane/status/1720496960489095668')).toBe(TWITTER_SOURCE) }) it('should assert we can check for x.com tweet regex', async () => { - expect(getInputType('https://x.com/bernaaaljg/status/1795260855002583101')).toBe(TWITTER_SOURCE) + expect(await getInputType('https://x.com/bernaaaljg/status/1795260855002583101')).toBe(TWITTER_SOURCE) }) it('should assert we can check for mp3 url regex', async () => { - expect(getInputType('https://hahaha.com/i/spaces/1zqKVqwrVzlxB?s=20.mp3')).toBe(LINK) + expect(await getInputType('https://hahaha.com/i/spaces/1zqKVqwrVzlxB?s=20.mp3')).toBe(LINK) }) - it('should assert we can check for Twitter broadcast regex', () => { - expect(getInputType('https://twitter.com/i/broadcasts/1YqxoDbOqevKv')).toBe(LINK) + it('should assert we can check for Twitter broadcast regex', async () => { + expect(await getInputType('https://twitter.com/i/broadcasts/1YqxoDbOqevKv')).toBe(LINK) }) it('should assert we can check for generic url regex', async () => { - expect(getInputType('https://idkwhat.com/routeing/tou')).toBe(WEB_PAGE) + jest.setTimeout(10000) + expect(await getInputType('https://idkwhat.com/routeing/tou')).toBe(WEB_PAGE) }) it('should assert we can check for youtube clip regex', async () => { - expect(getInputType('https://www.youtube.com/@MrBeast')).toBe(YOUTUBE_CHANNEL) + expect(await getInputType('https://www.youtube.com/@MrBeast')).toBe(YOUTUBE_CHANNEL) }) it('should assert we can check for twitter handle regex', async () => { - expect(getInputType('https://twitter.com/@KevKevPal')).toBe(TWITTER_HANDLE) + expect(await getInputType('https://twitter.com/@KevKevPal')).toBe(TWITTER_HANDLE) }) it('should assert we can check for x.com handle regex', async () => { - expect(getInputType('https://x.com/@KevKevPal')).toBe(TWITTER_HANDLE) + expect(await getInputType('https://x.com/@KevKevPal')).toBe(TWITTER_HANDLE) }) it('should assert we can check for youtube live clip regex', async () => { - expect(getInputType('https://www.youtube.com/@MrBeast')).toBe(YOUTUBE_CHANNEL) + expect(await getInputType('https://www.youtube.com/@MrBeast')).toBe(YOUTUBE_CHANNEL) }) it('should assert we can check for document regex', async () => { - expect(getInputType('some plain text')).toBe(DOCUMENT) + expect(await getInputType('some plain text')).toBe(DOCUMENT) }) }) @@ -102,9 +103,23 @@ describe('extractNameFromLink', () => { describe('getInputType', () => { it('should assert we can check for RSS feed url regex', async () => { - expect(getInputType('http://example.com/feed')).toBe(RSS) - expect(getInputType('http://example.com/rss')).toBe(RSS) - expect(getInputType('http://example.com/rss.xml')).toBe(RSS) - expect(getInputType('http://example.com/?feed=rss')).toBe(RSS) + expect(await getInputType('http://example.com/feed')).toBe(RSS) + expect(await getInputType('http://example.com/rss')).toBe(RSS) + expect(await getInputType('http://example.com/rss.xml')).toBe(RSS) + expect(await getInputType('http://example.com/?feed=rss')).toBe(RSS) + }) + + it('should assert we can check for RSS feed by content type', async () => { + global.fetch = jest.fn(() => + Promise.resolve({ + headers: { + get: (header) => (header === 'Content-Type' ? 'application/rss+xml' : null), + }, + }), + ) as jest.Mock + + expect(await getInputType('https://rss.arxiv.org/rss/cs.AI')).toBe(RSS) + + jest.restoreAllMocks() }) }) diff --git a/src/components/AddContentModal/utils/index.ts b/src/components/AddContentModal/utils/index.ts index 8ade526f61..d9a7e227f1 100644 --- a/src/components/AddContentModal/utils/index.ts +++ b/src/components/AddContentModal/utils/index.ts @@ -15,7 +15,18 @@ const youtubeChannelPattern = /https?:\/\/(www\.)?youtube\.com\/(user\/)?(@)?([\ const genericUrlRegex = /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/ const twitterBroadcastRegex = /https:\/\/twitter\.com\/i\/broadcasts\/([A-Za-z0-9_-]+)/ -export function getInputType(source: string) { +const checkIfRSS = async (url: string): Promise => { + try { + const response = await fetch(url, { method: 'HEAD' }) + const contentType = response.headers.get('Content-Type') + + return contentType?.includes('application/rss+xml') ?? false + } catch (error) { + return false + } +} + +export async function getInputType(source: string) { const linkPatterns = [ youtubeLiveRegex, twitterBroadcastRegex, @@ -46,6 +57,12 @@ export function getInputType(source: string) { } if (genericUrlRegex.test(source)) { + const isRSS = await checkIfRSS(source) + + if (isRSS) { + return RSS + } + return WEB_PAGE }