File size: 2,658 Bytes
5ef6e9d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | import { Router } from "express";
import { db, geminiAccountsTable } from "@workspace/db";
import { eq, desc } from "drizzle-orm";
import { requireAdmin } from "./admin";
import { requireJwtAuth } from "./auth";
const router = Router();
router.use(requireJwtAuth);
router.get("/", requireAdmin, async (_req, res) => {
const rows = await db
.select()
.from(geminiAccountsTable)
.orderBy(desc(geminiAccountsTable.createdAt));
res.json(
rows.map((r) => ({
id: r.id,
label: r.label,
tokenPreview: r.bearerToken ? r.bearerToken.substring(0, 12) + "..." : null,
hasRefreshToken: !!r.refreshToken,
isActive: r.isActive,
lastUsedAt: r.lastUsedAt?.toISOString() ?? null,
createdAt: r.createdAt.toISOString(),
}))
);
});
router.post("/", requireAdmin, async (req, res) => {
const { label, bearerToken, refreshToken } = req.body as {
label?: string;
bearerToken?: string;
refreshToken?: string;
};
if (!bearerToken?.trim()) {
return res.status(400).json({ error: "bearerToken is required" });
}
const [inserted] = await db
.insert(geminiAccountsTable)
.values({
label: (label || "帳戶").trim(),
bearerToken: bearerToken.trim(),
refreshToken: refreshToken?.trim() || null,
isActive: true,
})
.returning();
res.json({
id: inserted.id,
label: inserted.label,
tokenPreview: inserted.bearerToken.substring(0, 12) + "...",
isActive: inserted.isActive,
createdAt: inserted.createdAt.toISOString(),
});
});
router.patch("/:id/label", requireAdmin, async (req, res) => {
const id = Number(req.params.id);
const { label } = req.body as { label?: string };
if (!label?.trim()) return res.status(400).json({ error: "label is required" });
await db.update(geminiAccountsTable).set({ label: label.trim() }).where(eq(geminiAccountsTable.id, id));
res.json({ success: true });
});
router.patch("/:id/toggle", requireAdmin, async (req, res) => {
const id = Number(req.params.id);
const rows = await db.select().from(geminiAccountsTable).where(eq(geminiAccountsTable.id, id)).limit(1);
if (!rows.length) return res.status(404).json({ error: "Account not found" });
const newActive = !rows[0].isActive;
await db.update(geminiAccountsTable).set({ isActive: newActive }).where(eq(geminiAccountsTable.id, id));
res.json({ success: true, isActive: newActive });
});
router.delete("/:id", requireAdmin, async (req, res) => {
const id = Number(req.params.id);
await db.delete(geminiAccountsTable).where(eq(geminiAccountsTable.id, id));
res.json({ success: true });
});
export default router;
|