refactor(db): finish Drizzle migration for remaining actions and services

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
SimoandCursor committed 2026-08-01 13:27:59 +02:00
1 parent 22234fe102
commit 65b2fbee6a
19 files changed
+422 -342

No files matched your search

+86 -65
View File
@@ -1,12 +1,22 @@
"use server";
import { desc, eq, inArray, sql } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { auth } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import {
ClaimedReferralLogs,
db,
UserReferrals,
WebsiteSetting,
} from "@/lib/db";
import { clientIp, rateLimit } from "@/lib/rate-limit";
import { rcon } from "@/lib/services/rcon";
import { type CurrencyName, sendCurrency } from "@/lib/services/send-currency";
import {
type CurrencyName,
currencyDb,
sendCurrency,
} from "@/lib/services/send-currency";
/**
* Claim the referral reward for the SIGNED-IN user. Faithful to AtomCMS's
@@ -60,51 +70,54 @@ export async function claimReferral(_formData: FormData): Promise<void> {
} else {
// Reward configuration (CMS-owned website_settings). AtomCMS defaults:
// 5 referrals needed, 30 diamonds reward.
const [neededRaw, amountRaw, currencyRaw] = await Promise.all([
prisma.websiteSetting
.findUnique({
where: { key: "referrals_needed" },
select: { value: true },
})
.catch(() => null),
prisma.websiteSetting
.findUnique({
where: { key: "referral_reward_amount" },
select: { value: true },
})
.catch(() => null),
// The seeded key is referral_reward_currency_type; fall back to the
// shorter referral_reward_currency name if that is what is configured.
prisma.websiteSetting
.findFirst({
where: {
key: {
in: [
"referral_reward_currency_type",
"referral_reward_currency",
],
},
},
select: { value: true },
})
.catch(() => null),
]);
const settingKeys = [
"referrals_needed",
"referral_reward_amount",
"referral_reward_currency_type",
"referral_reward_currency",
] as const;
const needed = Number.parseInt(neededRaw?.value ?? "5", 10) || 5;
const amount = Number.parseInt(amountRaw?.value ?? "30", 10);
const currency = (currencyRaw?.value ?? "diamonds")
let settings: Array<{ key: string; value: string }> = [];
try {
settings = await db
.select({ key: WebsiteSetting.key, value: WebsiteSetting.value })
.from(WebsiteSetting)
.where(inArray(WebsiteSetting.key, [...settingKeys]));
} catch {
settings = [];
}
const byKey = new Map(settings.map((s) => [s.key, s.value]));
const neededRaw = byKey.get("referrals_needed");
const amountRaw = byKey.get("referral_reward_amount");
// The seeded key is referral_reward_currency_type; fall back to the
// shorter referral_reward_currency name if that is what is configured.
const currencyRaw =
byKey.get("referral_reward_currency_type") ??
byKey.get("referral_reward_currency");
const needed = Number.parseInt(neededRaw ?? "5", 10) || 5;
const amount = Number.parseInt(amountRaw ?? "30", 10);
const currency = (currencyRaw ?? "diamonds")
.trim()
.toLowerCase() as CurrencyName;
// The user's referral tally lives in user_referrals (one row per user).
const referrals = await prisma.userReferrals
.findFirst({
where: { userId },
select: { id: true, referralsTotal: true },
orderBy: { id: "desc" },
})
.catch(() => null);
let referrals: { id: bigint; referralsTotal: bigint } | undefined;
try {
const rows = await db
.select({
id: UserReferrals.id,
referralsTotal: UserReferrals.referralsTotal,
})
.from(UserReferrals)
.where(eq(UserReferrals.userId, userId))
.orderBy(desc(UserReferrals.id))
.limit(1);
referrals = rows[0];
} catch {
referrals = undefined;
}
const total = referrals ? Number(referrals.referralsTotal) : 0;
if (!referrals || total <= 0) {
@@ -117,40 +130,48 @@ export async function claimReferral(_formData: FormData): Promise<void> {
} else {
// Spend the threshold first so a concurrent double-submit can't claim
// twice off the same balance, then deliver the reward and log it.
await prisma.userReferrals.update({
where: { id: referrals.id },
data: { referralsTotal: { decrement: needed } },
});
await db
.update(UserReferrals)
.set({
referralsTotal: sql`${UserReferrals.referralsTotal} - ${needed}`,
})
.where(eq(UserReferrals.id, referrals.id));
try {
await sendCurrency({ rcon, db: prisma }, userId, currency, amount);
await sendCurrency(
{ rcon, db: currencyDb },
userId,
currency,
amount,
);
} catch {
// sendCurrency already falls back to a direct DB write; if it still
// throws the spend stands. Roll the threshold back so the user isn't
// charged for an undelivered reward.
await prisma.userReferrals
.update({
where: { id: referrals.id },
data: { referralsTotal: { increment: needed } },
})
.catch(() => {});
try {
await db
.update(UserReferrals)
.set({
referralsTotal: sql`${UserReferrals.referralsTotal} + ${needed}`,
})
.where(eq(UserReferrals.id, referrals.id));
} catch {
/* best-effort rollback */
}
outcome = "error";
throw new Error("currency-delivery-failed");
}
await prisma.claimedReferralLogs
.create({
data: {
userId,
ipAddress: await clientIp(),
createdAt: new Date(),
updatedAt: new Date(),
},
})
.catch(() => {
// Best-effort audit log; the reward already landed.
try {
await db.insert(ClaimedReferralLogs).values({
userId,
ipAddress: await clientIp(),
createdAt: new Date(),
updatedAt: new Date(),
});
} catch {
// Best-effort audit log; the reward already landed.
}
outcome = "claimed";
}
}