refactor: consolidate admin authorization into layout and introduce AdminShell component
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
"use server";
|
||||
|
||||
import { readdirSync } from "fs";
|
||||
import { join } from "path";
|
||||
|
||||
export async function refetchPlatform(
|
||||
platform: string
|
||||
): Promise<{ count: number | null }> {
|
||||
// Validate platform against actual files to prevent path traversal
|
||||
const dir = join(process.cwd(), "lib", "followers");
|
||||
const validPlatforms = readdirSync(dir)
|
||||
.filter((f) => f.endsWith(".ts") && f !== "index.ts")
|
||||
.map((f) => f.replace(".ts", ""));
|
||||
|
||||
if (!validPlatforms.includes(platform)) {
|
||||
throw new Error("Invalid platform");
|
||||
}
|
||||
|
||||
let count: number | null = null;
|
||||
let tiktokProfile = null;
|
||||
|
||||
try {
|
||||
const mod = await import(`@/lib/followers/${platform}`);
|
||||
const fns = Object.entries(mod).filter(
|
||||
([, v]) => typeof v === "function"
|
||||
) as [string, Function][];
|
||||
|
||||
// Prefer function with "Count" or "Member" in name
|
||||
const countFn = fns.find(([name]) => /count|member/i.test(name));
|
||||
const fn = countFn || fns[0];
|
||||
|
||||
if (fn) {
|
||||
const result = await fn[1]();
|
||||
if (typeof result === "number") {
|
||||
count = result;
|
||||
} else if (result === null) {
|
||||
count = null;
|
||||
} else if (
|
||||
result &&
|
||||
typeof result === "object" &&
|
||||
"followerCount" in result
|
||||
) {
|
||||
count = result.followerCount;
|
||||
tiktokProfile = result;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Failed to fetch ${platform}:`, err);
|
||||
throw new Error(`Failed to fetch ${platform}`);
|
||||
}
|
||||
|
||||
// Update Redis cache
|
||||
try {
|
||||
const { getRedisClient } = await import("@/lib/redis");
|
||||
const redis = await getRedisClient();
|
||||
|
||||
const cached = await redis.get("erika:follower_counts");
|
||||
const counts: Record<string, number | null> = cached
|
||||
? JSON.parse(cached)
|
||||
: {};
|
||||
counts[platform] = count;
|
||||
await redis.set("erika:follower_counts", JSON.stringify(counts), {
|
||||
ex: 3600,
|
||||
});
|
||||
|
||||
if (tiktokProfile) {
|
||||
await redis.set(
|
||||
"erika:tiktok_profile",
|
||||
JSON.stringify(tiktokProfile),
|
||||
{ ex: 3600 }
|
||||
);
|
||||
}
|
||||
} catch {
|
||||
// Redis unavailable
|
||||
}
|
||||
|
||||
return { count };
|
||||
}
|
||||
Reference in New Issue
Block a user