Commit 31d401e7dfd0f51742d584ee31934a78a6577f67
Commits[COMMIT BEGIN]commit 31d401e7dfd0f51742d584ee31934a78a6577f67 Author: 0x4248 <[email protected]> Date: Thu Dec 25 21:54:34 2025 +0000 intranet/web-management-core: initial commit Introducing the intranet web management core system, its really nothing special yet Its designed to look like thoese scanners you see in supermarkets if you ever worked in one. Idk I just find the UI simple and fast. This system supports: - Menus - Pages - Static content - Forums - Messages And really can have anything using its CSS and expandable system. Whats gunna go here? Well since my intranet is only used by me and a few friends, its mainly to maintain it and have a simple way to access some other services. However this seems very insecure to have an entire web management system exposed on the network, hence why its only accessible via VPN. Signed-off-by: 0x4248 <[email protected]> diff --git a/systems/linux/intranet/web-management-core/.gitignore b/systems/linux/intranet/web-management-core/.gitignore new file mode 100644 index 0000000..4a87502 --- /dev/null +++ b/systems/linux/intranet/web-management-core/.gitignore @@ -0,0 +1,2 @@ +# I actually don't know why git is ignoring this folder. Seems weird, +!pages/ \ No newline at end of file diff --git a/systems/linux/intranet/web-management-core/core/components.py b/systems/linux/intranet/web-management-core/core/components.py new file mode 100644 index 0000000..0f0377b --- /dev/null +++ b/systems/linux/intranet/web-management-core/core/components.py @@ -0,0 +1,6 @@ +def h(level: int, text: str): + return f"<h{level}>{text}</h{level}>" + + +def hr(): + return "<hr />" diff --git a/systems/linux/intranet/web-management-core/core/layout.py b/systems/linux/intranet/web-management-core/core/layout.py new file mode 100644 index 0000000..dcea49e --- /dev/null +++ b/systems/linux/intranet/web-management-core/core/layout.py @@ -0,0 +1,71 @@ +from fastapi import Request + +STYLE = """ +<style> +html, body { + background: #000000; + color: #ffffff; + font-family: monospace; + margin: 0; + padding: 0.5em; +} + +a { + color: #4da6ff; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +.header { + margin-bottom: 0.5em; +} + +hr { + border: none; + border-top: 1px solid #444; + margin: 0.5em 0; +} + +pre { + white-space: pre-wrap; +} + +input, textarea { + background: #000000; + color: #ffffff; + border: 1px solid #444; + font-family: monospace; + padding: 0.2em; +} + +input[type=submit] { + width: auto; +} + +textarea { + width: 100%; + height: 6em; +} + +.center { + text-align: center; +} +</style> +""" + +def layout(request: Request, title: str, buttons: list[tuple[str, str]], header_html: str | None, body_html: str) -> str: + nav = " ".join(f"<a href='{href}'>[{label}]</a>" for label, href in buttons) + header = header_html if header_html is not None else f"<div class='header'>{nav} {title}</div>" + return f""" + <html> + <head>{STYLE}</head> + <body> + {header} + <hr /> + {body_html} + </body> + </html> + """ diff --git a/systems/linux/intranet/web-management-core/core/page.py b/systems/linux/intranet/web-management-core/core/page.py new file mode 100644 index 0000000..d0f55fb --- /dev/null +++ b/systems/linux/intranet/web-management-core/core/page.py @@ -0,0 +1,51 @@ +from fastapi import Request +from fastapi.responses import HTMLResponse, RedirectResponse +from core.layout import layout + +# ---- Page helpers ---- + +def page(request: Request, title: str, buttons, body: str, header: str | None = None) -> HTMLResponse: + return HTMLResponse(layout(request, title, buttons, header, body)) + +# ---- Page types ---- + + + +def menu(request: Request, title: str, entries: list[tuple[str, str]]): + lines = [] + for label, href in entries: + lines.append(f"<a href='{href}'>[{label}]</a>") + body = "<pre>" + "\n".join(lines) + "</pre>" + return page(request, title, [("BACK", "/")], body) + + +def message(request: Request, title: str, text: str, ok_href: str = "/"): + body = f""" + <div class='center'> + <pre>{text}</pre> + <a href='{ok_href}'>[ OK ]</a> + </div> + """ + return page(request, title, [("BACK", ok_href)], body) + + +def form(request: Request, title: str, action: str, fields: list[dict], error: str | None = None): + rows = [] + for f in fields: + if f.get("type") == "textarea": + rows.append(f"<label>{f['name']}</label><br/><textarea name='{f['name']}'></textarea>") + else: + rows.append(f"<label>{f['name']}</label><br/><input name='{f['name']}' />") + err = f"<pre>ERROR: {error}</pre>" if error else "" + body = f""" + {err} + <form method='post' action='{action}'> + {'<br/>'.join(rows)} + <br/><input type='submit' value='SUBMIT' /> + </form> + """ + return page(request, title, [("BACK", "/")], body) + + +def static_html(request: Request, title: str, html: str): + return page(request, title, [("BACK", "/")], html) \ No newline at end of file diff --git a/systems/linux/intranet/web-management-core/main.py b/systems/linux/intranet/web-management-core/main.py new file mode 100644 index 0000000..70b9ad3 --- /dev/null +++ b/systems/linux/intranet/web-management-core/main.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from pages import demo + +app = FastAPI() +app.include_router(demo.router) + +if __name__ == "__main__": + import uvicorn + uvicorn.run(app, host="0.0.0.0", port=8000) \ No newline at end of file diff --git a/systems/linux/intranet/web-management-core/pages/demo.py b/systems/linux/intranet/web-management-core/pages/demo.py new file mode 100644 index 0000000..0d5280e --- /dev/null +++ b/systems/linux/intranet/web-management-core/pages/demo.py @@ -0,0 +1,53 @@ +from fastapi import APIRouter, Request, Form +from fastapi.responses import RedirectResponse +from core import page as p + +router = APIRouter() + [email protected]("/") +async def home(request: Request): + return p.menu( + request, + title="PAGE: DEMO", + entries=[ + ("MESSAGE", "/message"), + ("FORM", "/form"), + ], + ) + [email protected]("/message") +async def msg(request: Request): + return p.message(request, "MESSAGE", "Hello from server", "/") + [email protected]("/form") +async def form_page(request: Request): + return p.form( + request, + title="DATA FORM", + action="/form", + fields=[ + {"name": "summary"}, + {"name": "details", "type": "textarea"}, + ], + ) + [email protected]("/form") +async def form_submit(request: Request, summary: str = Form(...), details: str = Form(...)): + if not summary: + return p.form( + request, + title="DATA FORM", + action="/form", + fields=[ + {"name": "summary"}, + {"name": "details", "type": "textarea"}, + ], + error="summary required", + ) + return p.message( + request, + "FORM SUBMITTED", + f"Summary: {summary}\nDetails: {details}", + "/", + ) + \ No newline at end of file[COMMIT END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.