Chyba v readme + délka banu
This commit is contained in:
15
.vscode/launch.json
vendored
15
.vscode/launch.json
vendored
@@ -1,15 +0,0 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node-terminal",
|
||||
"name": "Run Script: start (czchan)",
|
||||
"request": "launch",
|
||||
"command": "npm run start",
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -7,7 +7,7 @@ Primárně český imageboardový engine zaměřený na rychlost, UX a dobrou ko
|
||||
- node 23+
|
||||
- postgres
|
||||
- valkey nebo redis
|
||||
- imagemagick 9+
|
||||
- imagemagick 7+
|
||||
- ffmpeg
|
||||
|
||||
## Instalace
|
||||
|
||||
10
package-lock.json
generated
10
package-lock.json
generated
@@ -11,6 +11,7 @@
|
||||
"dependencies": {
|
||||
"@kitajs/html": "^4.2.13",
|
||||
"@kitajs/ts-html-plugin": "^4.1.4",
|
||||
"@logdna/tail-file": "^4.0.2",
|
||||
"@minify-html/node": "^0.18.1",
|
||||
"apache-crypt": "^1.2.6",
|
||||
"async-mutex": "^0.5.0",
|
||||
@@ -2960,6 +2961,15 @@
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@logdna/tail-file": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@logdna/tail-file/-/tail-file-4.0.2.tgz",
|
||||
"integrity": "sha512-aEZF3LanJoewsQ9J1CRk5wvOqvQvw4lhxitSMXz3sQPgfezamzwW+pGvKXxvht7EvJEYSlYPxfSjL6T2bDSEkg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@minify-html/node": {
|
||||
"version": "0.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@minify-html/node/-/node-0.18.1.tgz",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"test": "echo \"Léky teď\"",
|
||||
"lint": "npx eslint .",
|
||||
"backend": "npx xss-scan && npx tsc",
|
||||
"js": "esbuild web/ts/main.ts --bundle --minify --outfile=public/js/bundle.tmp.js && npx babel public/js/bundle.tmp.js --out-file public/js/bundle.js && rm public/js/bundle.tmp.js",
|
||||
"css": "npx sass ./web/sass:./public/css --no-source-map --style compressed && npx postcss ./public/css/**/*.css --use autoprefixer --replace",
|
||||
@@ -55,6 +56,7 @@
|
||||
"dependencies": {
|
||||
"@kitajs/html": "^4.2.13",
|
||||
"@kitajs/ts-html-plugin": "^4.1.4",
|
||||
"@logdna/tail-file": "^4.0.2",
|
||||
"@minify-html/node": "^0.18.1",
|
||||
"apache-crypt": "^1.2.6",
|
||||
"async-mutex": "^0.5.0",
|
||||
|
||||
@@ -16,9 +16,9 @@ const SANE_DEFAULTS: Config = {
|
||||
},
|
||||
},
|
||||
tasks: {
|
||||
prune_bans_interval: 60_000,
|
||||
prune_captchas_interval: 60_000,
|
||||
prune_files_interval: 300_000,
|
||||
prune_bans_interval: 60,
|
||||
prune_captchas_interval: 60,
|
||||
prune_files_interval: 300,
|
||||
},
|
||||
ui: {
|
||||
name: "czchan",
|
||||
@@ -28,6 +28,7 @@ const SANE_DEFAULTS: Config = {
|
||||
reltime: true,
|
||||
page_size: 20,
|
||||
preview_replies: 5,
|
||||
default_ban_length: 86400,
|
||||
},
|
||||
secrets: {
|
||||
jwt: "",
|
||||
|
||||
@@ -30,6 +30,7 @@ type CzchanConfig = {
|
||||
reltime: boolean;
|
||||
page_size: number;
|
||||
preview_replies: number;
|
||||
default_ban_length: number;
|
||||
};
|
||||
secrets: {
|
||||
jwt: string;
|
||||
@@ -93,29 +94,9 @@ const jsonConf = async (file: string) => {
|
||||
return config;
|
||||
};
|
||||
|
||||
const normalizeSiteConfig = (site: Config): Config => {
|
||||
return {
|
||||
...site,
|
||||
server: {
|
||||
...site.server,
|
||||
headers: {
|
||||
real_ip: site.server.headers?.real_ip || "X-Real-IP",
|
||||
country_code: site.server.headers?.country_code || "X-Country-Code",
|
||||
region_code: site.server.headers?.region_code || "X-Region-Code",
|
||||
asn: site.server.headers?.asn || "X-ASN",
|
||||
},
|
||||
},
|
||||
tasks: {
|
||||
prune_bans_interval: site.tasks?.prune_bans_interval || 60_000,
|
||||
prune_captchas_interval: site.tasks?.prune_captchas_interval || 60_000,
|
||||
prune_files_interval: site.tasks?.prune_files_interval || 300_000,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const loadConfig = async (): Promise<CzchanConfig> => {
|
||||
return {
|
||||
site: normalizeSiteConfig(await jsonConf("./config/site.json")),
|
||||
site: await jsonConf("./config/site.json"),
|
||||
boardDefaults: await jsonConf("./config/board_defaults.json"),
|
||||
roles: await jsonConf("./config/roles.json"),
|
||||
assets: {
|
||||
@@ -144,7 +125,6 @@ const getConfig = async (): Promise<CzchanConfig> => {
|
||||
|
||||
return {
|
||||
...config,
|
||||
site: normalizeSiteConfig(config.site),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -219,6 +219,10 @@ const contrastingColor = (color: string) => {
|
||||
// Truncate
|
||||
|
||||
const truncate = (string: string, length: number) => {
|
||||
if (string.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string = string.replace(/\s+/g, " ").replace(/\|\|(.+?)\|\|/g, "[SPOILER]");
|
||||
return string.length > length ? `${string.slice(0, length)}...` : string;
|
||||
};
|
||||
|
||||
@@ -38,7 +38,7 @@ const scheduleTask = (
|
||||
|
||||
voidRun();
|
||||
|
||||
setInterval(voidRun, interval);
|
||||
setInterval(voidRun, interval * 1000);
|
||||
};
|
||||
|
||||
const main = async () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { canUser, CzchanPerm } from "../../../lib/permissions.js";
|
||||
import { secsToTimestring } from "../../../lib/time.js";
|
||||
import type { TemplateCtx } from "../../ctx.js";
|
||||
import { Form, FormButton, FormField, FormHeader } from "./form.js";
|
||||
import type { PropsWithChildren } from "@kitajs/html";
|
||||
@@ -82,7 +83,13 @@ const PostActionsForm = ({ ctx }: PropsWithChildren<{ ctx: TemplateCtx }>) => (
|
||||
</>
|
||||
}
|
||||
>
|
||||
<input name="ban_duration" type="text" />
|
||||
<input
|
||||
name="ban_duration"
|
||||
type="text"
|
||||
placeholder={secsToTimestring(
|
||||
ctx.config.site.ui.default_ban_length,
|
||||
)}
|
||||
/>
|
||||
</FormField>
|
||||
<FormField label="↳ Trvalý" wrapper>
|
||||
<input name="permanent_ban" type="checkbox" />
|
||||
|
||||
@@ -233,8 +233,11 @@ const modActions = async (
|
||||
const expires = form.permanent_ban
|
||||
? null
|
||||
: // TODO: make default ban duration a config field
|
||||
// 1 day for now
|
||||
new Date(Date.now() + (form.ban_duration ?? 86400) * 1000);
|
||||
new Date(
|
||||
Date.now() +
|
||||
(form.ban_duration ?? req.config.site.ui.default_ban_length) *
|
||||
1000,
|
||||
);
|
||||
|
||||
const ip_range = `${ip}/${prefix}`;
|
||||
|
||||
@@ -256,10 +259,10 @@ const modActions = async (
|
||||
post,
|
||||
`${
|
||||
post.content
|
||||
}\n\n<span class="red"><b>(${form.ban_message})</b></span>`,
|
||||
}${post.content.length > 0 ? "\n\n" : ""}<span class="red"><b>(${form.ban_message})</b></span>`,
|
||||
`${
|
||||
post.content_unformatted
|
||||
}\n\n##**${escapeHtml(form.ban_message)}**##`,
|
||||
}${post.content_unformatted.length > 0 ? "\n\n" : ""}##**${escapeHtml(form.ban_message)}**##`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ const Template = (
|
||||
ctx={ctx}
|
||||
title={`/${board.id}/ - ${op.subject ?? truncate(op.content_unformatted, 64) ?? "[bez obsahu]"}`}
|
||||
theme={board.config.theme}
|
||||
description={truncate(op.content_unformatted, 128)}
|
||||
description={truncate(op.content_unformatted, 128) ?? "[bez obsahu]"}
|
||||
/>
|
||||
<PageBody ctx={ctx}>
|
||||
<IBHeader banner={banner} board={board} />
|
||||
|
||||
Reference in New Issue
Block a user