Create skeleton of buyLeaderboardSlot cloud function.
This commit is contained in:
parent
17b9ccae83
commit
de562799f4
84
functions/src/buy-leaderboard-slot.tsx
Normal file
84
functions/src/buy-leaderboard-slot.tsx
Normal file
|
@ -0,0 +1,84 @@
|
|||
import * as functions from 'firebase-functions'
|
||||
import * as admin from 'firebase-admin'
|
||||
|
||||
import { User } from '../../common/user'
|
||||
|
||||
export const buyLeaderboardSlot = functions
|
||||
.runWith({ minInstances: 1 })
|
||||
.https.onCall(
|
||||
async (
|
||||
data: {
|
||||
slotId: string
|
||||
reassessValue: number
|
||||
},
|
||||
context
|
||||
) => {
|
||||
const userId = context?.auth?.uid
|
||||
if (!userId) return { status: 'error', message: 'Not authorized' }
|
||||
|
||||
// Run as transaction to prevent race conditions.
|
||||
return await firestore.runTransaction(async (transaction) => {
|
||||
const userDoc = firestore.doc(`users/${userId}`)
|
||||
const userSnap = await transaction.get(userDoc)
|
||||
if (!userSnap.exists)
|
||||
return { status: 'error', message: 'User not found' }
|
||||
const user = userSnap.data() as User
|
||||
|
||||
const { slotId, reassessValue } = data
|
||||
|
||||
// TODO: find most recent purchase of slotId.
|
||||
// Fake data below:
|
||||
const prevSlotPurchase = {
|
||||
id: slotId,
|
||||
reassessValue: 100,
|
||||
userId: '',
|
||||
timestamp: 0,
|
||||
}
|
||||
|
||||
if (prevSlotPurchase) {
|
||||
const prevSlotUserDoc = firestore.doc(
|
||||
`users/${prevSlotPurchase.userId}`
|
||||
)
|
||||
const prevSlotUserSnap = await transaction.get(prevSlotUserDoc)
|
||||
if (!prevSlotUserSnap.exists)
|
||||
return { status: 'error', message: 'Previous slot owner not found' }
|
||||
const prevSlotUser = prevSlotUserSnap.data() as User
|
||||
|
||||
const timeSinceLastPurchase = Date.now() - prevSlotPurchase.timestamp
|
||||
const hoursSinceLastPurchase =
|
||||
timeSinceLastPurchase / (1000 * 60 * 60)
|
||||
|
||||
const harbergerTax =
|
||||
prevSlotPurchase.reassessValue * 0.1 * hoursSinceLastPurchase
|
||||
const prevSlotUserBalance = prevSlotUser.balance - harbergerTax
|
||||
if (!isFinite(prevSlotUserBalance)) {
|
||||
throw new Error(
|
||||
'Invalid user balance for previous slot owner ' +
|
||||
prevSlotUser.username
|
||||
)
|
||||
}
|
||||
transaction.update(prevSlotUserDoc, { balance: prevSlotUserBalance })
|
||||
}
|
||||
|
||||
// TODO: If no prevSlotPurchase, use a default purchase price?
|
||||
const newBalance = user.balance - prevSlotPurchase.reassessValue
|
||||
if (!isFinite(newBalance)) {
|
||||
throw new Error('Invalid user balance for ' + user.username)
|
||||
}
|
||||
transaction.update(userDoc, { balance: newBalance })
|
||||
|
||||
const newSlotPurchase = {
|
||||
id: slotId,
|
||||
reassessValue,
|
||||
userId,
|
||||
timestamp: Date.now(),
|
||||
}
|
||||
|
||||
// TODO: save doc newSlotPurchase in some collection.
|
||||
|
||||
return { status: 'success', slotPurchase: newSlotPurchase }
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
const firestore = admin.firestore()
|
Loading…
Reference in New Issue
Block a user