重构中,配置存入数据库,第一次智能生成随机后台地址,登录密码

This commit is contained in:
lan
2023-01-16 16:03:25 +08:00
parent c19da62941
commit ee5beb2261
11 changed files with 230 additions and 230 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
# These are supported funding model platforms # These are supported funding model platforms
github: [vastsa] github: [ vastsa ]
custom: [https://share.lanol.cn] custom: [ https://share.lanol.cn ]
View File
+76
View File
@@ -0,0 +1,76 @@
import datetime
from sqlalchemy import Boolean, Column, Integer, String, DateTime, JSON, Text, select, insert, delete
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()
class Options(Base):
__tablename__ = 'options'
id = Column(Integer, primary_key=True, index=True)
key = Column(String, unique=True, index=True)
value = Column(JSON)
class Codes(Base):
__tablename__ = "codes"
id = Column(Integer, primary_key=True, index=True)
code = Column(String(10), unique=True, index=True)
key = Column(String(30), unique=True)
name = Column(String(500))
size = Column(Integer)
type = Column(String(20))
text = Column(Text)
used = Column(Boolean, default=False)
count = Column(Integer, default=-1)
use_time = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)
exp_time = Column(DateTime, nullable=True)
async def init_models():
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:
# 如果没有存在install,则清空表,并插入默认数据
await conn.execute(delete(table=Options))
await conn.execute(insert(table=Options, values=[
{'key': 'INSTALL', 'value': settings.VERSION},
{'key': 'BANNERS', 'value': settings.BANNERS},
{'key': 'ENABLE_UPLOAD', 'value': settings.ENABLE_UPLOAD},
{'key': 'MAX_DAYS', 'value': settings.MAX_DAYS},
{'key': 'ERROR_COUNT', 'value': settings.ERROR_COUNT},
{'key': 'ERROR_MINUTE', 'value': settings.ERROR_COUNT},
{'key': 'UPLOAD_COUNT', 'value': settings.UPLOAD_COUNT},
{'key': 'UPLOAD_MINUTE', 'value': settings.UPLOAD_MINUTE},
{'key': 'DELETE_EXPIRE_FILES_INTERVAL', 'value': settings.DELETE_EXPIRE_FILES_INTERVAL},
{'key': 'ADMIN_ADDRESS', 'value': settings.ADMIN_ADDRESS},
{'key': 'ADMIN_PASSWORD', 'value': settings.ADMIN_PASSWORD},
{'key': 'FILE_SIZE_LIMIT', 'value': settings.FILE_SIZE_LIMIT},
{'key': 'TITLE', 'value': settings.TITLE},
{'key': 'DESCRIPTION', 'value': settings.DESCRIPTION},
{'key': 'KEYWORDS', 'value': settings.KEYWORDS},
{'key': 'STORAGE_ENGINE', 'value': settings.STORAGE_ENGINE},
{'key': 'STORAGE_CONFIG', 'value': {}},
]))
print(
f'初始化数据库成功!\n'
f'如您未配置.env文件,将为您随机生成信息\n'
f'您的后台地址为:/{settings.ADMIN_ADDRESS}\n'
f'您的管理员密码为:{settings.ADMIN_PASSWORD}\n'
f'请尽快修改后台信息!\n'
f'FileCodeBox https://github.com/vastsa/FileCodeBox'
)
else:
# 从数据库更新缓存中的setting
await settings.update(await conn.execute(select(Options).filter()))
async def get_session():
async with AsyncSession(engine, expire_on_commit=False) as s:
yield s
+4 -1
View File
@@ -3,7 +3,7 @@ from datetime import datetime, timedelta
from fastapi import Header, HTTPException, Request from fastapi import Header, HTTPException, Request
import settings from settings import settings
async def admin_required(pwd: Union[str, None] = Header(default=None), request: Request = None): async def admin_required(pwd: Union[str, None] = Header(default=None), request: Request = None):
@@ -11,6 +11,9 @@ async def admin_required(pwd: Union[str, None] = Header(default=None), request:
if pwd != settings.ADMIN_PASSWORD and not settings.ENABLE_UPLOAD: if pwd != settings.ADMIN_PASSWORD and not settings.ENABLE_UPLOAD:
raise HTTPException(status_code=403, detail='本站上传功能已关闭,仅管理员可用') raise HTTPException(status_code=403, detail='本站上传功能已关闭,仅管理员可用')
else: else:
print(settings.ADMIN_PASSWORD)
if settings.ADMIN_PASSWORD is None:
raise HTTPException(status_code=404, detail='您未设置管理员密码,无法使用此功能,请更新配置文件后,重启系统')
if not pwd or pwd != settings.ADMIN_PASSWORD: if not pwd or pwd != settings.ADMIN_PASSWORD:
raise HTTPException(status_code=401, detail="密码错误,请重新登录") raise HTTPException(status_code=401, detail="密码错误,请重新登录")
+22 -10
View File
@@ -4,11 +4,19 @@ from datetime import datetime
from pathlib import Path from pathlib import Path
from typing import BinaryIO from typing import BinaryIO
from fastapi import UploadFile from fastapi import UploadFile
import settings
import oss2 from core.database import Codes
from settings import settings
if settings.STORAGE_ENGINE == 'aliyunsystem':
try:
import oss2
except ImportError:
os.system('pip install oss2')
import oss2
class AliyunFileStore: class AliyunFileStorage:
def __init__(self): def __init__(self):
auth = oss2.Auth(settings.KeyId, settings.KeySecret) auth = oss2.Auth(settings.KeyId, settings.KeySecret)
self.bucket = oss2.Bucket(auth, settings.OSS_ENDPOINT, settings.BUCKET_NAME) self.bucket = oss2.Bucket(auth, settings.OSS_ENDPOINT, settings.BUCKET_NAME)
@@ -21,10 +29,10 @@ class AliyunFileStore:
now = datetime.now() now = datetime.now()
path = f"FileCodeBox/upload/{now.year}/{now.month}/{now.day}" path = f"FileCodeBox/upload/{now.year}/{now.month}/{now.day}"
text = f"{path}/{f'{key}.{ext}'}" text = f"{path}/{f'{key}.{ext}'}"
return text return f"https://{settings.BUCKET_NAME}.{settings.OSS_ENDPOINT}/{text}"
async def get_filepath(self, text: str): async def get_url(self, info: Codes):
text = text.strip(f"https://{settings.BUCKET_NAME}.{settings.OSS_ENDPOINT}/") text = info.text.strip(f"https://{settings.BUCKET_NAME}.{settings.OSS_ENDPOINT}/")
url = self.bucket.sign_url('GET', text, settings.ACCESSTIME, slash_safe=True) url = self.bucket.sign_url('GET', text, settings.ACCESSTIME, slash_safe=True)
return url return url
@@ -47,10 +55,10 @@ class AliyunFileStore:
async def save_file(self, file: UploadFile, remote_filepath: str): async def save_file(self, file: UploadFile, remote_filepath: str):
now = int(datetime.now().timestamp()) now = int(datetime.now().timestamp())
upload_filepath = settings.DATA_ROOT+str(now) upload_filepath = settings.DATA_ROOT + str(now)
await asyncio.to_thread(self._save, upload_filepath, file.file) await asyncio.to_thread(self._save, upload_filepath, file.file)
self.upload_file(upload_filepath,remote_filepath) self.upload_file(upload_filepath, remote_filepath)
await asyncio.to_thread(os.remove,upload_filepath) await asyncio.to_thread(os.remove, upload_filepath)
async def delete_files(self, texts): async def delete_files(self, texts):
tasks = [self.delete_file(text) for text in texts] tasks = [self.delete_file(text) for text in texts]
@@ -66,10 +74,14 @@ class FileSystemStorage:
self.DATA_ROOT = Path(settings.DATA_ROOT) self.DATA_ROOT = Path(settings.DATA_ROOT)
self.STATIC_URL = settings.STATIC_URL self.STATIC_URL = settings.STATIC_URL
self.NAME = "filesystem" self.NAME = "filesystem"
self.DOWN_PATH = '/select'
async def get_filepath(self, text: str): async def get_filepath(self, text: str):
return self.DATA_ROOT / text.lstrip(self.STATIC_URL + '/') return self.DATA_ROOT / text.lstrip(self.STATIC_URL + '/')
async def get_url(self, info: Codes):
return f'{self.DOWN_PATH}?code={info.code}'
async def get_text(self, file: UploadFile, key: str): async def get_text(self, file: UploadFile, key: str):
ext = file.filename.split('.')[-1] ext = file.filename.split('.')[-1]
now = datetime.now() now = datetime.now()
@@ -122,5 +134,5 @@ class FileSystemStorage:
STORAGE_ENGINE = { STORAGE_ENGINE = {
"filesystem": FileSystemStorage, "filesystem": FileSystemStorage,
"aliyunsystem": AliyunFileStore "aliyunsystem": AliyunFileStorage
} }
+4 -4
View File
@@ -3,10 +3,10 @@ import random
import asyncio import asyncio
from sqlalchemy import or_, select, delete from sqlalchemy import or_, select, delete
from sqlalchemy.ext.asyncio.session import AsyncSession from sqlalchemy.ext.asyncio.session import AsyncSession
import settings from .database import Codes, engine
from database import Codes, engine from .depends import IPRateLimit
from depends import IPRateLimit from .storage import STORAGE_ENGINE
from storage import STORAGE_ENGINE from settings import settings
storage = STORAGE_ENGINE[settings.STORAGE_ENGINE]() storage = STORAGE_ENGINE[settings.STORAGE_ENGINE]()
-42
View File
@@ -1,42 +0,0 @@
import datetime
from sqlalchemy import Boolean, Column, Integer, String, DateTime, JSON, Text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.ext.asyncio.session import AsyncSession
import settings
engine = create_async_engine(settings.DATABASE_URL)
Base = declarative_base()
async def init_models():
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
async def get_session():
async with AsyncSession(engine, expire_on_commit=False) as s:
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)
code = Column(String(10), unique=True, index=True)
key = Column(String(30), unique=True, index=True)
name = Column(String(500))
size = Column(Integer)
type = Column(String(20))
text = Column(Text)
used = Column(Boolean, default=False)
count = Column(Integer, default=-1)
use_time = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)
exp_time = Column(DateTime, nullable=True)
+54 -110
View File
@@ -1,29 +1,18 @@
import datetime import datetime
import uuid import uuid
import asyncio
from pathlib import Path from pathlib import Path
import os from sqlalchemy import select, func, update
from sqlalchemy.ext.asyncio import AsyncSession
from starlette.requests import Request
from starlette.responses import HTMLResponse, FileResponse
from starlette.staticfiles import StaticFiles
try: from core.utils import error_ip_limit, upload_ip_limit, get_code, storage
from fastapi import FastAPI, Depends, UploadFile, Form, File, HTTPException, BackgroundTasks from core.depends import admin_required
from starlette.requests import Request from settings import settings
from starlette.responses import HTMLResponse, FileResponse from fastapi import FastAPI, Depends, UploadFile, Form, File, HTTPException, BackgroundTasks
from starlette.staticfiles import StaticFiles
from sqlalchemy import select, update, func
from sqlalchemy.ext.asyncio.session import AsyncSession
except ImportError:
os.system("pip install -r requirements.txt")
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, func
from sqlalchemy.ext.asyncio.session import AsyncSession
import settings from core.database import init_models, Options, Codes, get_session
from utils import delete_expire_files, storage, get_code, error_ip_limit, upload_ip_limit
from database import get_session, Codes, init_models, Values
from depends import admin_required
# 实例化FastAPI # 实例化FastAPI
app = FastAPI(debug=settings.DEBUG, docs_url=None, redoc_url=None) app = FastAPI(debug=settings.DEBUG, docs_url=None, redoc_url=None)
@@ -34,28 +23,30 @@ if not DATA_ROOT.exists():
DATA_ROOT.mkdir(parents=True) DATA_ROOT.mkdir(parents=True)
# 静态文件夹,这个固定就行了,静态资源都放在这里 # 静态文件夹,这个固定就行了,静态资源都放在这里
app.mount(settings.STATIC_URL, StaticFiles(directory='./static'), name="static") 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))
# 管理页面
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') @app.on_event('startup')
async def startup(): async def startup():
# 初始化数据库 # 初始化数据库
await init_models() await init_models()
# 启动后台任务,不定时删除过期文件
asyncio.create_task(delete_expire_files())
# 首页页面 @app.get('/')
index_html = open('templates/index.html', 'r', encoding='utf-8').read() \ async def index():
.replace('{{title}}', settings.TITLE) \ return HTMLResponse(index_html)
.replace('{{description}}', settings.DESCRIPTION) \
.replace('{{keywords}}', settings.KEYWORDS) \
.replace("'{{fileSizeLimit}}'", str(settings.FILE_SIZE_LIMIT)) \
# 管理页面
admin_html = open('templates/admin.html', 'r', encoding='utf-8').read() \
.replace('{{title}}', settings.TITLE) \
.replace('{{description}}', settings.DESCRIPTION) \
.replace('{{keywords}}', settings.KEYWORDS)
@app.get(f'/{settings.ADMIN_ADDRESS}', description='管理页面') @app.get(f'/{settings.ADMIN_ADDRESS}', description='管理页面')
@@ -65,26 +56,19 @@ async def admin():
@app.post(f'/{settings.ADMIN_ADDRESS}', dependencies=[Depends(admin_required)], description='查询数据库列表') @app.post(f'/{settings.ADMIN_ADDRESS}', dependencies=[Depends(admin_required)], description='查询数据库列表')
async def admin_post(page: int = Form(default=1), size: int = Form(default=10), s: AsyncSession = Depends(get_session)): 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() return {
total = (await s.execute(select(func.count(Codes.id)))).scalar() 'detail': '查询成功',
return {'detail': '查询成功', 'data': codes, 'paginate': { 'data': (await s.execute(select(Codes).offset((page - 1) * size).limit(size))).scalars().all(),
'page': page, 'paginate': {
'size': size, 'page': page,
'total': total 'size': size,
}} 'total': (await s.execute(select(func.count(Codes.id)))).scalar()
}}
@app.patch(f'/{settings.ADMIN_ADDRESS}', dependencies=[Depends(admin_required)], description='修改数据库数据') # @app.patch(f'/{settings.ADMIN_ADDRESS}', dependencies=[Depends(admin_required)], description='修改数据库数据')
async def admin_patch(request: Request, s: AsyncSession = Depends(get_session)): # async def admin_patch(request: Request, s: AsyncSession = Depends(get_session)):
# 从数据库获取系统配置 # return {'detail': '修改成功'}
# 如果不存在config这个key,就创建一个
value = (await s.execute(select(Values).filter(Values.key == 'config'))).scalar_one_or_none()
if not value:
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='删除数据库记录') @app.delete(f'/{settings.ADMIN_ADDRESS}', dependencies=[Depends(admin_required)], description='删除数据库记录')
@@ -103,11 +87,9 @@ async def admin_delete(code: str, s: AsyncSession = Depends(get_session)):
return {'detail': '删除成功'} return {'detail': '删除成功'}
@app.get('/config', description='获取系统配置', dependencies=[Depends(admin_required)]) @app.get(f'/{settings.ADMIN_ADDRESS}/config', description='获取系统配置', dependencies=[Depends(admin_required)])
async def config(s: AsyncSession = Depends(get_session)): async def config(s: AsyncSession = Depends(get_session)):
# 从数据库获取系统配置 return {'detail': '获取成功', 'data': (await s.execute(select(Options))).scalars().all()}
data = (await s.execute(select(Values).filter(Values.key == 'config'))).scalar_one_or_none()
return {'detail': '获取成功', 'data': data.value if data else {'banners': []}}
@app.get('/') @app.get('/')
@@ -127,57 +109,25 @@ async def index(code: str, ip: str = Depends(error_ip_limit), s: AsyncSession =
await s.execute(update(Codes).where(Codes.id == info.id).values(count=info.count - 1)) await s.execute(update(Codes).where(Codes.id == info.id).values(count=info.count - 1))
await s.commit() await s.commit()
if info.type != 'text': if info.type != 'text':
if settings.STORAGE_ENGINE == 'filesystem': info.text = await storage.get_url(info)
info.text = f'/select?code={code}' return {
return { 'detail': f'取件成功,文件将在{settings.DELETE_EXPIRE_FILES_INTERVAL}分钟后删除',
'detail': f'取件成功,文件将在{settings.DELETE_EXPIRE_FILES_INTERVAL}分钟后删除', 'data': {'type': info.type, 'text': info.text, 'name': info.name, 'code': info.code}
'data': {'type': info.type, 'text': info.text, 'name': info.name, 'code': info.code} }
}
elif settings.STORAGE_ENGINE == 'aliyunsystem':
info.text = await storage.get_filepath(info.text) @app.post(f'/{settings.ADMIN_ADDRESS}/download', dependencies=[Depends(admin_required)])
return { async def admin_download_file(filetext: str):
'detail': f'取件成功,链接将在{settings.ACCESSTIME}秒后失效', return await storage.get_text(filetext)
'data': {'type': info.type, 'text': info.text, 'name': info.name, 'code': info.code}
}
@app.post('/adminDownloadFile',dependencies=[Depends(admin_required)], description='管理员获取资源链接')
async def admindownloadfile(filetext: str, s: AsyncSession = Depends(get_session)):
if storage.STORAGE_ENGINE == 'aliyunsystem':
filetext = await storage.get_filepath(filetext)
return {
'detail': f'获取文件链接成功,链接将在{settings.ACCESSTIME}秒后失效',
'fileURL': filetext
}
elif storage.STORAGE_ENGINE == 'filesystem':
return {
'detail': f'获取文件链接成功',
'fileURL':filetext
}
@app.get('/banner') @app.get('/banner')
async def banner(request: Request, s: AsyncSession = Depends(get_session)): async def banner(request: Request):
# 数据库查询config # 数据库查询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'],
'enable': request.headers.get('pwd', '') == settings.ADMIN_PASSWORD or settings.ENABLE_UPLOAD,
}
# 如果不存在config,就返回默认的banner
return { return {
'detail': 'banner', 'detail': '查询成功',
'data': settings.BANNERS,
'enable': request.headers.get('pwd', '') == settings.ADMIN_PASSWORD or settings.ENABLE_UPLOAD, 'enable': request.headers.get('pwd', '') == settings.ADMIN_PASSWORD or settings.ENABLE_UPLOAD,
'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'
}]
} }
@@ -196,10 +146,7 @@ async def get_file(code: str, ip: str = Depends(error_ip_limit), s: AsyncSession
# 如果是文件,返回文件 # 如果是文件,返回文件
else: else:
filepath = await storage.get_filepath(info.text) filepath = await storage.get_filepath(info.text)
if settings.STORAGE_ENGINE == 'filesystem': return FileResponse(filepath, filename=info.name)
return FileResponse(filepath, filename=info.name)
else:
return {'detail': '查询成功', 'data': filepath}
@app.post('/share', dependencies=[Depends(admin_required)], description='分享文件') @app.post('/share', dependencies=[Depends(admin_required)], description='分享文件')
@@ -229,10 +176,7 @@ async def share(background_tasks: BackgroundTasks, text: str = Form(default=None
background_tasks.add_task(storage.save_file, file, _text) background_tasks.add_task(storage.save_file, file, _text)
else: else:
size, _text, _type, name = len(text), text, 'text', '文本分享' size, _text, _type, name = len(text), text, 'text', '文本分享'
if settings.STORAGE_ENGINE == 'aliyunsystem': s.add(Codes(code=code, text=_text, size=size, type=_type, name=name, count=exp_count, exp_time=exp_time, key=key))
_text = f"https://{settings.BUCKET_NAME}.{settings.OSS_ENDPOINT}/"+_text
info = Codes(code=code, text=_text, size=size, type=_type, name=name, count=exp_count, exp_time=exp_time, key=key)
s.add(info)
await s.commit() await s.commit()
upload_ip_limit.add_ip(ip) upload_ip_limit.add_ip(ip)
return { return {
+66 -58
View File
@@ -1,63 +1,71 @@
import uuid
from starlette.config import Config from starlette.config import Config
import os
import shutil
# 配置文件.env # 配置文件.env
# 请将.env移动至data目录,方便docker部署 # 请将.env移动至data目录,方便docker部署
# 判断根目录下是否存在.env文件
if os.path.exists('.env'):
# 将文件复制到data目录
shutil.copy('.env', 'data/.env')
config = Config("data/.env") config = Config("data/.env")
# 是否开启DEBUG模式
DEBUG = config('DEBUG', cast=bool, default=False)
# 端口 class Settings:
PORT = config('PORT', cast=int, default=12345) # 项目版本
# Sqlite数据库文件 VERSION: str = config("VERSION", default="1.6")
DATABASE_FILE = config('DATABASE_FILE', cast=str, default='data/database.db') # 是否开启DEBUG模式
# Sqlite套接字 DEBUG = config('DEBUG', cast=bool, default=False)
DATABASE_URL = config('DATABASE_URL', cast=str, default=f"sqlite+aiosqlite:///{DATABASE_FILE}") # 端口
# 数据存储文件夹,文件就不暴露在静态资源里面了 PORT = config('PORT', cast=int, default=12345)
DATA_ROOT = './data/' + config('DATA_ROOT', cast=str, default=f"static") # Sqlite数据库文件
# 静态文件夹URL DATABASE_FILE = config('DATABASE_FILE', cast=str, default='data/database.db')
STATIC_URL = config('STATIC_URL', cast=str, default="/static") # Sqlite套接字
# 开启上传 DATABASE_URL = config('DATABASE_URL', cast=str, default=f"sqlite+aiosqlite:///{DATABASE_FILE}")
ENABLE_UPLOAD = config('ENABLE_UPLOAD', cast=bool, default=True) # 数据存储文件夹,文件就不暴露在静态资源里面了
# 最长天数 DATA_ROOT = './data/' + config('DATA_ROOT', cast=str, default=f"static")
MAX_DAYS = config('MAX_DAYS', cast=int, default=7) # 静态文件夹URL
# 错误次数 STATIC_URL = config('STATIC_URL', cast=str, default="/static")
ERROR_COUNT = config('ERROR_COUNT', cast=int, default=5) # 开启上传
# 错误限制分钟数 ENABLE_UPLOAD = config('ENABLE_UPLOAD', cast=bool, default=True)
ERROR_MINUTE = config('ERROR_MINUTE', cast=int, default=10) # 最长天数
# 上传次数 MAX_DAYS = config('MAX_DAYS', cast=int, default=7)
UPLOAD_COUNT = config('UPLOAD_COUNT', cast=int, default=60) # 错误次数
# 上传限制分钟数 ERROR_COUNT = config('ERROR_COUNT', cast=int, default=5)
UPLOAD_MINUTE = config('UPLOAD_MINUTE', cast=int, default=1) # 错误限制分钟数
# 删除过期文件的间隔(分钟) ERROR_MINUTE = config('ERROR_MINUTE', cast=int, default=10)
DELETE_EXPIRE_FILES_INTERVAL = config('DELETE_EXPIRE_FILES_INTERVAL', cast=int, default=10) # 上传次数
# 管理地址 UPLOAD_COUNT = config('UPLOAD_COUNT', cast=int, default=60)
ADMIN_ADDRESS = config('ADMIN_ADDRESS', cast=str, default="admin") # 上传限制分钟数
# 管理密码 UPLOAD_MINUTE = config('UPLOAD_MINUTE', cast=int, default=1)
ADMIN_PASSWORD = config('ADMIN_PASSWORD', cast=str, default="admin") # 删除过期文件的间隔(分钟)
# 文件大小限制,默认10MB DELETE_EXPIRE_FILES_INTERVAL = config('DELETE_EXPIRE_FILES_INTERVAL', cast=int, default=10)
FILE_SIZE_LIMIT = config('FILE_SIZE_LIMIT', cast=int, default=10) * 1024 * 1024 # 管理地址
# 网站标题 ADMIN_ADDRESS = config('ADMIN_ADDRESS', cast=str, default=uuid.uuid4().hex)
TITLE = config('TITLE', cast=str, default="文件快递柜") # 管理密码
# 网站描述 ADMIN_PASSWORD = config('ADMIN_PASSWORD', cast=str, default=uuid.uuid4().hex)
DESCRIPTION = config('DESCRIPTION', cast=str, default="FileCodeBox,文件快递柜,口令传送箱,匿名口令分享文本,文件等文件") # 文件大小限制,默认10MB
# 网站关键词 FILE_SIZE_LIMIT = config('FILE_SIZE_LIMIT', cast=int, default=10) * 1024 * 1024
KEYWORDS = config('KEYWORDS', cast=str, default="FileCodeBox,文件快递柜,口令传送箱,匿名口令分享文本,文件等文件") # 网站标题
# 存储引擎:['aliyunsystem','filesystem'] TITLE = config('TITLE', cast=str, default="文件快递柜")
STORAGE_ENGINE = config('STORAGE_ENGINE', cast=str, default="filesystem") # 网站描述
# 如果使用阿里云OSS的话需要创建如下参数 DESCRIPTION = config('DESCRIPTION', cast=str, default="FileCodeBox,文件快递柜,口令传送箱,匿名口令分享文本,文件")
# 阿里云账号AccessKey # 网站关键词
KeyId = config('KeyId', cast=str, default="阿里云账号AccessKey") KEYWORDS = config('KEYWORDS', cast=str, default="FileCodeBox,文件快递柜,口令传送箱,匿名口令分享文本,文件")
# 阿里云账号AccessKeySecret # 存储引擎:['aliyunsystem','filesystem']
KeySecret = config('KeySecret', cast=str, default="阿里云账号AccessKeySecret") STORAGE_ENGINE = config('STORAGE_ENGINE', cast=str, default="filesystem")
# 阿里云OSS Bucket的地域节点 # 存储引擎配置
OSS_ENDPOINT = config('BUCKET_URL', cast=str, default="阿里云OSS Bucket的地域节点") STORAGE_CONFIG = {}
# 阿里云OSS Bucket的BucketName # Banners
BUCKET_NAME = config('BUCKET_NAME', cast=str, default="阿里云OSS Bucket的BucketName") BANNERS = [{
# 访问文件的读取时长(s 'text': 'FileCodeBox',
ACCESSTIME = config('ACCESSTIME', cast=int, default=60) 'url': 'https://github.com/vastsa/FileCodeBox',
'src': '/static/banners/img_1.png'
}, {
'text': 'LanBlog',
'url': 'https://www.lanol.cn',
'src': '/static/banners/img_2.png'
}]
async def update(self, options) -> None:
for i, key, value in options:
if hasattr(self, key):
setattr(self, key, value)
settings = Settings()
+1 -2
View File
@@ -126,12 +126,11 @@
if (pwd) { if (pwd) {
login = true; login = true;
this.pwd = pwd; this.pwd = pwd;
axios.get('/config', { axios.get('{{admin_address}}/config', {
headers: { headers: {
pwd: pwd pwd: pwd
} }
}).then(res => { }).then(res => {
console.log(res.data.data)
this.config = res.data.data; this.config = res.data.data;
}); });
this.loginAdmin(); this.loginAdmin();
+1 -1
View File
@@ -11,7 +11,7 @@
<meta name="description" content="{{description}}"/> <meta name="description" content="{{description}}"/>
<meta name="keywords" content="{{keywords}}"/> <meta name="keywords" content="{{keywords}}"/>
<meta name="generator" content="FileCodeBox"/> <meta name="generator" content="FileCodeBox"/>
<meta name="template" content="Lan-V1.5.9.2"/> <meta name="template" content="Lan-V1.6"/>
<style> <style>
body { body {
background: #f5f5f5; background: #f5f5f5;