Move reads into firebase transaction
This commit is contained in:
parent
7b83a3c7c9
commit
03a1c82c54
|
@ -2,7 +2,6 @@ import * as functions from 'firebase-functions'
|
||||||
import * as admin from 'firebase-admin'
|
import * as admin from 'firebase-admin'
|
||||||
import { REFERRAL_AMOUNT, User } from '../../common/user'
|
import { REFERRAL_AMOUNT, User } from '../../common/user'
|
||||||
import { HOUSE_LIQUIDITY_PROVIDER_ID } from '../../common/antes'
|
import { HOUSE_LIQUIDITY_PROVIDER_ID } from '../../common/antes'
|
||||||
import { getValues, getContract } from './utils'
|
|
||||||
import { createNotification } from './create-notification'
|
import { createNotification } from './create-notification'
|
||||||
import { ReferralTxn, Txn } from '../../common/txn'
|
import { ReferralTxn, Txn } from '../../common/txn'
|
||||||
import { Contract } from '../../common/contract'
|
import { Contract } from '../../common/contract'
|
||||||
|
@ -29,9 +28,10 @@ async function handleUserUpdatedReferral(user: User, eventId: string) {
|
||||||
}
|
}
|
||||||
const referredByUserId = user.referredByUserId
|
const referredByUserId = user.referredByUserId
|
||||||
|
|
||||||
|
await firestore.runTransaction(async (transaction) => {
|
||||||
// get user that referred this user
|
// get user that referred this user
|
||||||
const referredByUserDoc = firestore.doc(`users/${referredByUserId}`)
|
const referredByUserDoc = firestore.doc(`users/${referredByUserId}`)
|
||||||
const referredByUserSnap = await referredByUserDoc.get()
|
const referredByUserSnap = await transaction.get(referredByUserDoc)
|
||||||
if (!referredByUserSnap.exists) {
|
if (!referredByUserSnap.exists) {
|
||||||
console.log(`User ${referredByUserId} not found`)
|
console.log(`User ${referredByUserId} not found`)
|
||||||
return
|
return
|
||||||
|
@ -39,27 +39,35 @@ async function handleUserUpdatedReferral(user: User, eventId: string) {
|
||||||
const referredByUser = referredByUserSnap.data() as User
|
const referredByUser = referredByUserSnap.data() as User
|
||||||
|
|
||||||
let referredByContract: Contract | undefined = undefined
|
let referredByContract: Contract | undefined = undefined
|
||||||
if (user.referredByContractId)
|
if (user.referredByContractId) {
|
||||||
referredByContract = await getContract(user.referredByContractId)
|
const referredByContractDoc = firestore.doc(
|
||||||
|
`contracts/${user.referredByContractId}`
|
||||||
|
)
|
||||||
|
referredByContract = await transaction
|
||||||
|
.get(referredByContractDoc)
|
||||||
|
.then((snap) => snap.data() as Contract)
|
||||||
|
}
|
||||||
console.log(`referredByContract: ${referredByContract}`)
|
console.log(`referredByContract: ${referredByContract}`)
|
||||||
|
|
||||||
const txnQuery = firestore
|
const txns = (
|
||||||
|
await firestore
|
||||||
.collection('txns')
|
.collection('txns')
|
||||||
.where('toId', '==', referredByUserId)
|
.where('toId', '==', referredByUserId)
|
||||||
.where('category', '==', 'REFERRAL')
|
.where('category', '==', 'REFERRAL')
|
||||||
const referralTxns = await getValues<Txn>(txnQuery).catch((err) => {
|
.get()
|
||||||
|
).docs.map((txn) => txn.ref)
|
||||||
|
const referralTxns = await transaction.getAll(...txns).catch((err) => {
|
||||||
console.error('error getting txns:', err)
|
console.error('error getting txns:', err)
|
||||||
throw err
|
throw err
|
||||||
})
|
})
|
||||||
// If the referring user already has a referral txn due to referring this user, halt
|
// If the referring user already has a referral txn due to referring this user, halt
|
||||||
if (referralTxns.map((txn) => txn.description).includes(user.id)) {
|
if (referralTxns.map((txn) => txn.data()?.description).includes(user.id)) {
|
||||||
console.log('found referral txn with the same details, aborting')
|
console.log('found referral txn with the same details, aborting')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
console.log('creating referral txns')
|
console.log('creating referral txns')
|
||||||
const fromId = HOUSE_LIQUIDITY_PROVIDER_ID
|
const fromId = HOUSE_LIQUIDITY_PROVIDER_ID
|
||||||
|
|
||||||
await firestore.runTransaction(async (transaction) => {
|
|
||||||
// if they're updating their referredId, create a txn for both
|
// if they're updating their referredId, create a txn for both
|
||||||
const txn: ReferralTxn = {
|
const txn: ReferralTxn = {
|
||||||
id: eventId,
|
id: eventId,
|
||||||
|
|
|
@ -22,7 +22,7 @@ import { TweetButton } from '../tweet-button'
|
||||||
import { InfoTooltip } from '../info-tooltip'
|
import { InfoTooltip } from '../info-tooltip'
|
||||||
import { TagsInput } from 'web/components/tags-input'
|
import { TagsInput } from 'web/components/tags-input'
|
||||||
|
|
||||||
export const ContractDetailsButtonClassName =
|
export const contractDetailsButtonClassName =
|
||||||
'group flex items-center rounded-md px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-100 text-gray-400 hover:text-gray-500'
|
'group flex items-center rounded-md px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-100 text-gray-400 hover:text-gray-500'
|
||||||
|
|
||||||
export function ContractInfoDialog(props: { contract: Contract; bets: Bet[] }) {
|
export function ContractInfoDialog(props: { contract: Contract; bets: Bet[] }) {
|
||||||
|
@ -50,7 +50,7 @@ export function ContractInfoDialog(props: { contract: Contract; bets: Bet[] }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
className={ContractDetailsButtonClassName}
|
className={contractDetailsButtonClassName}
|
||||||
onClick={() => setOpen(true)}
|
onClick={() => setOpen(true)}
|
||||||
>
|
>
|
||||||
<DotsHorizontalIcon
|
<DotsHorizontalIcon
|
||||||
|
|
|
@ -42,7 +42,7 @@ function ReferralsDialog(props: {
|
||||||
const { user, referralIds, isOpen, setIsOpen } = props
|
const { user, referralIds, isOpen, setIsOpen } = props
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
prefetchUsers([...referralIds])
|
prefetchUsers(referralIds)
|
||||||
}, [referralIds])
|
}, [referralIds])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { contractPath } from 'web/lib/firebase/contracts'
|
||||||
import { ENV_CONFIG } from 'common/envs/constants'
|
import { ENV_CONFIG } from 'common/envs/constants'
|
||||||
import { ToastClipboard } from 'web/components/toast-clipboard'
|
import { ToastClipboard } from 'web/components/toast-clipboard'
|
||||||
import { track } from 'web/lib/service/analytics'
|
import { track } from 'web/lib/service/analytics'
|
||||||
import { ContractDetailsButtonClassName } from 'web/components/contract/contract-info-dialog'
|
import { contractDetailsButtonClassName } from 'web/components/contract/contract-info-dialog'
|
||||||
import { Group } from 'common/group'
|
import { Group } from 'common/group'
|
||||||
import { groupPath } from 'web/lib/firebase/groups'
|
import { groupPath } from 'web/lib/firebase/groups'
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ export function ShareIconButton(props: {
|
||||||
return (
|
return (
|
||||||
<div className="relative z-10 flex-shrink-0">
|
<div className="relative z-10 flex-shrink-0">
|
||||||
<button
|
<button
|
||||||
className={clsx(ContractDetailsButtonClassName, buttonClassName)}
|
className={clsx(contractDetailsButtonClassName, buttonClassName)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (contract) copyContractWithReferral(contract, username)
|
if (contract) copyContractWithReferral(contract, username)
|
||||||
if (group) copyGroupWithReferral(group, username)
|
if (group) copyGroupWithReferral(group, username)
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
updateDoc,
|
updateDoc,
|
||||||
where,
|
where,
|
||||||
} from 'firebase/firestore'
|
} from 'firebase/firestore'
|
||||||
import { sortBy } from 'lodash'
|
import { sortBy, uniq } from 'lodash'
|
||||||
import { Group } from 'common/group'
|
import { Group } from 'common/group'
|
||||||
import { getContractFromId } from './contracts'
|
import { getContractFromId } from './contracts'
|
||||||
import { db } from './init'
|
import { db } from './init'
|
||||||
|
@ -98,12 +98,13 @@ export async function getGroupsWithContractId(
|
||||||
export async function addUserToGroupViaSlug(groupSlug: string, userId: string) {
|
export async function addUserToGroupViaSlug(groupSlug: string, userId: string) {
|
||||||
// get group to get the member ids
|
// get group to get the member ids
|
||||||
const group = await getGroupBySlug(groupSlug)
|
const group = await getGroupBySlug(groupSlug)
|
||||||
if (group && !group.memberIds.includes(userId))
|
if (!group) {
|
||||||
return await updateGroup(group, {
|
console.error(`Group not found: ${groupSlug}`)
|
||||||
memberIds: [userId, ...group.memberIds],
|
return
|
||||||
})
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
return await joinGroup(group, userId)
|
||||||
|
}
|
||||||
|
|
||||||
export async function joinGroup(group: Group, userId: string): Promise<Group> {
|
export async function joinGroup(group: Group, userId: string): Promise<Group> {
|
||||||
const { memberIds } = group
|
const { memberIds } = group
|
||||||
if (memberIds.includes(userId)) {
|
if (memberIds.includes(userId)) {
|
||||||
|
@ -111,7 +112,7 @@ export async function joinGroup(group: Group, userId: string): Promise<Group> {
|
||||||
}
|
}
|
||||||
const newMemberIds = [...memberIds, userId]
|
const newMemberIds = [...memberIds, userId]
|
||||||
const newGroup = { ...group, memberIds: newMemberIds }
|
const newGroup = { ...group, memberIds: newMemberIds }
|
||||||
await updateGroup(newGroup, { memberIds: newMemberIds })
|
await updateGroup(newGroup, { memberIds: uniq(newMemberIds) })
|
||||||
return newGroup
|
return newGroup
|
||||||
}
|
}
|
||||||
export async function leaveGroup(group: Group, userId: string): Promise<Group> {
|
export async function leaveGroup(group: Group, userId: string): Promise<Group> {
|
||||||
|
@ -121,6 +122,6 @@ export async function leaveGroup(group: Group, userId: string): Promise<Group> {
|
||||||
}
|
}
|
||||||
const newMemberIds = memberIds.filter((id) => id !== userId)
|
const newMemberIds = memberIds.filter((id) => id !== userId)
|
||||||
const newGroup = { ...group, memberIds: newMemberIds }
|
const newGroup = { ...group, memberIds: newMemberIds }
|
||||||
await updateGroup(newGroup, { memberIds: newMemberIds })
|
await updateGroup(newGroup, { memberIds: uniq(newMemberIds) })
|
||||||
return newGroup
|
return newGroup
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user