2021-05-25 11:42:55 +02:00
|
|
|
<script>
|
|
|
|
import { onMount } from "svelte";
|
|
|
|
import { formatDate } from "../util/Formatting.svelte";
|
2022-01-17 12:37:37 +01:00
|
|
|
import Expandable from "../util/Expandable.svelte";
|
2022-04-26 15:23:57 +02:00
|
|
|
import LoadingIndicator from "../util/LoadingIndicator.svelte";
|
2021-05-25 11:42:55 +02:00
|
|
|
|
2024-09-24 22:46:45 +02:00
|
|
|
const abuse_types = [
|
|
|
|
"copyright",
|
|
|
|
"child_abuse",
|
|
|
|
"terrorism",
|
|
|
|
"gore",
|
|
|
|
"zoophilia",
|
|
|
|
"malware",
|
|
|
|
"doxing",
|
|
|
|
"revenge_porn",
|
|
|
|
]
|
|
|
|
|
2021-05-25 11:42:55 +02:00
|
|
|
let loading = true
|
|
|
|
let rows = []
|
2023-11-09 10:44:17 +01:00
|
|
|
let total_offences = 0
|
2021-05-25 11:42:55 +02:00
|
|
|
|
2022-01-17 12:37:37 +01:00
|
|
|
let expanded = false
|
2021-05-25 11:42:55 +02:00
|
|
|
let creating = false
|
|
|
|
let new_ban_address
|
2024-09-24 22:46:45 +02:00
|
|
|
let new_ban_reason = abuse_types[0]
|
2021-05-25 11:42:55 +02:00
|
|
|
|
|
|
|
const get_bans = async () => {
|
|
|
|
loading = true;
|
|
|
|
try {
|
|
|
|
const resp = await fetch(window.api_endpoint+"/admin/ip_ban");
|
|
|
|
if(resp.status >= 400) {
|
|
|
|
throw new Error(resp.text());
|
|
|
|
}
|
2021-06-14 14:55:34 +02:00
|
|
|
rows = await resp.json()
|
2023-11-09 10:44:17 +01:00
|
|
|
|
|
|
|
total_offences = rows.reduce(
|
|
|
|
(acc, curr) => acc + curr.offences.length, 0,
|
|
|
|
)
|
2021-05-25 11:42:55 +02:00
|
|
|
} catch (err) {
|
|
|
|
alert(err);
|
|
|
|
} finally {
|
|
|
|
loading = false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const create_ban = async () => {
|
|
|
|
if (!new_ban_address.value) {
|
|
|
|
alert("Please enter an IP address!")
|
|
|
|
return
|
|
|
|
} else if (!new_ban_reason) {
|
|
|
|
alert("Please enter a reason!")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const form = new FormData()
|
|
|
|
form.append("address", new_ban_address.value)
|
|
|
|
form.append("reason", new_ban_reason)
|
|
|
|
|
|
|
|
const resp = await fetch(
|
|
|
|
window.api_endpoint+"/admin/ip_ban",
|
|
|
|
{ method: "POST", body: form }
|
|
|
|
);
|
|
|
|
if(resp.status >= 400) {
|
|
|
|
throw new Error(await resp.text());
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
alert("Failed to add IP ban! "+err)
|
|
|
|
}
|
|
|
|
|
|
|
|
creating = false
|
|
|
|
get_bans();
|
|
|
|
}
|
|
|
|
|
|
|
|
const delete_ban = async (addr) => {
|
|
|
|
if (!confirm("Delete this banned address?\n\n"+addr)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const resp = await fetch(
|
|
|
|
window.api_endpoint+"/admin/ip_ban/"+encodeURI(addr),
|
|
|
|
{ method: "DELETE" }
|
|
|
|
);
|
|
|
|
if(resp.status >= 400) {
|
|
|
|
throw new Error(await resp.text());
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
alert("Failed to delete ban! "+err)
|
|
|
|
}
|
|
|
|
|
|
|
|
get_bans();
|
|
|
|
}
|
|
|
|
|
|
|
|
onMount(get_bans);
|
|
|
|
</script>
|
|
|
|
|
2022-04-26 15:23:57 +02:00
|
|
|
<LoadingIndicator loading={loading}/>
|
2022-01-11 13:28:22 +01:00
|
|
|
|
|
|
|
<section>
|
2022-01-17 12:37:37 +01:00
|
|
|
<div class="toolbar">
|
2023-11-09 10:44:17 +01:00
|
|
|
<div class="toolbar_label">
|
|
|
|
Bans {rows.length}
|
|
|
|
</div>
|
|
|
|
<div class="toolbar_label">
|
|
|
|
Offences {total_offences}
|
|
|
|
</div>
|
2022-01-11 13:28:22 +01:00
|
|
|
<div class="toolbar_spacer"></div>
|
2022-01-17 12:37:37 +01:00
|
|
|
<button class:button_highlight={expanded} on:click={() => {expanded = !expanded}}>
|
|
|
|
{#if expanded}
|
|
|
|
<i class="icon">unfold_less</i> Collapse all
|
|
|
|
{:else}
|
|
|
|
<i class="icon">unfold_more</i> Expand all
|
|
|
|
{/if}
|
|
|
|
</button>
|
2022-01-11 13:28:22 +01:00
|
|
|
<button class:button_highlight={creating} on:click={() => {creating = !creating}}>
|
|
|
|
<i class="icon">create</i> Add IP ban
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
{#if creating}
|
2022-03-22 23:02:47 +01:00
|
|
|
<div class="highlight_shaded">
|
2022-01-11 13:28:22 +01:00
|
|
|
<form on:submit|preventDefault={create_ban}>
|
2022-08-04 20:19:30 +02:00
|
|
|
<div class="form">
|
|
|
|
<label for="field_address">IP address</label>
|
|
|
|
<input id="field_address" type="text" bind:this={new_ban_address}/>
|
|
|
|
<label for="field_reason">Reason</label>
|
|
|
|
<div id="field_reason">
|
2024-09-24 22:46:45 +02:00
|
|
|
{#each abuse_types as t (t)}
|
|
|
|
<input id="reason_{t}" name="reporter_type" type="radio" bind:group={new_ban_reason} value="{t}" />
|
|
|
|
<label for="reason_{t}">{t}</label>
|
|
|
|
<br/>
|
|
|
|
{/each}
|
2022-08-04 20:19:30 +02:00
|
|
|
</div>
|
|
|
|
<button class="button_highlight" type="submit" style="float: right;">
|
|
|
|
<i class="icon">save</i> Save
|
|
|
|
</button>
|
|
|
|
</div>
|
2022-01-11 13:28:22 +01:00
|
|
|
</form>
|
2021-05-25 11:42:55 +02:00
|
|
|
</div>
|
|
|
|
{/if}
|
2022-01-11 13:28:22 +01:00
|
|
|
|
2022-01-17 12:37:37 +01:00
|
|
|
{#each rows as row (row.address)}
|
2022-01-17 13:36:00 +01:00
|
|
|
<Expandable expanded={expanded} click_expand>
|
2022-01-17 12:37:37 +01:00
|
|
|
<div slot="header" class="header">
|
|
|
|
<div class="title">{row.address}</div>
|
|
|
|
<div class="stats">
|
|
|
|
Offences<br/>
|
|
|
|
{row.offences.length}
|
|
|
|
</div>
|
|
|
|
<div class="stats">
|
|
|
|
Date<br/>
|
|
|
|
{formatDate(row.offences[0].ban_time, false, false, false)}
|
|
|
|
</div>
|
2022-01-17 13:36:00 +01:00
|
|
|
<button on:click|stopPropagation={() => {delete_ban(row.address)}} class="button button_red" style="align-self: center;">
|
2022-01-17 12:37:37 +01:00
|
|
|
<i class="icon">delete</i>
|
|
|
|
</button>
|
|
|
|
</div>
|
2022-01-17 15:46:36 +01:00
|
|
|
<div class="table_scroll">
|
|
|
|
<table>
|
2022-01-17 12:37:37 +01:00
|
|
|
<tr>
|
2022-01-17 15:46:36 +01:00
|
|
|
<td>Reason</td>
|
|
|
|
<td>Reporter</td>
|
|
|
|
<td>Ban time</td>
|
|
|
|
<td>Expire time</td>
|
|
|
|
<td>File</td>
|
2022-01-17 12:37:37 +01:00
|
|
|
</tr>
|
2022-01-17 15:46:36 +01:00
|
|
|
{#each row.offences as offence (offence.ban_time)}
|
|
|
|
<tr>
|
|
|
|
<td>{offence.reason}</td>
|
|
|
|
<td>{offence.reporter}</td>
|
|
|
|
<td>{formatDate(offence.ban_time, true, true, false)}</td>
|
|
|
|
<td>{formatDate(offence.expire_time, true, true, false)}</td>
|
|
|
|
<td>
|
2024-06-14 17:21:31 +02:00
|
|
|
{#if offence.file_link}
|
|
|
|
<a href={offence.file_link} target="_blank" rel="noreferrer">
|
2022-01-17 15:46:36 +01:00
|
|
|
{offence.file_name}
|
|
|
|
</a>
|
|
|
|
{/if}
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
{/each}
|
|
|
|
</table>
|
|
|
|
</div>
|
2022-01-17 12:37:37 +01:00
|
|
|
</Expandable>
|
|
|
|
{/each}
|
|
|
|
</section>
|
2021-05-25 11:42:55 +02:00
|
|
|
|
|
|
|
<style>
|
|
|
|
.toolbar {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: row;
|
|
|
|
width: 100%;
|
2022-01-17 12:37:37 +01:00
|
|
|
text-align: left;
|
|
|
|
margin-top: 10px;
|
2021-05-25 11:42:55 +02:00
|
|
|
}
|
|
|
|
.toolbar > * { flex: 0 0 auto; }
|
|
|
|
.toolbar_spacer { flex: 1 1 auto; }
|
2023-11-09 10:44:17 +01:00
|
|
|
.toolbar_label { margin: 5px; }
|
2022-01-17 12:37:37 +01:00
|
|
|
|
|
|
|
|
|
|
|
.header {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: row;
|
|
|
|
line-height: 1.2em;
|
|
|
|
}
|
|
|
|
.title {
|
|
|
|
flex: 1 1 auto;
|
|
|
|
align-self: center;
|
|
|
|
word-break: break-all;
|
|
|
|
padding-left: 8px;
|
|
|
|
}
|
|
|
|
.stats {
|
|
|
|
flex: 0 0 auto;
|
2022-01-17 13:36:00 +01:00
|
|
|
padding: 0 4px;
|
2022-03-29 21:41:46 +02:00
|
|
|
border-left: 1px solid var(--separator);
|
2022-01-17 12:37:37 +01:00
|
|
|
text-align: center;
|
|
|
|
}
|
2021-05-25 11:42:55 +02:00
|
|
|
</style>
|