forked from administration/panel
feat: add backup list/viewer
parent
a03c539890
commit
d1ff57b239
|
@ -0,0 +1,18 @@
|
||||||
|
import { JsonCard } from "@/components/cards/JsonCard";
|
||||||
|
import { Card, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
import { fetchBackup } from "@/lib/actions"
|
||||||
|
|
||||||
|
export default async function Report({ params }: { params: { name: string } }) {
|
||||||
|
const name = decodeURIComponent(params.name);
|
||||||
|
const backup = await fetchBackup(name);
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>{name}</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
</Card>
|
||||||
|
<br />
|
||||||
|
<JsonCard obj={backup} />
|
||||||
|
</>
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Card } from "@/components/ui/card";
|
||||||
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
||||||
|
import { fetchBackups } from "@/lib/actions";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
export default async function Backups() {
|
||||||
|
const backups = await fetchBackups();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead>Name</TableHead>
|
||||||
|
<TableHead>Type</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{backups.map((backup) => (
|
||||||
|
<TableRow key={backup.name}>
|
||||||
|
<TableCell>{backup.name}</TableCell>
|
||||||
|
<TableCell>{backup.type}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Link href={`/panel/backups/${encodeURIComponent(backup.name)}`}>
|
||||||
|
<Button>
|
||||||
|
Open
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { buttonVariants } from "../ui/button";
|
import { buttonVariants } from "../ui/button";
|
||||||
import {
|
import {
|
||||||
|
Bomb,
|
||||||
Eye,
|
Eye,
|
||||||
Globe2,
|
Globe2,
|
||||||
Home,
|
Home,
|
||||||
|
@ -38,6 +39,12 @@ export function NavigationLinks() {
|
||||||
>
|
>
|
||||||
<Search className="h-4 w-4" />
|
<Search className="h-4 w-4" />
|
||||||
</Link>
|
</Link>
|
||||||
|
<Link
|
||||||
|
className={buttonVariants({ variant: "outline", size: "icon" })}
|
||||||
|
href="/panel/backups"
|
||||||
|
>
|
||||||
|
<Bomb className="h-4 w-4" />
|
||||||
|
</Link>
|
||||||
{/*<Link
|
{/*<Link
|
||||||
className={buttonVariants({ variant: "outline", size: "icon" })}
|
className={buttonVariants({ variant: "outline", size: "icon" })}
|
||||||
href="/panel/discover"
|
href="/panel/discover"
|
||||||
|
|
|
@ -53,7 +53,8 @@ type Permission =
|
||||||
| `safety_notes${
|
| `safety_notes${
|
||||||
| ""
|
| ""
|
||||||
| `/fetch${"" | `/${SafetyNotes["_id"]["type"]}`}`
|
| `/fetch${"" | `/${SafetyNotes["_id"]["type"]}`}`
|
||||||
| `/update${"" | `/${SafetyNotes["_id"]["type"]}`}`}`;
|
| `/update${"" | `/${SafetyNotes["_id"]["type"]}`}`}`
|
||||||
|
| `backup${"" | `/fetch${"" | "/by-name"}`}`;
|
||||||
|
|
||||||
const PermissionSets = {
|
const PermissionSets = {
|
||||||
// Admin
|
// Admin
|
||||||
|
@ -149,6 +150,7 @@ const PermissionSets = {
|
||||||
"channels/create/dm",
|
"channels/create/dm",
|
||||||
|
|
||||||
"servers/update/quarantine",
|
"servers/update/quarantine",
|
||||||
|
"backup/fetch",
|
||||||
|
|
||||||
"reports/fetch/related/by-user",
|
"reports/fetch/related/by-user",
|
||||||
"reports/fetch/related/by-content",
|
"reports/fetch/related/by-content",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"use server";
|
"use server";
|
||||||
|
|
||||||
import { writeFile } from "fs/promises";
|
import { readFile, readdir, writeFile } from "fs/promises";
|
||||||
import { PLATFORM_MOD_ID, RESTRICT_ACCESS_LIST } from "./constants";
|
import { PLATFORM_MOD_ID, RESTRICT_ACCESS_LIST } from "./constants";
|
||||||
import mongo, {
|
import mongo, {
|
||||||
Account,
|
Account,
|
||||||
|
@ -862,3 +862,26 @@ export async function cancelAccountDeletion(accountId: string) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function fetchBackups() {
|
||||||
|
await checkPermission("backup/fetch", null);
|
||||||
|
|
||||||
|
return await Promise.all(
|
||||||
|
(await readdir("./exports", { withFileTypes: true }))
|
||||||
|
.filter((file) => file.isFile() && file.name.endsWith(".json"))
|
||||||
|
.map(async (file) => {
|
||||||
|
let type: string | null = null;
|
||||||
|
try {
|
||||||
|
type = JSON.parse((await readFile(`./exports/${file.name}`)).toString("utf-8"))._event;
|
||||||
|
} catch(e) {}
|
||||||
|
|
||||||
|
return { name: file.name, type: type }
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchBackup(name: string) {
|
||||||
|
await checkPermission("backup/fetch/by-name", null);
|
||||||
|
|
||||||
|
return JSON.parse((await readFile(`./exports/${name}`)).toString("utf-8"));
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue