createUser cloud function; change User object
This commit is contained in:
parent
56c7e2597d
commit
3b2be5800a
|
@ -1,12 +1,14 @@
|
|||
export type User = {
|
||||
id: string
|
||||
email: string
|
||||
createdTime: number
|
||||
|
||||
name: string
|
||||
username: string
|
||||
avatarUrl: string
|
||||
avatarUrl?: string
|
||||
|
||||
balance: number
|
||||
createdTime: number
|
||||
lastUpdatedTime: number
|
||||
totalPnLCached: number
|
||||
creatorVolumeCached: number
|
||||
}
|
||||
|
||||
export const STARTING_BALANCE = 1000
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
export const randomString = () => Math.random().toString(16).substr(2, 14)
|
||||
export const randomString = (length = 12) =>
|
||||
Math.random()
|
||||
.toString(16)
|
||||
.substring(2, length + 2)
|
||||
|
||||
export function createRNG(seed: string) {
|
||||
// https://stackoverflow.com/a/47593316/1592933
|
||||
|
|
54
functions/src/create-user.ts
Normal file
54
functions/src/create-user.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
import * as functions from 'firebase-functions'
|
||||
import * as admin from 'firebase-admin'
|
||||
|
||||
import { STARTING_BALANCE, User } from '../../common/user'
|
||||
import { getUser, getUserByUsername } from './utils'
|
||||
import { slugify } from '../../common/util/slugify'
|
||||
import { randomString } from '../../common/util/random'
|
||||
|
||||
export const createUser = functions
|
||||
.runWith({ minInstances: 1 })
|
||||
.https.onCall(async (_, context) => {
|
||||
const userId = context?.auth?.uid
|
||||
if (!userId) return { status: 'error', message: 'Not authorized' }
|
||||
|
||||
const preexistingUser = await getUser(userId)
|
||||
if (preexistingUser)
|
||||
return { status: 'error', message: 'User already created' }
|
||||
|
||||
const fbUser = await admin.auth().getUser(userId)
|
||||
|
||||
const email = fbUser.email
|
||||
const emailName = email?.replace(/@.*$/, '')
|
||||
|
||||
const name = fbUser.displayName || emailName || 'User' + randomString(4)
|
||||
let username = cleanUsername(name)
|
||||
|
||||
const sameNameUser = await getUserByUsername(username)
|
||||
if (sameNameUser) {
|
||||
username += randomString(4)
|
||||
}
|
||||
|
||||
const avatarUrl = fbUser.photoURL
|
||||
|
||||
const user: User = {
|
||||
id: userId,
|
||||
name,
|
||||
username,
|
||||
avatarUrl,
|
||||
balance: STARTING_BALANCE,
|
||||
createdTime: Date.now(),
|
||||
}
|
||||
|
||||
await firestore.collection('users').doc(userId).create(user)
|
||||
|
||||
console.log('created user', username, 'firebase id:', userId)
|
||||
|
||||
return { status: 'success', user }
|
||||
})
|
||||
|
||||
const cleanUsername = (name: string) => {
|
||||
return slugify(name.replace(/\s+/g, ''))
|
||||
}
|
||||
|
||||
const firestore = admin.firestore()
|
|
@ -9,5 +9,6 @@ export * from './resolve-market'
|
|||
export * from './stripe'
|
||||
export * from './sell-bet'
|
||||
export * from './create-contract'
|
||||
export * from './create-user'
|
||||
export * from './update-contract-metrics'
|
||||
export * from './update-user-metrics'
|
||||
|
|
|
@ -22,6 +22,15 @@ export const getUser = (userId: string) => {
|
|||
return getValue<User>('users', userId)
|
||||
}
|
||||
|
||||
export const getUserByUsername = async (username: string) => {
|
||||
const snap = await firestore
|
||||
.collection('users')
|
||||
.where('username', '==', username)
|
||||
.get()
|
||||
|
||||
return snap.empty ? undefined : (snap.docs[0].data() as User)
|
||||
}
|
||||
|
||||
const firestore = admin.firestore()
|
||||
|
||||
const updateUserBalance = (userId: string, delta: number) => {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { getFunctions, httpsCallable } from 'firebase/functions'
|
||||
import { User } from '../../../common/user'
|
||||
|
||||
const functions = getFunctions()
|
||||
|
||||
|
@ -11,3 +12,8 @@ export const placeBet = cloudFunction('placeBet')
|
|||
export const resolveMarket = cloudFunction('resolveMarket')
|
||||
|
||||
export const sellBet = cloudFunction('sellBet')
|
||||
|
||||
export const createUser = () =>
|
||||
cloudFunction('createUser')({}).then(
|
||||
(r) => (r.data as any)?.user as User | undefined
|
||||
)
|
||||
|
|
|
@ -21,10 +21,9 @@ import {
|
|||
|
||||
import { User } from '../../../common/user'
|
||||
import { listenForValues } from './utils'
|
||||
import { createUser } from './api-call'
|
||||
export type { User }
|
||||
|
||||
export const STARTING_BALANCE = 1000
|
||||
|
||||
const db = getFirestore(app)
|
||||
export const auth = getAuth(app)
|
||||
|
||||
|
@ -54,31 +53,22 @@ export function listenForUser(userId: string, setUser: (user: User) => void) {
|
|||
}
|
||||
|
||||
const CACHED_USER_KEY = 'CACHED_USER_KEY'
|
||||
|
||||
export function listenForLogin(onUser: (user: User | null) => void) {
|
||||
const cachedUser = localStorage.getItem(CACHED_USER_KEY)
|
||||
onUser(cachedUser ? JSON.parse(cachedUser) : null)
|
||||
|
||||
if (!cachedUser) createUser().catch(() => {}) // warm up cloud function
|
||||
|
||||
return onAuthStateChanged(auth, async (fbUser) => {
|
||||
if (fbUser) {
|
||||
let user = await getUser(fbUser.uid)
|
||||
let user: User | null = await getUser(fbUser.uid)
|
||||
|
||||
if (!user) {
|
||||
// User just created an account; save them to our database.
|
||||
user = {
|
||||
id: fbUser.uid,
|
||||
name: fbUser.displayName || 'Default Name',
|
||||
username:
|
||||
fbUser.displayName?.replace(/\s+/g, '') || 'DefaultUsername',
|
||||
avatarUrl: fbUser.photoURL || '',
|
||||
email: fbUser.email || 'default@blah.com',
|
||||
balance: STARTING_BALANCE,
|
||||
// TODO: use Firestore timestamp?
|
||||
createdTime: Date.now(),
|
||||
lastUpdatedTime: Date.now(),
|
||||
totalPnLCached: 0,
|
||||
creatorVolumeCached: 0,
|
||||
}
|
||||
await setUser(fbUser.uid, user)
|
||||
user = (await createUser()) || null
|
||||
}
|
||||
|
||||
onUser(user)
|
||||
|
||||
// Persist to local storage, to reduce login blink next time.
|
||||
|
|
Loading…
Reference in New Issue
Block a user