refactor(db): migrate staff and app actions from Prisma facade to Drizzle
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
9854719cfd
commit
ed9c23c702
85 files changed
+2612
-1832
No files matched your search
+52
-30
@@ -1,11 +1,12 @@
|
||||
"use server";
|
||||
|
||||
import { and, eq, sql } from "drizzle-orm";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { db, WebsiteShopVouchers, WebsiteUsedShopVouchers } from "@/lib/db";
|
||||
import { clientIp, rateLimit } from "@/lib/rate-limit";
|
||||
import { rcon } from "@/lib/services/rcon";
|
||||
import { sendCurrency } from "@/lib/services/send-currency";
|
||||
import { currencyDb, sendCurrency } from "@/lib/services/send-currency";
|
||||
|
||||
/** Feedback returned to the <RedeemForm/> client component via useActionState. */
|
||||
export type RedeemState = { ok: boolean; message: string } | null;
|
||||
@@ -20,7 +21,7 @@ export type RedeemState = { ok: boolean; message: string } | null;
|
||||
* - on success the reward `amount` is granted, the used-row is inserted,
|
||||
* use_count is incremented, and the voucher is expired once max_uses is hit.
|
||||
*
|
||||
* The reward is delivered through sendCurrency({ rcon, db: prisma }); the
|
||||
* The reward is delivered through sendCurrency({ rcon, db: currencyDb }); the
|
||||
* voucher schema carries a single `amount`, granted as the website credits
|
||||
* wallet currency.
|
||||
*/
|
||||
@@ -65,16 +66,18 @@ export async function redeem(
|
||||
expiresAt: Date | null;
|
||||
} | null;
|
||||
try {
|
||||
voucher = await prisma.websiteShopVouchers.findUnique({
|
||||
where: { code },
|
||||
select: {
|
||||
id: true,
|
||||
amount: true,
|
||||
maxUses: true,
|
||||
useCount: true,
|
||||
expiresAt: true,
|
||||
},
|
||||
});
|
||||
const [row] = await db
|
||||
.select({
|
||||
id: WebsiteShopVouchers.id,
|
||||
amount: WebsiteShopVouchers.amount,
|
||||
maxUses: WebsiteShopVouchers.maxUses,
|
||||
useCount: WebsiteShopVouchers.useCount,
|
||||
expiresAt: WebsiteShopVouchers.expiresAt,
|
||||
})
|
||||
.from(WebsiteShopVouchers)
|
||||
.where(eq(WebsiteShopVouchers.code, code))
|
||||
.limit(1);
|
||||
voucher = row ?? null;
|
||||
} catch {
|
||||
return {
|
||||
ok: false,
|
||||
@@ -95,10 +98,16 @@ export async function redeem(
|
||||
|
||||
// One redemption per user.
|
||||
try {
|
||||
const already = await prisma.websiteUsedShopVouchers.findFirst({
|
||||
where: { userId, voucherId: voucher.id },
|
||||
select: { id: true },
|
||||
});
|
||||
const [already] = await db
|
||||
.select({ id: WebsiteUsedShopVouchers.id })
|
||||
.from(WebsiteUsedShopVouchers)
|
||||
.where(
|
||||
and(
|
||||
eq(WebsiteUsedShopVouchers.userId, userId),
|
||||
eq(WebsiteUsedShopVouchers.voucherId, voucher.id),
|
||||
),
|
||||
)
|
||||
.limit(1);
|
||||
if (already) {
|
||||
return { ok: false, message: "You can only use each shop voucher once." };
|
||||
}
|
||||
@@ -111,8 +120,9 @@ export async function redeem(
|
||||
|
||||
// Record the redemption first so a successful grant can never be double-claimed.
|
||||
try {
|
||||
await prisma.websiteUsedShopVouchers.create({
|
||||
data: { userId, voucherId: voucher.id },
|
||||
await db.insert(WebsiteUsedShopVouchers).values({
|
||||
userId,
|
||||
voucherId: voucher.id,
|
||||
});
|
||||
} catch {
|
||||
// Most likely a race (another tab redeemed it) — treat as already used.
|
||||
@@ -121,7 +131,12 @@ export async function redeem(
|
||||
|
||||
// Grant the reward. The voucher carries a single amount, delivered as credits.
|
||||
try {
|
||||
await sendCurrency({ rcon, db: prisma }, userId, "credits", voucher.amount);
|
||||
await sendCurrency(
|
||||
{ rcon, db: currencyDb },
|
||||
userId,
|
||||
"credits",
|
||||
voucher.amount,
|
||||
);
|
||||
} catch {
|
||||
// sendCurrency already falls back to a direct DB write; if it still throws,
|
||||
// the used-row stands and the balance simply wasn't credited — surface that.
|
||||
@@ -134,16 +149,23 @@ export async function redeem(
|
||||
|
||||
// Bump use_count and expire the voucher once the cap is reached.
|
||||
try {
|
||||
const updated = await prisma.websiteShopVouchers.update({
|
||||
where: { id: voucher.id },
|
||||
data: { useCount: { increment: 1 } },
|
||||
select: { maxUses: true, useCount: true },
|
||||
});
|
||||
if (updated.maxUses && updated.useCount >= updated.maxUses) {
|
||||
await prisma.websiteShopVouchers.update({
|
||||
where: { id: voucher.id },
|
||||
data: { expiresAt: new Date() },
|
||||
});
|
||||
await db
|
||||
.update(WebsiteShopVouchers)
|
||||
.set({ useCount: sql`${WebsiteShopVouchers.useCount} + 1` })
|
||||
.where(eq(WebsiteShopVouchers.id, voucher.id));
|
||||
const [updated] = await db
|
||||
.select({
|
||||
maxUses: WebsiteShopVouchers.maxUses,
|
||||
useCount: WebsiteShopVouchers.useCount,
|
||||
})
|
||||
.from(WebsiteShopVouchers)
|
||||
.where(eq(WebsiteShopVouchers.id, voucher.id))
|
||||
.limit(1);
|
||||
if (updated?.maxUses && updated.useCount >= updated.maxUses) {
|
||||
await db
|
||||
.update(WebsiteShopVouchers)
|
||||
.set({ expiresAt: new Date() })
|
||||
.where(eq(WebsiteShopVouchers.id, voucher.id));
|
||||
}
|
||||
} catch {
|
||||
// Reward already delivered; the counter bump is best-effort.
|
||||
|
||||
Reference in new issue
Block a user