Skip to content

Commit

Permalink
Merge pull request #24 from DSC-best/Bot-Admin
Browse files Browse the repository at this point in the history
Bot Admin page + endpoints
  • Loading branch information
mikaib authored Dec 4, 2023
2 parents e6efdfa + a1d8161 commit bdd4593
Show file tree
Hide file tree
Showing 9 changed files with 518 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/lib/structures/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default function SafeBot(bot: Bot | null, actor?: User) {
approval_status: bot?.approval_status,
owner_id: bot?.owner_id,
owner: (bot as any)?.owner ? SafeUser((bot as any)?.owner) : null,
approver: (bot as any)?.approver ? SafeUser((bot as any)?.approver) : null,
approved_time: bot?.approved_time,
created_time: bot?.created_time,
modified_time: bot?.modified_time
Expand Down
3 changes: 3 additions & 0 deletions src/routes/+layout.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import prisma from '$lib/server/prisma';
/** @type {import('./$types').LayoutServerLoad} */
export async function load({ locals }) {
const isApprover = RoleUtility.hasRole(locals?.actor?.role!, Roles.Approver);
const isModerator = RoleUtility.hasRole(locals?.actor?.role!, Roles.Moderator);

let botQueueCount = 0;

if (isApprover) {
Expand All @@ -28,6 +30,7 @@ export async function load({ locals }) {
return {
actor: locals?.actor ? SafeUser(locals.actor as User | null) : null,
isApprover,
isModerator,
botQueueCount
};
}
25 changes: 25 additions & 0 deletions src/routes/admin/bots/[bot_id]/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import requireActorRole from '$lib/server/middleware/requireActorRole';
import prisma from '$lib/server/prisma';
import { Roles } from '$lib/server/roles';
import SafeBot from '$lib/structures/bot.js';
import { error } from '@sveltejs/kit';

export async function load({ locals, params }) {
await requireActorRole(locals, Roles.Moderator);

const bot = await prisma.bot.findFirst({
where: {
id: params.bot_id
},
include: {
owner: true,
approver: true
}
});

if (!bot) throw error(404, 'Bot not found');

return {
bot: SafeBot(bot)
};
}
282 changes: 282 additions & 0 deletions src/routes/admin/bots/[bot_id]/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
<script lang="ts">
import DataTable, { Head, Body, Row, Cell } from '@smui/data-table';
import Paper, { Title, Content } from '@smui/paper';
import LinearProgress from '@smui/linear-progress';
import Button from '@smui/button';
import axios from 'axios';
import { goto } from '$app/navigation';
import BotBadges from '$lib/components/botBadges.svelte';
import { BotApprovalStatus } from '@prisma/client';
import UserButton from '$lib/components/userButton.svelte';
import { dateFormatEurope } from '$lib/utils/date.js';
import moment from 'moment';
export let data;
$: bot = (data as any)?.bot as any; // weird bug lol
let errorMessage: string = '';
let tableLoaded = true;
function toggleVerified() {
tableLoaded = false;
axios
.post(`/api/v1/bots/${bot?.id}/verified`)
.then((d: any) => {
bot['verified'] = d.data?.['verified'];
})
.catch((e) => {
errorMessage = e?.response?.data?.message ?? 'Unable to send request.';
})
.finally(() => {
tableLoaded = true;
});
}
function toggleNSFW() {
tableLoaded = false;
axios
.post(`/api/v1/bots/${bot?.id}/nsfw`)
.then((d) => {
bot['nsfw'] = d.data?.['nsfw'];
})
.catch((e) => {
errorMessage = e?.response?.data?.message ?? 'Unable to send request.';
})
.finally(() => {
tableLoaded = true;
});
}
function forceReject() {
tableLoaded = false;
axios
.post(`/api/v1/bots/${bot?.id}/force-reject`)
.then((d: any) => {
bot['approval_status'] = d.data?.['approval_status'];
})
.catch((e) => {
errorMessage = e?.response?.data?.message ?? 'Unable to send request.';
})
.finally(() => {
tableLoaded = true;
});
}
function toggleBan() {
tableLoaded = false;
axios
.post(`/api/v1/bots/${bot?.id}/ban`)
.then((d: any) => {
bot['approval_status'] = d.data?.['approval_status'];
})
.catch((e) => {
errorMessage = e?.response?.data?.message ?? 'Unable to send request.';
})
.finally(() => {
tableLoaded = true;
});
}
</script>

<div class="paper-container align-flex-center">
<Paper class="paper">
<Title>Bot Admin</Title>
<Content>
{#if errorMessage}
<div class="mb-2">
<Paper color="primary" class="paper-theme--outline-danger" style="padding: 10px;">
<Content>
{errorMessage}
</Content>
</Paper>
</div>
{/if}

<div class="bot-display">
<img src={bot?.avatar} alt="Avatar" class="bot-avatar" />
<div class="bot-display-contents">
<h4>{bot?.username}</h4>
<BotBadges {bot} />
</div>
</div>

<DataTable table$aria-label="People list" style="max-width: 100%;">
<Head>
<Row>
<Cell>Key</Cell>
<Cell>Value</Cell>
<Cell>Action</Cell>
</Row>
</Head>
<Body>
<Row>
<Cell>ID</Cell>
<Cell>{bot?.id}</Cell>
<Cell>
<Button
variant="outlined"
disabled={!tableLoaded}
on:click={() => {
goto(`/bots/${bot?.id}`);
}}
>
View Bot
</Button>
</Cell>
</Row>
<Row>
<Cell>Username</Cell>
<Cell>{bot?.username}</Cell>
<Cell></Cell>
</Row>
<Row>
<Cell>Owner</Cell>
<Cell>
<UserButton user={bot?.owner} />
</Cell>
<Cell>
<Button
variant="outlined"
disabled={!tableLoaded}
on:click={() => {
goto(`/admin/users/${bot?.owner?.id}`);
}}
>
Admin View
</Button>
</Cell>
</Row>
<Row>
<Cell>Approver</Cell>
<Cell>
{#if bot?.approver === null}
Not approved yet.
{:else}
<UserButton user={bot?.approver} />
{/if}
</Cell>
<Cell>
{#if bot?.approver !== null}
<Button
variant="outlined"
disabled={!tableLoaded}
on:click={() => {
goto(`/admin/users/${bot?.approver?.id}`);
}}
>
Admin View
</Button>
{/if}
</Cell>
</Row>
<Row>
<Cell>Vote Count</Cell>
<Cell>{bot?.vote_count}</Cell>
<Cell></Cell>
</Row>
<Row>
<Cell>Created Time</Cell>
<Cell>
{dateFormatEurope(bot?.created_time)} ({moment(bot?.created_time).fromNow()})
</Cell>
<Cell></Cell>
</Row>
<Row>
<Cell>Approval Req. Time</Cell>
<Cell>
{dateFormatEurope(bot?.approval_request_time)} ({moment(
bot?.approval_request_time
).fromNow()})
</Cell>
<Cell></Cell>
</Row>
<Row>
<Cell>Approved Time</Cell>
<Cell>
{#if bot?.approved_time === null}
Not approved yet.
{:else}
{dateFormatEurope(bot?.approved_time)} ({moment(bot?.approved_time).fromNow()})
{/if}
</Cell>
<Cell></Cell>
</Row>
<Row>
<Cell>NSFW</Cell>
<Cell>{bot?.nsfw}</Cell>
<Cell>
<Button variant="outlined" disabled={!tableLoaded} on:click={toggleNSFW}>
{bot?.nsfw ? 'Unset NSFW' : 'Set NSFW'}
</Button>
</Cell>
</Row>
<Row>
<Cell>Verified</Cell>
<Cell>{bot?.verified}</Cell>
<Cell>
<Button variant="outlined" disabled={!tableLoaded} on:click={toggleVerified}>
{bot?.verified ? 'Unverify' : 'Verify'}
</Button>
</Cell>
</Row>
<Row>
<Cell>Approval Status</Cell>
<Cell>{bot?.approval_status}</Cell>
<Cell>
{#if bot?.approval_status === BotApprovalStatus.APPROVED}
<Button variant="outlined" disabled={!tableLoaded} on:click={forceReject}>
Force Reject
</Button>
<Button variant="outlined" disabled={!tableLoaded} on:click={toggleBan}>Ban</Button>
{/if}
{#if bot?.approval_status === BotApprovalStatus.BANNED}
<Button variant="outlined" disabled={!tableLoaded} on:click={toggleBan}>
Unban
</Button>
{/if}
</Cell>
</Row>
</Body>

<LinearProgress
indeterminate
bind:closed={tableLoaded}
aria-label="Data is being loaded..."
slot="progress"
/>
</DataTable>
</Content>
</Paper>
</div>

<style>
.bot-display {
display: flex;
align-items: center;
margin-bottom: 16px;
}
.bot-display-contents {
margin-left: 7px;
}
.paper-container {
padding: 24px;
}
.bot-avatar {
width: 50px;
height: 50px;
border-radius: 10px;
}
.mb-2 {
margin-bottom: 16px;
}
</style>
Loading

0 comments on commit bdd4593

Please sign in to comment.