Referrals bug fix and attribute group
This commit is contained in:
parent
db537a97ba
commit
39c38a669e
|
@ -63,3 +63,4 @@ export type notification_reason_types =
|
|||
| 'on_group_you_are_member_of'
|
||||
| 'tip_received'
|
||||
| 'bet_fill'
|
||||
| 'user_joined_from_your_group_invite'
|
||||
|
|
|
@ -38,6 +38,7 @@ export type User = {
|
|||
|
||||
referredByUserId?: string
|
||||
referredByContractId?: string
|
||||
referredByGroupId?: string
|
||||
lastPingTime?: number
|
||||
}
|
||||
|
||||
|
|
|
@ -22,11 +22,11 @@ service cloud.firestore {
|
|||
allow read;
|
||||
allow update: if resource.data.id == request.auth.uid
|
||||
&& request.resource.data.diff(resource.data).affectedKeys()
|
||||
.hasOnly(['bio', 'bannerUrl', 'website', 'twitterHandle', 'discordHandle', 'followedCategories', 'referredByContractId', 'lastPingTime']);
|
||||
.hasOnly(['bio', 'bannerUrl', 'website', 'twitterHandle', 'discordHandle', 'followedCategories', 'lastPingTime']);
|
||||
// User referral rules
|
||||
allow update: if resource.data.id == request.auth.uid
|
||||
&& request.resource.data.diff(resource.data).affectedKeys()
|
||||
.hasOnly(['referredByUserId'])
|
||||
.hasOnly(['referredByUserId', 'referredByContractId', 'referredByGroupId'])
|
||||
// only one referral allowed per user
|
||||
&& !("referredByUserId" in resource.data)
|
||||
// user can't refer themselves
|
||||
|
|
|
@ -253,20 +253,6 @@ export const createNotification = async (
|
|||
}
|
||||
}
|
||||
|
||||
const notifyUserReceivedReferralBonus = async (
|
||||
userToReasonTexts: user_to_reason_texts,
|
||||
relatedUserId: string
|
||||
) => {
|
||||
if (shouldGetNotification(relatedUserId, userToReasonTexts))
|
||||
userToReasonTexts[relatedUserId] = {
|
||||
// If the referrer is the market creator, just tell them they joined to bet on their market
|
||||
reason:
|
||||
sourceContract?.creatorId === relatedUserId
|
||||
? 'user_joined_to_bet_on_your_market'
|
||||
: 'you_referred_user',
|
||||
}
|
||||
}
|
||||
|
||||
const notifyContractCreatorOfUniqueBettorsBonus = async (
|
||||
userToReasonTexts: user_to_reason_texts,
|
||||
userId: string
|
||||
|
@ -284,8 +270,6 @@ export const createNotification = async (
|
|||
} else if (sourceType === 'group' && relatedUserId) {
|
||||
if (sourceUpdateType === 'created')
|
||||
await notifyUserAddedToGroup(userToReasonTexts, relatedUserId)
|
||||
} else if (sourceType === 'user' && relatedUserId) {
|
||||
await notifyUserReceivedReferralBonus(userToReasonTexts, relatedUserId)
|
||||
}
|
||||
|
||||
// The following functions need sourceContract to be defined.
|
||||
|
@ -435,3 +419,52 @@ export const createGroupCommentNotification = async (
|
|||
}
|
||||
await notificationRef.set(removeUndefinedProps(notification))
|
||||
}
|
||||
|
||||
export const createReferralNotification = async (
|
||||
toUser: User,
|
||||
referredUser: User,
|
||||
idempotencyKey: string,
|
||||
bonusAmount: string,
|
||||
referredByContract?: Contract,
|
||||
referredByGroup?: Group
|
||||
) => {
|
||||
const notificationRef = firestore
|
||||
.collection(`/users/${toUser.id}/notifications`)
|
||||
.doc(idempotencyKey)
|
||||
const notification: Notification = {
|
||||
id: idempotencyKey,
|
||||
userId: toUser.id,
|
||||
reason: referredByGroup
|
||||
? 'user_joined_from_your_group_invite'
|
||||
: referredByContract?.creatorId === toUser.id
|
||||
? 'user_joined_to_bet_on_your_market'
|
||||
: 'you_referred_user',
|
||||
createdTime: Date.now(),
|
||||
isSeen: false,
|
||||
sourceId: referredUser.id,
|
||||
sourceType: 'user',
|
||||
sourceUpdateType: 'updated',
|
||||
sourceContractId: referredByContract?.id,
|
||||
sourceUserName: referredUser.name,
|
||||
sourceUserUsername: referredUser.username,
|
||||
sourceUserAvatarUrl: referredUser.avatarUrl,
|
||||
sourceText: bonusAmount,
|
||||
// Only pass the contract referral details if they weren't referred to a group
|
||||
sourceContractCreatorUsername: !referredByGroup
|
||||
? referredByContract?.creatorUsername
|
||||
: undefined,
|
||||
sourceContractTitle: !referredByGroup
|
||||
? referredByContract?.question
|
||||
: undefined,
|
||||
sourceContractSlug: !referredByGroup ? referredByContract?.slug : undefined,
|
||||
sourceSlug: referredByGroup
|
||||
? groupPath(referredByGroup.slug)
|
||||
: referredByContract?.slug,
|
||||
sourceTitle: referredByGroup
|
||||
? referredByGroup.name
|
||||
: referredByContract?.question,
|
||||
}
|
||||
await notificationRef.set(removeUndefinedProps(notification))
|
||||
}
|
||||
|
||||
const groupPath = (groupSlug: string) => `/group/${groupSlug}`
|
||||
|
|
|
@ -2,11 +2,12 @@ import * as functions from 'firebase-functions'
|
|||
import * as admin from 'firebase-admin'
|
||||
import { REFERRAL_AMOUNT, User } from '../../common/user'
|
||||
import { HOUSE_LIQUIDITY_PROVIDER_ID } from '../../common/antes'
|
||||
import { createNotification } from './create-notification'
|
||||
import { createReferralNotification } from './create-notification'
|
||||
import { ReferralTxn } from '../../common/txn'
|
||||
import { Contract } from '../../common/contract'
|
||||
import { LimitBet } from 'common/bet'
|
||||
import { QuerySnapshot } from 'firebase-admin/firestore'
|
||||
import { Group } from 'common/group'
|
||||
const firestore = admin.firestore()
|
||||
|
||||
export const onUpdateUser = functions.firestore
|
||||
|
@ -54,6 +55,17 @@ async function handleUserUpdatedReferral(user: User, eventId: string) {
|
|||
}
|
||||
console.log(`referredByContract: ${referredByContract}`)
|
||||
|
||||
let referredByGroup: Group | undefined = undefined
|
||||
if (user.referredByGroupId) {
|
||||
const referredByGroupDoc = firestore.doc(
|
||||
`groups/${user.referredByGroupId}`
|
||||
)
|
||||
referredByGroup = await transaction
|
||||
.get(referredByGroupDoc)
|
||||
.then((snap) => snap.data() as Group)
|
||||
}
|
||||
console.log(`referredByGroup: ${referredByGroup}`)
|
||||
|
||||
const txns = (
|
||||
await firestore
|
||||
.collection('txns')
|
||||
|
@ -100,18 +112,13 @@ async function handleUserUpdatedReferral(user: User, eventId: string) {
|
|||
totalDeposits: referredByUser.totalDeposits + REFERRAL_AMOUNT,
|
||||
})
|
||||
|
||||
await createNotification(
|
||||
user.id,
|
||||
'user',
|
||||
'updated',
|
||||
await createReferralNotification(
|
||||
referredByUser,
|
||||
user,
|
||||
eventId,
|
||||
txn.amount.toString(),
|
||||
referredByContract,
|
||||
'user',
|
||||
referredByUser.id,
|
||||
referredByContract?.slug,
|
||||
referredByContract?.question
|
||||
referredByGroup
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -89,11 +89,11 @@ export async function getGroupsWithContractId(
|
|||
setGroups(await getValues<Group>(q))
|
||||
}
|
||||
|
||||
export async function addUserToGroupViaSlug(groupSlug: string, userId: string) {
|
||||
export async function addUserToGroupViaId(groupId: string, userId: string) {
|
||||
// get group to get the member ids
|
||||
const group = await getGroupBySlug(groupSlug)
|
||||
const group = await getGroup(groupId)
|
||||
if (!group) {
|
||||
console.error(`Group not found: ${groupSlug}`)
|
||||
console.error(`Group not found: ${groupId}`)
|
||||
return
|
||||
}
|
||||
return await joinGroup(group, userId)
|
||||
|
|
|
@ -35,7 +35,7 @@ import { feed } from 'common/feed'
|
|||
import { CATEGORY_LIST } from 'common/categories'
|
||||
import { safeLocalStorage } from '../util/local'
|
||||
import { filterDefined } from 'common/util/array'
|
||||
import { addUserToGroupViaSlug } from 'web/lib/firebase/groups'
|
||||
import { addUserToGroupViaId } from 'web/lib/firebase/groups'
|
||||
import { removeUndefinedProps } from 'common/util/object'
|
||||
import { randomString } from 'common/util/random'
|
||||
import dayjs from 'dayjs'
|
||||
|
@ -99,13 +99,13 @@ export function listenForPrivateUser(
|
|||
const CACHED_USER_KEY = 'CACHED_USER_KEY'
|
||||
const CACHED_REFERRAL_USERNAME_KEY = 'CACHED_REFERRAL_KEY'
|
||||
const CACHED_REFERRAL_CONTRACT_ID_KEY = 'CACHED_REFERRAL_CONTRACT_KEY'
|
||||
const CACHED_REFERRAL_GROUP_SLUG_KEY = 'CACHED_REFERRAL_GROUP_KEY'
|
||||
const CACHED_REFERRAL_GROUP_ID_KEY = 'CACHED_REFERRAL_GROUP_KEY'
|
||||
|
||||
export function writeReferralInfo(
|
||||
defaultReferrerUsername: string,
|
||||
contractId?: string,
|
||||
referralUsername?: string,
|
||||
groupSlug?: string
|
||||
groupId?: string
|
||||
) {
|
||||
const local = safeLocalStorage()
|
||||
const cachedReferralUser = local?.getItem(CACHED_REFERRAL_USERNAME_KEY)
|
||||
|
@ -121,7 +121,7 @@ export function writeReferralInfo(
|
|||
local?.setItem(CACHED_REFERRAL_USERNAME_KEY, referralUsername)
|
||||
|
||||
// Always write the most recent explicit group invite query value
|
||||
if (groupSlug) local?.setItem(CACHED_REFERRAL_GROUP_SLUG_KEY, groupSlug)
|
||||
if (groupId) local?.setItem(CACHED_REFERRAL_GROUP_ID_KEY, groupId)
|
||||
|
||||
// Write the first contract id that we see.
|
||||
const cachedReferralContract = local?.getItem(CACHED_REFERRAL_CONTRACT_ID_KEY)
|
||||
|
@ -134,14 +134,14 @@ async function setCachedReferralInfoForUser(user: User | null) {
|
|||
// if the user wasn't created in the last minute, don't bother
|
||||
const now = dayjs().utc()
|
||||
const userCreatedTime = dayjs(user.createdTime)
|
||||
if (now.diff(userCreatedTime, 'minute') > 1) return
|
||||
if (now.diff(userCreatedTime, 'minute') > 5) return
|
||||
|
||||
const local = safeLocalStorage()
|
||||
const cachedReferralUsername = local?.getItem(CACHED_REFERRAL_USERNAME_KEY)
|
||||
const cachedReferralContractId = local?.getItem(
|
||||
CACHED_REFERRAL_CONTRACT_ID_KEY
|
||||
)
|
||||
const cachedReferralGroupSlug = local?.getItem(CACHED_REFERRAL_GROUP_SLUG_KEY)
|
||||
const cachedReferralGroupId = local?.getItem(CACHED_REFERRAL_GROUP_ID_KEY)
|
||||
|
||||
// get user via username
|
||||
if (cachedReferralUsername)
|
||||
|
@ -155,6 +155,9 @@ async function setCachedReferralInfoForUser(user: User | null) {
|
|||
referredByContractId: cachedReferralContractId
|
||||
? cachedReferralContractId
|
||||
: undefined,
|
||||
referredByGroupId: cachedReferralGroupId
|
||||
? cachedReferralGroupId
|
||||
: undefined,
|
||||
})
|
||||
)
|
||||
.catch((err) => {
|
||||
|
@ -165,15 +168,14 @@ async function setCachedReferralInfoForUser(user: User | null) {
|
|||
userId: user.id,
|
||||
referredByUserId: referredByUser.id,
|
||||
referredByContractId: cachedReferralContractId,
|
||||
referredByGroupSlug: cachedReferralGroupSlug,
|
||||
referredByGroupId: cachedReferralGroupId,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
if (cachedReferralGroupSlug)
|
||||
addUserToGroupViaSlug(cachedReferralGroupSlug, user.id)
|
||||
if (cachedReferralGroupId) addUserToGroupViaId(cachedReferralGroupId, user.id)
|
||||
|
||||
local?.removeItem(CACHED_REFERRAL_GROUP_SLUG_KEY)
|
||||
local?.removeItem(CACHED_REFERRAL_GROUP_ID_KEY)
|
||||
local?.removeItem(CACHED_REFERRAL_USERNAME_KEY)
|
||||
local?.removeItem(CACHED_REFERRAL_CONTRACT_ID_KEY)
|
||||
}
|
||||
|
|
|
@ -161,7 +161,7 @@ export default function GroupPage(props: {
|
|||
referrer?: string
|
||||
}
|
||||
if (!user && router.isReady)
|
||||
writeReferralInfo(creator.username, undefined, referrer, group?.slug)
|
||||
writeReferralInfo(creator.username, undefined, referrer, group?.id)
|
||||
}, [user, creator, group, router])
|
||||
|
||||
const { width } = useWindowSize()
|
||||
|
|
|
@ -713,8 +713,12 @@ function QuestionOrGroupLink(props: {
|
|||
href={
|
||||
sourceContractCreatorUsername
|
||||
? `/${sourceContractCreatorUsername}/${sourceContractSlug}`
|
||||
: (sourceType === 'group' || sourceType === 'tip') && sourceSlug
|
||||
: // User's added to group or received a tip there
|
||||
(sourceType === 'group' || sourceType === 'tip') && sourceSlug
|
||||
? `${groupPath(sourceSlug)}`
|
||||
: // User referral via group
|
||||
sourceSlug?.includes('/group/')
|
||||
? `${sourceSlug}`
|
||||
: ''
|
||||
}
|
||||
onClick={() =>
|
||||
|
@ -745,12 +749,16 @@ function getSourceUrl(notification: Notification) {
|
|||
} = notification
|
||||
if (sourceType === 'follow') return `/${sourceUserUsername}`
|
||||
if (sourceType === 'group' && sourceSlug) return `${groupPath(sourceSlug)}`
|
||||
// User referral via contract:
|
||||
if (
|
||||
sourceContractCreatorUsername &&
|
||||
sourceContractSlug &&
|
||||
sourceType === 'user'
|
||||
)
|
||||
return `/${sourceContractCreatorUsername}/${sourceContractSlug}`
|
||||
// User referral:
|
||||
if (sourceType === 'user' && !sourceContractSlug)
|
||||
return `/${sourceUserUsername}`
|
||||
if (sourceType === 'tip' && sourceContractSlug)
|
||||
return `/${sourceContractCreatorUsername}/${sourceContractSlug}#${sourceSlug}`
|
||||
if (sourceType === 'tip' && sourceSlug) return `${groupPath(sourceSlug)}`
|
||||
|
|
Loading…
Reference in New Issue
Block a user