完成后台
This commit is contained in:
parent
e9c8d2710f
commit
10988194a8
|
@ -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": ""}
|
63
server/db.py
63
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 def create_db():
|
||||||
async with db.acquire() as conn:
|
async with db.acquire() as conn:
|
||||||
await (await conn.cursor()).execute(
|
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 cur.execute("INSERT INTO users (username, password, email, accoutpwd) VALUES (%s, %s, %s, %s)", (username, password, email, uuid.uuid4().hex))
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
|
|
||||||
|
await recreate()
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,6 +98,16 @@ async def update_passwd(username: str, password: str):
|
||||||
async with conn.cursor() as cur:
|
async with conn.cursor() as cur:
|
||||||
await cur.execute("UPDATE users SET password = %s WHERE username = %s", (password, username))
|
await cur.execute("UPDATE users SET password = %s WHERE username = %s", (password, username))
|
||||||
await conn.commit()
|
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
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,3 +119,40 @@ async def get_email(username: str):
|
||||||
if result:
|
if result:
|
||||||
return result[0]
|
return result[0]
|
||||||
return None
|
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
|
||||||
|
|
|
@ -7,6 +7,7 @@ from contextlib import asynccontextmanager
|
||||||
from . import db
|
from . import db
|
||||||
from . import email as email_sys
|
from . import email as email_sys
|
||||||
from . import cfg
|
from . import cfg
|
||||||
|
from . import admin
|
||||||
import hashlib
|
import hashlib
|
||||||
import uuid
|
import uuid
|
||||||
from typing import Annotated
|
from typing import Annotated
|
||||||
|
@ -52,9 +53,7 @@ def clean_uuid(uuid: str):
|
||||||
return uuid.replace("/", "")
|
return uuid.replace("/", "")
|
||||||
|
|
||||||
|
|
||||||
async def clean_sys():
|
async def run_clean():
|
||||||
while 1:
|
|
||||||
await asyncio.sleep(CLEAN_TIMEOUT)
|
|
||||||
sys.stderr.write("==> clean\n")
|
sys.stderr.write("==> clean\n")
|
||||||
for k, v in tokens.items():
|
for k, v in tokens.items():
|
||||||
if (v[1] < datetime.now()):
|
if (v[1] < datetime.now()):
|
||||||
|
@ -67,6 +66,12 @@ async def clean_sys():
|
||||||
del emails[k]
|
del emails[k]
|
||||||
|
|
||||||
|
|
||||||
|
async def clean_sys():
|
||||||
|
while 1:
|
||||||
|
await asyncio.sleep(CLEAN_TIMEOUT)
|
||||||
|
await run_clean()
|
||||||
|
|
||||||
|
|
||||||
async def send_email():
|
async def send_email():
|
||||||
while 1:
|
while 1:
|
||||||
if (len(email_send_lst) > 0):
|
if (len(email_send_lst) > 0):
|
||||||
|
@ -314,6 +319,8 @@ async def reload(key: str):
|
||||||
await reload_cfg()
|
await reload_cfg()
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
admin.bind_admin(app, templates, run_clean, tokens, reload_cfg)
|
||||||
|
|
||||||
for i in os.listdir("plugin"):
|
for i in os.listdir("plugin"):
|
||||||
if (len(i.split(".")) != 2 or i.split(".")[1] != 'py'):
|
if (len(i.split(".")) != 2 or i.split(".")[1] != 'py'):
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -0,0 +1,448 @@
|
||||||
|
<html class="mdui-theme-auto">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="https://learn.study-area.org.cn/theme/css/mdui.css">
|
||||||
|
<script src="https://learn.study-area.org.cn/theme/js/mdui.global.js" type="text/javascript"></script>
|
||||||
|
<link href="https://learn.study-area.org.cn/theme/css/icons.css" rel="stylesheet">
|
||||||
|
<script src="https://cdn.bootcdn.net/ajax/libs/ace/1.36.0/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="https://cdn.bootcdn.net/ajax/libs/ace/1.36.0/theme-clouds_midnight.js" type="text/javascript"
|
||||||
|
charset="utf-8"></script>
|
||||||
|
<script src="https://cdn.bootcdn.net/ajax/libs/ace/1.36.0/mode-toml.js" type="text/javascript"
|
||||||
|
charset="utf-8"></script>
|
||||||
|
<title>{{ui.title}}</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pages {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
width: calc(100% - 5rem);
|
||||||
|
height: calc(100% - 4rem);
|
||||||
|
max-height: calc(100% - 4rem);
|
||||||
|
top: 4rem;
|
||||||
|
left: 5rem;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
width: calc(100% - 40px);
|
||||||
|
height: calc(100% - 40px);
|
||||||
|
max-height: calc(100% - 40px);
|
||||||
|
min-width: calc(100% - 40px);
|
||||||
|
min-height: calc(100% - 40px);
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infocard {
|
||||||
|
width: 200px;
|
||||||
|
height: 120px;
|
||||||
|
margin-right: 8px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Code Pro';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local("SourceCodePro") url('https://learn.study-area.org.cn/font/sourcecodepro.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
.ace_editor,
|
||||||
|
.ace_text-input,
|
||||||
|
.ace_hidpi,
|
||||||
|
.ace_text-layer,
|
||||||
|
.ace_gutter-layer,
|
||||||
|
.ace_content,
|
||||||
|
.ace_gutter {
|
||||||
|
font-family: 'Source Code Pro' !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
font-family: 'Source Code Pro', Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btns {
|
||||||
|
margin: -10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<body style="margin:0;padding:0;">
|
||||||
|
<mdui-dialog id="dialog" close-on-overlay-click>
|
||||||
|
</mdui-dialog>
|
||||||
|
<mdui-snackbar placement="top" action="确定" closeable id="snackbar" auto-close-delay="0"></mdui-snackbar>
|
||||||
|
<mdui-dialog id="chpwd_inputdialog" headline="更改密码" description="长度需>8,请至少包含大小写字母和数字" close-on-overlay-click>
|
||||||
|
<mdui-text-field id="inputdialog_text"></mdui-text-field>
|
||||||
|
<mdui-button slot="action" variant="text"
|
||||||
|
onclick="document.getElementById('chpwd_inputdialog').open = false">取消</mdui-button>
|
||||||
|
<mdui-button slot="action" variant="tonal" onclick="allowchangepasswd()">确认</mdui-button>
|
||||||
|
</mdui-dialog>
|
||||||
|
<mdui-dialog id="newuser_inputdialog" headline="创建用户" description="" close-on-overlay-click>
|
||||||
|
<mdui-text-field id="username" label="用户名"></mdui-text-field>
|
||||||
|
<mdui-text-field id="email" label="邮箱"></mdui-text-field>
|
||||||
|
<mdui-text-field id="passwd" label="密码"></mdui-text-field>
|
||||||
|
<mdui-button slot="action" variant="text"
|
||||||
|
onclick="document.getElementById('newuser_inputdialog').open = false">取消</mdui-button>
|
||||||
|
<mdui-button slot="action" variant="tonal" onclick="allowcreateuser()">确认</mdui-button>
|
||||||
|
</mdui-dialog>
|
||||||
|
|
||||||
|
<mdui-layout style="height: 100%">
|
||||||
|
<mdui-top-app-bar>
|
||||||
|
<mdui-top-app-bar-title>{{ui.prod_name}}</mdui-top-app-bar-title>
|
||||||
|
</mdui-top-app-bar>
|
||||||
|
|
||||||
|
<mdui-navigation-rail value="page_home">
|
||||||
|
<mdui-navigation-rail-item icon="home" value="page_home"
|
||||||
|
onclick="update_btn('page_home')">主页</mdui-navigation-rail-item>
|
||||||
|
<mdui-navigation-rail-item icon="settings" value="page_settings"
|
||||||
|
onclick="update_btn('page_settings')">配置</mdui-navigation-rail-item>
|
||||||
|
<mdui-navigation-rail-item icon="account_circle" value="page_user"
|
||||||
|
onclick="update_btn('page_user')">账户</mdui-navigation-rail-item>
|
||||||
|
</mdui-navigation-rail>
|
||||||
|
|
||||||
|
<mdui-layout-main style="height: 100%">
|
||||||
|
<div class="pages" id="page_home">
|
||||||
|
<div class="container">
|
||||||
|
<div style="display:block;height:128px;position:static">
|
||||||
|
<mdui-card class="infocard">
|
||||||
|
<div style="margin-left:20px">
|
||||||
|
<h2>用户数</h2>
|
||||||
|
<span id="users">unkonwn</span>
|
||||||
|
</div>
|
||||||
|
</mdui-card>
|
||||||
|
<mdui-card class="infocard">
|
||||||
|
<div style="margin-left:20px">
|
||||||
|
<h2>活跃用户数</h2>
|
||||||
|
<span id="tokens">unkonwn</span>
|
||||||
|
</div>
|
||||||
|
</mdui-card>
|
||||||
|
<!-- <div style="flex-grow: 1"></div> -->
|
||||||
|
<div style="position: absolute;top:40px;right:40px;display:block;">
|
||||||
|
<mdui-dropdown>
|
||||||
|
<mdui-button slot="trigger" end-icon="settings" stype="">管理功能</mdui-button>
|
||||||
|
<mdui-menu>
|
||||||
|
<mdui-menu-item onclick="init_db()">初始化数据库</mdui-menu-item>
|
||||||
|
<mdui-menu-item onclick="reload_cfg()">重载配置</mdui-menu-item>
|
||||||
|
<mdui-menu-item onclick="clean_cache()">清理过期token</mdui-menu-item>
|
||||||
|
</mdui-menu>
|
||||||
|
</mdui-dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pages hide" id="page_settings">
|
||||||
|
<div class="container">
|
||||||
|
<div id="editor" style="height: calc(100% - 72px); width: 100%">Loading...</div>
|
||||||
|
<div style="display:flex">
|
||||||
|
<mdui-button end-icon="save" onclick="save_cfg()">保存</mdui-button>
|
||||||
|
<span>注意:程序不会自动重载配置文件,错误的配置文件可能会导致程序崩溃!</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pages hide" id="page_user">
|
||||||
|
<div class="container">
|
||||||
|
<div class="mdui-table" style="display:block;height:100%;width:100%">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">用户名</th>
|
||||||
|
<th scope="col">邮箱</th>
|
||||||
|
<th scope="col">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="main_users">
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td scope="row" colspan="2">
|
||||||
|
<div style="display:flex">
|
||||||
|
<mdui-button onclick="user_search()">筛选</mdui-button>
|
||||||
|
<mdui-text-field label="" style="height:40px"
|
||||||
|
id="search_username"></mdui-text-field>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span id="page_cnt">1/0</span>
|
||||||
|
<mdui-button onclick="user_prevpage()">上一页</mdui-button>
|
||||||
|
<mdui-button onclick="user_nextpage()">下一页</mdui-button><mdui-button-icon
|
||||||
|
onclick="newuser()" icon="control_point"></mdui-button-icon>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mdui-layout-main>
|
||||||
|
</mdui-layout>
|
||||||
|
<script>
|
||||||
|
var now_userpage = 1;
|
||||||
|
var max_userpage = 0;
|
||||||
|
var search_str = "";
|
||||||
|
function user_refersh() {
|
||||||
|
const Http = new XMLHttpRequest();
|
||||||
|
const url = '/admin/users?page=' + now_userpage.toString() + "&username=" + search_str;
|
||||||
|
Http.open("GET", url);
|
||||||
|
Http.send();
|
||||||
|
|
||||||
|
Http.addEventListener('loadend', () => {
|
||||||
|
var ret = JSON.parse(Http.responseText)
|
||||||
|
if (ret.msg == undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (ret.msg == "") {
|
||||||
|
max_userpage = ret.pages
|
||||||
|
if (now_userpage > max_userpage) {
|
||||||
|
now_userpage = max_userpage
|
||||||
|
if (now_userpage == 0) {
|
||||||
|
now_userpage = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.getElementById("page_cnt").innerText = now_userpage.toString() + "/" + max_userpage.toString()
|
||||||
|
var allstr = ""
|
||||||
|
ret.users.forEach((val) => {
|
||||||
|
var htmls = `
|
||||||
|
<tr>
|
||||||
|
<th scope="row">`+ val[0] + `</th>
|
||||||
|
<td>`+ val[1] + `</td>
|
||||||
|
<td>
|
||||||
|
<mdui-button variant="standard" icon="delete" onclick=delete_user("`+ val[0] + `") class="btns">删除用户</mdui-button>
|
||||||
|
<mdui-button variant="standard" icon="edit" onclick=ch_passwd_user("`+ val[0] + `") class="btns">更改密码</mdui-button>
|
||||||
|
</td>
|
||||||
|
</tr>`
|
||||||
|
allstr = allstr + htmls
|
||||||
|
})
|
||||||
|
document.getElementById("main_users").innerHTML = allstr
|
||||||
|
} else {
|
||||||
|
dialog(ret.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function newuser() {
|
||||||
|
newuser_inputdialog.open = true
|
||||||
|
}
|
||||||
|
function allowcreateuser() {
|
||||||
|
const Http = new XMLHttpRequest();
|
||||||
|
const url = '/admin/create';
|
||||||
|
Http.open("POST", url);
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append('username', document.getElementById("username").value);
|
||||||
|
formData.append('email', document.getElementById("email").value);
|
||||||
|
formData.append('passwd', document.getElementById("passwd").value)
|
||||||
|
Http.send(formData);
|
||||||
|
|
||||||
|
Http.addEventListener('loadend', () => {
|
||||||
|
newuser_inputdialog.open = false
|
||||||
|
var ret = JSON.parse(Http.responseText)
|
||||||
|
if (ret.msg == undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (ret.msg != "") {
|
||||||
|
dialog(ret.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
var snackbar_callback = function () {
|
||||||
|
console.log(1)
|
||||||
|
}
|
||||||
|
function delete_user(username) {
|
||||||
|
snackbar.innerHTML = "删除用户 \"" + username + "\"?"
|
||||||
|
snackbar_callback = function () {
|
||||||
|
snackbar.actionLoading = true;
|
||||||
|
const Http = new XMLHttpRequest();
|
||||||
|
const url = '/admin/users?username=' + username;
|
||||||
|
Http.open("DELETE", url);
|
||||||
|
Http.send();
|
||||||
|
|
||||||
|
Http.addEventListener('loadend', () => {
|
||||||
|
snackbar.actionLoading = false;
|
||||||
|
snackbar.open = false
|
||||||
|
var ret = JSON.parse(Http.responseText)
|
||||||
|
if (ret.msg == undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (ret.msg != "") {
|
||||||
|
dialog(ret.msg)
|
||||||
|
}
|
||||||
|
user_refersh()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
snackbar.open = true;
|
||||||
|
}
|
||||||
|
var allowchangepasswd = function () { }
|
||||||
|
function ch_passwd_user(username) {
|
||||||
|
document.getElementById("chpwd_inputdialog").open = true
|
||||||
|
allowchangepasswd = function () {
|
||||||
|
document.getElementById("chpwd_inputdialog").open = false
|
||||||
|
const Http = new XMLHttpRequest();
|
||||||
|
const url = '/admin/users';
|
||||||
|
Http.open("POST", url);
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append('username', username);
|
||||||
|
formData.append('passwd', document.getElementById("inputdialog_text").value);
|
||||||
|
Http.send(formData);
|
||||||
|
Http.addEventListener('loadend', () => {
|
||||||
|
var ret = JSON.parse(Http.responseText)
|
||||||
|
if (ret.msg == undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (ret.msg != "") {
|
||||||
|
dialog(ret.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function user_search() {
|
||||||
|
now_userpage = 1
|
||||||
|
search_str = document.getElementById("search_username").value
|
||||||
|
user_refersh()
|
||||||
|
}
|
||||||
|
function user_prevpage() {
|
||||||
|
if (now_userpage > 1) {
|
||||||
|
now_userpage -= 1
|
||||||
|
user_refersh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function user_nextpage() {
|
||||||
|
if (now_userpage < max_userpage) {
|
||||||
|
now_userpage += 1
|
||||||
|
user_refersh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
user_refersh()
|
||||||
|
|
||||||
|
var editor = null;
|
||||||
|
window.onload = function () {
|
||||||
|
snackbar.addEventListener("action-click", () => {
|
||||||
|
snackbar_callback()
|
||||||
|
})
|
||||||
|
const Http = new XMLHttpRequest();
|
||||||
|
const url = '/admin/cfg';
|
||||||
|
Http.open("GET", url);
|
||||||
|
Http.send();
|
||||||
|
|
||||||
|
Http.addEventListener('loadend', () => {
|
||||||
|
var ret = JSON.parse(Http.responseText)
|
||||||
|
if (ret.msg == undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (ret.msg == "") {
|
||||||
|
editor = ace.edit("editor")
|
||||||
|
editor.setTheme("ace/theme/clouds_midnight");
|
||||||
|
editor.setValue(ret.cfg)
|
||||||
|
setTimeout(() => {
|
||||||
|
editor.session.setMode("ace/mode/toml");
|
||||||
|
}, 100)
|
||||||
|
editor.setFontSize(14);
|
||||||
|
} else {
|
||||||
|
dialog(ret.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var last_id = "page_home"
|
||||||
|
function dialog(str) {
|
||||||
|
document.getElementById("dialog").innerHTML = str
|
||||||
|
document.getElementById("dialog").setAttribute("open", "")
|
||||||
|
}
|
||||||
|
function update_btn(page) {
|
||||||
|
document.getElementById(last_id).classList.add("hide")
|
||||||
|
document.getElementById(page).classList.remove("hide")
|
||||||
|
last_id = page
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function update_data() {
|
||||||
|
const Http = new XMLHttpRequest();
|
||||||
|
const url = '/admin/getinfo';
|
||||||
|
Http.open("GET", url);
|
||||||
|
Http.send();
|
||||||
|
|
||||||
|
Http.addEventListener('loadend', () => {
|
||||||
|
var ret = JSON.parse(Http.responseText)
|
||||||
|
if (ret.msg == undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (ret.msg == "") {
|
||||||
|
document.getElementById("users").innerText = ret.users
|
||||||
|
document.getElementById("tokens").innerText = ret.tokens
|
||||||
|
} else {
|
||||||
|
dialog(ret.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function init_db() {
|
||||||
|
const Http = new XMLHttpRequest();
|
||||||
|
const url = '/admin/init';
|
||||||
|
Http.open("POST", url);
|
||||||
|
Http.send();
|
||||||
|
Http.addEventListener('loadend', () => {
|
||||||
|
var ret = JSON.parse(Http.responseText)
|
||||||
|
if (ret.msg == undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dialog(ret.msg)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function reload_cfg() {
|
||||||
|
const Http = new XMLHttpRequest();
|
||||||
|
const url = '/admin/reload';
|
||||||
|
Http.open("POST", url);
|
||||||
|
Http.send();
|
||||||
|
Http.addEventListener('loadend', () => {
|
||||||
|
var ret = JSON.parse(Http.responseText)
|
||||||
|
if (ret.msg == undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dialog(ret.msg)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function clean_cache() {
|
||||||
|
const Http = new XMLHttpRequest();
|
||||||
|
const url = '/admin/clean';
|
||||||
|
Http.open("POST", url);
|
||||||
|
Http.send();
|
||||||
|
Http.addEventListener('loadend', () => {
|
||||||
|
var ret = JSON.parse(Http.responseText)
|
||||||
|
if (ret.msg == undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dialog(ret.msg)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
update_data()
|
||||||
|
setInterval(update_data, 10000)
|
||||||
|
|
||||||
|
function save_cfg() {
|
||||||
|
const Http = new XMLHttpRequest();
|
||||||
|
const url = '/admin/cfg';
|
||||||
|
Http.open("POST", url);
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append('wcfg', editor.getValue());
|
||||||
|
Http.send(formData);
|
||||||
|
Http.addEventListener('loadend', () => {
|
||||||
|
var ret = JSON.parse(Http.responseText)
|
||||||
|
if (ret.msg == undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dialog(ret.msg)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
Loading…
Reference in New Issue