diff --git a/lib/crawler.js b/lib/crawler.js deleted file mode 100644 index a8fcaaf..0000000 --- a/lib/crawler.js +++ /dev/null @@ -1,47 +0,0 @@ -const request = require('request') -const { checkURLFormat, checkNumberURLParameter } = require('./utils') - -const useMobileURL = (originalURL) => { - const urlWithProtocol = originalURL.includes('http') ? - originalURL : - `https://${originalURL}` - const url = new URL(urlWithProtocol) - - return `${url.protocol}//mobile.facebook.com${url.port}${url.pathname}${url.hash}` -} - -const createURL = (originalURL) => { - if (checkURLFormat(originalURL)) { - return originalURL - } - - if (checkNumberURLParameter(originalURL)) { - return `https://facebook.com/events/${originalURL}` - } - - return '' -} - -const crawl = async (originalURL) => { - const url = useMobileURL(createURL(originalURL)) - return new Promise((resolve, reject) => { - console.info(`Started request for URL: ${url}`) - request({ - url, - headers: { - 'Accept-Language': 'en-US, en', - 'User-Agent': 'request', - }, - }, (err, res, body) => { - if (err) { - reject(err) - return - } - - console.info(`Finished request for URL: ${url}`) - resolve(body) - }) - }) -} - -module.exports = crawl diff --git a/lib/index.js b/lib/index.js index 84f9fbe..7949470 100644 --- a/lib/index.js +++ b/lib/index.js @@ -4,10 +4,12 @@ const path = require('path') const favicon = require('serve-favicon') const rateLimit = require('express-rate-limit') -const crawl = require('./crawler') -const parseHTML = require('./parser') -const generateICS = require('./ics') -const { genericErrorHandler, checkURLParameter, forceSecure } = require('./middlewares') +const retrieveICS = require('./services/ics-retriever') +const { + genericErrorHandler, + checkURLParameter, + forceSecure, +} = require('./middlewares') const port = process.env.PORT const certEndpoint = process.env.CERT_ENDPOINT || '' @@ -50,22 +52,17 @@ app.get('*', (req, res) => { app.use('/download', checkURLParameter) app.use('/download', rateLimit()) app.post('/download', async (req, res, next) => { - const { url } = req.body - try { - const html = await crawl(url) - const data = parseHTML(html) - const ics = await generateICS(data) + const { url } = req.body - if (ics) { - return res - .contentType('text/calendar') - .status(200) - .send(new Buffer(ics, 'utf8')) - } + const ics = await retrieveICS(url) + + res + .contentType('text/calendar') + .status(200) + .send(new Buffer(ics, 'utf8')) } catch (err) { next(err) - return } }) diff --git a/lib/services/crawler.js b/lib/services/crawler.js new file mode 100644 index 0000000..5a36455 --- /dev/null +++ b/lib/services/crawler.js @@ -0,0 +1,24 @@ +const request = require('request') + +const crawl = async (url) => { + return new Promise((resolve, reject) => { + console.info(`Started request for URL: ${url}`) + request({ + url, + headers: { + 'Accept-Language': 'en-US, en', + 'User-Agent': 'request', + }, + }, (err, res, body) => { + if (err) { + reject(err) + return + } + + console.info(`Finished request for URL: ${url}`) + resolve(body) + }) + }) +} + +module.exports = crawl diff --git a/lib/ics.js b/lib/services/ics-generator.js similarity index 100% rename from lib/ics.js rename to lib/services/ics-generator.js diff --git a/lib/services/ics-retriever.js b/lib/services/ics-retriever.js new file mode 100644 index 0000000..97daab2 --- /dev/null +++ b/lib/services/ics-retriever.js @@ -0,0 +1,18 @@ +const crawl = require('./crawler') +const parseHTML = require('./parser') +const generateICS = require('./ics-generator') +const { getNormalizedUrl } = require('../utils') + +const retrieveICS = async (URLparameter) => { + try { + const url = getNormalizedUrl(URLparameter) + const html = await crawl(url) + const eventData = parseHTML(html) + const icsFile = await generateICS(eventData) + return icsFile + } catch (err) { + throw err + } +} + +module.exports = retrieveICS diff --git a/lib/parser.js b/lib/services/parser.js similarity index 97% rename from lib/parser.js rename to lib/services/parser.js index c7cc315..70eed7d 100644 --- a/lib/parser.js +++ b/lib/services/parser.js @@ -1,6 +1,6 @@ const dayjs = require('dayjs') const cheerio = require('cheerio') -const { createParserError } = require('./utils') +const { createParserError } = require('../utils') // NOTE: Specific formatting for `ics` library const parseDates = (startDate, endDate) => { diff --git a/lib/utils.js b/lib/utils.js index 1c70dac..7ceeed3 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -18,9 +18,44 @@ const createParserError = () => { return err } +// NOTE: Using mobile facebook URL because it usually +// contains stringified JSON with event information +const createMobileURL = (originalURL) => { + const urlWithProtocol = originalURL.includes('http') ? + originalURL : + `https://${originalURL}` + const url = new URL(urlWithProtocol) + + return `${url.protocol}//mobile.facebook.com${url.port}${url.pathname}${url.hash}` +} + +// NOTE: Detect whether URL parameter contains +// number or http address +const createURL = (param) => { + if (checkURLFormat(param)) { + return param + } + + if (checkNumberURLParameter(param)) { + return `https://facebook.com/events/${param}` + } + + return '' +} + +const getNormalizedUrl = (URLparameter) => { + const fbURL = createURL(URLparameter) + const mobileUrl = createMobileURL(fbURL) + + return mobileUrl +} + module.exports = { checkValidURL, checkURLFormat, checkNumberURLParameter, createParserError, + createMobileURL, + createURL, + getNormalizedUrl, }