niming_backend/utils/dbhelper.py

154 lines
5.2 KiB
Python
Raw Normal View History

2024-11-19 21:22:01 +08:00
from typing import Tuple, Dict, List
2024-11-26 17:38:28 +08:00
from flask import make_response, Response, abort
2024-11-26 09:17:44 +08:00
from sqlalchemy.orm import sessionmaker, aliased
from sqlalchemy import desc, func, literal, and_
2024-11-19 21:22:01 +08:00
from utils import pgclass
2024-11-26 17:38:28 +08:00
from utils.misc import error
2024-11-25 21:51:50 +08:00
from protobuf_files import niming_pb2
2024-11-19 21:22:01 +08:00
class db:
_engine = None
@classmethod
2024-11-19 23:29:01 +08:00
def __init__(cls, engine):
cls._engine = engine
2024-11-19 21:22:01 +08:00
@classmethod
2024-11-19 23:29:01 +08:00
def getsession(cls):
Session = sessionmaker(bind=cls._engine)
2024-11-19 21:22:01 +08:00
return Session()
2024-11-26 09:17:44 +08:00
2024-11-19 21:22:01 +08:00
# role (general) (owner) (admin)
# 獲取單一文章
2024-11-26 17:38:28 +08:00
def solo_article_fetcher(role:str, key) -> Tuple[Dict, int]: # admin, owner, general
2024-11-26 09:17:44 +08:00
table = pgclass.SQLarticle # main
table2 = aliased(table) # comment
2024-11-19 21:22:01 +08:00
with db.getsession() as session:
# query
2024-11-26 09:17:44 +08:00
res = session.query(table.id,
table.content,
table.reference,
table.file_list,
table.hash,
table.igid,
table.mark,
table.ip,
func.coalesce(func.array_agg(table2.id), literal([])).label("comments"))
2024-11-19 21:22:01 +08:00
if role == "owner":
2024-11-26 09:17:44 +08:00
res = res.join(table2, table2.reference == table.id, isouter=True) \
.filter(table.hash == key[0], table.id == key[1])
2024-11-19 21:22:01 +08:00
elif role == "admin":
2024-11-26 09:17:44 +08:00
res = res.join(table2, table2.reference == table.id, isouter=True) \
.filter(table.id == key)
2024-11-19 21:22:01 +08:00
elif role == "general":
2024-11-26 09:17:44 +08:00
res = res.join(table2, and_(table2.reference == table.id, table2.mark == "visible"), isouter=True) \
.filter(table.id == key, table.mark == "visible")
res = res.group_by(table.id, table.content, table.reference, table.file_list,
table.hash, table.igid, table.mark, table.ip).first()
if res is None:
2024-11-26 17:38:28 +08:00
return abort(404)
2024-11-19 21:22:01 +08:00
# mapping
2024-11-26 09:17:44 +08:00
one = {
"id": res[0],
"content":res[1],
"igid":res[5],
"mark":res[6],
"reference":res[2],
"files_id":res[3],
"comments":res[8]
}
if role == "admin":
one["ip"] = res[7]
if role == "owner" or role == "admin":
one["hash"] = res[4]
return one, 200
2024-11-19 21:22:01 +08:00
# 獲取文章列表
2024-11-26 09:17:44 +08:00
def multi_article_fetcher(role:str, page:str, count:int) -> Tuple[bytes, int]: # general, admin
2024-11-19 21:22:01 +08:00
# checker
2024-11-25 21:51:50 +08:00
if page is None or not page.isdigit():
2024-11-26 17:38:28 +08:00
return abort(400)
2024-11-26 09:17:44 +08:00
page = int(page)*count
2024-11-19 21:22:01 +08:00
table = pgclass.SQLarticle
2024-11-26 17:38:28 +08:00
resfn = niming_pb2.FetchResponse()
2024-11-19 21:22:01 +08:00
with db.getsession() as session:
# query
2024-11-26 09:17:44 +08:00
res = session.query(table)
2024-11-19 21:22:01 +08:00
if role == "general":
2024-11-26 09:17:44 +08:00
res = res.filter(table.mark == "visible", table.reference == None)
2024-11-19 21:22:01 +08:00
elif role == "admin":
2024-11-26 09:17:44 +08:00
res = res.filter(table.reference == None)
2024-11-25 21:51:50 +08:00
res = res.order_by(desc(table.id)).offset(page).limit(count).all()
2024-11-26 09:17:44 +08:00
2024-11-19 21:22:01 +08:00
# mapping
for r in res:
2024-11-26 09:17:44 +08:00
one = niming_pb2.FetchResponse.Message(
id = r.id,
content = r.content,
files_id = r.file_list,
igid = r.igid,
mark = r.mark,
ref = r.reference
)
if role == "admin": # 如果是管理員 多給ip 跟 hash
one.hash = r.hash
one.ip = r.ip
resfn.posts.append(one)
2024-11-19 21:22:01 +08:00
2024-11-26 09:17:44 +08:00
return resfn.SerializeToString(), 200
2024-11-19 21:22:01 +08:00
# 刪除文章
2024-11-26 17:38:28 +08:00
def solo_article_remover(role:str, hash:str=None, id:int=None) -> Tuple[Dict, int]: # admin, owner
2024-11-19 21:22:01 +08:00
key = None
if role == "admin": key = id
2024-11-26 09:17:44 +08:00
elif role == "owner": key = (hash, id)
2024-11-19 21:22:01 +08:00
table = pgclass.SQLarticle
with db.getsession() as session:
# 獲取本體
if role == "admin":
res = session.query(table).filter(table.id == key).first()
2024-11-26 09:17:44 +08:00
elif role == "owner":
res = session.query(table).filter(table.hash == key[0], table.id == key[1]).first()
2024-11-19 21:22:01 +08:00
if res is None: # 檢查本體是否存在
2024-11-26 17:38:28 +08:00
return abort(404)
2024-11-19 21:22:01 +08:00
# 刪本體
session.delete(res)
session.commit()
2024-11-26 09:17:44 +08:00
return {"id":res.id, "mark":res.mark}, 200
2024-11-19 21:22:01 +08:00
# 獲取檔案
def solo_file_fetcher(role:str, id:int) -> Tuple[Response, int]: # general, admin
table = pgclass.SQLarticle
ftab = pgclass.SQLfile
with db.getsession() as session:
fres = session.query(ftab).filter(ftab.id == id).first()
if fres is None: # 檢查檔案是否存在
return error("File not found"), 404
if role == "general":
article = session.query(table).filter(table.hash == fres.reference, table.mark == 'visible').first()
elif role == "admin":
article = session.query(table).filter(table.hash == fres.reference).first()
if article is None: # 檢查文章本體是否存在/可以閱覽
return error("File not found"), 404
resp = make_response(fres.binary)
resp.headers.set("Content-Type", fres.type)
resp.headers.set("Content-Disposition", f"attachment; filename=file{fres.id}")
return resp, 200