integrated the forum plugin
This commit is contained in:
parent
4a0214f020
commit
46cd28ba54
5 changed files with 122 additions and 4 deletions
77
handlers.py
77
handlers.py
|
|
@ -6,9 +6,11 @@ from datetime import datetime
|
|||
from urllib.parse import unquote
|
||||
|
||||
from db import get_db, return_db, get_setting, set_setting, get_site_name, index_url, clean_url
|
||||
import templates as templates_mod
|
||||
from templates import esc, wrap_page, DEFAULT_TEMPLATE
|
||||
from rns_client import fetch_remote_sites
|
||||
|
||||
forum_plugin = None
|
||||
_request_local = threading.local()
|
||||
|
||||
|
||||
|
|
@ -360,7 +362,7 @@ def handle_search(query):
|
|||
)
|
||||
|
||||
|
||||
def handle_add_form(msg="", action_type="index"):
|
||||
def handle_add_form(msg="", action_type="index", prefill_url=""):
|
||||
if action_type == "subscribe":
|
||||
return _respond(
|
||||
f"<h1>subscribe</h1>"
|
||||
|
|
@ -374,12 +376,13 @@ def handle_add_form(msg="", action_type="index"):
|
|||
f"<p>{msg}</p>"
|
||||
f'<a href="/">back</a>'
|
||||
)
|
||||
url_value = f'value="{esc(prefill_url)}" ' if prefill_url else ""
|
||||
return _respond(
|
||||
f"<h1>add url</h1>"
|
||||
f"<p>Add a site to your index</p>"
|
||||
f'<form method="post" action="/add">'
|
||||
f'{_csrf_field()}'
|
||||
f'<input name="url" placeholder="https://example.com" size="50"><br><br>'
|
||||
f'<input name="url" placeholder="https://example.com" size="50" {url_value}><br><br>'
|
||||
f'<input name="note" placeholder="why are you saving this? (optional)" size="50"><br><br>'
|
||||
f'<input name="tags" placeholder="tags (comma-separated, e.g. solarpunk, mesh)" size="50"><br>'
|
||||
f'<small>tag: private to exclude from sharing</small><br><br>'
|
||||
|
|
@ -814,6 +817,8 @@ def handle_style_form(msg=""):
|
|||
sharing = get_setting("sharing_enabled", "0")
|
||||
checked = " checked" if sharing == "1" else ""
|
||||
sharing_mode = get_setting("sharing_mode", "exclude_private")
|
||||
forum = get_setting("forum_enabled", "0")
|
||||
forum_checked = " checked" if forum == "1" else ""
|
||||
exclude_checked = " checked" if sharing_mode != "require_public" else ""
|
||||
require_checked = " checked" if sharing_mode == "require_public" else ""
|
||||
shared_count = _count_shared_pages()
|
||||
|
|
@ -840,6 +845,17 @@ def handle_style_form(msg=""):
|
|||
lora_txpower = get_setting("lora_txpower", "7")
|
||||
lora_sf = get_setting("lora_sf", "8")
|
||||
lora_cr = get_setting("lora_cr", "5")
|
||||
if forum_plugin is not None:
|
||||
forum_section = (
|
||||
f"<h2>forum</h2>"
|
||||
f'<label><input type="checkbox" name="forum_enabled" value="1"{forum_checked}>'
|
||||
f" enable forum (shared URL discussion board)</label><br>"
|
||||
f"<small>Share URLs and discuss them with other TinyWeb instances. "
|
||||
f"Requires <code>tinyweb-forum</code> — "
|
||||
f'<a href="https://git.derickphan.com/lichenblankie/tinyweb-forum">more info</a>.</small><br><br>'
|
||||
)
|
||||
else:
|
||||
forum_section = ""
|
||||
return _respond(
|
||||
f"<h1>customize</h1>"
|
||||
f"<h2>name your search engine</h2>"
|
||||
|
|
@ -915,6 +931,7 @@ def handle_style_form(msg=""):
|
|||
f"<small>Saves ~50% on storage for embeddings. Slight quality reduction at large scale.</small><br><br>"
|
||||
f'<a href="/reindex">manage semantic index</a><br><br>'
|
||||
f"</div>"
|
||||
{forum_section}
|
||||
f"<h2>custom html</h2>"
|
||||
f"<p>Edit the full page template. Use <code>{esc('{{content}}')}</code> "
|
||||
f"where page content should appear.</p>"
|
||||
|
|
@ -974,6 +991,27 @@ def handle_style_submit(body):
|
|||
set_setting("lora_txpower", body.get("lora_txpower", ["7"])[0].strip())
|
||||
set_setting("lora_sf", body.get("lora_sf", ["8"])[0].strip())
|
||||
set_setting("lora_cr", body.get("lora_cr", ["5"])[0].strip())
|
||||
forum_enabled = "1" if body.get("forum_enabled") else "0"
|
||||
current_forum = get_setting("forum_enabled", "0")
|
||||
if forum_enabled != current_forum:
|
||||
if forum_enabled == "1" and forum_plugin is None:
|
||||
return handle_style_form(
|
||||
"Forum plugin not installed. Run: pip install tinyweb-forum"
|
||||
)
|
||||
if forum_enabled == "1":
|
||||
forum_plugin.enable()
|
||||
try:
|
||||
forum_plugin.fdb.set_setting("forum_enabled", "1")
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
forum_plugin.disable()
|
||||
try:
|
||||
forum_plugin.fdb.set_setting("forum_enabled", "0")
|
||||
except Exception:
|
||||
pass
|
||||
set_setting("forum_enabled", forum_enabled)
|
||||
templates_mod.FORUM_ENABLED = (forum_enabled == "1")
|
||||
return handle_style_form("Saved. Restart TinyWeb for mesh network changes to take effect.")
|
||||
|
||||
|
||||
|
|
@ -1654,7 +1692,11 @@ def _dispatch_inner(data):
|
|||
return handle_search(query)
|
||||
elif path == "/add":
|
||||
action_type = query.get("type", ["index"])[0]
|
||||
return handle_add_form(action_type=action_type if action_type == "subscribe" else "index")
|
||||
prefill_url = query.get("url", [""])[0].strip()
|
||||
return handle_add_form(
|
||||
action_type=action_type if action_type == "subscribe" else "index",
|
||||
prefill_url=prefill_url,
|
||||
)
|
||||
elif path == "/pages":
|
||||
return handle_pages(query)
|
||||
elif path.startswith("/edit/"):
|
||||
|
|
@ -1689,7 +1731,15 @@ def _dispatch_inner(data):
|
|||
elif path.startswith("/subscriptions/browse/"):
|
||||
sid = extract_id("/subscriptions/browse/")
|
||||
return handle_subscription_browse(sid) if sid is not None else _error(400)
|
||||
elif path.startswith("/forum"):
|
||||
if forum_plugin and forum_plugin.is_enabled():
|
||||
return forum_plugin.handle(method, path, query, {}, data.get("cookies", {}))
|
||||
return _error(404)
|
||||
elif method == "POST":
|
||||
if path.startswith("/forum"):
|
||||
if forum_plugin and forum_plugin.is_enabled():
|
||||
return forum_plugin.handle(method, path, query, body, data.get("cookies", {}))
|
||||
return _error(404)
|
||||
if not _check_csrf(body):
|
||||
return _respond("<h1>403 Forbidden</h1><p>Invalid or missing CSRF token.</p>", status=403)
|
||||
if path == "/add":
|
||||
|
|
@ -1737,7 +1787,28 @@ def _dispatch_inner(data):
|
|||
|
||||
|
||||
def dispatch_request(data):
|
||||
path = data.get("path", "/")
|
||||
cookies = data.get("cookies", {})
|
||||
|
||||
# Forum handles its own CSRF — skip main CSRF to avoid cookie conflicts
|
||||
if path.startswith("/forum") and forum_plugin and forum_plugin.is_enabled():
|
||||
resp = _dispatch_inner(data)
|
||||
resp.setdefault("headers", {})
|
||||
resp["headers"]["X-Frame-Options"] = "DENY"
|
||||
resp["headers"]["X-Content-Type-Options"] = "nosniff"
|
||||
if resp.get("content_type", "").startswith("text/html"):
|
||||
resp["body"] = wrap_page(resp.get("body", ""))
|
||||
resp["headers"]["Content-Security-Policy"] = (
|
||||
"default-src 'self'; "
|
||||
"script-src 'self' 'unsafe-inline'; "
|
||||
"style-src 'self' 'unsafe-inline'; "
|
||||
"img-src * data:; "
|
||||
"frame-ancestors 'none'; "
|
||||
"form-action 'self'; "
|
||||
"base-uri 'self'"
|
||||
)
|
||||
return resp
|
||||
|
||||
csrf_token = cookies.get("_csrf", "")
|
||||
if not csrf_token:
|
||||
csrf_token = secrets.token_hex(32)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue