UNPKG

formio-sfds

Version:
226 lines (200 loc) • 6.45 kB
const fetch = require('node-fetch') const { URL } = require('url') const { join } = require('path') const nunjucks = require('nunjucks') const Phrase = require('../src/phrase') const { Proxy } = require('../lib/proxy') const defaultData = require('../views/data') const { // TODO: use https://forms.api.sf.gov FORMS_API_URL = 'https://sfgov-forms.herokuapp.com' } = process.env const templates = nunjucks.configure(join(__dirname, '../views'), { autoescape: false }) const languageNames = { en: 'English', es: 'Spanish', zh: 'Chinese', 'zh-hant': 'Chinese (Traditional)', 'zh-hans': 'Chinese (Simplified)', 'zh-tw': 'Chinese (Taiwan)', fil: 'Filipino', tl: 'Tagalog' } module.exports = async (req, res) => { const { query } = req const { url } = query const allPages = await getSFGovPages() const uniques = new Set() const uniquePages = allPages .filter(node => { if (uniques.has(node.url)) { return false } else { uniques.add(node.url) return true } }) .sort((a, b) => a.title.localeCompare(b.title)) const data = Object.assign({ query, pages: uniquePages, sfgov: {}, formio: {}, formiojs: {}, theme: {}, translation: {}, warnings: [] }, defaultData) if (url) { const parsed = new URL(url) if (isSFGovURL(parsed)) { await getSFgovData(url, data) } else if (isFormioPortalURL(parsed)) { const parts = parsed.hash.replace(/^#\//, '').split('/') if (parts[0] === 'project' && parts[2] === 'form' && parts[3]) { const formId = parts[3] const [form] = await fetch(`http://sfds.form.io/form?_id__eq=${formId}`).then(res => res.json()) if (form) { data.formio.form = form data.formio.url = `https://sfds.form.io/${form.path}` } else { data.error = `Unable to find form with ID: "${formId}"` } } } else if (isDataSourceURL(parsed)) { data.formio.url = url data.formio.form = await fetch(url).then(res => res.json()) } const { form } = data.formio if (form) { const phrase = new Phrase(form) const info = phrase.getTranslationInfo() if (info && info.url) { data.translation.url = info.url data.translation.source = { title: `Phrase project <code>${info.projectId}</code>` } } if (!data.sfgov.url) { const dataSourceURL = data.formio.url console.warn('Looking up sf.gov page by form URL:', dataSourceURL) const pages = uniquePages.filter(d => { const url = d.field_formio_data_source console.warn(' ?', url) return url === dataSourceURL }) if (pages.length >= 1) { const [page] = pages data.sfgov.url = page.url data.sfgov.title = page.title await getSFgovData(page.url, data) if (pages.length > 1) { data.warnings.push(` Multiple pages on sf.gov were found with this data source URL: <ul> ${pages.map(page => ` <li> <b>${page.title}</b> (<a href="${page.url}"><code>${new URL(page.url).pathname}</code></a>) </li> `).join('')} </ul> `) } } else if (pages.length === 0) { data.error = `No sf.gov form pages were found with data source URL: "${dataSourceURL}"` } } } } else { // data.error = 'Please enter a URL from sf.gov or form.io' } res.setHeader('Content-Type', 'text/html') const content = templates.render('wtf.html', data) res.send(content) } function isSFGovURL (url) { return url.hostname === 'sf.gov' || ( url.hostname.includes('sfgov') && url.hostname.endsWith('.pantheonsite.io') ) } function isFormioPortalURL (url) { return url.hostname === 'portal.form.io' } function isDataSourceURL (url) { return url.hostname.endsWith('.form.io') && url.hostname.includes('sfds') } function getUnpkgVersion (url) { const match = url.match(/@([^/]+)/) return match ? match[1] : undefined } async function getSFgovData (url, data) { const { pathname } = new URL(url) const base = Object.assign(new URL(url), { pathname: '' }).href const proxy = new Proxy({ base }) const { body, document } = await proxy.fetch(pathname) data.body = body data.sfgov.url = url data.sfgov.title = document.title.replace(/\s*\|\s*San Francisco\s*$/, '') const { lang } = document.documentElement data.lang = { code: lang, name: languageNames[lang.toLowerCase()], links: Array.from(document.querySelectorAll('link[rel="alternate"]'), link => { const code = link.hreflang return { href: link.href, lang: { code, name: languageNames[code] } } }) .filter(link => link.lang.code !== lang) } const elements = Array.from( document.querySelectorAll('[data-source]') ) const element = elements.find(el => { return el.getAttribute('data-source') !== '-' }) if (element) { data.formio.url = element.getAttribute('data-source') console.warn('form url:', data.formio.url) const form = await fetch(data.formio.url) .then(res => res.json()) .catch(error => console.error('fetch error:', error)) data.formio.form = form if (element.hasAttribute('data-options')) { const options = JSON.parse(element.getAttribute('data-options')) data.formio.options = options if (typeof options.i18n === 'string') { data.translation.url = options.i18n const match = options.i18n.match(/google\/([^@]+)/) data.translation.source = { title: 'Google Sheets', url: `https://docs.google.com/spreadsheets/d/${match[1]}/edit` } } } } const formioScript = proxy.getScript('formiojs') if (formioScript) { data.formiojs.url = formioScript.src data.formiojs.version = getUnpkgVersion(formioScript.src) } const themeScript = proxy.getScript('formio-sfds') if (themeScript) { data.theme.url = themeScript.src data.theme.version = getUnpkgVersion(themeScript.src) } } async function getSFGovPages (options) { const { data } = await fetch(`${FORMS_API_URL}/api/sfgov`) .then(res => res.json()) return (data && data.forms) || [] }