Merge pull request #1 from hackclub/airtable-based-login

Setup airtable based login fields & redirect
This commit is contained in:
Clay Nicholson 2024-08-16 12:06:20 -04:00 committed by GitHub
commit b64edae3e8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 113 additions and 0 deletions

View file

@ -0,0 +1,53 @@
import AirtablePlus from "airtable-plus"
const airtable = new AirtablePlus({
apiKey: process.env.AIRTABLE_API_KEY,
baseID: 'app4kCWulfB02bV8Q',
tableName: "Users"
})
async function getUserFromLogin(loginToken) {
// only alphanumeric & '-' characters are allowed in the token
const safeLoginToken = loginToken.replace(/[^a-zA-Z0-9-]/g, '')
const results = await airtable.read({
filterByFormula: `{Login Token} = '${safeLoginToken}'`,
maxRecords: 1
})
return results[0]
}
async function scrubLoginToken(userID) {
console.log(`Scrubbing login token for user ${userID}`)
await airtable.update(userID, {
'Login Token': ''
})
}
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ error: "Method not allowed" })
}
const { token } = req.query
if (!token) {
return res.status(400).json({ error: "Token is required" })
}
const user = await getUserFromLogin(token)
if (!user) {
return res.status(404).json({ error: "User not found" })
}
const authToken = user.fields['Auth Token']
if (!authToken) {
return res.status(500).json({ error: "Auth Token not found" })
}
await scrubLoginToken(user.id)
// return back the user's AuthToken
res.status(200).json({ authToken })
}

View file

@ -0,0 +1,60 @@
import { useEffect, useState } from 'react'
const sample = arr => arr[Math.floor(Math.random() * arr.length)]
const languages = "Python Rust COBOL Wasm tailwind ".split(" ")
const tinyEyes = [
"if you can see this, you're too close",
"what are you looking at, tiny-eyes?",
"I see you",
"What is this, a website for ants?",
"plz help, my font size has fallen and it can't get up",
"*small loading sounds*"
]
const flavorText = [
`I would've been faster written in ${sample(languages)}`,
'Wait your turn!',
'Form an orderly queue!',
"I'm a teapo WAIT WRONG ENDPOINT",
"GET outta here with that request!",
"PUT that request back where it came from or so help me",
"POST haste!",
"TODO: Delete this message",
<p style={{fontSize: "3px"}}>{sample(tinyEyes)}</p>,
"Caution: objects in loading box are slower than they appear",
"Caution: wet pixels, do not touch",
"*Fax machine noises*",
]
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
const LoginPage = ({token}) => {
const [ status, setStatus ] = useState('Loading...')
useEffect(async () => {
const minWaitTime = sleep(3 * 1000)
const response = fetch(`/api/arcade/showcase/login/${token}`, {method: 'POST'})
const data = response.json()
const [ _wait, _data ] = await Promise.all([minWaitTime, data])
if (data.error) {
setStatus(data.error)
} else {
setStatus("Redirecting!")
window.localStorage.setItem('arcade.authToken', data.authToken)
await sleep(250)
window.location.href = '/arcade/showcase/my'
}
}, [])
return (
<div>
<p>{status}</p>
<p><em>{sample(flavorText)}</em></p>
</div>
)
}
export default LoginPage
export function getServerSideProps(context) {
const { token } = context.query
return { props: { token } }
}