Merge remote-tracking branch 'upstream/main' into api/v1/instance

pull/366/head
Jorge Caballero (DataDrivenMD) 2023-03-07 09:58:13 -08:00
commit 4a698bda0e
24 zmienionych plików z 133 dodań i 242 usunięć

Wyświetl plik

@ -53,6 +53,9 @@ jobs:
- name: Check frontend linting - name: Check frontend linting
run: yarn lint:frontend run: yarn lint:frontend
- name: Check frontend types
run: yarn --cwd types-check
test-ui: test-ui:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

Wyświetl plik

@ -270,7 +270,8 @@ function getContentRewriter() {
contentRewriter.on('*', { contentRewriter.on('*', {
element(el) { element(el) {
if (!['p', 'span', 'br', 'a'].includes(el.tagName)) { if (!['p', 'span', 'br', 'a'].includes(el.tagName)) {
el.tagName = 'p' const element = el as { tagName: string }
element.tagName = 'p'
} }
if (el.hasAttribute('class')) { if (el.hasAttribute('class')) {

Wyświetl plik

@ -0,0 +1,29 @@
import { type Database } from 'wildebeest/backend/src/database'
export async function getRules(db: Database): Promise<Array<{ id: string; text: string }>> {
const query = `SELECT * from server_rules;`
const result = await db.prepare(query).all<{ id: string; text: string }>()
if (!result.success) {
throw new Error('SQL error: ' + result.error)
}
return result.results ?? []
}
export async function upsertRule(db: Database, rule: { id?: number; text: string } | string) {
const id = typeof rule === 'string' ? null : rule.id ?? null
const text = typeof rule === 'string' ? rule : rule.text
return await db
.prepare(
`INSERT INTO server_rules (id, text)
VALUES (?, ?)
ON CONFLICT(id) DO UPDATE SET text=excluded.text;`
)
.bind(id, text)
.run()
}
export async function deleteRule(db: Database, ruleId: number) {
return await db.prepare('DELETE FROM server_rules WHERE id=?').bind(ruleId).run()
}

Wyświetl plik

@ -0,0 +1,49 @@
import { type Database } from 'wildebeest/backend/src/database'
import { type ServerSettingsData } from 'wildebeest/frontend/src/routes/(admin)/settings/(admin)/server-settings/layout'
export async function getSettings(db: Database): Promise<ServerSettingsData> {
const query = `SELECT * from server_settings`
const result = await db.prepare(query).all<{ setting_name: string; setting_value: string }>()
const data = (result.results ?? []).reduce(
(settings, { setting_name, setting_value }) => ({
...settings,
[setting_name]: setting_value,
}),
{} as Object
)
if (!result.success) {
throw new Error('SQL Error: ' + result.error)
}
return data
}
export async function updateSettings(db: Database, data: ServerSettingsData) {
const result = await upsertServerSettings(db, data)
if (result && !result.success) {
throw new Error('SQL Error: ' + result.error)
}
return new Response('', { status: 200 })
}
export async function upsertServerSettings(db: Database, settings: Partial<ServerSettingsData>) {
const settingsEntries = Object.entries(settings)
if (!settingsEntries.length) {
return null
}
const query = `
INSERT INTO server_settings (setting_name, setting_value)
VALUES ${settingsEntries.map(() => `(?, ?)`).join(', ')}
ON CONFLICT(setting_name) DO UPDATE SET setting_value=excluded.setting_value
`
return await db
.prepare(query)
.bind(...settingsEntries.flat())
.run()
}

Wyświetl plik

@ -4,7 +4,7 @@ import type { Env } from 'wildebeest/backend/src/types/env'
function sqliteToPsql(query: string): string { function sqliteToPsql(query: string): string {
let c = 0 let c = 0
return query.replaceAll(/\?([0-9])?/g, (match: string, p1: string) => { return query.replace(/\?([0-9])?/g, (match: string, p1: string) => {
c += 1 c += 1
return `$${p1 || c}` return `$${p1 || c}`
}) })

Wyświetl plik

@ -281,11 +281,12 @@ export function parseRequest(request: Request, options?: Options): ParsedSignatu
if (h === 'request-line') { if (h === 'request-line') {
if (!options.strict) { if (!options.strict) {
const cf = (request as { cf?: IncomingRequestCfProperties }).cf
/* /*
* We allow headers from the older spec drafts if strict parsing isn't * We allow headers from the older spec drafts if strict parsing isn't
* specified in options. * specified in options.
*/ */
parsed.signingString += request.method + ' ' + request.url + ' ' + request.cf?.httpProtocol parsed.signingString += request.method + ' ' + request.url + ' ' + cf?.httpProtocol
} else { } else {
/* Strict parsing doesn't allow older draft headers. */ /* Strict parsing doesn't allow older draft headers. */
throw new StrictParsingError('request-line is not a valid header ' + 'with strict parsing enabled.') throw new StrictParsingError('request-line is not a valid header ' + 'with strict parsing enabled.')

Wyświetl plik

@ -19,7 +19,8 @@ export function initSentry(request: Request, env: Env, context: any) {
request, request,
transportOptions: { headers }, transportOptions: { headers },
}) })
const colo = request.cf && request.cf.colo ? request.cf.colo : 'UNKNOWN' const cf = (request as { cf?: IncomingRequestCfProperties }).cf
const colo = cf?.colo ? cf.colo : 'UNKNOWN'
sentry.setTag('colo', colo) sentry.setTag('colo', colo)
// cf-connecting-ip should always be present, but if not we can fallback to XFF. // cf-connecting-ip should always be present, but if not we can fallback to XFF.

Wyświetl plik

@ -26,12 +26,12 @@ export function arrayBufferToBase64(buffer: ArrayBuffer): string {
} }
export function b64ToUrlEncoded(str: string): string { export function b64ToUrlEncoded(str: string): string {
return str.replaceAll(/\+/g, '-').replaceAll(/\//g, '_').replace(/=+/g, '') return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+/g, '')
} }
export function urlEncodedToB64(str: string): string { export function urlEncodedToB64(str: string): string {
const padding = '='.repeat((4 - (str.length % 4)) % 4) const padding = '='.repeat((4 - (str.length % 4)) % 4)
return str.replaceAll(/-/g, '+').replaceAll(/_/g, '/') + padding return str.replace(/-/g, '+').replace(/_/g, '/') + padding
} }
export function stringToU8Array(str: string): Uint8Array { export function stringToU8Array(str: string): Uint8Array {

Wyświetl plik

@ -1,4 +1,4 @@
import { cloudflarePagesAdaptor } from '@builder.io/qwik-city/adaptors/cloudflare-pages/vite' import { cloudflarePagesAdapter } from '@builder.io/qwik-city/adapters/cloudflare-pages/vite'
import { extendConfig } from '@builder.io/qwik-city/vite' import { extendConfig } from '@builder.io/qwik-city/vite'
import baseConfig from '../../vite.config' import baseConfig from '../../vite.config'
@ -11,7 +11,7 @@ export default extendConfig(baseConfig, () => {
}, },
}, },
plugins: [ plugins: [
cloudflarePagesAdaptor({ cloudflarePagesAdapter({
// Do not SSG as the D1 database is not available at build time, I think. // Do not SSG as the D1 database is not available at build time, I think.
// staticGenerate: true, // staticGenerate: true,
}), }),

Wyświetl plik

@ -7,8 +7,8 @@ import { createReply as createReplyInBackend } from 'wildebeest/backend/test/sha
import { createStatus } from 'wildebeest/backend/src/mastodon/status' import { createStatus } from 'wildebeest/backend/src/mastodon/status'
import type { APObject } from 'wildebeest/backend/src/activitypub/objects' import type { APObject } from 'wildebeest/backend/src/activitypub/objects'
import { type Database } from 'wildebeest/backend/src/database' import { type Database } from 'wildebeest/backend/src/database'
import { upsertRule } from 'wildebeest/functions/api/wb/settings/server/rules' import { upsertRule } from 'wildebeest/backend/src/config/rules'
import { upsertServerSettings } from 'wildebeest/functions/api/wb/settings/server/server' import { upsertServerSettings } from 'wildebeest/backend/src/config/server'
/** /**
* Run helper commands to initialize the database with actors, statuses, etc. * Run helper commands to initialize the database with actors, statuses, etc.

Wyświetl plik

@ -7,6 +7,8 @@
}, },
"private": true, "private": true,
"scripts": { "scripts": {
"pretypes-check": "yarn build",
"types-check": "tsc",
"lint": "eslint src mock-db adaptors", "lint": "eslint src mock-db adaptors",
"build": "vite build && vite build -c adaptors/cloudflare-pages/vite.config.ts", "build": "vite build && vite build -c adaptors/cloudflare-pages/vite.config.ts",
"dev": "vite --mode ssr", "dev": "vite --mode ssr",

Wyświetl plik

@ -57,7 +57,7 @@ export default component$(() => {
{!isAuthorized && ( {!isAuthorized && (
<a <a
class="w-full block mb-4 no-underline text-center bg-wildebeest-vibrant-600 hover:bg-wildebeest-vibrant-500 p-2 text-white text-uppercase border-wildebeest-vibrant-600 text-lg text-semi outline-none border rounded hover:border-wildebeest-vibrant-500 focus:border-wildebeest-vibrant-500" class="w-full block mb-4 no-underline text-center bg-wildebeest-vibrant-600 hover:bg-wildebeest-vibrant-500 p-2 text-white text-uppercase border-wildebeest-vibrant-600 text-lg text-semi outline-none border rounded hover:border-wildebeest-vibrant-500 focus:border-wildebeest-vibrant-500"
href={loginUrl} href={`${loginUrl}`}
> >
Sign in Sign in
</a> </a>

Wyświetl plik

@ -1,7 +1,7 @@
import { component$ } from '@builder.io/qwik' import { component$ } from '@builder.io/qwik'
import { action$, Form, Link, z, zod$ } from '@builder.io/qwik-city' import { action$, Form, Link, z, zod$ } from '@builder.io/qwik-city'
import { getDatabase } from 'wildebeest/backend/src/database' import { getDatabase } from 'wildebeest/backend/src/database'
import { handleRequestPost } from 'wildebeest/functions/api/wb/settings/server/server' import { updateSettings } from 'wildebeest/backend/src/config/server'
import { TextArea } from '~/components/Settings/TextArea' import { TextArea } from '~/components/Settings/TextArea'
import { serverSettingsLoader } from '../layout' import { serverSettingsLoader } from '../layout'
@ -12,16 +12,12 @@ const zodSchema = zod$({
export type ServerAboutData = Awaited<typeof zodSchema>['_type'] export type ServerAboutData = Awaited<typeof zodSchema>['_type']
export const action = action$(async (data, { request, platform }) => { export const action = action$(async (data, { platform }) => {
const db = await getDatabase(platform)
let success = false let success = false
try { try {
const response = await handleRequestPost( await updateSettings(db, data)
await getDatabase(platform), success = true
new Request(request, { body: JSON.stringify(data) }),
platform.ACCESS_AUTH_DOMAIN,
platform.ACCESS_AUD
)
success = response.ok
} catch (e: unknown) { } catch (e: unknown) {
success = false success = false
} }
@ -36,7 +32,7 @@ export default component$(() => {
const saveAction = action() const saveAction = action()
return ( return (
<Form action={saveAction} spaReset> <Form action={saveAction}>
<p class="mt-12 mb-9">Provide in-depth information about how the server is operated, moderated, funded.</p> <p class="mt-12 mb-9">Provide in-depth information about how the server is operated, moderated, funded.</p>
<div class="mb-12"> <div class="mb-12">

Wyświetl plik

@ -1,7 +1,7 @@
import { component$ } from '@builder.io/qwik' import { component$ } from '@builder.io/qwik'
import { action$, Form, zod$, z } from '@builder.io/qwik-city' import { action$, Form, zod$, z } from '@builder.io/qwik-city'
import { getDatabase } from 'wildebeest/backend/src/database' import { getDatabase } from 'wildebeest/backend/src/database'
import { handleRequestPost } from 'wildebeest/functions/api/wb/settings/server/server' import { updateSettings } from 'wildebeest/backend/src/config/server'
import { TextArea } from '~/components/Settings/TextArea' import { TextArea } from '~/components/Settings/TextArea'
import { TextInput } from '~/components/Settings/TextInput' import { TextInput } from '~/components/Settings/TextInput'
import { serverSettingsLoader } from '../layout' import { serverSettingsLoader } from '../layout'
@ -13,16 +13,12 @@ const zodSchema = zod$({
export type ServerBrandingData = Awaited<typeof zodSchema>['_type'] export type ServerBrandingData = Awaited<typeof zodSchema>['_type']
export const action = action$(async (data, { request, platform }) => { export const action = action$(async (data, { platform }) => {
const db = await getDatabase(platform)
let success = false let success = false
try { try {
const response = await handleRequestPost( await updateSettings(db, data)
await getDatabase(platform), success = true
new Request(request, { body: JSON.stringify(data) }),
platform.ACCESS_AUTH_DOMAIN,
platform.ACCESS_AUD
)
success = response.ok
} catch (e: unknown) { } catch (e: unknown) {
success = false success = false
} }
@ -37,7 +33,7 @@ export default component$(() => {
const saveAction = action() const saveAction = action()
return ( return (
<Form action={saveAction} spaReset> <Form action={saveAction}>
<p class="mt-12 mb-9"> <p class="mt-12 mb-9">
Your server's branding differentiates it from other servers in the network. This information may be displayed Your server's branding differentiates it from other servers in the network. This information may be displayed
across a variety of environments, such as Mastodon's web interface, native applications, in link previews on across a variety of environments, such as Mastodon's web interface, native applications, in link previews on

Wyświetl plik

@ -1,7 +1,7 @@
import { component$, Slot } from '@builder.io/qwik' import { component$, Slot } from '@builder.io/qwik'
import { Link, loader$, useLocation } from '@builder.io/qwik-city' import { Link, loader$, useLocation } from '@builder.io/qwik-city'
import { getDatabase } from 'wildebeest/backend/src/database' import { getDatabase } from 'wildebeest/backend/src/database'
import { handleRequestGet } from 'wildebeest/functions/api/wb/settings/server/server' import { getSettings } from 'wildebeest/backend/src/config/server'
import { ServerAboutData } from './about' import { ServerAboutData } from './about'
import { ServerBrandingData } from './branding' import { ServerBrandingData } from './branding'
@ -10,7 +10,7 @@ export type ServerSettingsData = ServerBrandingData & ServerAboutData
export const serverSettingsLoader = loader$<Promise<Partial<ServerSettingsData>>>(async ({ platform }) => { export const serverSettingsLoader = loader$<Promise<Partial<ServerSettingsData>>>(async ({ platform }) => {
const database = await getDatabase(platform) const database = await getDatabase(platform)
const settingsResp = await handleRequestGet(database) const settingsResp = await getSettings(database)
let settingsData: Partial<ServerSettingsData> = {} let settingsData: Partial<ServerSettingsData> = {}
try { try {
settingsData = await settingsResp.json() settingsData = await settingsResp.json()

Wyświetl plik

@ -1,8 +1,7 @@
import { component$ } from '@builder.io/qwik' import { component$ } from '@builder.io/qwik'
import { action$, Form, loader$, useNavigate, z, zod$ } from '@builder.io/qwik-city' import { action$, Form, loader$, useNavigate, z, zod$ } from '@builder.io/qwik-city'
import { getDatabase } from 'wildebeest/backend/src/database' import { getDatabase } from 'wildebeest/backend/src/database'
import { handleRequestGet } from 'wildebeest/functions/api/v1/instance/rules' import { getRules, upsertRule } from 'wildebeest/backend/src/config/rules'
import { upsertRule } from 'wildebeest/functions/api/wb/settings/server/rules'
import { TextArea } from '~/components/Settings/TextArea' import { TextArea } from '~/components/Settings/TextArea'
import { getErrorHtml } from '~/utils/getErrorHtml/getErrorHtml' import { getErrorHtml } from '~/utils/getErrorHtml/getErrorHtml'
@ -33,14 +32,7 @@ export const editAction = action$(
export const ruleLoader = loader$<Promise<{ id: number; text: string }>>(async ({ params, platform, html }) => { export const ruleLoader = loader$<Promise<{ id: number; text: string }>>(async ({ params, platform, html }) => {
const database = await getDatabase(platform) const database = await getDatabase(platform)
const rules = await getRules(database)
const settingsResp = await handleRequestGet(database)
let rules: { id: number; text: string }[] = []
try {
rules = await settingsResp.json()
} catch {
rules = []
}
const rule: { id: number; text: string } | undefined = rules.find((r) => r.id === +params['id']) const rule: { id: number; text: string } | undefined = rules.find((r) => r.id === +params['id'])
@ -63,7 +55,7 @@ export default component$(() => {
return ( return (
<> <>
<Form action={editActionObj} spaReset> <Form action={editActionObj}>
<p class="mt-12 mb-9"> <p class="mt-12 mb-9">
While most claim to have read and agree to the terms of service, usually people do not read through until While most claim to have read and agree to the terms of service, usually people do not read through until
after a problem arises. Make it easier to see your server's rules at a glance by providing them in a flat after a problem arises. Make it easier to see your server's rules at a glance by providing them in a flat

Wyświetl plik

@ -1,8 +1,7 @@
import { component$ } from '@builder.io/qwik' import { component$ } from '@builder.io/qwik'
import { action$, Form, Link, loader$, z, zod$ } from '@builder.io/qwik-city' import { action$, Form, Link, loader$, z, zod$ } from '@builder.io/qwik-city'
import { getDatabase } from 'wildebeest/backend/src/database' import { getDatabase } from 'wildebeest/backend/src/database'
import { handleRequestGet } from 'wildebeest/functions/api/v1/instance/rules' import { getRules, deleteRule, upsertRule } from 'wildebeest/backend/src/config/rules'
import { deleteRule, upsertRule } from 'wildebeest/functions/api/wb/settings/server/rules'
import { TextArea } from '~/components/Settings/TextArea' import { TextArea } from '~/components/Settings/TextArea'
export type ServerSettingsData = { rules: string[] } export type ServerSettingsData = { rules: string[] }
@ -48,15 +47,7 @@ export const deleteAction = action$(
export const rulesLoader = loader$<Promise<{ id: number; text: string }[]>>(async ({ platform }) => { export const rulesLoader = loader$<Promise<{ id: number; text: string }[]>>(async ({ platform }) => {
const database = await getDatabase(platform) const database = await getDatabase(platform)
const rules = await getRules(database)
const settingsResp = await handleRequestGet(database)
let rules: { id: number; text: string }[] = []
try {
rules = await settingsResp.json()
} catch {
rules = []
}
return JSON.parse(JSON.stringify(rules)) return JSON.parse(JSON.stringify(rules))
}) })
@ -94,11 +85,11 @@ export default component$(() => {
</Form> </Form>
<div> <div>
{rules.value.map(({ id, text }, idx) => { {rules.value.map(({ id, text }, idx) => {
const ruleId = idx + 1 const ruleNumber = idx + 1
const ruleBtnText = `${ruleId}. ${text.slice(0, 27)}${text.length > 27 ? '...' : ''}` const ruleBtnText = `${ruleNumber}. ${text.slice(0, 27)}${text.length > 27 ? '...' : ''}`
return ( return (
<div key={id} class="p-4 my-4 bg-wildebeest-600 rounded"> <div key={id} class="p-4 my-4 bg-wildebeest-600 rounded">
<Link href={`./edit/${ruleId}`} class="max-w-max inline-block mb-4 no-underline text-lg font-semibold"> <Link href={`./edit/${id}`} class="max-w-max inline-block mb-4 no-underline text-lg font-semibold">
{ruleBtnText} {ruleBtnText}
</Link> </Link>
<div class="flex justify-between text-wildebeest-400"> <div class="flex justify-between text-wildebeest-400">

Wyświetl plik

@ -2,11 +2,10 @@ import { component$ } from '@builder.io/qwik'
import { DocumentHead, loader$ } from '@builder.io/qwik-city' import { DocumentHead, loader$ } from '@builder.io/qwik-city'
import { getDatabase } from 'wildebeest/backend/src/database' import { getDatabase } from 'wildebeest/backend/src/database'
import { getDomain } from 'wildebeest/backend/src/utils/getDomain' import { getDomain } from 'wildebeest/backend/src/utils/getDomain'
import { handleRequestGet as settingsHandleRequestGet } from 'wildebeest/functions/api/wb/settings/server/server' import { getSettings } from 'wildebeest/backend/src/config/server'
import { handleRequestGet as rulesHandleRequestGet } from 'wildebeest/functions/api/v1/instance/rules' import { getRules } from 'wildebeest/backend/src/config/rules'
import { Accordion } from '~/components/Accordion/Accordion' import { Accordion } from '~/components/Accordion/Accordion'
import { HtmlContent } from '~/components/HtmlContent/HtmlContent' import { HtmlContent } from '~/components/HtmlContent/HtmlContent'
import { ServerSettingsData } from '~/routes/(admin)/settings/(admin)/server-settings/layout'
import { Account } from '~/types' import { Account } from '~/types'
import { getDocumentHead } from '~/utils/getDocumentHead' import { getDocumentHead } from '~/utils/getDocumentHead'
import { instanceLoader } from '../layout' import { instanceLoader } from '../layout'
@ -28,25 +27,9 @@ type AboutInfo = {
export const aboutInfoLoader = loader$<Promise<AboutInfo>>(async ({ resolveValue, request, platform }) => { export const aboutInfoLoader = loader$<Promise<AboutInfo>>(async ({ resolveValue, request, platform }) => {
// TODO: fetching the instance for the thumbnail, but that should be part of the settings // TODO: fetching the instance for the thumbnail, but that should be part of the settings
const instance = await resolveValue(instanceLoader) const instance = await resolveValue(instanceLoader)
const database = await getDatabase(platform) const database = await getDatabase(platform)
const brandingData = await getSettings(database)
const brandingDataResp = await settingsHandleRequestGet(database) const rules = await getRules(database)
let brandingData: ServerSettingsData | null
try {
brandingData = await brandingDataResp.json()
} catch {
brandingData = null
}
const rulesResp = await rulesHandleRequestGet(database)
let rules: { id: number; text: string }[] = []
try {
rules = await rulesResp.json()
} catch {
rules = []
}
const admins = await getAdmins(database) const admins = await getAdmins(database)
let adminAccount: Account | null = null let adminAccount: Account | null = null
@ -122,10 +105,10 @@ export default component$(() => {
<div class="my-1"> <div class="my-1">
<Accordion title="Server rules"> <Accordion title="Server rules">
<ol class="list-none flex flex-col gap-1 my-5 px-6"> <ol class="list-none flex flex-col gap-1 my-5 px-6">
{aboutInfo.rules.map(({ id, text }) => ( {aboutInfo.rules.map(({ id, text }, idx) => (
<li key={id} class="flex items-center border-wildebeest-700 border-b last-of-type:border-b-0 py-2"> <li key={id} class="flex items-center border-wildebeest-700 border-b last-of-type:border-b-0 py-2">
<span class="bg-wildebeest-vibrant-400 text-wildebeest-900 mr-4 my-1 p-4 rounded-full w-5 h-5 grid place-content-center"> <span class="bg-wildebeest-vibrant-400 text-wildebeest-900 mr-4 my-1 p-4 rounded-full w-5 h-5 grid place-content-center">
{id} {idx + 1}
</span> </span>
<span>{text}</span> <span>{text}</span>
</li> </li>

Wyświetl plik

@ -59,12 +59,12 @@ export async function handleRequest(
if (formData.has('display_name')) { if (formData.has('display_name')) {
const value = formData.get('display_name')! const value = formData.get('display_name')!
await updateActorProperty(db, connectedActor.id, 'name', value) await updateActorProperty(db, connectedActor.id, 'name', value as string)
} }
if (formData.has('note')) { if (formData.has('note')) {
const value = formData.get('note')! const value = formData.get('note')!
await updateActorProperty(db, connectedActor.id, 'summary', value) await updateActorProperty(db, connectedActor.id, 'summary', value as string)
} }
if (formData.has('avatar')) { if (formData.has('avatar')) {

Wyświetl plik

@ -1,80 +0,0 @@
import type { Env } from 'wildebeest/backend/src/types/env'
import type { ContextData } from 'wildebeest/backend/src/types/context'
import * as errors from 'wildebeest/backend/src/errors'
import { type Database, getDatabase } from 'wildebeest/backend/src/database'
import { parse } from 'cookie'
import { isUserAdmin } from 'wildebeest/backend/src/utils/auth/isUserAdmin'
export const onRequestGet: PagesFunction<Env, any, ContextData> = async ({ env, request }) => {
return handleRequestPost(await getDatabase(env), request, env.ACCESS_AUTH_DOMAIN, env.ACCESS_AUD)
}
export async function handleRequestGet(db: Database) {
const query = `SELECT * from server_rules;`
const result = await db.prepare(query).all<{ id: string; text: string }>()
if (!result.success) {
return new Response('SQL error: ' + result.error, { status: 500 })
}
return new Response(JSON.stringify(result.results ?? []), { status: 200 })
}
export const onRequestPost: PagesFunction<Env, any, ContextData> = async ({ env, request }) => {
return handleRequestPost(await getDatabase(env), request, env.ACCESS_AUTH_DOMAIN, env.ACCESS_AUD)
}
export async function handleRequestPost(db: Database, request: Request, accessAuthDomain: string, accessAud: string) {
const cookie = parse(request.headers.get('Cookie') || '')
const jwt = cookie['CF_Authorization']
const isAdmin = await isUserAdmin(request, jwt, accessAuthDomain, accessAud, db)
if (!isAdmin) {
return errors.notAuthorized('Lacking authorization rights to edit server rules')
}
const rule = await request.json<{ id?: number; text: string }>()
const result = await upsertRule(db, rule)
if (!result.success) {
return new Response('SQL error: ' + result.error, { status: 500 })
}
return new Response('', { status: 200 })
}
export async function upsertRule(db: Database, rule: { id?: number; text: string } | string) {
const id = typeof rule === 'string' ? null : rule.id ?? null
const text = typeof rule === 'string' ? rule : rule.text
return await db
.prepare(
`INSERT INTO server_rules (id, text)
VALUES (?, ?)
ON CONFLICT(id) DO UPDATE SET text=excluded.text;`
)
.bind(id, text)
.run()
}
export async function handleRequestDelete(db: Database, request: Request, accessAuthDomain: string, accessAud: string) {
const cookie = parse(request.headers.get('Cookie') || '')
const jwt = cookie['CF_Authorization']
const isAdmin = await isUserAdmin(request, jwt, accessAuthDomain, accessAud, db)
if (!isAdmin) {
return errors.notAuthorized('Lacking authorization rights to edit server rules')
}
const rule = await request.json<{ id: number }>()
const result = await deleteRule(db, rule.id)
if (!result.success) {
return new Response('SQL error: ' + result.error, { status: 500 })
}
return new Response('', { status: 200 })
}
export async function deleteRule(db: Database, ruleId: number) {
return await db.prepare('DELETE FROM server_rules WHERE id=?').bind(ruleId).run()
}

Wyświetl plik

@ -1,73 +0,0 @@
import type { Env } from 'wildebeest/backend/src/types/env'
import type { ContextData } from 'wildebeest/backend/src/types/context'
import * as errors from 'wildebeest/backend/src/errors'
import { type Database, getDatabase } from 'wildebeest/backend/src/database'
import { parse } from 'cookie'
import { ServerSettingsData } from 'wildebeest/frontend/src/routes/(admin)/settings/(admin)/server-settings/layout'
import { isUserAdmin } from 'wildebeest/backend/src/utils/auth/isUserAdmin'
export const onRequestGet: PagesFunction<Env, any, ContextData> = async ({ env, request }) => {
return handleRequestPost(await getDatabase(env), request, env.ACCESS_AUTH_DOMAIN, env.ACCESS_AUD)
}
export async function handleRequestGet(db: Database) {
const query = `SELECT * from server_settings`
const result = await db.prepare(query).all<{ setting_name: string; setting_value: string }>()
const data = (result.results ?? []).reduce(
(settings, { setting_name, setting_value }) => ({
...settings,
[setting_name]: setting_value,
}),
{} as Object
)
if (!result.success) {
return new Response('SQL error: ' + result.error, { status: 500 })
}
return new Response(JSON.stringify(data), { status: 200 })
}
export const onRequestPost: PagesFunction<Env, any, ContextData> = async ({ env, request }) => {
return handleRequestPost(await getDatabase(env), request, env.ACCESS_AUTH_DOMAIN, env.ACCESS_AUD)
}
export async function handleRequestPost(db: Database, request: Request, accessAuthDomain: string, accessAud: string) {
const cookie = parse(request.headers.get('Cookie') || '')
const jwt = cookie['CF_Authorization']
const isAdmin = await isUserAdmin(request, jwt, accessAuthDomain, accessAud, db)
if (!isAdmin) {
return errors.notAuthorized('Lacking authorization rights to edit server settings')
}
const data = await request.json<ServerSettingsData>()
const result = await upsertServerSettings(db, data)
if (result && !result.success) {
return new Response('SQL error: ' + result.error, { status: 500 })
}
return new Response('', { status: 200 })
}
export async function upsertServerSettings(db: Database, settings: Partial<ServerSettingsData>) {
const settingsEntries = Object.entries(settings)
if (!settingsEntries.length) {
return null
}
const query = `
INSERT INTO server_settings (setting_name, setting_value)
VALUES ${settingsEntries.map(() => `(?, ?)`).join(', ')}
ON CONFLICT(setting_name) DO UPDATE SET setting_value=excluded.setting_value
`
return await db
.prepare(query)
.bind(...settingsEntries.flat())
.run()
}

Wyświetl plik

@ -42,11 +42,11 @@ export async function handlePostRequest(
const properties: Record<string, string> = {} const properties: Record<string, string> = {}
if (formData.has('username')) { if (formData.has('username')) {
properties.preferredUsername = formData.get('username') || '' properties.preferredUsername = (formData.get('username') as string) || ''
} }
if (formData.has('name')) { if (formData.has('name')) {
properties.name = formData.get('name') || '' properties.name = (formData.get('name') as string) || ''
} }
await createPerson(domain, db, userKEK, email, properties) await createPerson(domain, db, userKEK, email, properties)

Wyświetl plik

@ -50,7 +50,7 @@
"http-message-signatures": "^0.1.2", "http-message-signatures": "^0.1.2",
"toucan-js": "^3.1.0" "toucan-js": "^3.1.0"
}, },
"simple-git-hooks": { "simple-git-hooks": {
"pre-commit": "yarn lint" "pre-commit": "yarn lint"
} }
} }