-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Finish admin dash (mostly) * use PPR * add user management stuff * remove .then and other things that idk of
- Loading branch information
1 parent
37edef6
commit d4617d0
Showing
33 changed files
with
1,263 additions
and
1,003 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,3 +38,6 @@ next-env.d.ts | |
.tmp | ||
docker/ | ||
.assets | ||
|
||
# IDE | ||
.idea/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
"use server"; | ||
|
||
import docker from "@/lib/docker"; | ||
import { db } from "@/lib/drizzle/db"; | ||
import { image, insertImageSchema } from "@/lib/drizzle/schema"; | ||
import { revalidatePath } from "next/cache"; | ||
|
||
export async function addImage(data: FormData) { | ||
const validatedFields = insertImageSchema.safeParse({ | ||
dockerImage: data.get("dockerImage"), | ||
friendlyName: data.get("friendlyName"), | ||
category: data | ||
.get("category") | ||
?.toString() | ||
.split(",") | ||
.map((cat) => cat.trim()), | ||
icon: data.get("icon"), | ||
pulled: true, | ||
}); | ||
if (!validatedFields.success) { | ||
return { | ||
errors: validatedFields.error.flatten().fieldErrors, | ||
}; | ||
} | ||
await new Promise((resolve, reject) => | ||
docker.pull(validatedFields.data.dockerImage, (_err: Error, stream: NodeJS.ReadableStream) => { | ||
docker.modem.followProgress(stream, (err, res) => { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
resolve(res); | ||
} | ||
}); | ||
}), | ||
); | ||
await db | ||
.insert(image) | ||
.values({ | ||
category: [validatedFields.data.category as string], | ||
dockerImage: validatedFields.data.dockerImage, | ||
friendlyName: validatedFields.data.friendlyName, | ||
icon: validatedFields.data.icon, | ||
pulled: validatedFields.data.pulled, | ||
}) | ||
.onConflictDoUpdate({ | ||
target: image.dockerImage, | ||
set: { | ||
category: [validatedFields.data.category as string], | ||
friendlyName: validatedFields.data.friendlyName, | ||
icon: validatedFields.data.icon, | ||
pulled: validatedFields.data.pulled, | ||
}, | ||
}); | ||
revalidatePath("/admin/images"); | ||
return { success: true }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
"use server"; | ||
|
||
import { auth } from "@/lib/auth"; | ||
import { db, session, user } from "@/lib/drizzle/db"; | ||
import { deleteSession } from "@/lib/session"; | ||
import { and, eq } from "drizzle-orm"; | ||
import { revalidatePath } from "next/cache"; | ||
|
||
export async function deleteUser(userId: string) { | ||
const userSession = await auth(); | ||
const { sessions, currentUser } = await db.transaction(async (tx) => { | ||
const sessions = await tx.select().from(session).where(eq(session.userId, userId)); | ||
const currentUser = await tx.query.user.findFirst({ | ||
where: (users, { eq }) => and(eq(users.email, userSession?.user?.email as string), eq(user.id, userId)), | ||
}); | ||
return { sessions, currentUser }; | ||
}); | ||
if (currentUser?.isAdmin) { | ||
throw new Error("Cannot delete the current user"); | ||
} | ||
await Promise.all(sessions.map((session) => deleteSession(session.id))); | ||
await db.delete(user).where(eq(user.id, userId)); | ||
revalidatePath("/admin/users"); | ||
return { success: true }; | ||
} | ||
export async function deleteUserSessions(userId: string) { | ||
const sessions = await db.select().from(session).where(eq(session.userId, userId)); | ||
await Promise.all(sessions.map((session) => deleteSession(session.id))); | ||
revalidatePath("/admin/users"); | ||
|
||
return { success: true }; | ||
} | ||
export async function changeUserAdminStatus(userId: string, isAdmin: boolean) { | ||
const userSession = await auth(); | ||
const currentUser = await db.query.user.findFirst({ | ||
where: (users, { eq }) => and(eq(users.email, userSession?.user?.email as string), eq(user.id, userId)), | ||
}); | ||
if (currentUser?.isAdmin) { | ||
throw new Error("Cannot change the admin status of the current user"); | ||
} | ||
const [update] = await db.update(user).set({ isAdmin }).where(eq(user.id, userId)).returning(); | ||
revalidatePath("/admin/users"); | ||
return { success: true, admin: update.isAdmin }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,59 @@ | ||
import { db } from "@/lib/drizzle/db"; | ||
import { columns } from "./columns"; | ||
import { DataTable } from "@/components/ui/data-table"; | ||
import { StyledSubmit } from "@/components/submit-button"; | ||
import { Button } from "@/components/ui/button"; | ||
import { | ||
Dialog, | ||
DialogContent, | ||
DialogDescription, | ||
DialogHeader, | ||
DialogTitle, | ||
DialogTrigger, | ||
} from "@/components/ui/dialog"; | ||
import { Input } from "@/components/ui/input"; | ||
import { Label } from "@/components/ui/label"; | ||
import type { Metadata } from "next"; | ||
import { addImage } from "@/actions/image"; | ||
export const metadata: Metadata = { | ||
title: "Images", | ||
}; | ||
export default async function AdminPage() { | ||
const sessions = await db.query.image.findMany({ | ||
const data = await db.query.image.findMany({ | ||
with: { | ||
session: true, | ||
}, | ||
}); | ||
return ( | ||
<div className="flex h-full flex-col"> | ||
<h1 className="ml-10 py-6 text-3xl font-bold">Images</h1> | ||
<section className="flex justify-center items-start w-full h-full"> | ||
<DataTable columns={columns} data={sessions} /> | ||
<h1 className="py-6 text-3xl font-bold">Images</h1> | ||
<section className="-ml-8"> | ||
<DataTable data={data} columns={columns} /> | ||
</section> | ||
<div className="flex justify-start items-center"> | ||
<Dialog> | ||
<DialogTrigger asChild> | ||
<Button className="ml-2">Add Image</Button> | ||
</DialogTrigger> | ||
<DialogContent> | ||
<DialogHeader> | ||
<DialogTitle>Add Image</DialogTitle> | ||
<DialogDescription>The image will automatically save after you click the button.</DialogDescription> | ||
</DialogHeader> | ||
<form action={addImage} className="flex flex-col gap-2 w-full"> | ||
<Label htmlFor="name">Name</Label> | ||
<Input id="name" placeholder="Name" name="friendlyName" minLength={2} required /> | ||
<Label htmlFor="cat">Category (comma seperated)</Label> | ||
<Input id="cat" placeholder="Category" name="category" /> | ||
<Label htmlFor="img">Docker pull URL</Label> | ||
<Input id="img" placeholder="ghcr.io/spaceness/xxxx" name="dockerImage" required /> | ||
<Label htmlFor="icon">Icon</Label> | ||
<Input id="icon" placeholder="Icon URL" name="icon" required /> | ||
<StyledSubmit>Submit</StyledSubmit> | ||
</form> | ||
</DialogContent> | ||
</Dialog> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.