Revert "Merge remote-tracking branch 'upstream/main' into fix-spread-and-rest-based-binding"

This reverts commit 85b0ac44a7, reversing
changes made to 05c993151b.
pull/366/head
Jorge Caballero (DataDrivenMD) 2023-03-07 12:41:39 -08:00
rodzic 1d571d686e
commit b7b8651384
25 zmienionych plików z 176 dodań i 146 usunięć

Wyświetl plik

@ -53,9 +53,6 @@ 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

@ -325,8 +325,7 @@ 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)) {
const element = el as { tagName: string } el.tagName = 'p'
element.tagName = 'p'
} }
if (el.hasAttribute('class')) { if (el.hasAttribute('class')) {

Wyświetl plik

@ -1,29 +0,0 @@
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

@ -1,49 +0,0 @@
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.replace(/\?([0-9])?/g, (match: string, p1: string) => { return query.replaceAll(/\?([0-9])?/g, (match: string, p1: string) => {
c += 1 c += 1
return `$${p1 || c}` return `$${p1 || c}`
}) })

Wyświetl plik

@ -281,12 +281,11 @@ 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 + ' ' + cf?.httpProtocol parsed.signingString += request.method + ' ' + request.url + ' ' + request.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,8 +19,7 @@ export function initSentry(request: Request, env: Env, context: any) {
request, request,
transportOptions: { headers }, transportOptions: { headers },
}) })
const cf = (request as { cf?: IncomingRequestCfProperties }).cf const colo = request.cf && request.cf.colo ? request.cf.colo : 'UNKNOWN'
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.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+/g, '') return str.replaceAll(/\+/g, '-').replaceAll(/\//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.replace(/-/g, '+').replace(/_/g, '/') + padding return str.replaceAll(/-/g, '+').replaceAll(/_/g, '/') + padding
} }
export function stringToU8Array(str: string): Uint8Array { export function stringToU8Array(str: string): Uint8Array {

Wyświetl plik

@ -1,4 +1,4 @@
import { cloudflarePagesAdapter } from '@builder.io/qwik-city/adapters/cloudflare-pages/vite' import { cloudflarePagesAdaptor } from '@builder.io/qwik-city/adaptors/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: [
cloudflarePagesAdapter({ cloudflarePagesAdaptor({
// 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/backend/src/config/rules' import { upsertRule } from 'wildebeest/functions/api/wb/settings/server/rules'
import { upsertServerSettings } from 'wildebeest/backend/src/config/server' import { upsertServerSettings } from 'wildebeest/functions/api/wb/settings/server/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,8 +7,6 @@
}, },
"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

@ -1,5 +1,4 @@
import { component$, useContext } from '@builder.io/qwik' import { component$, useContext } from '@builder.io/qwik'
import { Link } from '@builder.io/qwik-city'
import { InstanceConfigContext } from '~/utils/instanceConfig' import { InstanceConfigContext } from '~/utils/instanceConfig'
import { useDomain } from '~/utils/useDomain' import { useDomain } from '~/utils/useDomain'
@ -17,12 +16,6 @@ export default component$(() => {
<img class="w-full" src={config.thumbnail} alt="Wildebeest instance thumbnail" /> <img class="w-full" src={config.thumbnail} alt="Wildebeest instance thumbnail" />
<p>{config.description}</p> <p>{config.description}</p>
</div> </div>
<Link
class="block text-wildebeest-500 border border-current my-4 p-2 text-center rounded-md no-underline"
href="/about"
>
Learn More
</Link>
</div> </div>
) )
}) })

Wyświetl plik

