diff --git a/.gitignore b/.gitignore index c3de1f6..b33c49a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ .cache/ public .env -functions/* \ No newline at end of file +# Local Netlify folder +.netlify \ No newline at end of file diff --git a/functions/airtable.js b/functions/airtable.js new file mode 100644 index 0000000..d61960b --- /dev/null +++ b/functions/airtable.js @@ -0,0 +1,178 @@ +const Airtable = require('airtable'); +const axios = require('axios'); + +const ERROR_MSGS = { + UNSUPPORTED_METHOD: 'Unsupported method', + UNKNOWN_ERROR: 'Server Error', +}; + +exports.handler = async event => { + try { + const atClient = _configureAirtable(); + const atService = AirtableService(atClient); + switch (event.httpMethod) { + case 'GET': + return await retrieveAttendees(atService, event); + case 'POST': + return await insertAttendee(atService, event); + case 'DELETE': + return await removeAttendee(atService, event); + default: + callback(Error({ message: ERROR_MSGS.UNSUPPORTED_METHOD }), { + statusCode: 405, + body: ERROR_MSGS.UNSUPPORTED_METHOD, + }); + } + } catch (e) { + callback(Error(e), { + statusCode: 500, + body: ERROR_MSGS.UNKNOWN_ERROR, + }); + } +}; + +async function retrieveAttendees(Client, event) { + let attendees; + const { eventId, username } = event.queryStringParameters; + if (eventId && username) { + attendees = await Client.getSingleAttendee({ eventId, username }); + } else if (eventId) { + attendees = await Client.listAttendees({ eventId }); + } else { + throw new Error('Missing parameters'); + } + return { + statusCode: 200, + body: JSON.stringify(attendees), + }; +} + +async function insertAttendee(Client, event) { + if (event.httpMethod !== 'POST') { + return callback(Error({ message: ERROR_MSGS.UNSUPPORTED_METHOD }), { + statusCode: 405, + body: ERROR_MSGS.UNSUPPORTED_METHOD, + }); + } + const userDetails = await axios({ + method: 'GET', + url: 'https://api.github.com/user', + headers: { + Accept: 'application/vnd.github.v3+json', + Authorization: event.headers.authorization, + }, + }); + const { + data: { login, name }, + } = userDetails; + const { eventId } = JSON.parse(event.body); + const userRecord = await Client.getSingleAttendee({ + eventId, + username: login, + }); + if (userRecord && userRecord.id) { + return { + statusCode: 409, + body: `You are already signed up!`, + }; + } + await Client.insertAttendee({ eventId, name, login }); + return { + statusCode: 200, + body: JSON.stringify({ name, eventId }), + }; +} + +async function removeAttendee(Client, event) { + const { eventId } = JSON.parse(event.body); + if (!eventId) { + throw new Error('Missing Parameters: eventId'); + } + const userDetails = await axios({ + method: 'GET', + url: 'https://api.github.com/user', + headers: { + Accept: 'application/vnd.github.v3+json', + Authorization: event.headers.authorization, + }, + }); + const { + data: { login }, + } = userDetails; + const userRecord = await Client.getSingleAttendee({ + eventId, + username: login, + }); + if (!userRecord) { + return { + statusCode: 404, + body: 'User not found', + }; + } + const { id } = userRecord; + await Client.removeAttendee({ id }); + return { statusCode: 200 }; +} + +/****** UTILS ******/ + +function _configureAirtable() { + if (!process.env.AIRTABLE_BASE_ID) + throw new Error('must set process.env.AIRTABLE_BASE_ID'); + if (!process.env.AIRTABLE_API_KEY) + throw new Error('must set process.env.AIRTABLE_API_KEY'); + Airtable.configure({ apiKey: process.env.AIRTABLE_API_KEY }); + return Airtable.base(process.env.AIRTABLE_BASE_ID)('Attendees'); +} + +function AirtableService(client) { + return { + async getSingleAttendee({ eventId, username }) { + let attendees = []; + await client + .select({ + filterByFormula: `AND( + SEARCH("${eventId}",{Event ID}), + SEARCH("${username}",{Github Username}) + )`, + }) + .eachPage((records, fetchNextPage) => { + records.forEach(function(record) { + attendees.push({ ...record.fields, id: record.id }); + }); + fetchNextPage(); + }); + return attendees[0]; // there should only be one + }, + async listAttendees({ eventId }) { + let attendees = []; + await client + .select({ + filterByFormula: `SEARCH("${eventId}",{Event ID})`, + }) + .eachPage((records, fetchNextPage) => { + records.forEach(function(record) { + attendees.push(record.fields); + }); + fetchNextPage(); + }); + return attendees; + }, + insertAttendee({ name, login, eventId }) { + return client.create([ + { + fields: { + Name: name, + 'Github Username': login, + 'Event ID': eventId, + Type: 'Attendee', + 'Created Date': new Date().toISOString(), + }, + }, + ]); + }, + removeAttendee({ id }) { + return client.destroy([id]); + }, + }; +} diff --git a/functions/auth.js b/functions/auth.js new file mode 100644 index 0000000..8e3b6cf --- /dev/null +++ b/functions/auth.js @@ -0,0 +1,46 @@ +const axios = require('axios'); +const qs = require('query-string'); + +exports.handler = async event => { + try { + return await _retrieveToken(event); + } catch (e) { + let body = `Server Error`; + if (e.message) { + body = `${body} - ${e.message}`; + } + return { + statusCode: 500, + body, + }; + } +}; + +async function _retrieveToken(event) { + if (!process.env.RK_RSVP_CLIENT_ID) + throw new Error('OAuth Client ID is not set'); + if (!process.env.RK_RSVP_CLIENT_SECRET) + throw new Error('OAuth Client Secret is not set'); + const { code, state } = event.queryStringParameters; + if (!code || !state) { + throw new Error('Missing parameters'); + } + const parameters = qs.stringify({ + code, + client_id: process.env.RK_RSVP_CLIENT_ID, + client_secret: process.env.RK_RSVP_CLIENT_SECRET, + state, + }); + const res = await axios({ + method: 'post', + url: `https://github.com/login/oauth/access_token?${parameters}`, + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + }); + return { + statusCode: 200, + body: JSON.stringify(res.data), + }; +} diff --git a/gatsby-browser.js b/gatsby-browser.js index 7332da0..a83b4ae 100644 --- a/gatsby-browser.js +++ b/gatsby-browser.js @@ -1,4 +1,10 @@ +import React from 'react'; import ReactDOM from 'react-dom'; +import { AuthProvider } from './src/context/auth'; + +export const wrapRootElement = ({ element }) => ( + {element} +); // https://twitter.com/EphemeralCircle/status/1190670453221842944?s=20 // our own @thchia actually also pointed this out as well diff --git a/gatsby-config.js b/gatsby-config.js index bd33c0b..e337e85 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -129,17 +129,5 @@ module.exports = { fetchOptions: {}, }, }, - { - resolve: `gatsby-source-airtable`, - options: { - apiKey: process.env.AIRTABLE_API_KEY, - tables: [ - { - baseId: process.env.AIRTABLE_BASE_ID, - tableName: 'Attendees', - }, - ], - }, - }, ], }; diff --git a/gatsby-node.js b/gatsby-node.js index 4f036d0..fbb14ab 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -1,28 +1,34 @@ const path = require('path'); const { createFilePath } = require('gatsby-source-filesystem'); -const axios = require('axios') +const axios = require('axios'); -// exports.sourceNodes = async ({ actions, reporter, createContentDigest }) => { -// const { createNode } = actions -// const host = process.env.NODE_ENV === 'production' ? `https://reactknowledgeable.org` : `` -// const data = await axios.get(`${host}/.netlify/functions/airtable`) -// if (data.status >= 200 && data.status < 300) { -// data.data.forEach(datum => createNode({ -// ...datum, -// id: `${datum.Name}-${datum["Created Date"]}`, -// parent: null, -// children: [], -// internal: { -// type: "RKAttendee", -// contentDigest: createContentDigest(datum) -// } -// })) -// reporter.success("Retrieved attendee data") -// } else { -// reporter.error("Error encountered retrieving attendees") -// } -// return -// } +exports.sourceNodes = async ({ actions, reporter, createContentDigest }) => { + const { createNode } = actions; + const host = `https://reactknowledgeable.org`; + // const host = + // process.env.NODE_ENV === 'production' + // ? `https://reactknowledgeable.org` + // : ``; + const data = await axios.get(`${host}/.netlify/functions/airtable`); + if (data.status >= 200 && data.status < 300) { + data.data.forEach(datum => + createNode({ + ...datum, + id: `${datum.Name}-${datum['Created Date']}`, + parent: null, + children: [], + internal: { + type: 'RKAttendee', + contentDigest: createContentDigest(datum), + }, + }) + ); + reporter.success('Retrieved attendee data'); + } else { + reporter.error('Error encountered retrieving attendees'); + } + return; +}; exports.onCreateNode = ({ node, actions, getNode }) => { const { createNodeField } = actions; @@ -102,7 +108,7 @@ exports.createPages = ({ graphql, actions }) => { }); }); meetups.forEach(meetup => { - const id = meetup.fields.slug.replace(/[^\d]+/g, "") // to remove everything except the numbers + const id = meetup.fields.slug.replace(/[^\d]+/g, ''); // to remove everything except the numbers createPage({ path: `${meetup.fields.slug}`, component: meetupTemplate, diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 0000000..d35aace --- /dev/null +++ b/netlify.toml @@ -0,0 +1,4 @@ +[build] + publish = "public" + command = "yarn build" + functions = "functions" \ No newline at end of file diff --git a/package.json b/package.json index ae3dbfb..3444666 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "dependencies": { "@raae/gatsby-remark-oembed": "^0.1.1", "@reach/router": "^1.2.1", + "airtable": "^0.8.1", "axios": "^0.19.0", "classnames": "^2.2.6", "gatsby": "^2.17.4", @@ -40,8 +41,7 @@ "scripts": { "develop": "gatsby develop", "start": "npm run develop", - "build": "yarn run functions && gatsby build", - "functions": "cd src/functions && yarn run build" + "build": "GATSBY_URL=$DEPLOY_PRIME_URL gatsby build" }, "resolutions": { "gatsby-plugin-favicon/favicons-webpack-plugin/favicons/sharp": "^0.23.1" diff --git a/prettier.config.js b/prettier.config.js index 213ea50..d6b8d13 100644 --- a/prettier.config.js +++ b/prettier.config.js @@ -1,9 +1,9 @@ module.exports = { - singleQuote: true, - trailingComma: 'es5', - bracketSpacing: true, - jsxBracketSameLine: false, - printWidth: 80, - parser: 'babel-flow', - } - \ No newline at end of file + singleQuote: true, + trailingComma: 'es5', + bracketSpacing: true, + jsxBracketSameLine: false, + printWidth: 80, + parser: 'babel-flow', + semi: true, +} diff --git a/src/components/Participants/index.jsx b/src/components/Participants/index.jsx index 569ae8d..150c440 100644 --- a/src/components/Participants/index.jsx +++ b/src/components/Participants/index.jsx @@ -9,16 +9,13 @@ const getAvatarProps = username => ({ const Participants = ({ rawParticipants }) => { const participants = new Set(); - rawParticipants.map(({ node: { data: { Github_Username: username } } }) => { + rawParticipants.forEach(({ node: { Github_Username: username } }) => { // dedupe participants.add(username ? username.toLowerCase() : 'react-knowledgeable'); }); const numberOfSecretParticipants = rawParticipants.filter( - ({ - node: { - data: { Github_Username: username }, - }, - }) => !username || username === 'react-knowledgeable' + ({ node: { Github_Username: username } }) => + !username || username === 'react-knowledgeable' ).length; return participants.size > 0 ? ( diff --git a/src/components/RSVP/GitHub-Mark-Light-64px.png b/src/components/RSVP/GitHub-Mark-Light-64px.png new file mode 100644 index 0000000..73db1f6 Binary files /dev/null and b/src/components/RSVP/GitHub-Mark-Light-64px.png differ diff --git a/src/components/RSVP/index.js b/src/components/RSVP/index.js index b20b60d..f322d2a 100644 --- a/src/components/RSVP/index.js +++ b/src/components/RSVP/index.js @@ -1,134 +1,243 @@ import React from 'react'; import axios from 'axios'; +import qs from 'query-string'; import s from './s.module.scss'; +import githubLogo from './GitHub-Mark-Light-64px.png'; +import AuthContext from '../../context/auth'; + +export default ({ eventId, calendarLink }) => { + const { token } = React.useContext(AuthContext); + const [state, dispatch] = React.useReducer(reducer, initialState); + const handleError = React.useCallback(() => makeHandleError(dispatch), [ + dispatch, + ]); + React.useLayoutEffect(() => { + dispatch({ type: 'REQUEST_STATUS' }); + if (!token) { + dispatch({ + type: 'RECEIVE_AUTH', + payload: { + authStatus: false, + }, + }); + return; + } + dispatch({ + type: 'RECEIVE_AUTH', + payload: { + authStatus: true, + }, + }); + }, [token]); + React.useEffect(() => { + if (state.isAuthed && token) { + getRSVPStatus(eventId, token) + .then(rsvpName => { + dispatch({ + type: 'RECEIVE_RSVP', + payload: { rsvpStatus: !!rsvpName, rsvpName }, + }); + }) + .catch(err => { + handleError(err); + }); + } + }, [state.isAuthed, token, handleError, eventId]); + + async function sendRSVP(isGoing) { + try { + let rsvpName = ''; + dispatch({ type: 'SEND_RSVP', payload: { rsvpStatus: isGoing } }); + if (isGoing) { + const { + data: { name }, + } = await insertAttendee({ eventId, token }); + rsvpName = name; + } else { + await removeAttendee({ eventId, token }); + } + dispatch({ + type: 'RECEIVE_RSVP', + payload: { rsvpStatus: isGoing, rsvpName }, + }); + } catch (e) { + handleError(e); + } + } + + return taggedSum( + state, + { + isError: err =>

{err}

, + isWorking: () =>

Hard at work...

, + isGoing: name => ( + +

+ See you there {name} :) Would you like to{' '} + + add this to your calendar + + ? +

+ +
+ ), + isAuthed: () => ( + + +

+ We will record your attendance using your Github details +

+
+ ), + }, + () => ( + + github-logo + Login to RSVP + + ) + ); +}; + +function insertAttendee({ eventId, token }) { + return axios({ + method: 'post', + url: `/.netlify/functions/airtable`, + data: { + eventId, + }, + headers: { + Authorization: `token ${token}`, + }, + }); +} + +function removeAttendee({ eventId, token }) { + return axios({ + method: 'delete', + url: `/.netlify/functions/airtable`, + data: { + eventId, + }, + headers: { + Authorization: `token ${token}`, + }, + }); +} + +function getGithubURL() { + const base = process.env.GATSBY_URL || 'http://localhost:8000'; + const from = typeof window !== 'undefined' ? window.location.pathname : '/'; + return ( + 'https://github.com/login/oauth/authorize?' + + qs.stringify({ + client_id: 'e3a62ea68aca5801ec9b', + state: 'home', + redirect_uri: `${base}/LoginCallback?from=${from}`, + scope: 'read:user', + }) + ); +} + +function getRSVPStatus(eventId, token) { + return axios({ + method: 'GET', + url: 'https://api.github.com/user', + headers: { + Accept: 'application/vnd.github.v3+json', + Authorization: `token ${token}`, + }, + }) + .then(({ data: { login } }) => { + return axios({ + method: 'get', + url: `/.netlify/functions/airtable?eventId=${eventId}&username=${login}`, + }); + }) + .then(({ data }) => { + if (data) return data.Name; + }); +} + +function taggedSum(state, pattern, def) { + if (state.error) return pattern.isError(state.error); + if (state.isWorking) return pattern.isWorking(); + if (state.isGoing) return pattern.isGoing(state.rsvpName); + if (state.isAuthed) return pattern.isAuthed(); + return def(); +} const initialState = { - name: '', - username: '', - submissionError: '', - submitting: false, - submissionSuccess: false, + isWorking: false, + isAuthed: false, + isGoing: false, + rsvpName: '', + error: '', }; + function reducer(state = initialState, action = { type: '' }) { switch (action.type) { - case 'input': + case 'REQUEST_STATUS': + return { + ...state, + isWorking: true, + error: '', + }; + case 'RECEIVE_AUTH': return { ...state, - [action.payload.name]: action.payload.value, - submission_error: '', - submissionSuccess: false, + isWorking: false, + isAuthed: action.payload.authStatus, + // if not authed, clear out any stale rsvp status + isGoing: action.payload.authStatus === false ? false : state.isGoing, + rsvpName: action.payload.authStatus === false ? '' : state.rsvpName, }; - case 'submit': + case 'RECEIVE_RSVP': return { ...state, - submissionError: '', - submissionSuccess: false, - submitting: true, + isWorking: false, + isAuthed: true, + isGoing: action.payload.rsvpStatus, + rsvpName: action.payload.rsvpName, }; - case 'submission_error': + case 'SEND_RSVP': return { ...state, - submissionError: action.payload.error, - submissionSuccess: false, - submitting: false, + isWorking: true, + isGoing: action.payload.rsvpStatus, }; - case 'submission_success': + case 'RECEIVE_ERROR': return { ...state, - name: '', - username: '', - submissionSuccess: true, - submissionError: '', - submitting: false, + isWorking: false, + error: action.payload.error, }; default: return state; } } -export default ({ eventId, calendarLink }) => { - const [formVisible, setFormVisible] = React.useState(false); - const [nameError, setNameError] = React.useState(''); - const [state, dispatch] = React.useReducer(reducer, initialState); - const handleSubmit = e => { - e.preventDefault(); - if (!state.name) { - return setNameError('Required'); +function makeHandleError(dispatch) { + return function handleError(err) { + const { response } = err; + if (response) { + const { data } = response; + const errorMessage = + typeof data === 'string' ? data : 'Something went wrong :('; + dispatch({ + type: 'RECEIVE_ERROR', + payload: { error: errorMessage }, + }); } else { - dispatch({ type: 'submit' }); - insertAttendee({ name: state.name, username: state.username, eventId }) - .then(() => { - dispatch({ type: 'submission_success' }); - setFormVisible(false); - }) - .catch(() => { - dispatch({ - type: 'submission_error', - payload: { - error: "Oops, we couldn't register you, please try again.", - }, - }); - }); + dispatch({ + type: 'RECEIVE_ERROR', + payload: { error: 'Something went wrong :(' }, + }); } }; - return ( - - {!state.submissionSuccess && ( - - )} -
- - - {state.submissionError && ( -

{state.submissionError}

- )} - {/* Ask if they want their name to be shown? */} - -
- {state.submissionSuccess && ( -

- See you there :) Would you like to{' '} - - add this to your calendar - - ? -

- )} -
- ); -}; - -function insertAttendee({ eventId, username, name }) { - return axios.post(`/.netlify/functions/airtable`, { - name, - username, - eventId, - }); } diff --git a/src/components/RSVP/s.module.scss b/src/components/RSVP/s.module.scss index 568f493..a5051e6 100644 --- a/src/components/RSVP/s.module.scss +++ b/src/components/RSVP/s.module.scss @@ -21,6 +21,19 @@ } } +.link { + @extend .btn; + background-color: black; + border-color: white; + color: white; + display: inline-flex; + align-items: center; + margin-bottom: 0.5em; + img { + margin: 0 1em 0 0; + } +} + .formField { display: block; margin: 0.5em 0em; @@ -38,7 +51,7 @@ .fieldCaption { color: #777; font-size: .75em; - margin-bottom: .5em; + margin: .5em 0; } .fieldError { diff --git a/src/context/auth.js b/src/context/auth.js new file mode 100644 index 0000000..b265fda --- /dev/null +++ b/src/context/auth.js @@ -0,0 +1,25 @@ +import React from 'react'; + +const defaultContext = { + token: '', + setToken: () => {}, +}; + +const AuthContext = React.createContext(defaultContext); + +function AuthProvider({ children }) { + const [token, setToken] = React.useState(''); + const contextValue = React.useMemo( + () => ({ + token, + setToken, + }), + [token, setToken] + ); + return ( + {children} + ); +} + +export { AuthProvider }; +export default AuthContext; diff --git a/src/functions/airtable.js b/src/functions/airtable.js deleted file mode 100644 index b4e6967..0000000 --- a/src/functions/airtable.js +++ /dev/null @@ -1,81 +0,0 @@ -import Airtable from 'airtable' - -const ERROR_MSGS = { - UNSUPPORTED_METHOD: 'Unsupported method', - UNKNOWN_ERROR: 'Server Error', -} - -export const handler = async (event, _, callback) => { - try { - const atClient = _configureAirtable() - switch (event.httpMethod) { - case 'POST': - await insertAttendee(atClient, event, callback) - break - case 'GET': - await retrieveAttendees(atClient, event, callback) - break - default: - callback(Error({ message: ERROR_MSGS.UNSUPPORTED_METHOD }), { - status: 405, - body: ERROR_MSGS.UNSUPPORTED_METHOD, - }) - } - } catch (e) { - callback(Error(e), { - status: 500, - body: ERROR_MSGS.UNKNOWN_ERROR, - }) - } -} - -async function retrieveAttendees(Client, event, callback) { - let attendees = [] - let selectOpts = {} - const { eventId } = event.queryStringParameters - if (eventId) { - selectOpts = { filterByFormula: `SEARCH("${eventId}",{Event ID})` } - } - await Client('Attendees') - .select(selectOpts) - .eachPage((records, fetchNextPage) => { - records.forEach(function(record) { - attendees.push(record.fields) - }) - fetchNextPage() - }) - callback(null, { - status: 200, - body: JSON.stringify(attendees), - }) -} - -async function insertAttendee(Client, event, callback) { - if (event.httpMethod !== 'POST') { - return callback(Error({ message: ERROR_MSGS.UNSUPPORTED_METHOD }), { - status: 405, - body: ERROR_MSGS.UNSUPPORTED_METHOD, - }) - } - const { eventId, name, username } = JSON.parse(event.body) - await Client('Attendees').create([ - { - fields: { - Name: name, - 'Github Username': username, - 'Event ID': eventId, - Type: 'Attendee', - 'Created Date': new Date().toISOString(), - }, - }, - ]) - callback(null, { - status: 200, - body: JSON.stringify({ name, eventId }), - }) -} - -function _configureAirtable() { - Airtable.configure({ apiKey: '__AIRTABLE_API_KEY__' }) - return Airtable.base('__AIRTABLE_BASE_ID__') -} diff --git a/src/functions/package.json b/src/functions/package.json deleted file mode 100644 index 22332e4..0000000 --- a/src/functions/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "rk-functions", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "build": "yarn && rollup --config && cp -r node_modules ../../functions" - }, - "author": "", - "license": "ISC", - "devDependencies": { - "@rollup/plugin-replace": "^2.2.0", - "airtable": "^0.7.2", - "rollup": "^1.26.3" - } -} diff --git a/src/functions/rollup.config.js b/src/functions/rollup.config.js deleted file mode 100644 index 5a1a004..0000000 --- a/src/functions/rollup.config.js +++ /dev/null @@ -1,50 +0,0 @@ -/* This is for building the Netlify functions (lambdas) only! */ - -const fs = require('fs'); -const path = require('path'); -const promisify = require('util').promisify; -const readdir = promisify(fs.readdir); -const replace = require('@rollup/plugin-replace'); - -export default () => { - return new Promise(res => { - _getFunctionPaths().then(paths => { - res( - paths.map(func => ({ - input: func.input, - output: { - file: path.resolve(__dirname, '../../functions', func.filePath), - format: 'cjs', - }, - plugins: [ - replace({ - __AIRTABLE_API_KEY__: process.env.AIRTABLE_API_KEY, - __AIRTABLE_BASE_ID__: process.env.AIRTABLE_BASE_ID, - }), - ], - external: ['airtable'] - })) - ); - }); - }); -}; - -async function _getFunctionPaths() { - const functionSrc = path.resolve(__dirname); - const functionPaths = await readdir(functionSrc); - return functionPaths - .filter(filePath => { - return ![ - 'node_modules', - 'package.json', - 'yarn.lock', - 'rollup.config.js' - ].includes( - filePath - ); - }) - .map(filePath => ({ - input: path.resolve(functionSrc, filePath), - filePath, - })); -} diff --git a/src/functions/yarn.lock b/src/functions/yarn.lock deleted file mode 100644 index 1ad72d7..0000000 --- a/src/functions/yarn.lock +++ /dev/null @@ -1,570 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@rollup/plugin-replace@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-2.2.0.tgz#e3b11881fb1ab1be7570e1ccd175b8249e448c52" - integrity sha512-DnALjyAdfAyQ4i6tJdi4v6rJwx5tzV9/+M7G8qA3cHpPOYQOgM4U8bU4lSM24h9hFIbycxRTHtE+TkENLqRlEA== - dependencies: - magic-string "^0.25.2" - rollup-pluginutils "^2.6.0" - typescript "^3.4.3" - -"@types/estree@*": - version "0.0.39" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" - integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== - -"@types/node@*": - version "12.12.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.5.tgz#66103d2eddc543d44a04394abb7be52506d7f290" - integrity sha512-KEjODidV4XYUlJBF3XdjSH5FWoMCtO0utnhtdLf1AgeuZLOrRbvmU/gaRCVg7ZaQDjVf3l84egiY0mRNe5xE4A== - -acorn@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c" - integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ== - -airtable@^0.7.2: - version "0.7.2" - resolved "https://registry.yarnpkg.com/airtable/-/airtable-0.7.2.tgz#106e87b7139f6a2c9f1bd856583e83626e2f3c04" - integrity sha512-BwHIJyXmtUJ78EpnNzs+aYmPK9r0xNeFyKkmSn9I6WvG6QYcXlbDe6rhoEwqEdrjPVL6ZCoNwimJN4l6y5TUJg== - dependencies: - lodash "4.17.15" - request "2.88.0" - xhr "2.3.3" - -ajv@^6.5.5: - version "6.10.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" - integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== - dependencies: - fast-deep-equal "^2.0.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" - integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -core-util-is@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -dom-walk@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" - integrity sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg= - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -es-abstract@^1.13.0: - version "1.16.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.16.0.tgz#d3a26dc9c3283ac9750dca569586e976d9dcc06d" - integrity sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg== - dependencies: - es-to-primitive "^1.2.0" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.0" - is-callable "^1.1.4" - is-regex "^1.0.4" - object-inspect "^1.6.0" - object-keys "^1.1.1" - string.prototype.trimleft "^2.1.0" - string.prototype.trimright "^2.1.0" - -es-to-primitive@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" - integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -estree-walker@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" - integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= - -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= - -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= - -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - -global@~4.3.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" - integrity sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8= - dependencies: - min-document "^2.19.0" - process "~0.5.1" - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.1.0: - version "5.1.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== - dependencies: - ajv "^6.5.5" - har-schema "^2.0.0" - -has-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" - integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= - -has@^1.0.1, has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -is-callable@^1.1.3, is-callable@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" - integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== - -is-date-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= - -is-function@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" - integrity sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU= - -is-regex@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= - dependencies: - has "^1.0.1" - -is-symbol@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" - integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== - dependencies: - has-symbols "^1.0.0" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -lodash@4.17.15: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== - -magic-string@^0.25.2: - version "0.25.4" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.4.tgz#325b8a0a79fc423db109b77fd5a19183b7ba5143" - integrity sha512-oycWO9nEVAP2RVPbIoDoA4Y7LFIJ3xRYov93gAyJhZkET1tNuB0u7uWkZS2LpBWTJUWnmau/To8ECWRC+jKNfw== - dependencies: - sourcemap-codec "^1.4.4" - -mime-db@1.40.0: - version "1.40.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" - integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== - -mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.24" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" - integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== - dependencies: - mime-db "1.40.0" - -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= - dependencies: - dom-walk "^0.1.0" - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - -object-inspect@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" - integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== - -object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -parse-headers@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.2.tgz#9545e8a4c1ae5eaea7d24992bca890281ed26e34" - integrity sha512-/LypJhzFmyBIDYP9aDVgeyEb5sQfbfY5mnDq4hVhlQ69js87wXfmEI5V3xI6vvXasqebp0oCytYFLxsBVfCzSg== - dependencies: - for-each "^0.3.3" - string.prototype.trim "^1.1.2" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -process@~0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" - integrity sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8= - -psl@^1.1.24: - version "1.4.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.4.0.tgz#5dd26156cdb69fa1fdb8ab1991667d3f80ced7c2" - integrity sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw== - -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - -request@2.88.0: - version "2.88.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" - integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.0" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.4.3" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - -rollup-pluginutils@^2.6.0: - version "2.8.2" - resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" - integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== - dependencies: - estree-walker "^0.6.1" - -rollup@^1.26.3: - version "1.26.3" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.26.3.tgz#3e71b8120a4ccc745a856e926cab0efbe0eead90" - integrity sha512-8MhY/M8gnv3Q/pQQSWYWzbeJ5J1C5anCNY5BK1kV8Yzw9RFS0FF4lbLt+uyPO3wLKWXSXrhAL5pWL85TZAh+Sw== - dependencies: - "@types/estree" "*" - "@types/node" "*" - acorn "^7.1.0" - -safe-buffer@^5.0.1, safe-buffer@^5.1.2: - version "5.2.0" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" - integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== - -safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sourcemap-codec@^1.4.4: - version "1.4.6" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz#e30a74f0402bad09807640d39e971090a08ce1e9" - integrity sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg== - -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -string.prototype.trim@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.0.tgz#75a729b10cfc1be439543dae442129459ce61e3d" - integrity sha512-9EIjYD/WdlvLpn987+ctkLf0FfvBefOCuiEr2henD8X+7jfwPnyvTdmW8OJhj5p+M0/96mBdynLWkxUr+rHlpg== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.13.0" - function-bind "^1.1.1" - -string.prototype.trimleft@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" - integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw== - dependencies: - define-properties "^1.1.3" - function-bind "^1.1.1" - -string.prototype.trimright@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" - integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg== - dependencies: - define-properties "^1.1.3" - function-bind "^1.1.1" - -tough-cookie@~2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" - integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== - dependencies: - psl "^1.1.24" - punycode "^1.4.1" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - -typescript@^3.4.3: - version "3.6.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.4.tgz#b18752bb3792bc1a0281335f7f6ebf1bbfc5b91d" - integrity sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg== - -uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== - dependencies: - punycode "^2.1.0" - -uuid@^3.3.2: - version "3.3.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" - integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -xhr@2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.3.3.tgz#ad6b810e0917ce72b5ec704f5d41f1503b8e7524" - integrity sha1-rWuBDgkXznK17HBPXUHxUDuOdSQ= - dependencies: - global "~4.3.0" - is-function "^1.0.1" - parse-headers "^2.0.0" - xtend "^4.0.0" - -xtend@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== diff --git a/src/pages/LoginCallback/index.jsx b/src/pages/LoginCallback/index.jsx new file mode 100644 index 0000000..85e9482 --- /dev/null +++ b/src/pages/LoginCallback/index.jsx @@ -0,0 +1,36 @@ +import * as React from 'react'; +import qs from 'query-string'; +import axios from 'axios'; +import { navigate } from '@reach/router'; +import AuthContext from '../../context/auth'; + +const LoginCallback = () => { + const { setToken } = React.useContext(AuthContext); + React.useEffect(() => { + const { code, state, from } = qs.parse(window.location.search); + const nextPage = from || '/'; + axios({ + method: 'get', + url: `/.netlify/functions/auth?code=${code}&state=${state}`, + headers: { + Accept: 'application/json', + }, + }) + .then(res => { + const { + data: { access_token }, + } = res; + if (!access_token || typeof access_token !== 'string') { + throw new Error(); + } + setToken(access_token); + navigate(nextPage); + }) + .catch(() => { + navigate(nextPage); + }); + }, [setToken]); + return
logging in...
; +}; + +export default LoginCallback; diff --git a/src/templates/Meetup/index.jsx b/src/templates/Meetup/index.jsx index 11a0469..3d5b37e 100644 --- a/src/templates/Meetup/index.jsx +++ b/src/templates/Meetup/index.jsx @@ -40,7 +40,7 @@ export default ({ location, pageContext: { id }, data: { - allAirtable: { edges: rawParticipants }, + allRkAttendee: { edges: rawParticipants }, site: { siteMetadata: { description, @@ -62,7 +62,6 @@ export default ({ venueAddressLink, sponsors, talks: talkIssueIds, - issueLink, calendarLink, }, htmlAst, @@ -178,7 +177,11 @@ export default ({ {venueAddressLink && ( <> ,{' '} - + Google Map @@ -294,19 +297,24 @@ export default ({ export const pageQuery = graphql` query MeetupQuery($slug: String!, $id: String!) { - # allRkAttendee(filter: { Event_ID: { eq: $id } }) { - # totalCount - # } - allAirtable(filter: { data: { Event_ID: { eq: $id } } }) { + allRkAttendee(filter: { Event_ID: { eq: $id } }) { totalCount edges { node { - data { - Github_Username - } + Github_Username } } } + # allAirtable(filter: { data: { Event_ID: { eq: $id } } }) { + # totalCount + # edges { + # node { + # data { + # Github_Username + # } + # } + # } + # } site { siteMetadata { title diff --git a/src/utils/axios.js b/src/utils/axios.js new file mode 100644 index 0000000..9211254 --- /dev/null +++ b/src/utils/axios.js @@ -0,0 +1,7 @@ +const axios = require('axios'); + +module.exports = axios.create({ + validateStatus: function(status) { + return status >= 200 && status < 300; + }, +}); diff --git a/yarn.lock b/yarn.lock index 99db21d..97b904a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1799,6 +1799,16 @@ airtable@^0.7.2: request "2.88.0" xhr "2.3.3" +airtable@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/airtable/-/airtable-0.8.1.tgz#8d10f04f41673b86ed75fa054f54470357e36ae0" + integrity sha512-Cxw55ta1olDwDERz++HFJOBX6LONtg+d7+wOcYguqI4PR4P5RHmgjTbY8tPKgLHb8U3FVOyAbpb7NpLRSnLGgg== + dependencies: + es6-promise "4.2.8" + lodash "4.17.15" + request "2.88.0" + xhr "2.3.3" + ajv-errors@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" @@ -4717,6 +4727,11 @@ es-to-primitive@^1.2.0: is-date-object "^1.0.1" is-symbol "^1.0.2" +es6-promise@4.2.8: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + es6-promise@^3.0.2: version "3.3.1" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613"