diff --git a/docs/docs/api.md b/docs/docs/api.md index 1c73fc05..59dd4768 100644 --- a/docs/docs/api.md +++ b/docs/docs/api.md @@ -46,6 +46,10 @@ Gets a user by their unique ID. Many other API endpoints return this as the `use Requires no authorization. +### GET /v0/me + +Returns the authenticated user. + ### `GET /v0/groups` Gets all groups, in no particular order. diff --git a/functions/src/get-current-user.ts b/functions/src/get-current-user.ts new file mode 100644 index 00000000..409f897f --- /dev/null +++ b/functions/src/get-current-user.ts @@ -0,0 +1,18 @@ +import { User } from 'common/user' +import * as admin from 'firebase-admin' +import { newEndpoint, APIError } from './api' + +export const getcurrentuser = newEndpoint( + { method: 'GET' }, + async (_req, auth) => { + const userDoc = firestore.doc(`users/${auth.uid}`) + const [userSnap] = await firestore.getAll(userDoc) + if (!userSnap.exists) throw new APIError(400, 'User not found.') + + const user = userSnap.data() as User + + return user + } +) + +const firestore = admin.firestore() diff --git a/functions/src/index.ts b/functions/src/index.ts index 239806de..b8f3eedb 100644 --- a/functions/src/index.ts +++ b/functions/src/index.ts @@ -44,6 +44,7 @@ import { creategroup } from './create-group' import { resolvemarket } from './resolve-market' import { unsubscribe } from './unsubscribe' import { stripewebhook, createcheckoutsession } from './stripe' +import { getcurrentuser } from './get-current-user' const toCloudFunction = ({ opts, handler }: EndpointDefinition) => { return onRequest(opts, handler as any) @@ -66,6 +67,7 @@ const resolveMarketFunction = toCloudFunction(resolvemarket) const unsubscribeFunction = toCloudFunction(unsubscribe) const stripeWebhookFunction = toCloudFunction(stripewebhook) const createCheckoutSessionFunction = toCloudFunction(createcheckoutsession) +const getCurrentUserFunction = toCloudFunction(getcurrentuser) export { healthFunction as health, @@ -86,4 +88,5 @@ export { unsubscribeFunction as unsubscribe, stripeWebhookFunction as stripewebhook, createCheckoutSessionFunction as createcheckoutsession, + getCurrentUserFunction as getcurrentuser, } diff --git a/functions/src/serve.ts b/functions/src/serve.ts index 77282951..0064b69f 100644 --- a/functions/src/serve.ts +++ b/functions/src/serve.ts @@ -25,6 +25,7 @@ import { creategroup } from './create-group' import { resolvemarket } from './resolve-market' import { unsubscribe } from './unsubscribe' import { stripewebhook, createcheckoutsession } from './stripe' +import { getcurrentuser } from './get-current-user' type Middleware = (req: Request, res: Response, next: NextFunction) => void const app = express() @@ -62,6 +63,7 @@ addJsonEndpointRoute('/creategroup', creategroup) addJsonEndpointRoute('/resolvemarket', resolvemarket) addJsonEndpointRoute('/unsubscribe', unsubscribe) addJsonEndpointRoute('/createcheckoutsession', createcheckoutsession) +addJsonEndpointRoute('/getcurrentuser', getcurrentuser) addEndpointRoute('/stripewebhook', stripewebhook, express.raw()) app.listen(PORT) diff --git a/web/lib/firebase/api.ts b/web/lib/firebase/api.ts index 27d6caa3..87d94dce 100644 --- a/web/lib/firebase/api.ts +++ b/web/lib/firebase/api.ts @@ -80,3 +80,7 @@ export function claimManalink(params: any) { export function createGroup(params: any) { return call(getFunctionUrl('creategroup'), 'POST', params) } + +export function getCurrentUser(params: any) { + return call(getFunctionUrl('getcurrentuser'), 'GET', params) +} diff --git a/web/pages/api/v0/me.ts b/web/pages/api/v0/me.ts new file mode 100644 index 00000000..da7edb10 --- /dev/null +++ b/web/pages/api/v0/me.ts @@ -0,0 +1,25 @@ +import { User } from 'common/user' +import { NextApiRequest, NextApiResponse } from 'next' +import { fetchBackend } from 'web/lib/api/proxy' +import { LiteUser, ApiError, toLiteUser } from './_types' + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + try { + const backendRes = await fetchBackend(req, 'getcurrentuser') + + const user = (await backendRes.json()) as User + if (!user) { + res.status(404).json({ error: 'User not found' }) + return + } + res.setHeader('Cache-Control', 'no-cache') + res.status(200).json(toLiteUser(user)) + return + } catch (err) { + console.error('Error talking to cloud function: ', err) + res.status(500).json({ error: 'Error communicating with backend.' }) + } +}