feat: edit people on the admin dashboard

This commit is contained in:
TheClashFruit 2024-08-30 19:09:39 +02:00
parent a65bb1bb5d
commit d3a8d01824
Signed by: TheClashFruit
GPG key ID: 09BB24C34C2F3204
6 changed files with 188 additions and 10 deletions

View file

@ -18,9 +18,20 @@ interface UserTable {
username: string;
global_name: string;
email: string;
avatar: string;
banner: string;
accent_color: number;
avatar?: string;
banner?: string;
accent_color?: number;
permissions: number;
}
interface UserTableWithoutEmail {
id: number;
did: string;
username: string;
global_name: string;
avatar?: string;
banner?: string;
accent_color?: number;
permissions: number;
}
@ -147,6 +158,12 @@ class Database {
return (rows as UserTable[])[0];
}
async getUsers(): Promise<UserTableWithoutEmail[]> {
const [ rows ] = await this.mysqlPool!.execute('SELECT id, did, username, global_name, avatar, banner, accent_color, permissions FROM users');
return rows as UserTableWithoutEmail[];
}
async getUserUsername(username: string): Promise<UserTable> {
const [ rows ] = await this.mysqlPool!.execute('SELECT * FROM users WHERE username = ?', [ username ]);
@ -196,6 +213,12 @@ class Database {
return rows;
}
async updateUserPermissions(id: number, permissions: any) {
await this.mysqlPool!.execute('UPDATE users SET permissions = ? WHERE id = ?', [ permissions, id ]);
return;
}
}
export default Database;

View file

@ -1,11 +1,52 @@
import PageContent from '@/components/PageContent';
import { useUser } from '@/context/UserContext';
import { getCookieFromContext } from '@/utils/cookies';
import { useRef } from 'react';
import { use, useEffect, useState } from 'react';
import Image from 'next/image';
export default function Admin() {
const { user, isLoggedIn } = useUser();
const [ users, setUsers ] = useState<any[]>([]);
useEffect(() => {
fetch('/api/v1/users')
.then((response) => response.json())
.then((data) => {
setUsers(data);
});
}, [ ]);
const addTeamMember = (userId: number) => {
alert(userId);
};
const editPermissions = (user: any) => {
const perms = prompt('Enter new permissions for user (1 == Admin; There is nothing more.):', user.permissions);
if (perms === null) {
return;
}
fetch(`/api/v1/user/${user.username}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
permissions: perms,
})
})
.then((response) => {
if (response.status === 204) {
alert('Permissions updated.');
} else {
alert('Failed to update permissions.');
}
});
};
if (!isLoggedIn) {
return null;
}
@ -18,6 +59,43 @@ export default function Admin() {
<p>What are we doin&apos; today?</p>
<h2>Users</h2>
<table>
<thead>
<tr>
<th>Avatar</th>
<th>Username</th>
<th>Global Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{users && (
users.map((u) => (
<tr key={u.id}>
<td>
<Image src={`https://cdn.discordapp.com/avatars/${u.did}/${u.avatar}.png`} alt={user.global_name} width={32} height={32} />
</td>
<td>{u.username}</td>
<td>{u.global_name}</td>
<td>
<button onClick={() => { addTeamMember(u.id); }}>
Add As Team Member (On the /about page.)
</button>
<button onClick={() => { editPermissions(u); }}>
Edit Permissions
</button>
<button onClick={() => { alert('GDPR? Yeah no, will implement later.'); }}>
Delete
</button>
</td>
</tr>
))
)}
</tbody>
</table>
<h2>Your User in JSON Format</h2>
<p>In case you need it for some reason.</p>

View file

@ -9,9 +9,9 @@ type Data = {
global_name: string;
};
email: string;
avatar: string;
banner: string;
accent_color: number;
avatar?: string;
banner?: string;
accent_color?: number;
permissions: number;
};

View file

@ -1,4 +1,5 @@
import Database from '@/lib/Database';
import { isUserAdmin } from '@/utils/auth_util';
import type { NextApiRequest, NextApiResponse } from 'next';
type Data = {
@ -8,9 +9,9 @@ type Data = {
username: string;
global_name: string;
};
avatar: string;
banner: string;
accent_color: number;
avatar?: string;
banner?: string;
accent_color?: number;
permissions: number;
};
@ -30,6 +31,29 @@ export default async function handler(
return res.status(404).json({ error: 'Not Found' });
}
// hehe only admins update users :trolley:
// also validation yeah uh... didn't have budget for that
// tech debt for the win
if (req.method === 'PATCH') {
const sid = req.cookies.session;
const isAdmin = isUserAdmin(sid);
if (!isAdmin) {
return res.status(401).json({ error: 'Unauthorized' });
}
const { permissions } = req.body;
if (permissions) {
await db.updateUserPermissions(user.id, permissions);
}
res.status(204).end();
return;
}
res.status(200).json({
id: user.id,
discord_id: user.did,

24
pages/api/v1/users.ts Normal file
View file

@ -0,0 +1,24 @@
import Database from '@/lib/Database';
import type { NextApiRequest, NextApiResponse } from 'next';
interface Response {
id: number;
did: string;
username: string;
global_name: string;
avatar?: string;
banner?: string;
accent_color?: number;
permissions: number;
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<Response[]>,
) {
const db = new Database();
const users = await db.getUsers();
res.status(200).json(users);
}

29
utils/auth_util.ts Normal file
View file

@ -0,0 +1,29 @@
import Database from '@/lib/Database';
import { hasPermission, Permission } from './permissions';
const db = new Database();
interface doas {
user?: any;
hasPermission: boolean;
}
export async function isUserAdmin(sid?: string): Promise<doas> {
if (!sid)
return { hasPermission: false };
const session = await db.getSession(sid!);
if (!session)
return { hasPermission: false };
const user = await db.getUser(session.uid);
if (!user)
return { hasPermission: false };
return {
user,
hasPermission: hasPermission(user.permissions, Permission.Admin)
};
}