From 12c200b31c9a9155ba1ae54712ba1f9515fd42a7 Mon Sep 17 00:00:00 2001 From: shuQAQshu Date: Sat, 27 Dec 2025 17:18:53 +0800 Subject: [PATCH] Initial commit --- app/__pycache__/main.cpython-310.pyc | Bin 0 -> 832 bytes app/__pycache__/settings.cpython-310.pyc | Bin 0 -> 389 bytes app/api/__pycache__/db.cpython-310.pyc | Bin 0 -> 638 bytes app/api/__pycache__/login.cpython-310.pyc | Bin 0 -> 1309 bytes .../__pycache__/submit_record.cpython-310.pyc | Bin 0 -> 1687 bytes app/api/db.py | 24 +++++++++ app/api/login.py | 31 +++++++++++ app/api/submit_record.py | 43 +++++++++++++++ app/base_packages.txt | 7 +++ app/main.py | 28 ++++++++++ app/requirements.txt | 28 ++++++++++ app/settings.py | 12 +++++ environment.yml | 49 ++++++++++++++++++ start_server.py | 9 ++++ 14 files changed, 231 insertions(+) create mode 100644 app/__pycache__/main.cpython-310.pyc create mode 100644 app/__pycache__/settings.cpython-310.pyc create mode 100644 app/api/__pycache__/db.cpython-310.pyc create mode 100644 app/api/__pycache__/login.cpython-310.pyc create mode 100644 app/api/__pycache__/submit_record.cpython-310.pyc create mode 100644 app/api/db.py create mode 100644 app/api/login.py create mode 100644 app/api/submit_record.py create mode 100644 app/base_packages.txt create mode 100644 app/main.py create mode 100644 app/requirements.txt create mode 100644 app/settings.py create mode 100644 environment.yml create mode 100644 start_server.py diff --git a/app/__pycache__/main.cpython-310.pyc b/app/__pycache__/main.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1602bf839a62264e61cc94e0be14ec1667517c6b GIT binary patch literal 832 zcmY*X%We}f6dlhqnPk!=ycTTOri)Q4b_gL_DkOwjsC>wP>5S#~p4#V?>}?#S#Tm2X*anm%BWG7BWjytX(lRWZDY`I=e=%`xDP= z^hn`7W=gMZKS9`f^lWE$Qvk&LkV%e=E3=8_vS$|dI#axGc{&nlx#HuN==o~2ySIax zJrF4z*SFUPHWrDqk6 z7CPod1GpMWk!z8qh4+$6RRXfS*RyHB;y62uGAXdOqMh?}C^_&{3l^(|BH{WVgUj@Q zGeD!li8I`YcW`sb_r(#lH5;KyO$Le3k>tZn!dCAZ_4ct9EEm$m)6-iQS(sdQBt)f> z_zVmzndc#D!^&LRCD*KQblx+1W1+ZGhhD#uF2w#q3@p6#D4bPnbx<{8drApJXtJ`2&JG)iQ>r(In+)<7`=`X_9ide{9brHX<8` K`@37eN&W&jDf1Zs literal 0 HcmV?d00001 diff --git a/app/__pycache__/settings.cpython-310.pyc b/app/__pycache__/settings.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c2d3035ceeaac95d02259406804cbb365fa20d09 GIT binary patch literal 389 zcmYjN%T9w(6of*xsWzIp@fW&*LTQY|m_jer8lVW&#v2ksdyx{$LoQWm;s^OlZ2b#Y zLT#ew?;S4@MaN(`7Rl@>wMRbyl`E1_Cn?_lMLzI zW_b)GTaqP9ac8Dlwk2cYK5(vOo8`&;c48~)#IoJWp(^F+A2FJ$GfjtQ)=btWwreV* zsR@2B)7#A&cq8Yt;wmdKMy1^g?iaWm!o2LQ558v!YkDAAnrlKN1FbRqk zOa(>2d>_bAMMbp5q3o%+h_^VBdnzds2FNhku%eH_28tA8(GxxFi}*`eT*HXCOzer| zGZX{SpFy7fq&biWZcuCF7U$S5nigGhjFwNiqN-^{?Pp#EBal#f(%hx;2`p^j z1H4Z!;T14=4VUnheIq1b_7A^T;o=3_xu|Y>HQuV=W6T1Uuv>w?PVGrP zbg4O$T-Hle7n(c-9a1T7|7S;dZbv&y(-B>8!<`GAR@z(bGMYXzXl>IjjE+4OUs<5Y t0znpNufs(X+Wc0-_P2J*&>trcRVUUGANhTn8&vioWByCRI2=-D;UB$SpH2V( literal 0 HcmV?d00001 diff --git a/app/api/__pycache__/login.cpython-310.pyc b/app/api/__pycache__/login.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..42dedd8195e11b97ec77795d99758df6b8f361c9 GIT binary patch literal 1309 zcmYjQ%}*Og6rY*>_IF8wa&)C0;z}Wh-lDW3fLoBjATUB&Sz0YS18mt3GrJaGnJR&( zhpLv+CY4G_UQeO6S-!P4oSGfrmnNs`)#<5)x>dhFHeF3hmx}S(>BX6vBR+if zNFa>DjfR0RWMYa;vWS?(WQy-Wn;=~&$yI&Z_2$_|i$!swFd@|{N}^j}>9Y9z+3l=~?tal*lGxVGcd?;AI zQa14>suXJN8w=Ix>Uh08KD$_}-}<;x{(OFRrrg%bOOw_4YPoHcKP}%)OXE36nqwfQ z7PTA);L#GQ{^`&C)0c0bbkE)#022d)TF4iJV&n!e6p6x+=e|se4 zK3BkEW-gU!rAY=bIs&gp=rY&9Bhj1N)DB|T;kpoW!XB|Wc7xUEN?%l-Zhwm3L~e$# lDNmPX_0ws&A=XWY|^ zy(=3993%v?gakwhv5^;XfCD&i;Si!6_!n~}YvL0ZP6z?jvrfE5^r&m9tE#K3s=w-} zShNs~3zPHyppMY5a?v|LhAzQOz5+rK#Q_SjjYDFSP_Y#(Wh78T&DJtr3G~pgjf__V zGtAk!jMoAy%-i{l*MmY>w2K*U1f{TKmonZA`s_Z2caYuxDxx`RT}RYn`5na`VEqS! zG~dRIu-pz_#k9Z%Xpw2FDlO5z>)H;s&r!3AD*eY0C#ooEZgOFEF=`0LQ)8ONtWJ}( z_}bFa!px?}V&O;i3QmnGOOh_D3brXgq^~jI&=ufvQ*OfMBFX|-oU2})nwwp67H3|$ zvN-K5O-@~&0kKJ4!Gs^Oc~73(I}})4f|)!EgdrPKWRt6iDNLn!qWdQ&e`Nwu6{6SR zoW@G%i$&%|oG!BU21`V0H4?@h7P@|rmZF$(SH|y%X3Ww;A|mdtF(-CKZ5}+Bj#GC- z<~XV4IAKH^f#eI0v)*un6OEDxp7uG8TdzkVbCx*Hw}=lxs2Tb5rRnkIO*f3=<(i<8 zmn<(#%}r0eu)N}WZ$mAYUC_9(zno;@Iy{SaEN=2VxG2c9O&}IBv55;fleS71yVlQl zty6=a%}ef7QpWv%!>k3LKUj+lJ~J72MX2Nc$*0I zK-(g~DMF{ZFm5Ai>?=EXTiwD3=9UWkb6bk^0@I@Ap4uiDfiB-h06%~m&F_&nQ5C63 z6q>JNv<;AM^?^lETEM9VS`?)%0NZV}PrBz*uzFY9z#FJiny(OBZ^S|5(o_f7Fv0v! zFhY&zAcdn(cOTr_`|XFjoi9J`-2dRXefQ|*VR^V~K3qQf@J4yKyJxsU(tHBf(nuT+ z;3s_vxcXLcGV$Gu)tXyhtGRybf>rJrv-8!N#ijD>{L+qdFx6f&db9>@Sx&#VDL zqvc)*RnB;QWAgIVnQD1tyw~0MfBp3eGKb^;@3EqC35_!thJbhxguEm*M$+&+=*h+t zk4yIO`#YU`pLc%x@xlH5&UZJVIC{4@sS$!DK;QpE7I{$a*xT)V)b8B+=J>N)4-XH2 z|M`nbU)Q@Ty{mCkv{F;{Yb&ZVE-{uW^=N}j#POV58f=q!^4XA)c7xKrD1@F&bB~{n z)Z|eR$X?*`*ow~2OY0|r*rr$W>#ieO{ApOG8niHPrkI^J7njMU#WSrl0HS0R2)Rax z1ubI%RSCh?Kf0!3f>rp;zf8SAO2owHv3ZUB%|~EEWhgaPT_{QHbJ;{(K0G|jx0I|0 zZs65e*c^*^$TiTU)~PT{JGG#f$6)suUEzkbFykh5>%#ZA?BTQ^^$8QgudgLpk+Q<^ zXQWc+*&CZRIMg?SheZa}lWg{;WEqnAk{~oiFMLXOs$On1-fq4 A@&Et; literal 0 HcmV?d00001 diff --git a/app/api/db.py b/app/api/db.py new file mode 100644 index 0000000..bfd5a36 --- /dev/null +++ b/app/api/db.py @@ -0,0 +1,24 @@ +from sqlalchemy import create_engine, MetaData +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker +from app.settings import DATABASE_URL + +# 创建SQLAlchemy引擎 +engine = create_engine(DATABASE_URL) + +# 创建元数据对象 +metadata = MetaData() + +# 创建会话工厂 +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +# 创建基类 +Base = declarative_base() + +# 依赖项:获取数据库会话 +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() \ No newline at end of file diff --git a/app/api/login.py b/app/api/login.py new file mode 100644 index 0000000..7712232 --- /dev/null +++ b/app/api/login.py @@ -0,0 +1,31 @@ +from fastapi import APIRouter, Depends, HTTPException +from sqlalchemy.orm import Session +from sqlalchemy import text +from app.api.db import get_db +from pydantic import BaseModel +from app.settings import WHITELIST_TABLE, WHITELIST_COLUMN + +router = APIRouter() + +# 请求模型 +class EmailRequest(BaseModel): + email: str + +# 检查邮箱是否在白名单中 +@router.post("/check-email") +async def check_email_in_whitelist(request: EmailRequest, db: Session = Depends(get_db)): + try: + # 构建查询语句 + query = text(f"SELECT COUNT(*) FROM {WHITELIST_TABLE} WHERE {WHITELIST_COLUMN} = :email") + + # 执行查询 + result = db.execute(query, {"email": request.email}) + count = result.scalar() + + if count > 0: + return {"status": "success", "message": "继续操作"} + else: + raise HTTPException(status_code=403, detail="邮箱不在白名单中,请联系管理员") + + except Exception as e: + raise HTTPException(status_code=500, detail=f"服务器错误:{str(e)}") \ No newline at end of file diff --git a/app/api/submit_record.py b/app/api/submit_record.py new file mode 100644 index 0000000..962042e --- /dev/null +++ b/app/api/submit_record.py @@ -0,0 +1,43 @@ +from fastapi import APIRouter, Depends, HTTPException +from sqlalchemy.orm import Session +from sqlalchemy import text +from app.api.db import get_db +from pydantic import BaseModel +from app.settings import SUBMIT_RECORD_TABLE +from datetime import datetime +import pytz + +router = APIRouter() + +class SubmitRecordRequest(BaseModel): + user_email: str + operation_type: str + storage_path: str + +@router.post("/submit-record") +async def submit_record(request: SubmitRecordRequest, db: Session = Depends(get_db)): + try: + if request.operation_type not in ['upload', 'delete']: + raise HTTPException(status_code=400, detail="操作类型必须是 'upload' 或 'delete'") + + china_tz = pytz.timezone('Asia/Shanghai') + operation_time = datetime.now(china_tz) + + query = text(f""" + INSERT INTO {SUBMIT_RECORD_TABLE} (user_email, operation_time, operation_type, storage_path) + VALUES (:user_email, :operation_time, :operation_type, :storage_path) + """) + + db.execute(query, { + "user_email": request.user_email, + "operation_time": operation_time, + "operation_type": request.operation_type, + "storage_path": request.storage_path + }) + db.commit() + + return {"status": "success", "message": "操作记录已保存"} + + except Exception as e: + db.rollback() + raise HTTPException(status_code=500, detail=f"服务器错误:{str(e)}") \ No newline at end of file diff --git a/app/base_packages.txt b/app/base_packages.txt new file mode 100644 index 0000000..4a1d7e1 --- /dev/null +++ b/app/base_packages.txt @@ -0,0 +1,7 @@ +name: backend_env +channels: + - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ + - defaults +dependencies: + - python=3.10 +prefix: D:\anaconda3\envs\backend_env diff --git a/app/main.py b/app/main.py new file mode 100644 index 0000000..1d19149 --- /dev/null +++ b/app/main.py @@ -0,0 +1,28 @@ +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware +from app.api.login import router as login_router +from app.api.submit_record import router as submit_record_router +from app.api.db import Base, engine +from app.settings import API_V1_STR + +# 创建数据库表 +Base.metadata.create_all(bind=engine) + +app = FastAPI( + title="PBMDB API", + description="微生物数据库后端API", + version="1.0.0" +) + +# 配置CORS +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], # 在生产环境中应该设置具体的前端域名 + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +# 包含路由 +app.include_router(login_router, prefix=API_V1_STR, tags=["login"]) +app.include_router(submit_record_router, prefix=API_V1_STR, tags=["submit_record"]) diff --git a/app/requirements.txt b/app/requirements.txt new file mode 100644 index 0000000..5063652 --- /dev/null +++ b/app/requirements.txt @@ -0,0 +1,28 @@ +annotated-doc==0.0.4 +annotated-types==0.7.0 +anyio==4.12.0 +async-timeout==5.0.1 +asyncpg==0.31.0 +click==8.3.1 +colorama==0.4.6 +databases==0.9.0 +exceptiongroup==1.3.1 +fastapi==0.125.0 +greenlet==3.3.0 +h11==0.16.0 +httptools==0.7.1 +idna==3.11 +psycopg2==2.9.11 +psycopg2-binary==2.9.11 +pydantic==2.12.5 +pydantic_core==2.41.5 +python-dotenv==1.2.1 +pytz==2025.2 +PyYAML==6.0.3 +SQLAlchemy==2.0.45 +starlette==0.50.0 +typing-inspection==0.4.2 +typing_extensions==4.15.0 +uvicorn==0.38.0 +watchfiles==1.1.1 +websockets==15.0.1 diff --git a/app/settings.py b/app/settings.py new file mode 100644 index 0000000..6cbcec1 --- /dev/null +++ b/app/settings.py @@ -0,0 +1,12 @@ +# 数据库配置 +DATABASE_URL = 'postgresql://ABM_DB_user:4FynWQfy0AEotP1dgyimrGF7PSDJh1nDYnDwg4hN@122.205.95.244:5433/ABM_DB' + +# API配置 +API_V1_STR = "/api/v1" + +# 白名单验证相关配置 +WHITELIST_TABLE = "submit_user" +WHITELIST_COLUMN = "user_email" + +# 操作记录相关配置 +SUBMIT_RECORD_TABLE = "submit_record" \ No newline at end of file diff --git a/environment.yml b/environment.yml new file mode 100644 index 0000000..9b7e6a2 --- /dev/null +++ b/environment.yml @@ -0,0 +1,49 @@ +name: backend_env +channels: + - defaults + - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ +dependencies: + - bzip2=1.0.8=h2bbff1b_6 + - ca-certificates=2025.12.2=haa95532_0 + - expat=2.7.3=h885b0b7_4 + - libexpat=2.7.3=h885b0b7_4 + - libffi=3.4.4=hd77b12b_1 + - libzlib=1.3.1=h02ab6af_0 + - openssl=3.0.18=h543e019_0 + - pip=25.3=pyhc872135_0 + - python=3.10.19=h981015d_0 + - setuptools=80.9.0=py310haa95532_0 + - sqlite=3.51.0=hda9a48d_0 + - tk=8.6.15=hf199647_0 + - tzdata=2025b=h04d1e81_0 + - ucrt=10.0.22621.0=haa95532_0 + - vc=14.3=h2df5915_10 + - vc14_runtime=14.44.35208=h4927774_10 + - vs2015_runtime=14.44.35208=ha6b5a95_10 + - wheel=0.45.1=py310haa95532_0 + - xz=5.6.4=h4754444_1 + - zlib=1.3.1=h02ab6af_0 + - pip: + - annotated-doc==0.0.4 + - annotated-types==0.7.0 + - anyio==4.12.0 + - click==8.3.1 + - colorama==0.4.6 + - exceptiongroup==1.3.1 + - fastapi==0.125.0 + - greenlet==3.3.0 + - h11==0.16.0 + - httptools==0.7.1 + - idna==3.11 + - pydantic==2.12.5 + - pydantic-core==2.41.5 + - python-dotenv==1.2.1 + - pyyaml==6.0.3 + - sqlalchemy==2.0.45 + - starlette==0.50.0 + - typing-extensions==4.15.0 + - typing-inspection==0.4.2 + - uvicorn==0.38.0 + - watchfiles==1.1.1 + - websockets==15.0.1 +prefix: D:\anaconda3\envs\backend_env diff --git a/start_server.py b/start_server.py new file mode 100644 index 0000000..e35dd69 --- /dev/null +++ b/start_server.py @@ -0,0 +1,9 @@ +import uvicorn + +if __name__ == "__main__": + uvicorn.run( + "app.main:app", + host="0.0.0.0", + port=8000, + reload=True + ) \ No newline at end of file