This commit is contained in:
parent
44454f445f
commit
235dfe3094
@ -5,6 +5,8 @@ export class Permissions {
|
||||
static readonly UserWrite = 16;
|
||||
static readonly ReportRead = 32;
|
||||
static readonly ReportWrite = 64;
|
||||
static readonly SettingsRead = 128;
|
||||
static readonly SettingsWrite = 256;
|
||||
|
||||
readonly value: number;
|
||||
|
||||
@ -33,7 +35,9 @@ export class Permissions {
|
||||
Permissions.UserRead,
|
||||
Permissions.UserWrite,
|
||||
Permissions.ReportRead,
|
||||
Permissions.ReportWrite
|
||||
Permissions.ReportWrite,
|
||||
Permissions.SettingsRead,
|
||||
Permissions.SettingsWrite
|
||||
];
|
||||
}
|
||||
|
||||
@ -55,6 +59,12 @@ export class Permissions {
|
||||
reportWrite(): boolean {
|
||||
return (this.value & Permissions.ReportWrite) != 0;
|
||||
}
|
||||
settingsRead(): boolean {
|
||||
return (this.value & Permissions.SettingsRead) != 0;
|
||||
}
|
||||
settingsWrite(): boolean {
|
||||
return (this.value & Permissions.SettingsWrite) != 0;
|
||||
}
|
||||
|
||||
asArray(): number[] {
|
||||
const array = [];
|
||||
|
@ -103,8 +103,23 @@ export class Admin extends Model {
|
||||
}
|
||||
}
|
||||
|
||||
@Table({ modelName: 'settings', underscored: true })
|
||||
export class Settings extends Model {
|
||||
@Column({ type: DataTypes.STRING, allowNull: false, unique: true })
|
||||
declare key: string;
|
||||
@Column({
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
get(this: Settings): any {
|
||||
const value = this.getDataValue('value');
|
||||
return value != null ? JSON.parse(value) : null;
|
||||
}
|
||||
})
|
||||
declare value: string;
|
||||
}
|
||||
|
||||
export const sequelize = new Sequelize(building ? 'sqlite::memory:' : env.DATABASE_URI, {
|
||||
// only log sql queries in dev mode
|
||||
logging: dev ? console.log : false,
|
||||
models: [User, Report, Admin]
|
||||
models: [User, Report, Admin, Settings]
|
||||
});
|
||||
|
@ -16,6 +16,7 @@ export const load: LayoutServerLoad = async ({ route, cookies }) => {
|
||||
? await Report.count({ where: { draft: false, status: ['none', 'review'] } })
|
||||
: null,
|
||||
adminCount: session?.permissions.adminRead() ? await Admin.count() : null,
|
||||
settingsRead: session?.permissions.settingsRead(),
|
||||
self: session
|
||||
? JSON.parse(JSON.stringify(await Admin.findOne({ where: { id: session.userId } })))
|
||||
: null
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { env } from '$env/dynamic/public';
|
||||
import { ArrowLeftOnRectangle, Flag, UserGroup, Users } from 'svelte-heros-v2';
|
||||
import { ArrowLeftOnRectangle, Cog6Tooth, Flag, UserGroup, Users } from 'svelte-heros-v2';
|
||||
import { buttonTriggeredRequest } from '$lib/components/utils';
|
||||
import { goto } from '$app/navigation';
|
||||
import type { LayoutData } from './$types';
|
||||
@ -44,6 +44,13 @@
|
||||
name: 'Website Admins',
|
||||
badge: $adminCount,
|
||||
enabled: data.adminCount != null
|
||||
},
|
||||
{
|
||||
path: `${env.PUBLIC_BASE_PATH}/admin/settings`,
|
||||
icon: Cog6Tooth,
|
||||
name: 'Website Einstellungen',
|
||||
badge: null,
|
||||
enabled: data.settingsRead
|
||||
}
|
||||
];
|
||||
</script>
|
||||
@ -57,7 +64,9 @@
|
||||
<a href={tab.path}>
|
||||
<svelte:component this={tab.icon} />
|
||||
<span class="mr-1" class:underline={$page.url.pathname === tab.path}>{tab.name}</span>
|
||||
<div class="badge">{tab.badge}</div>
|
||||
{#if tab.badge != null}
|
||||
<div class="badge">{tab.badge}</div>
|
||||
{/if}
|
||||
</a>
|
||||
</li>
|
||||
{/if}
|
||||
@ -74,7 +83,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-full w-full overflow-y-scroll overflow-x-hidden">
|
||||
<div class="h-full w-full -mt-12 pt-12 overflow-y-scroll overflow-x-hidden">
|
||||
<slot />
|
||||
</div>
|
||||
{:else}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import { env } from '$env/dynamic/public';
|
||||
import { Flag, UserGroup, Users } from 'svelte-heros-v2';
|
||||
import { Cog6Tooth, Flag, UserGroup, Users } from 'svelte-heros-v2';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
@ -23,6 +23,12 @@
|
||||
icon: Users,
|
||||
name: 'Website Admins',
|
||||
enabled: data.adminCount != null
|
||||
},
|
||||
{
|
||||
path: `${env.PUBLIC_BASE_PATH}/admin/settings`,
|
||||
icon: Cog6Tooth,
|
||||
name: 'Website Einstellungen',
|
||||
enabled: data.settingsRead
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
@ -16,7 +16,9 @@
|
||||
'User Read': Permissions.UserRead,
|
||||
'User Write': Permissions.UserWrite,
|
||||
'Report Read': Permissions.ReportRead,
|
||||
'Report Write': Permissions.ReportWrite
|
||||
'Report Write': Permissions.ReportWrite,
|
||||
'Settings Read': Permissions.SettingsRead,
|
||||
'Settings Write': Permissions.SettingsWrite
|
||||
};
|
||||
|
||||
let newAdminUsername: string;
|
||||
|
30
src/routes/admin/settings/+page.server.ts
Normal file
30
src/routes/admin/settings/+page.server.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { getSession } from '$lib/server/session';
|
||||
import { Permissions } from '$lib/permissions';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { env } from '$env/dynamic/public';
|
||||
import { Settings } from '$lib/server/database';
|
||||
|
||||
export const load: PageServerLoad = async ({ parent, cookies }) => {
|
||||
if (getSession(cookies, { permissions: [Permissions.SettingsRead] }) == null) {
|
||||
throw redirect(302, `${env.PUBLIC_BASE_PATH}/admin`);
|
||||
}
|
||||
|
||||
const { self } = await parent();
|
||||
|
||||
const settings = (await Settings.findAll()).reduce(
|
||||
(prev, curr) => {
|
||||
return { ...prev, [curr.key]: curr.value };
|
||||
},
|
||||
{} as { [key: string]: any }
|
||||
);
|
||||
|
||||
return {
|
||||
settings: {
|
||||
register: {
|
||||
enabled: settings['register.enabled'] ?? true
|
||||
}
|
||||
},
|
||||
self: self
|
||||
};
|
||||
};
|
42
src/routes/admin/settings/+page.svelte
Normal file
42
src/routes/admin/settings/+page.svelte
Normal file
@ -0,0 +1,42 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import { env } from '$env/dynamic/public';
|
||||
export let data: PageData;
|
||||
let settings = structuredClone(data.settings);
|
||||
|
||||
async function change() {
|
||||
await fetch(`${env.PUBLIC_BASE_PATH}/admin/settings`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
register: {
|
||||
enabled: returnIfNoDup(settings.register.enabled, data.settings.register.enabled)
|
||||
}
|
||||
} as PageData['settings'])
|
||||
});
|
||||
data.settings = settings;
|
||||
settings = structuredClone(data.settings);
|
||||
}
|
||||
|
||||
function returnIfNoDup<T>(value: T, original: T): T | undefined {
|
||||
return value != original ? value : undefined;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="h-full flex flex-col items-center justify-between">
|
||||
<div class="grid grid-cols-3 w-full [&>*]:mx-8">
|
||||
<div>
|
||||
<div class="divider">Anmeldung</div>
|
||||
<label class="label cursor-pointer">
|
||||
<span class="label-text">Aktiviert</span>
|
||||
<input type="checkbox" class="toggle" bind:checked={settings.register.enabled} />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-6">
|
||||
<button
|
||||
class="btn btn-success mt-auto"
|
||||
class:btn-disabled={JSON.stringify(data.settings) === JSON.stringify(settings)}
|
||||
on:click={change}>Speichern</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
30
src/routes/admin/settings/+server.ts
Normal file
30
src/routes/admin/settings/+server.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import type { PageData } from './$types';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { getSession } from '$lib/server/session';
|
||||
import { Permissions } from '$lib/permissions';
|
||||
import { Settings } from '$lib/server/database';
|
||||
|
||||
export const POST = (async ({ request, cookies }) => {
|
||||
if (getSession(cookies, { permissions: [Permissions.SettingsWrite] }) == null) {
|
||||
return new Response(null, {
|
||||
status: 401
|
||||
});
|
||||
}
|
||||
|
||||
const settings: PageData['settings'] = await request.json();
|
||||
|
||||
for (const [key, value] of Object.entries(settings.register)) {
|
||||
const setting = await Settings.findOne({ where: { key: `register.${key}` } });
|
||||
if (setting) {
|
||||
setting.value = JSON.stringify(value);
|
||||
await setting.save();
|
||||
} else {
|
||||
await Settings.create({
|
||||
key: `register.${key}`,
|
||||
value: JSON.stringify(value)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return new Response();
|
||||
}) satisfies RequestHandler;
|
8
src/routes/register/+page.server.ts
Normal file
8
src/routes/register/+page.server.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { Settings } from '$lib/server/database';
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
return {
|
||||
enabled: (await Settings.findOne({ where: { key: 'register.enabled' } }))?.value ?? true
|
||||
};
|
||||
};
|
@ -2,9 +2,12 @@
|
||||
import { fly } from 'svelte/transition';
|
||||
import RegistrationComplete from './RegistrationComplete.svelte';
|
||||
import Register from './Register.svelte';
|
||||
import type { PageData } from './$types';
|
||||
|
||||
let registered = false;
|
||||
let username: string | null = null;
|
||||
|
||||
export let data: PageData;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@ -13,9 +16,16 @@
|
||||
|
||||
<!--the tooltip when not all fields are correctly filled won't completely show if the overflow is hidden-->
|
||||
<div
|
||||
class="grid card w-11/12 xl:w-2/3 2xl:w-1/2 p-6 my-12 bg-base-100 shadow-lg h-min"
|
||||
class="relative grid card w-11/12 xl:w-2/3 2xl:w-1/2 p-6 my-12 bg-base-100 shadow-lg h-min"
|
||||
class:overflow-hidden={registered}
|
||||
>
|
||||
{#if !data.enabled}
|
||||
<div
|
||||
class="absolute top-0 left-0 w-full h-full bg-black bg-opacity-50 backdrop-blur-sm z-50 rounded-xl flex justify-center md:items-center pt-20 md:pt-0"
|
||||
>
|
||||
<h1 class="text-2xl sm:text-3xl md:text-5xl text-white">Anmeldung geschlossen</h1>
|
||||
</div>
|
||||
{/if}
|
||||
{#if !registered}
|
||||
<div class="col-[1] row-[1]" transition:fly={{ x: -200, duration: 300 }}>
|
||||
<Register
|
||||
|
@ -1,8 +1,12 @@
|
||||
import { ApiError, getJavaUuid, getNoAuthUuid, UserNotFoundError } from '$lib/server/minecraft';
|
||||
import { error, type RequestHandler } from '@sveltejs/kit';
|
||||
import { User } from '$lib/server/database';
|
||||
import { Settings, User } from '$lib/server/database';
|
||||
|
||||
export const POST = (async ({ request }) => {
|
||||
if ((await Settings.findOne({ where: { key: 'register.enabled' } }))?.value === false) {
|
||||
throw error(400, 'Anmeldung geschlossen');
|
||||
}
|
||||
|
||||
const data = await request.formData();
|
||||
const firstname = data.get('firstname') as string | null;
|
||||
const lastname = data.get('lastname') as string | null;
|
||||
|
Loading…
x
Reference in New Issue
Block a user