@ -37,7 +37,7 @@ export default component$(() => {
{ iconName: 'fa-globe', linkText: 'Federated', linkTarget: '/public', linkActiveRegex: /^\/public\/?$/ }, { iconName: 'fa-globe', linkText: 'Federated', linkTarget: '/public', linkActiveRegex: /^\/public\/?$/ },
] ]
const aboutLink = { iconName: 'fa-ellipsis', linkText: 'About', linkTarget: '/about', linkActiveRegex: /^\/about/ } // const aboutLink = { iconName: 'fa-ellipsis', linkText: 'About', linkTarget: '/about', linkActiveRegex: /^\/about/ }
return ( return (
<div class="bg-wildebeest-600 xl:bg-transparent flex flex-col justify-between right-column-wrapper text-wildebeest-200 flex-1 z-10"> <div class="bg-wildebeest-600 xl:bg-transparent flex flex-col justify-between right-column-wrapper text-wildebeest-200 flex-1 z-10">
@ -49,15 +49,16 @@ export default component$(() => {
</div> </div>
<hr class="hidden xl:block border-t border-wildebeest-700 my-3" /> <hr class="hidden xl:block border-t border-wildebeest-700 my-3" />
{links.map((link) => renderNavLink(link))} {links.map((link) => renderNavLink(link))}
<div class="xl:hidden"> {/* *********** Hiding the about link until the backend support is available ***************** */}
{/* <div class="xl:hidden">
<hr class="border-t border-wildebeest-700 my-3" /> <hr class="border-t border-wildebeest-700 my-3" />
{renderNavLink(aboutLink)} {renderNavLink(aboutLink)}
</div> </div> */}
{!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 { updateSettings } from 'wildebeest/backend/src/config/server' import { handleRequestPost } from 'wildebeest/functions/api/wb/settings/server/server'
import { TextArea } from '~/components/Settings/TextArea' import { TextArea } from '~/components/Settings/TextArea'
import { serverSettingsLoader } from '../layout' import { serverSettingsLoader } from '../layout'
@ -12,12 +12,16 @@ const zodSchema = zod$({
export type ServerAboutData = Awaited<typeof zodSchema>['_type'] export type ServerAboutData = Awaited<typeof zodSchema>['_type']
export const action = action$(async (data, { platform }) => { export const action = action$(async (data, { request, platform }) => {
const db = await getDatabase(platform)
let success = false let success = false
try { try {
await updateSettings(db, data) const response = await handleRequestPost(
success = true await getDatabase(platform),
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
} }
@ -32,7 +36,7 @@ export default component$(() => {
const saveAction = action() const saveAction = action()
return ( return (
<Form action={saveAction}> <Form action={saveAction} spaReset>
<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 { updateSettings } from 'wildebeest/backend/src/config/server' import { handleRequestPost } from 'wildebeest/functions/api/wb/settings/server/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,12 +13,16 @@ const zodSchema = zod$({
export type ServerBrandingData = Awaited<typeof zodSchema>['_type'] export type ServerBrandingData = Awaited<typeof zodSchema>['_type']
export const action = action$(async (data, { platform }) => { export const action = action$(async (data, { request, platform }) => {
const db = await getDatabase(platform)
let success = false let success = false
try { try {
await updateSettings(db, data) const response = await handleRequestPost(
success = true await getDatabase(platform),
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
} }
@ -33,7 +37,7 @@ export default component$(() => {
const saveAction = action() const saveAction = action()
return ( return (
<Form action={saveAction}> <Form action={saveAction} spaReset>
<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 { getSettings } from 'wildebeest/backend/src/config/server' import { handleRequestGet } from 'wildebeest/functions/api/wb/settings/server/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 getSettings(database) const settingsResp = await handleRequestGet(database)
let settingsData: Partial<ServerSettingsData> = {} let settingsData: Partial<ServerSettingsData> = {}
try { try {
settingsData = await settingsResp.json() settingsData = await settingsResp.json()

Wyświetl plik

@ -1,7 +1,8 @@
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 { getRules, upsertRule } from 'wildebeest/backend/src/config/rules' import { handleRequestGet } from 'wildebeest/functions/api/v1/instance/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'
@ -32,7 +33,14 @@ 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'])
@ -55,7 +63,7 @@ export default component$(() => {
return ( return (
<> <>
<Form action={editActionObj}> <Form action={editActionObj} spaReset>
<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,7 +1,8 @@
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 { getRules, deleteRule, upsertRule } from 'wildebeest/backend/src/config/rules' import { handleRequestGet } from 'wildebeest/functions/api/v1/instance/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[] }
@ -47,7 +48,15 @@ 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))
}) })
@ -85,11 +94,11 @@ export default component$(() => {
</Form> </Form>
<div> <div>
{rules.value.map(({ id, text }, idx) => { {rules.value.map(({ id, text }, idx) => {
const ruleNumber = idx + 1 const ruleId = idx + 1
const ruleBtnText = `${ruleNumber}. ${text.slice(0, 27)}${text.length > 27 ? '...' : ''}` const ruleBtnText = `${ruleId}. ${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/${id}`} class="max-w-max inline-block mb-4 no-underline text-lg font-semibold"> <Link href={`./edit/${ruleId}`} 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,10 +2,11 @@ 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 { getSettings } from 'wildebeest/backend/src/config/server' import { handleRequestGet as settingsHandleRequestGet } from 'wildebeest/functions/api/wb/settings/server/server'
import { getRules } from 'wildebeest/backend/src/config/rules' import { handleRequestGet as rulesHandleRequestGet } from 'wildebeest/functions/api/v1/instance/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'
@ -27,9 +28,25 @@ 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 rules = await getRules(database) const brandingDataResp = await settingsHandleRequestGet(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
@ -105,10 +122,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 }, idx) => ( {aboutInfo.rules.map(({ id, text }) => (
<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">
{idx + 1} {id}
</span> </span>
<span>{text}</span> <span>{text}</span>
</li> </li>

Wyświetl plik

@ -60,12 +60,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 as string) await updateActorProperty(db, connectedActor.id, 'name', value)
} }
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 as string) await updateActorProperty(db, connectedActor.id, 'summary', value)
} }
if (formData.has('avatar')) { if (formData.has('avatar')) {

Wyświetl plik

@ -0,0 +1,80 @@
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

@ -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') as string) || '' properties.preferredUsername = formData.get('username') || ''
} }
if (formData.has('name')) { if (formData.has('name')) {
properties.name = (formData.get('name') as string) || '' properties.name = formData.get('name') || ''
} }
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"
} }
} }

Wyświetl plik

@ -19,14 +19,14 @@ const config: PlaywrightTestConfig = {
* Maximum time expect() should wait for the condition to be met. * Maximum time expect() should wait for the condition to be met.
* For example in `await expect(locator).toHaveText();` * For example in `await expect(locator).toHaveText();`
*/ */
timeout: (process.env.CI ? 30 : 5) * 1000, timeout: process.env.CI ? 5000 : 500,
}, },
/* Run tests in files in parallel */ /* Run tests in files in parallel */
fullyParallel: true, fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */ /* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI, forbidOnly: !!process.env.CI,
/* Retry on CI only */ /* Retry on CI only */
retries: process.env.CI ? 1 : 0, retries: process.env.CI ? 3 : 0,
/* Opt out of parallel tests on CI. */ /* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined, workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
@ -34,7 +34,7 @@ const config: PlaywrightTestConfig = {
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: { use: {
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
actionTimeout: (process.env.CI ? 30 : 10) * 1000, actionTimeout: 0,
/* Base URL to use in actions like `await page.goto('/')`. */ /* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://localhost:3000', // baseURL: 'http://localhost:3000',