diff --git a/database.py b/database.py index d8eea01..41322ed 100644 --- a/database.py +++ b/database.py @@ -1,5 +1,5 @@ import datetime -from sqlalchemy import Boolean, Column, Integer, String, DateTime +from sqlalchemy import Boolean, Column, Integer, String, DateTime, JSON from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.ext.asyncio.session import AsyncSession @@ -20,6 +20,13 @@ async def get_session(): yield s +class Values(Base): + __tablename__ = 'values' + id = Column(Integer, primary_key=True, index=True) + key = Column(String, unique=True) + value = Column(JSON) + + class Codes(Base): __tablename__ = "codes" id = Column(Integer, primary_key=True, index=True) diff --git a/main.py b/main.py index ff77e57..e48f755 100644 --- a/main.py +++ b/main.py @@ -4,15 +4,16 @@ import asyncio from pathlib import Path from fastapi import FastAPI, Depends, UploadFile, Form, File, HTTPException, BackgroundTasks +from starlette.requests import Request from starlette.responses import HTMLResponse, FileResponse from starlette.staticfiles import StaticFiles -from sqlalchemy import select, update +from sqlalchemy import select, update, func from sqlalchemy.ext.asyncio.session import AsyncSession import settings from utils import delete_expire_files, storage, get_code, error_ip_limit, upload_ip_limit -from database import get_session, Codes, init_models +from database import get_session, Codes, init_models, Values from depends import admin_required # 实例化FastAPI @@ -48,16 +49,33 @@ admin_html = open('templates/admin.html', 'r', encoding='utf-8').read() \ .replace('{{keywords}}', settings.KEYWORDS) -@app.get(f'/{settings.ADMIN_ADDRESS}', description='管理页面', response_class=HTMLResponse) +@app.get(f'/{settings.ADMIN_ADDRESS}', description='管理页面') async def admin(): return HTMLResponse(admin_html) @app.post(f'/{settings.ADMIN_ADDRESS}', dependencies=[Depends(admin_required)], description='查询数据库列表') -async def admin_post(s: AsyncSession = Depends(get_session)): - # 查询数据库列表 - codes = (await s.execute(select(Codes))).scalars().all() - return {'detail': '查询成功', 'data': codes} +async def admin_post(page: int = Form(default=1), size: int = Form(default=10), s: AsyncSession = Depends(get_session)): + codes = (await s.execute(select(Codes).offset((page - 1) * size).limit(size))).scalars().all() + total = (await s.execute(select(func.count(Codes.id)))).scalar() + return {'detail': '查询成功', 'data': codes, 'paginate': { + 'page': page, + 'size': size, + 'total': total + }} + + +@app.patch(f'/{settings.ADMIN_ADDRESS}', dependencies=[Depends(admin_required)], description='修改数据库数据') +async def admin_patch(request: Request, s: AsyncSession = Depends(get_session)): + # 从数据库获取系统配置 + # 如果不存在config这个key,就创建一个 + config = (await s.execute(select(Values).filter(Values.key == 'config'))).scalar_one_or_none() + if not config: + s.add(Values(key='config', value=await request.json())) + else: + await s.execute(update(Values).where(Values.key == 'config').values(value=await request.json())) + await s.commit() + return {'detail': '修改成功'} @app.delete(f'/{settings.ADMIN_ADDRESS}', dependencies=[Depends(admin_required)], description='删除数据库记录') @@ -76,16 +94,40 @@ async def admin_delete(code: str, s: AsyncSession = Depends(get_session)): return {'detail': '删除成功'} +@app.get('/config', description='获取系统配置', dependencies=[Depends(admin_required)]) +async def config(s: AsyncSession = Depends(get_session)): + # 从数据库获取系统配置 + data = (await s.execute(select(Values).filter(Values.key == 'config'))).scalar_one_or_none() + return {'detail': '获取成功', 'data': data.value} + + @app.get('/') async def index(): return HTMLResponse(index_html) @app.get('/banner') -async def banner(): +async def banner(s: AsyncSession = Depends(get_session)): + # 数据库查询config + config = (await s.execute(select(Values).filter(Values.key == 'config'))).scalar_one_or_none() + # 如果存在config,就返回config的value + if config and config.value.get('banners'): + return { + 'detail': '查询成功', + 'data': config.value['banners'] + } + # 如果不存在config,就返回默认的banner return { 'detail': 'banner', - 'data': settings.UPLOAD_BANNERS.split(',') + 'data': [{ + 'text': 'FileCodeBox', + 'url': 'https://github.com/vastsa/FileCodeBox', + 'src': '/static/banners/img_1.png' + }, { + 'text': 'FileCodeBox', + 'url': 'https://www.lanol.cn', + 'src': '/static/banners/img_2.png' + }] } diff --git a/templates/admin.html b/templates/admin.html index 8a130e7..b7f159f 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -12,18 +12,26 @@ - + +
- -   + + + 文件管理 + 系统配置 + - - - + + + @@ -49,8 +57,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+ 删除 +
+
+ + 新增Banner + + + 更新 + +
-  
@@ -69,12 +156,25 @@ return { login: false, pwd: '', - files: [], + activeIndex: '2', config: { - error_count: 0, - file_size: 0, - admin_pwd: 'admin' - } + // enable_upload: true, + // max_days: 7, + // error_count: 3, + // error_minute: 10, + // upload_count: 10, + // upload_minute: 10, + // delete_expire_files_interval: 10, + // admin_password: 'admin', + // file_size_limit: 10, + banners: [] + }, + files: [], + paginate: { + page: 1, + size: 10, + total: 0, + }, }; }, mounted: function () { @@ -82,13 +182,55 @@ if (pwd) { login = true; this.pwd = pwd; + axios.get('/config', { + headers: { + pwd: pwd + } + }).then(res => { + console.log(res.data.data) + this.config = res.data.data; + }); this.loginAdmin(); } }, methods: { - loginAdmin: function () { - axios.post('', {}, {'headers': {'pwd': this.pwd}}).then(res => { - this.files = res.data.data; + updateSize: function (value) { + this.paginate.size = value; + this.loginAdmin(); + }, + deleteBanner: function (index) { + this.config.banners.splice(index, 1); + }, + addBanner: function () { + this.config.banners.push({ + 'url': '', + 'src': '', + 'text': '', + }) + }, + updateConfig: function () { + axios.patch('', this.config, { + 'headers': { + 'pwd': this.pwd, + 'Content-Type': 'multipart/json' + } + }).then(res => { + this.$message({ + message: res.data.detail, + type: 'success' + }); + }) + }, + loginAdmin: function (current_page = 1) { + this.paginate.page = current_page; + axios.post('', this.paginate, { + 'headers': { + 'pwd': this.pwd, + 'Content-Type': 'multipart/form-data' + } + }).then(res => { + this.paginate = res.data.paginate; + this.files = res.data.data this.login = true; localStorage.setItem('pwd', this.pwd); }).catch(e => { @@ -96,6 +238,9 @@ this.$message({'message': e.response.data.detail, 'type': 'error'}); }); }, + handleSelect(key, keyPath) { + this.activeIndex = key; + }, deleteFile: function (code) { axios.delete('?code=' + code, {'headers': {'pwd': this.pwd}}).then(res => { this.files = this.files.filter(item => item.code !== code) diff --git a/templates/index.html b/templates/index.html index 6507508..788074b 100644 --- a/templates/index.html +++ b/templates/index.html @@ -93,8 +93,8 @@