feat(admin): drizzle trade-lock + RCON sync and photo local purge
CI / check (push) Successful in 24s
CI / release (push) Skipped
CI / deploy (push) Successful in 1m2s

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
SimoandCursor committed 2026-07-31 21:14:03 +02:00
1 parent 67656a9aad
commit 9854719cfd
7 files changed
+250 -45

No files matched your search

+39
View File
@@ -0,0 +1,39 @@
import { unlink } from "node:fs/promises";
import path from "node:path";
/**
* Best-effort local file delete for camera photos hosted under /public.
* External CDN URLs are left alone (no purge credentials in this CMS).
*/
export async function tryRemoveLocalPhotoFile(url: string): Promise<boolean> {
if (!url?.trim()) return false;
let pathname = url.trim();
if (/^https?:\/\//i.test(pathname)) {
try {
const parsed = new URL(pathname);
const app = (
process.env.APP_URL ||
process.env.NEXT_PUBLIC_APP_URL ||
""
).replace(/\/$/, "");
if (!app || !pathname.startsWith(app)) return false;
pathname = parsed.pathname;
} catch {
return false;
}
}
if (!pathname.startsWith("/")) return false;
const rel = pathname.replace(/^\/+/, "");
if (!rel || rel.includes("..")) return false;
const publicRoot = path.resolve(process.cwd(), "public");
const full = path.resolve(publicRoot, rel);
if (!full.startsWith(publicRoot + path.sep) && full !== publicRoot) {
return false;
}
try {
await unlink(full);
return true;
} catch {
return false;
}
}
+11
View File
@@ -140,6 +140,17 @@ export class RconClient {
unmuteUser(userId: number) {
return this.send("unmuteuser", { user_id: userId });
}
/**
* Best-effort live trade lock sync. Polaris/Arcturus forks may expose
* `settradelock`; unknown keys are ignored by the emulator. Prefer updating
* `users_settings.can_trade` in DB and disconnecting online users.
*/
setTradeLock(userId: number, locked: boolean) {
return this.send("settradelock", {
user_id: userId,
enabled: locked ? 0 : 1,
});
}
}
const globalForRcon = globalThis as unknown as { rcon?: RconClient };
+10
View File
@@ -111,6 +111,16 @@ describe("staff smoke contract", () => {
expect(src).toContain("bulkAdjustCurrency");
expect(src).toContain("setTradeLock");
expect(src).toContain("tradeLockedUntil");
expect(src).toContain("UsersSettings");
expect(src).toContain("rcon.setTradeLock");
});
it("deletes photos via Drizzle with local file purge helper", () => {
const src = readFileSync("src/actions/admin-photos.ts", "utf8");
expect(src).toContain("CameraWeb");
expect(src).toContain("tryRemoveLocalPhotoFile");
expect(src).toContain("@/lib/admin/photo-files");
expect(src).not.toContain("@/lib/prisma");
});
it("guards dual ticket queues on admin and mod", () => {