niming_backend/blueprints/article.py
2024-11-25 13:51:50 +00:00

161 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import time
import hashlib
import magic
from flask import Blueprint, request, jsonify
from google.protobuf.message import DecodeError
from utils import logger, pgclass, setting_loader
from utils.dbhelper import db, solo_article_fetcher, multi_article_fetcher, solo_file_fetcher, solo_article_remover
from utils.misc import error, error_proto, internal_json2protobuf
from protobuf_files import niming_pb2
"""
TODO:
- IG post ( Po文、刪文、只PO本體文章 )
- log 的方式之後要重新設計 > 正規化
- IP Record (deploy之前配合rev proxy)
- gunicorn
- 檔案完成但是再看看要不要讓發文者持sha256存取自己發的文的檔案
"""
article = Blueprint('article', __name__)
# 匿名文列表
@article.route('/list', methods = ["GET"])
def listing():
res, code = multi_article_fetcher("general", request.args.get("page"), 30)
res = internal_json2protobuf(res)
return res, code
# 獲取匿名文附檔
@article.route("/file/<int:id>", methods=["GET"])
def getfile(id:int):
resp, code = solo_file_fetcher("general", id)
return resp, code
# 只有發文者可以看到的獲取指定文章
# 只有發文者可以做到的刪除文章
@article.route("/own/<sha256>", methods = ["GET", "DELETE"])
def owner_getarticle(sha256:str):
table = pgclass.SQLarticle
ftab = pgclass.SQLfile
# 獲取指定文章
if request.method == "GET":
resfn, code = solo_article_fetcher("owner", key=sha256)
return jsonify(resfn), code
# 刪除指定文章跟他們的留言、檔案
elif request.method == "DELETE":
result, code = solo_article_remover("general", hash=sha256)
if "error" in result: return jsonify(result), code
logger.logger("delpost", "Delete post (id=%d with comments %s): last_status=%s"
%(result["id"], str(result["rcl"]), str(result["mark"])))
return jsonify({"result":"OK"}), code
# 獲取指定文章
@article.route("/<int:id>", methods = ["GET"])
def getarticle(id:int):
resfn, code = solo_article_fetcher("general", key=id)
return jsonify(resfn), code
# 上傳文章 / 留言
@article.route("/", methods = ["POST"])
def posting():
# flow:
# ctx -> hash -> reference -> file -> IP -> IG -> mark -> post | -> log
# loadset
opt = setting_loader.loadset()
chk_before_post = opt["Check_Before_Post"]
maxword = opt["Niming_Max_Word"]
# protobuf parse
recv = niming_pb2.Post()
try: recv.ParseFromString(request.data)
except DecodeError: return error_proto("Protobuf decode error"), 400
# content
ctx = str(recv.content)
if len(ctx) == 0 or len(ctx) > maxword: # length check
return error_proto("no content or too many words"), 400
# hash
seed = ctx + str(time.time())
hash = hashlib.sha256(seed.encode()).hexdigest()
# SQL start
table = pgclass.SQLarticle
with db.getsession() as session:
# reference
ref = int(recv.ref)
if not (ref == 0): # 如果ref不是0
# 檢查是不是指向存在的文章
chk = session.query(table).filter(table.id == ref, table.mark == "visible").first()
if chk is None: return error_proto("Invalid Reference"), 400
# 檢查指向的文章是否也是留言
if not(chk.reference is None): return error_proto("Invalid Reference"), 400
else:
ref = None
# file processing
files = recv.files
# check - size
atts = opt["Attachment_Count"]
sizelimit = opt["Attachment_Size"]
if len(files) > atts: return error_proto("Too many files"), 400
for f in files:
if len(f) <= 0 or len(f) > sizelimit: return error_proto("File size error"), 400
# check - mimetype
allowed_mime = opt["Allowed_MIME"]
for f in files:
mime = magic.Magic(mime=True)
type = mime.from_buffer(f)
if not(type in allowed_mime): return error_proto("File format error"), 400
# run processor
ftab = pgclass.SQLfile
for f in files:
mime = magic.Magic(mime=True)
type = mime.from_buffer(f)
fsql = ftab(reference = hash, binary = f, type = type)
session.add(fsql)
# IP
ip = request.remote_addr
# ig posting
if chk_before_post:
igid = None
# Go posting
igid = None
# Coming Soon...
# mark
if chk_before_post: mark = "pending"
else: mark = "visible"
# posting
data = table(hash = hash, content = ctx, igid = igid, mark = mark, reference = ref, ip = ip)
session.add(data)
session.commit()
result, code = solo_article_fetcher(role="owner", key=hash)
# logger
logger.logger("newpost", "New post (id=%d point to %s): %s"%(result["id"], ref, mark))
# to protobuf
proto = niming_pb2.PostResponse()
proto.status = niming_pb2.PostStatus.Success
proto.hash = hash
proto.id = int(result["id"])
proto_stres = proto.SerializeToString()
rr = niming_pb2.PostResponse()
rr.ParseFromString(proto_stres)
print(rr.hash)
print(proto_stres)
return proto_stres, code
# 介面全部改成protobuf傳輸
# 檔案傳輸加低畫質版本(縮圖)