fix:admin

This commit is contained in:
lan
2023-01-16 20:20:46 +08:00
parent a8052c647d
commit b6c0bc04fa
5 changed files with 81 additions and 84 deletions
+14 -5
View File
@@ -4,10 +4,10 @@ from sqlalchemy import Boolean, Column, Integer, String, DateTime, JSON, Text, s
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.ext.asyncio.session import AsyncSession
from settings import settings
engine = create_async_engine(settings.DATABASE_URL)
Base = declarative_base()
@@ -33,7 +33,7 @@ class Codes(Base):
exp_time = Column(DateTime, nullable=True)
async def init_models():
async def init_models(s):
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
if await conn.scalar(select(Options).filter(Options.key == 'INSTALL')) is None:
@@ -41,6 +41,12 @@ async def init_models():
await conn.execute(delete(table=Options))
await conn.execute(insert(table=Options, values=[
{'key': 'INSTALL', 'value': settings.VERSION},
{'key': 'DEBUG', 'value': settings.DEBUG},
{'key': 'DATABASE_FILE', 'value': settings.DATABASE_FILE},
{'key': 'PORT', 'value': settings.PORT},
{'key': 'DATA_ROOT', 'value': settings.DATA_ROOT},
{'key': 'LOCAL_ROOT', 'value': settings.LOCAL_ROOT},
{'key': 'STATIC_URL', 'value': settings.STATIC_URL},
{'key': 'BANNERS', 'value': settings.BANNERS},
{'key': 'ENABLE_UPLOAD', 'value': settings.ENABLE_UPLOAD},
{'key': 'MAX_DAYS', 'value': settings.MAX_DAYS},
@@ -66,9 +72,12 @@ async def init_models():
f'请尽快修改后台信息!\n'
f'FileCodeBox https://github.com/vastsa/FileCodeBox'
)
else:
# 从数据库更新缓存中的setting
await settings.updates(await conn.execute(select(Options).filter()))
await settings.updates(await conn.execute(select(Options).filter()))
async def get_config(key):
async with engine.begin() as conn:
return await conn.scalar(select(Options.value).filter(Options.key == key))
async def get_session():
+2
View File
@@ -58,6 +58,8 @@ class AliyunFileStorage:
upload_filepath = settings.DATA_ROOT + str(now)
await asyncio.to_thread(self._save, upload_filepath, file.file)
self.upload_file(upload_filepath, remote_filepath)
remote_filepath = remote_filepath.strip(f"https://{settings.BUCKET_NAME}.{settings.OSS_ENDPOINT}/")
self.upload_file(upload_filepath, remote_filepath)
await asyncio.to_thread(os.remove, upload_filepath)
async def delete_files(self, texts):
+27 -28
View File
@@ -1,3 +1,4 @@
import asyncio
import datetime
import uuid
from pathlib import Path
@@ -6,16 +7,25 @@ from sqlalchemy.ext.asyncio import AsyncSession
from starlette.requests import Request
from starlette.responses import HTMLResponse, FileResponse
from starlette.staticfiles import StaticFiles
import os, shutil
from core.utils import error_ip_limit, upload_ip_limit, get_code, storage
import os
import shutil
from core.utils import error_ip_limit, upload_ip_limit, get_code, storage, delete_expire_files
from core.depends import admin_required
from settings import settings
from fastapi import FastAPI, Depends, UploadFile, Form, File, HTTPException, BackgroundTasks
from core.database import init_models, Options, Codes, get_session
from settings import settings
# 实例化FastAPI
app = FastAPI(debug=settings.DEBUG, docs_url=None, redoc_url=None)
app = FastAPI(debug=settings.DEBUG, redoc_url=None, )
@app.on_event('startup')
async def startup(s: AsyncSession = Depends(get_session)):
# 初始化数据库
await init_models(s)
# 启动后台任务,不定时删除过期文件
asyncio.create_task(delete_expire_files())
# 数据存储文件夹
DATA_ROOT = Path(settings.DATA_ROOT)
@@ -28,34 +38,27 @@ if not LOCAL_ROOT.exists():
# 静态文件夹,这个固定就行了,静态资源都放在这里
app.mount('/static', StaticFiles(directory='./static'), name="static")
# 首页页面
index_html = open('templates/index.html', 'r', encoding='utf-8').read() \
.replace('{{title}}', settings.TITLE) \
.replace('{{description}}', settings.DESCRIPTION) \
.replace('{{keywords}}', settings.KEYWORDS) \
.replace("'{{fileSizeLimit}}'", str(settings.FILE_SIZE_LIMIT))
index_html = open('templates/index.html', 'r', encoding='utf-8').read()
# 管理页面
admin_html = open('templates/admin.html', 'r', encoding='utf-8').read() \
.replace('{{title}}', settings.TITLE) \
.replace('{{description}}', settings.DESCRIPTION) \
.replace('{{admin_address}}', settings.ADMIN_ADDRESS) \
.replace('{{keywords}}', settings.KEYWORDS)
@app.on_event('startup')
async def startup():
# 初始化数据库
await init_models()
admin_html = open('templates/admin.html', 'r', encoding='utf-8').read()
@app.get('/')
async def index():
return HTMLResponse(index_html)
return HTMLResponse(
index_html.replace('{{title}}', settings.TITLE).replace('{{description}}', settings.DESCRIPTION).replace(
'{{keywords}}', settings.KEYWORDS).replace("'{{fileSizeLimit}}'", str(settings.FILE_SIZE_LIMIT))
)
@app.get(f'/{settings.ADMIN_ADDRESS}', description='管理页面')
async def admin():
return HTMLResponse(admin_html)
return HTMLResponse(
admin_html.replace('{{title}}', settings.TITLE).replace('{{description}}', settings.DESCRIPTION).replace(
'{{admin_address}}', settings.ADMIN_ADDRESS).replace('{{keywords}}', settings.KEYWORDS)
)
@app.get(f'/{settings.ADMIN_ADDRESS}/files', dependencies=[Depends(admin_required)])
@@ -150,14 +153,10 @@ async def admin_patch(request: Request, s: AsyncSession = Depends(get_session)):
await s.execute(update(Options).where(Options.key == key).values(value=value))
await settings.update(key, value)
await s.commit()
await settings.updates([[i.id, i.key, i.value] for i in (await s.execute(select(Options))).scalars().all()])
return {'detail': '修改成功'}
@app.get('/')
async def index():
return HTMLResponse(index_html)
@app.post('/')
async def index(code: str, ip: str = Depends(error_ip_limit), s: AsyncSession = Depends(get_session)):
query = select(Codes).where(Codes.code == code)
+16 -5
View File
@@ -1,8 +1,8 @@
import uuid
from starlette.config import Config
# 配置文件.env
# 请将.env移动至data目录,方便docker部署
# 配置文件.env,存放为data/.env
config = Config("data/.env")
@@ -65,14 +65,25 @@ class Settings:
}]
int_dict = {'PORT', 'MAX_DAYS', 'ERROR_COUNT', 'ERROR_MINUTE', 'UPLOAD_COUNT', 'UPLOAD_MINUTE',
'DELETE_EXPIRE_FILES_INTERVAL', 'FILE_SIZE_LIMIT'}
bool_dict = {'DEBUG', 'ENABLE_UPLOAD'}
async def update(self, key, value) -> None:
if hasattr(self, key):
setattr(self, key, int(value) if key in self.int_dict else value)
if key in self.int_dict:
value = int(value)
elif key in self.bool_dict:
value = value == 'true'
setattr(self, key, value)
async def updates(self, options) -> None:
for i, key, value in options:
await self.update(key, value)
with open('data/.env', 'w', encoding='utf-8') as f:
for i, key, value in options:
print(i, key, value)
# 更新env文件
f.write(f"{key}={value}\n")
# 更新配置
await self.update(key, value)
f.flush()
settings = Settings()
+22 -46
View File
@@ -22,34 +22,6 @@
body {
background: #f5f5f5;
}
@media (prefers-color-scheme: dark) {
body {
background-color: #18181c;
}
.el-card, .el-textarea__inner, .el-upload-dragger {
border-radius: 20px;
border: 1px solid transparent;
background-color: rgba(255, 255, 255, 0.1);
box-shadow: 5px 5px 0 0 rgba(0, 0, 0, 0.2);
}
#app * {
color: #ccc !important;
}
.el-input-group__prepend, .el-menu, .el-menu-item, .el-input__inner, .el-input-group__append, .el-empty__description, .el-select-dropdown, .el-button {
border: 1px solid transparent;
background-color: rgba(0, 0, 0, 0.2);
}
.el-drawer, #el-drawer__title, .el-drawer__body, .el-drawer__wrapper {
background-color: rgba(0, 0, 0, 0.5);
border: 1px solid transparent;
}
}
</style>
</head>
<body>
@@ -74,7 +46,7 @@
<div>&nbsp;&nbsp; ${ file.count }</div>
<div>&nbsp;&nbsp; ${ file.exp_time.slice(0,19) }</div>
<div v-if="file.type==='text'">
<span>&nbsp;&nbsp; ${ file.text }</span>
<span style="white-space: pre-line">&nbsp;&nbsp; ${ file.text }</span>
</div>
<div v-else>
<span>&nbsp;&nbsp; </span>
@@ -121,12 +93,12 @@
</el-col>
<el-col v-if="activeIndex === '4'">
<el-row>
<el-col :span="5" style="height: 88vh;overflow: scroll" :gutter="10">
<el-col :span="4" style="height: 88vh;overflow: scroll;text-align: center" :gutter="10">
<el-card v-for="menu in menus" :key="menu.key">
<div style="cursor: pointer;" @click="updateTab=menu.key">${menu.name}</div>
</el-card>
</el-col>
<el-col :span="19">
<el-col :span="20">
<el-card style="height: 88vh;overflow: scroll">
<div v-if="updateTab=='INSTALL'">
<div>
@@ -158,13 +130,8 @@
<div v-else-if="updateTab=='WEBSITE'">
<el-form ref="form" style="margin:1rem auto" :model="config" label-width="200px">
<el-form-item label="后台密码">
<el-input type="password" v-model="config.ADMIN_PASSWORD" placeholder="网站名称"></el-input>
</el-form-item>
<el-form-item>
<el-alert
title="下列信息修改后需要手动重启系统"
type="warning">
</el-alert>
<el-input type="password" v-model="config.ADMIN_PASSWORD"
placeholder="网站名称"></el-input>
</el-form-item>
<el-form-item label="网站名称">
<el-input v-model="config.TITLE" placeholder="网站名称"></el-input>
@@ -175,6 +142,12 @@
<el-form-item label="网站关键词">
<el-input v-model="config.KEYWORDS" placeholder="网站关键词"></el-input>
</el-form-item>
<el-form-item>
<el-alert
title="下列信息修改后需要手动重启系统"
type="warning">
</el-alert>
</el-form-item>
<el-form-item label="后台地址">
<el-input v-model="config.ADMIN_ADDRESS" placeholder="后台地址"></el-input>
</el-form-item>
@@ -272,19 +245,21 @@
if (pwd) {
login = true;
this.pwd = pwd;
axios.get(window.location.href + '/config', {
headers: {
pwd: pwd
}
}).then(res => {
this.config = res.data.data;
this.menus = res.data.menus;
});
this.loginAdmin();
this.getLocalFiles();
}
},
methods: {
getConfig: function () {
axios.get(window.location.href + '/config', {
headers: {
pwd: this.pwd
}
}).then(res => {
this.config = res.data.data;
this.menus = res.data.menus;
});
},
updateSize: function (value) {
this.paginate.size = value;
this.loginAdmin();
@@ -327,6 +302,7 @@
this.files = res.data.data
this.login = true;
localStorage.setItem('pwd', this.pwd);
this.getConfig();
}).catch(e => {
localStorage.clear()
this.$message({'message': e.response.data.detail, 'type': 'error'});