mirror of
https://github.com/anomalyco/opencode.git
synced 2026-06-02 07:31:29 +00:00
153 lines
5.9 KiB
TypeScript
153 lines
5.9 KiB
TypeScript
import { and, Database, eq, inArray, isNull } from "../src/drizzle/index.js"
|
|
import { Identifier } from "../src/identifier.js"
|
|
import { Referral } from "../src/referral.js"
|
|
import { LiteTable } from "../src/schema/billing.sql.js"
|
|
import { ReferralRewardTable, ReferralTable } from "../src/schema/referral.sql.js"
|
|
import { UserTable } from "../src/schema/user.sql.js"
|
|
import { WorkspaceTable } from "../src/schema/workspace.sql.js"
|
|
|
|
const backfills = [
|
|
{
|
|
inviterWorkspaceID: "wrk_00000000000000000000000000",
|
|
inviteeWorkspaceID: "wrk_00000000000000000000000000",
|
|
inviteeAccountID: "acc_00000000000000000000000000",
|
|
},
|
|
]
|
|
|
|
console.log(`Backfilling ${backfills.length} referrals`)
|
|
|
|
for (const [index, backfill] of backfills.entries()) {
|
|
console.log(`[${index + 1}/${backfills.length}] ${backfill.inviterWorkspaceID} -> ${backfill.inviteeWorkspaceID}`)
|
|
console.log(` invitee account: ${backfill.inviteeAccountID}`)
|
|
|
|
const result = await Database.transaction(async (tx) => {
|
|
if (backfill.inviterWorkspaceID === backfill.inviteeWorkspaceID) throw new Error("Self-referral workspace mismatch")
|
|
|
|
const inviterWorkspace = await tx
|
|
.select({ id: WorkspaceTable.id })
|
|
.from(WorkspaceTable)
|
|
.where(and(eq(WorkspaceTable.id, backfill.inviterWorkspaceID), isNull(WorkspaceTable.timeDeleted)))
|
|
.then((rows) => rows[0])
|
|
if (!inviterWorkspace) throw new Error(`Inviter workspace not found: ${backfill.inviterWorkspaceID}`)
|
|
|
|
const inviteeWorkspace = await tx
|
|
.select({ id: WorkspaceTable.id })
|
|
.from(WorkspaceTable)
|
|
.where(and(eq(WorkspaceTable.id, backfill.inviteeWorkspaceID), isNull(WorkspaceTable.timeDeleted)))
|
|
.then((rows) => rows[0])
|
|
if (!inviteeWorkspace) throw new Error(`Invitee workspace not found: ${backfill.inviteeWorkspaceID}`)
|
|
|
|
const inviteeUser = await tx
|
|
.select({ id: UserTable.id })
|
|
.from(UserTable)
|
|
.where(
|
|
and(
|
|
eq(UserTable.workspaceID, backfill.inviteeWorkspaceID),
|
|
eq(UserTable.accountID, backfill.inviteeAccountID),
|
|
eq(UserTable.role, "admin"),
|
|
isNull(UserTable.timeDeleted),
|
|
),
|
|
)
|
|
.then((rows) => rows[0])
|
|
if (!inviteeUser) throw new Error(`Invitee workspace owner not found: ${backfill.inviteeAccountID}`)
|
|
|
|
const inviterUser = await tx
|
|
.select({ id: UserTable.id })
|
|
.from(UserTable)
|
|
.where(
|
|
and(
|
|
eq(UserTable.workspaceID, backfill.inviterWorkspaceID),
|
|
eq(UserTable.accountID, backfill.inviteeAccountID),
|
|
isNull(UserTable.timeDeleted),
|
|
),
|
|
)
|
|
.then((rows) => rows[0])
|
|
if (inviterUser) throw new Error(`Self-referral is not allowed: ${backfill.inviteeAccountID}`)
|
|
|
|
const lite = await tx
|
|
.select({ id: LiteTable.id })
|
|
.from(LiteTable)
|
|
.where(
|
|
and(
|
|
eq(LiteTable.workspaceID, backfill.inviteeWorkspaceID),
|
|
eq(LiteTable.userID, inviteeUser.id),
|
|
isNull(LiteTable.timeDeleted),
|
|
),
|
|
)
|
|
.then((rows) => rows[0])
|
|
if (!lite) throw new Error(`Invitee Lite subscription not found: ${backfill.inviteeWorkspaceID}`)
|
|
|
|
const existingReferral = await tx
|
|
.select({ id: ReferralTable.id, workspaceID: ReferralTable.workspaceID })
|
|
.from(ReferralTable)
|
|
.where(and(eq(ReferralTable.inviteeAccountID, backfill.inviteeAccountID), isNull(ReferralTable.timeDeleted)))
|
|
.then((rows) => rows[0])
|
|
if (existingReferral && existingReferral.workspaceID !== backfill.inviterWorkspaceID) {
|
|
throw new Error(`Referral already belongs to ${existingReferral.workspaceID}: ${existingReferral.id}`)
|
|
}
|
|
|
|
const referralID = existingReferral?.id ?? Identifier.create("referral")
|
|
if (!existingReferral) {
|
|
await tx.insert(ReferralTable).ignore().values({
|
|
workspaceID: backfill.inviterWorkspaceID,
|
|
id: referralID,
|
|
inviteeAccountID: backfill.inviteeAccountID,
|
|
})
|
|
|
|
const referral = await tx
|
|
.select({ id: ReferralTable.id })
|
|
.from(ReferralTable)
|
|
.where(and(eq(ReferralTable.inviteeAccountID, backfill.inviteeAccountID), isNull(ReferralTable.timeDeleted)))
|
|
.then((rows) => rows[0])
|
|
if (!referral) throw new Error(`Referral not created: ${backfill.inviteeAccountID}`)
|
|
if (referral.id !== referralID) throw new Error(`Referral already redeemed: ${referral.id}`)
|
|
}
|
|
|
|
const rewardInsert = await tx
|
|
.insert(ReferralRewardTable)
|
|
.ignore()
|
|
.values([
|
|
{
|
|
workspaceID: backfill.inviterWorkspaceID,
|
|
referralID,
|
|
amount: Referral.REWARD_AMOUNT,
|
|
},
|
|
{
|
|
workspaceID: backfill.inviteeWorkspaceID,
|
|
referralID,
|
|
amount: Referral.REWARD_AMOUNT,
|
|
},
|
|
])
|
|
|
|
const rewards = await tx
|
|
.select({ workspaceID: ReferralRewardTable.workspaceID, amount: ReferralRewardTable.amount })
|
|
.from(ReferralRewardTable)
|
|
.where(
|
|
and(
|
|
eq(ReferralRewardTable.referralID, referralID),
|
|
inArray(ReferralRewardTable.workspaceID, [backfill.inviterWorkspaceID, backfill.inviteeWorkspaceID]),
|
|
isNull(ReferralRewardTable.timeDeleted),
|
|
),
|
|
)
|
|
if (rewards.length !== 2) throw new Error(`Referral rewards not created: ${referralID}`)
|
|
if (rewards.some((reward) => reward.amount !== Referral.REWARD_AMOUNT)) {
|
|
throw new Error(`Referral reward amount mismatch: ${referralID}`)
|
|
}
|
|
|
|
return {
|
|
referralID,
|
|
createdReferral: !existingReferral,
|
|
createdRewards: rewardInsert.rowsAffected,
|
|
inviteeUserID: inviteeUser.id,
|
|
liteID: lite.id,
|
|
rewardWorkspaces: rewards.map((reward) => reward.workspaceID),
|
|
}
|
|
})
|
|
|
|
console.log(` invitee user: ${result.inviteeUserID}`)
|
|
console.log(` lite: ${result.liteID}`)
|
|
console.log(` referral: ${result.referralID} (${result.createdReferral ? "created" : "existing"})`)
|
|
console.log(` rewards: ${result.rewardWorkspaces.join(", ")} (${result.createdRewards} inserted)`)
|
|
}
|
|
|
|
console.log("Referral backfill complete")
|