mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-22 20:05:23 +00:00
core: let users apply Go referral credit by invite
Users can preview and apply available Go referral credit from the referral itself, avoiding hidden reward ids that do not map to the invite they see.
This commit is contained in:
@@ -70,9 +70,9 @@ export const queryGoReferral = query(async (workspaceID: string) => {
|
||||
}, workspaceID)
|
||||
}, "go.referral.get")
|
||||
|
||||
export const queryGoReferralUsagePreview = query(async (workspaceID: string, rewardID?: string) => {
|
||||
export const queryGoReferralUsagePreview = query(async (workspaceID: string, referralID?: string) => {
|
||||
"use server"
|
||||
if (!rewardID) return null
|
||||
if (!referralID) return null
|
||||
return withActor(async () => {
|
||||
const row = await Database.use((tx) =>
|
||||
tx
|
||||
@@ -91,7 +91,7 @@ export const queryGoReferralUsagePreview = query(async (workspaceID: string, rew
|
||||
.where(
|
||||
and(
|
||||
eq(ReferralRewardTable.workspaceID, workspaceID),
|
||||
eq(ReferralRewardTable.id, rewardID),
|
||||
eq(ReferralRewardTable.referralID, referralID),
|
||||
isNull(ReferralRewardTable.timeApplied),
|
||||
isNull(ReferralRewardTable.timeDeleted),
|
||||
isNull(LiteTable.timeDeleted),
|
||||
@@ -145,12 +145,12 @@ export const queryGoReferralUsagePreview = query(async (workspaceID: string, rew
|
||||
}, workspaceID)
|
||||
}, "go.referral.usagePreview")
|
||||
|
||||
export const applyGoReferralReward = action(async (workspaceID: string, rewardID: string) => {
|
||||
export const applyGoReferralReward = action(async (workspaceID: string, referralID: string) => {
|
||||
"use server"
|
||||
return json(
|
||||
await withActor(
|
||||
() =>
|
||||
Referral.applyReward({ rewardID })
|
||||
Referral.applyReward({ referralID })
|
||||
.then((data) => ({ error: undefined, data }))
|
||||
.catch((e) => ({ error: e.message as string, data: undefined })),
|
||||
workspaceID,
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
DROP INDEX `referral_reward_workspace_time` ON `referral_reward`;--> statement-breakpoint
|
||||
ALTER TABLE `referral_reward` DROP PRIMARY KEY;--> statement-breakpoint
|
||||
ALTER TABLE `referral_reward` ADD PRIMARY KEY (`workspace_id`,`referral_id`);--> statement-breakpoint
|
||||
ALTER TABLE `referral_reward` DROP COLUMN `id`;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,6 @@ export namespace Identifier {
|
||||
payment: "pay",
|
||||
provider: "prv",
|
||||
referral: "ref",
|
||||
referralReward: "rrw",
|
||||
subscription: "sub",
|
||||
usage: "usg",
|
||||
user: "usr",
|
||||
|
||||
@@ -61,7 +61,6 @@ export namespace Referral {
|
||||
const rows = await Database.use(async (tx) => {
|
||||
const rewards = await tx
|
||||
.select({
|
||||
id: ReferralRewardTable.id,
|
||||
referralID: ReferralRewardTable.referralID,
|
||||
workspaceID: ReferralRewardTable.workspaceID,
|
||||
referralWorkspaceID: ReferralTable.workspaceID,
|
||||
@@ -114,7 +113,7 @@ export namespace Referral {
|
||||
const rewardReferralIDs = new Set(rows.rewards.map((reward) => reward.referralID))
|
||||
const inviteeRewardReferralIDs = new Set(rows.inviteeRewards.map((reward) => reward.referralID))
|
||||
const rewards = rows.rewards.map((reward) => ({
|
||||
id: reward.id,
|
||||
id: reward.referralID,
|
||||
source: reward.workspaceID === reward.referralWorkspaceID ? ("inviter" as const) : ("invitee" as const),
|
||||
status: reward.timeApplied ? ("applied" as const) : ("available" as const),
|
||||
amount: microCentsToCents(reward.amount),
|
||||
@@ -158,17 +157,17 @@ export namespace Referral {
|
||||
}
|
||||
})
|
||||
|
||||
export const applyReward = fn(z.object({ rewardID: z.string() }), async (input) => {
|
||||
export const applyReward = fn(z.object({ referralID: z.string() }), async (input) => {
|
||||
const workspaceID = Actor.workspace()
|
||||
|
||||
return Database.transaction(async (tx) => {
|
||||
const reward = await tx
|
||||
.select({ id: ReferralRewardTable.id, amount: ReferralRewardTable.amount, timeApplied: ReferralRewardTable.timeApplied })
|
||||
.select({ amount: ReferralRewardTable.amount, timeApplied: ReferralRewardTable.timeApplied })
|
||||
.from(ReferralRewardTable)
|
||||
.where(
|
||||
and(
|
||||
eq(ReferralRewardTable.workspaceID, workspaceID),
|
||||
eq(ReferralRewardTable.id, input.rewardID),
|
||||
eq(ReferralRewardTable.referralID, input.referralID),
|
||||
isNull(ReferralRewardTable.timeDeleted),
|
||||
),
|
||||
)
|
||||
@@ -191,7 +190,7 @@ export namespace Referral {
|
||||
.where(
|
||||
and(
|
||||
eq(ReferralRewardTable.workspaceID, workspaceID),
|
||||
eq(ReferralRewardTable.id, input.rewardID),
|
||||
eq(ReferralRewardTable.referralID, input.referralID),
|
||||
isNull(ReferralRewardTable.timeApplied),
|
||||
isNull(ReferralRewardTable.timeDeleted),
|
||||
),
|
||||
@@ -312,7 +311,7 @@ export namespace Referral {
|
||||
if (!referral) return { status: "missing-referral" as const }
|
||||
|
||||
const existingRewards = await tx
|
||||
.select({ id: ReferralRewardTable.id })
|
||||
.select({ referralID: ReferralRewardTable.referralID })
|
||||
.from(ReferralRewardTable)
|
||||
.where(and(eq(ReferralRewardTable.referralID, referral.id), isNull(ReferralRewardTable.timeDeleted)))
|
||||
if (existingRewards.length > 0) return { status: "already-completed" as const }
|
||||
@@ -322,13 +321,11 @@ export namespace Referral {
|
||||
.values([
|
||||
{
|
||||
workspaceID: referral.workspaceID,
|
||||
id: Identifier.create("referralReward"),
|
||||
referralID: referral.id,
|
||||
amount: REWARD_AMOUNT,
|
||||
},
|
||||
{
|
||||
workspaceID: input.workspaceID,
|
||||
id: Identifier.create("referralReward"),
|
||||
referralID: referral.id,
|
||||
amount: REWARD_AMOUNT,
|
||||
},
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
import { bigint, index, mysqlTable, uniqueIndex } from "drizzle-orm/mysql-core"
|
||||
import { timestamps, ulid, utc } from "../drizzle/types"
|
||||
import { bigint, mysqlTable, primaryKey, uniqueIndex } from "drizzle-orm/mysql-core"
|
||||
import { timestamps, ulid, utc, workspaceColumns } from "../drizzle/types"
|
||||
import { workspaceIndexes } from "./workspace.sql"
|
||||
|
||||
export const ReferralTable = mysqlTable(
|
||||
"referral",
|
||||
{
|
||||
id: ulid("id").notNull().primaryKey(),
|
||||
workspaceID: ulid("workspace_id").notNull(),
|
||||
...workspaceColumns,
|
||||
...timestamps,
|
||||
inviteeAccountID: ulid("invitee_account_id").notNull(),
|
||||
},
|
||||
(table) => [
|
||||
...workspaceIndexes(table),
|
||||
uniqueIndex("referral_invitee_account_id").on(table.inviteeAccountID),
|
||||
index("referral_workspace_id").on(table.workspaceID),
|
||||
],
|
||||
)
|
||||
|
||||
export const ReferralRewardTable = mysqlTable(
|
||||
"referral_reward",
|
||||
{
|
||||
id: ulid("id").notNull().primaryKey(),
|
||||
workspaceID: ulid("workspace_id"),
|
||||
workspaceID: ulid("workspace_id").notNull(),
|
||||
...timestamps,
|
||||
referralID: ulid("referral_id").notNull(),
|
||||
amount: bigint("amount", { mode: "number" }).notNull(),
|
||||
timeApplied: utc("time_applied"),
|
||||
},
|
||||
(table) => [index("referral_reward_workspace_time").on(table.workspaceID, table.timeCreated)],
|
||||
(table) => [primaryKey({ columns: [table.workspaceID, table.referralID] })],
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user