From 10988194a89df2bac83bb12cb06c87dbe8d7eead Mon Sep 17 00:00:00 2001 From: cxykevin Date: Fri, 30 Aug 2024 17:43:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=90=8E=E5=8F=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/admin.py | 96 +++++++++++ server/db.py | 63 +++++++ server/main.py | 27 +-- src/admin.html | 448 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 624 insertions(+), 10 deletions(-) create mode 100644 server/admin.py create mode 100644 src/admin.html diff --git a/server/admin.py b/server/admin.py new file mode 100644 index 0000000..a5d21ee --- /dev/null +++ b/server/admin.py @@ -0,0 +1,96 @@ +from fastapi import FastAPI, Cookie, Response, Form, HTTPException +from fastapi.templating import Jinja2Templates +import hashlib +from . import cfg +from . import db +from typing import Annotated + + +def bind_admin(app: FastAPI, templates: Jinja2Templates, run_clean, tokens: list, reload_cfg): + @app.get("/admin/auth/{key}") + async def admin_auth(response: Response, key: str): + if (cfg.config["common"]["manage_key"] == key): + response.set_cookie("adminsession", key) + return {} + raise HTTPException(status_code=404) + + @app.get("/admin") + async def admin(adminsession: Annotated[str | None, Cookie()] = None): + if (cfg.config["common"]["manage_key"] != adminsession): + raise HTTPException(status_code=404) + return templates.TemplateResponse("admin.html", {"request": {}, "ui": cfg.config["ui"], "lang": cfg.lang}) + + @app.post("/admin/clean") + async def admin_clean(adminsession: Annotated[str | None, Cookie()] = None): + if (cfg.config["common"]["manage_key"] != adminsession): + raise HTTPException(status_code=404) + await run_clean() + return {"msg": "Cleaned!"} + + @app.post("/admin/init") + async def admin_init(adminsession: Annotated[str | None, Cookie()] = None): + if (cfg.config["common"]["manage_key"] != adminsession): + raise HTTPException(status_code=404) + await db.create_db() + return {"msg": "Init!"} + + @app.post("/admin/reload") + async def admin_reload(adminsession: Annotated[str | None, Cookie()] = None): + if (cfg.config["common"]["manage_key"] != adminsession): + raise HTTPException(status_code=404) + await reload_cfg() + return {"msg": "Reloaded!"} + + @app.get("/admin/getinfo") + async def admin_getinfo(adminsession: Annotated[str | None, Cookie()] = None): + if (cfg.config["common"]["manage_key"] != adminsession): + raise HTTPException(status_code=404) + return {"users": await db.get_userscount(), "tokens": len(tokens), "msg": ""} + + @app.get("/admin/cfg") + async def admin_getcfg(adminsession: Annotated[str | None, Cookie()] = None): + if (cfg.config["common"]["manage_key"] != adminsession): + raise HTTPException(status_code=404) + with open("config/config.toml", 'r', encoding='utf-8') as file: + cfgs = file.read() + return {"cfg": cfgs, "msg": ""} + + @app.post("/admin/cfg") + async def admin_setcfg(wcfg: str = Form(), adminsession: Annotated[str | None, Cookie()] = None): + if (cfg.config["common"]["manage_key"] != adminsession): + raise HTTPException(status_code=404) + with open("config/config.toml", 'w', encoding='utf-8') as file: + file.write(wcfg) + return {"msg": "Saved!"} + + @app.post("/admin/create") + async def admin_createuser(username: str = Form(), passwd: str = Form(), email: str = Form(), adminsession: Annotated[str | None, Cookie()] = None): + if (cfg.config["common"]["manage_key"] != adminsession): + raise HTTPException(status_code=404) + if await db.create_user(username, hashlib.sha256(passwd.encode("utf-8")).hexdigest(), email) == 0: + return {"msg": "Created!"} + return {"msg": "Fail!"} + + @app.get("/admin/users") + async def admin_getusers(page: int = 1, username: str = "", adminsession: Annotated[str | None, Cookie()] = None): + if (cfg.config["common"]["manage_key"] != adminsession): + raise HTTPException(status_code=404) + PAGE_CNT = 20 + users = await db.search_user(page, username, PAGE_CNT) + if (users is None): + users = [] + return {"msg": "", "users": users, "pages": (((await db.search_user_len(page, username, PAGE_CNT))-1)//PAGE_CNT)+1} + + @app.delete("/admin/users") + async def admin_deleteusers(username: str, adminsession: Annotated[str | None, Cookie()] = None): + if (cfg.config["common"]["manage_key"] != adminsession): + raise HTTPException(status_code=404) + await db.delete_user(username) + return {"msg": ""} + + @app.post("/admin/users") + async def admin_ch_passwd(username: str = Form(), passwd: str = Form(), adminsession: Annotated[str | None, Cookie()] = None): + if (cfg.config["common"]["manage_key"] != adminsession): + raise HTTPException(status_code=404) + await db.update_passwd(username, hashlib.sha256(passwd.encode("utf-8")).hexdigest()) + return {"msg": ""} diff --git a/server/db.py b/server/db.py index 6a607b9..d377ed8 100644 --- a/server/db.py +++ b/server/db.py @@ -27,6 +27,20 @@ async def connect_db(): ) +async def recreate(): + global db + db.close() + db = await aiomysql.create_pool( + host=HOST, + port=PORT, + user=USER, + password=PASSWD, + db=DB, + maxsize=MAXSIZE, + minsize=MINSIZE + ) + + async def create_db(): async with db.acquire() as conn: await (await conn.cursor()).execute( @@ -64,6 +78,8 @@ async def create_user(username: str, password: str, email: str): # 创建新用户 await cur.execute("INSERT INTO users (username, password, email, accoutpwd) VALUES (%s, %s, %s, %s)", (username, password, email, uuid.uuid4().hex)) await conn.commit() + + await recreate() return 0 @@ -82,6 +98,16 @@ async def update_passwd(username: str, password: str): async with conn.cursor() as cur: await cur.execute("UPDATE users SET password = %s WHERE username = %s", (password, username)) await conn.commit() + await recreate() + return 0 + + +async def delete_user(username: str): + async with db.acquire() as conn: + async with conn.cursor() as cur: + await cur.execute("DELETE FROM users WHERE username = %s;COMMIT;", (username)) + await conn.commit() + await recreate() return 0 @@ -93,3 +119,40 @@ async def get_email(username: str): if result: return result[0] return None + + +async def get_userscount(): + async with db.acquire() as conn: + async with conn.cursor() as cur: + await cur.execute("SELECT COUNT(*) FROM users") + result = await cur.fetchone() + if result: + return result[0] + return None + + +async def search_user(page: int, username: str, PAGE_CNT): + async with db.acquire() as conn: + async with conn.cursor() as cur: + username_search = ('WHERE username LIKE "%%'+username + + '%%"' if username != "" else "") + cmd = 'SELECT * FROM users '+username_search+' LIMIT ' + \ + str(page*PAGE_CNT-PAGE_CNT)+','+str(PAGE_CNT)+';' + await cur.execute(cmd) + result = await cur.fetchall() + if result: + return [(i[0], i[2]) for i in result] + return None + + +async def search_user_len(page: int, username: str, PAGE_CNT): + async with db.acquire() as conn: + async with conn.cursor() as cur: + username_search = ('WHERE username LIKE "%%'+username + + '%%"' if username != "" else "") + cmd = 'SELECT COUNT(*) FROM users '+username_search+';' + await cur.execute(cmd) + result = await cur.fetchone() + if result: + return result[0] + return None diff --git a/server/main.py b/server/main.py index 885568c..9d38d93 100644 --- a/server/main.py +++ b/server/main.py @@ -7,6 +7,7 @@ from contextlib import asynccontextmanager from . import db from . import email as email_sys from . import cfg +from . import admin import hashlib import uuid from typing import Annotated @@ -52,19 +53,23 @@ def clean_uuid(uuid: str): return uuid.replace("/", "") +async def run_clean(): + sys.stderr.write("==> clean\n") + for k, v in tokens.items(): + if (v[1] < datetime.now()): + del tokens[k] + for k, v in apikeys.items(): + if (v[1] < datetime.now()): + del apikeys[k] + for k, v in emails.items(): + if (v[2] < datetime.now()): + del emails[k] + + async def clean_sys(): while 1: await asyncio.sleep(CLEAN_TIMEOUT) - sys.stderr.write("==> clean\n") - for k, v in tokens.items(): - if (v[1] < datetime.now()): - del tokens[k] - for k, v in apikeys.items(): - if (v[1] < datetime.now()): - del apikeys[k] - for k, v in emails.items(): - if (v[2] < datetime.now()): - del emails[k] + await run_clean() async def send_email(): @@ -314,6 +319,8 @@ async def reload(key: str): await reload_cfg() return 0 +admin.bind_admin(app, templates, run_clean, tokens, reload_cfg) + for i in os.listdir("plugin"): if (len(i.split(".")) != 2 or i.split(".")[1] != 'py'): continue diff --git a/src/admin.html b/src/admin.html new file mode 100644 index 0000000..8b8b532 --- /dev/null +++ b/src/admin.html @@ -0,0 +1,448 @@ + + + + + + + + + + {{ui.title}} + + + + + + + + + + + + + 取消 + 确认 + + + + + + 取消 + 确认 + + + + + {{ui.prod_name}} + + + + 主页 + 配置 + 账户 + + + +
+
+
+ +
+

用户数

+ unkonwn +
+
+ +
+

活跃用户数

+ unkonwn +
+
+ +
+ + 管理功能 + + 初始化数据库 + 重载配置 + 清理过期token + + +
+
+
+
+
+
+
Loading...
+
+ 保存 + 注意:程序不会自动重载配置文件,错误的配置文件可能会导致程序崩溃! +
+
+
+
+
+
+ + + + + + + + + + + + + + + + +
用户名邮箱操作
+
+ 筛选 + +
+
+ 1/0 + 上一页 + 下一页 +
+
+
+
+
+
+ + + + \ No newline at end of file