This commit is contained in:
p23 2024-11-26 09:38:28 +00:00
parent a548599662
commit 34fe546cd6
6 changed files with 30 additions and 49 deletions

View File

@ -4,12 +4,12 @@ import math
import json import json
import jwt import jwt
from flask import Blueprint, request, jsonify, make_response, g from flask import Blueprint, request, jsonify, make_response, g, abort
from bcrypt import hashpw, gensalt, checkpw from bcrypt import hashpw, gensalt, checkpw
from functools import wraps from functools import wraps
from utils import pgclass, setting_loader, logger from utils import pgclass, setting_loader, logger
from utils.misc import error, internal_json2protobuf, error_proto from utils.misc import error, internal_json2protobuf
from utils.dbhelper import db, solo_article_fetcher, multi_article_fetcher, solo_file_fetcher, solo_article_remover from utils.dbhelper import db, solo_article_fetcher, multi_article_fetcher, solo_file_fetcher, solo_article_remover
from utils.platform_consts import PLIST, PLIST_ROOT from utils.platform_consts import PLIST, PLIST_ROOT
from protobuf_files import niming_pb2 from protobuf_files import niming_pb2
@ -204,7 +204,6 @@ def article_del(id:int):
logger.logger("article.delete", "User:%s deleted post (id=%d): last_status=%s"%(opuser.user, result["id"], result["mark"])) logger.logger("article.delete", "User:%s deleted post (id=%d): last_status=%s"%(opuser.user, result["id"], result["mark"]))
return niming_pb2.FetchResponse( return niming_pb2.FetchResponse(
status = niming_pb2.Status.Success,
posts = [ niming_pb2.FetchResponse.Message(id = result["id"], mark = result["mark"]) ] posts = [ niming_pb2.FetchResponse.Message(id = result["id"], mark = result["mark"]) ]
).SerializeToString(), 200 ).SerializeToString(), 200
@ -216,20 +215,20 @@ def article_pend(id:int):
with db.getsession() as session: with db.getsession() as session:
# 確保文章存在 # 確保文章存在
res = session.query(table).filter(table.id==int(id)).first() res = session.query(table).filter(table.id==int(id)).first()
if res is None: return error_proto("fetch", "Post not found"), 404 if res is None: return abort(404)
# 如果文章已經公開 # 如果文章已經公開
if res.mark == "visible": if res.mark == "visible":
return error_proto("fetch", "Post is already visible."), 400 return abort(400)
elif res.mark == "pending": elif res.mark == "pending":
res.mark = "visible" res.mark = "visible"
session.commit() session.commit()
# run IG Post # run IG Post
return niming_pb2.FetchResponse(status=niming_pb2.Status.Success).SerializeToString(), 200 return abort(200)
else: else:
return error_proto("fetch", "Post mark error"), 500 return abort(500)
#################### ####################
# Setting Area # # Setting Area #

View File

@ -3,12 +3,12 @@ import hashlib
import secrets import secrets
import magic import magic
from flask import Blueprint, request, jsonify from flask import Blueprint, request, abort
from google.protobuf.message import DecodeError from google.protobuf.message import DecodeError
from utils import logger, pgclass, setting_loader 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.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 utils.misc import error, internal_json2protobuf
from protobuf_files import niming_pb2 from protobuf_files import niming_pb2
""" """
@ -62,7 +62,6 @@ def owner_getarticle(id:int):
logger.logger("delpost", "Delete post (id=%d): last_status=%s" logger.logger("delpost", "Delete post (id=%d): last_status=%s"
%(result["id"], str(result["mark"]))) %(result["id"], str(result["mark"])))
return niming_pb2.FetchResponse( return niming_pb2.FetchResponse(
status = niming_pb2.Status.Success,
posts = [ niming_pb2.FetchResponse.Message(id = result["id"], mark = result["mark"]) ] posts = [ niming_pb2.FetchResponse.Message(id = result["id"], mark = result["mark"]) ]
).SerializeToString(), 200 ).SerializeToString(), 200
@ -88,12 +87,12 @@ def posting():
# protobuf parse # protobuf parse
recv = niming_pb2.Post() recv = niming_pb2.Post()
try: recv.ParseFromString(request.data) try: recv.ParseFromString(request.data)
except DecodeError: return error_proto("post", "Protobuf decode error"), 400 except DecodeError: return abort(400)
# content and check # content and check
ctx = str(recv.content) ctx = str(recv.content)
if len(ctx) == 0 or len(ctx) > maxword: # length check if len(ctx) == 0 or len(ctx) > maxword: # length check
return error_proto("post", "no content or too many words"), 400 return abort(400)
# hash # hash
seed = ctx + str(time.time()) + str(secrets.token_urlsafe(nbytes=16)) seed = ctx + str(time.time()) + str(secrets.token_urlsafe(nbytes=16))
@ -105,7 +104,7 @@ def posting():
# 檢查指向的文章是否也是留言 # 檢查指向的文章是否也是留言
reftg, code = solo_article_fetcher(role="general", key=ref) reftg, code = solo_article_fetcher(role="general", key=ref)
if code != 200 or reftg["reference"]: if code != 200 or reftg["reference"]:
return error_proto("post", "Invalid Reference"), 400 return abort(400)
else: else:
ref = None ref = None
@ -114,16 +113,16 @@ def posting():
# check - size # check - size
atts = opt["Attachment_Count"] atts = opt["Attachment_Count"]
sizelimit = opt["Attachment_Size"] sizelimit = opt["Attachment_Size"]
if len(files) > atts: return error_proto("post", "Too many files"), 400 if len(files) > atts: return abort(400)
for f in files: for f in files:
if len(f) <= 0 or len(f) > sizelimit: return error_proto("post", "File size error"), 400 if len(f) <= 0 or len(f) > sizelimit: return abort(400)
# check - mimetype # check - mimetype
allowed_mime = opt["Allowed_MIME"] allowed_mime = opt["Allowed_MIME"]
fmimes = [] fmimes = []
for f in files: for f in files:
mime = magic.Magic(mime=True) mime = magic.Magic(mime=True)
type = mime.from_buffer(f) type = mime.from_buffer(f)
if not(type in allowed_mime): return error_proto("post", "File format error"), 400 if not(type in allowed_mime): return abort(400)
fmimes.append(type) fmimes.append(type)
# IP # IP
@ -163,14 +162,13 @@ def posting():
session.commit() # second commit session.commit() # second commit
result_id = data.id result_id = data.id
except: except:
return error_proto("post", "Create new post failed"), 400 return abort(400)
# logger # logger
logger.logger("newpost", "New post (id=%d point to %s): %s"%(result_id, ref, mark)) logger.logger("newpost", "New post (id=%d point to %s): %s"%(result_id, ref, mark))
# to protobuf & return # to protobuf & return
proto_stres = niming_pb2.PostResponse( proto_stres = niming_pb2.PostResponse(
status = niming_pb2.Status.Success,
hash = hash, hash = hash,
id = int(result_id) id = int(result_id)
).SerializeToString() ).SerializeToString()

View File

@ -37,7 +37,5 @@ message FetchResponse {
repeated uint64 comments_id = 9; repeated uint64 comments_id = 9;
} }
// Several post info // Several post info
Status status = 1; repeated Message posts = 1;
repeated Message posts = 2;
optional string failed_message = 3;
} }

View File

@ -13,21 +13,21 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cniming.proto\"@\n\x04Post\x12\x0f\n\x07\x63ontent\x18\x01 \x01(\t\x12\x10\n\x03ref\x18\x02 \x01(\x03H\x00\x88\x01\x01\x12\r\n\x05\x66iles\x18\x03 \x03(\x0c\x42\x06\n\x04_ref\"q\n\x0cPostResponse\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\x12\x0c\n\x04hash\x18\x02 \x01(\t\x12\n\n\x02id\x18\x03 \x01(\x04\x12\x1b\n\x0e\x66\x61iled_message\x18\x04 \x01(\tH\x00\x88\x01\x01\x42\x11\n\x0f_failed_message\"\xb9\x02\n\rFetchResponse\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\x12%\n\x05posts\x18\x02 \x03(\x0b\x32\x16.FetchResponse.Message\x12\x1b\n\x0e\x66\x61iled_message\x18\x03 \x01(\tH\x00\x88\x01\x01\x1a\xb7\x01\n\x07Message\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x0f\n\x07\x63ontent\x18\x02 \x01(\t\x12\x10\n\x03ref\x18\x03 \x01(\x04H\x00\x88\x01\x01\x12\x10\n\x08\x66iles_id\x18\x04 \x03(\x04\x12\x11\n\x04hash\x18\x05 \x01(\tH\x01\x88\x01\x01\x12\x0c\n\x04igid\x18\x06 \x01(\t\x12\x0c\n\x04mark\x18\x07 \x01(\t\x12\x0f\n\x02ip\x18\x08 \x01(\tH\x02\x88\x01\x01\x12\x13\n\x0b\x63omments_id\x18\t \x03(\x04\x42\x06\n\x04_refB\x07\n\x05_hashB\x05\n\x03_ipB\x11\n\x0f_failed_message*!\n\x06Status\x12\n\n\x06\x46\x61iled\x10\x00\x12\x0b\n\x07Success\x10\x01\x62\x06proto3') DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cniming.proto\"@\n\x04Post\x12\x0f\n\x07\x63ontent\x18\x01 \x01(\t\x12\x10\n\x03ref\x18\x02 \x01(\x03H\x00\x88\x01\x01\x12\r\n\x05\x66iles\x18\x03 \x03(\x0c\x42\x06\n\x04_ref\"q\n\x0cPostResponse\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\x12\x0c\n\x04hash\x18\x02 \x01(\t\x12\n\n\x02id\x18\x03 \x01(\x04\x12\x1b\n\x0e\x66\x61iled_message\x18\x04 \x01(\tH\x00\x88\x01\x01\x42\x11\n\x0f_failed_message\"\xf0\x01\n\rFetchResponse\x12%\n\x05posts\x18\x01 \x03(\x0b\x32\x16.FetchResponse.Message\x1a\xb7\x01\n\x07Message\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x0f\n\x07\x63ontent\x18\x02 \x01(\t\x12\x10\n\x03ref\x18\x03 \x01(\x04H\x00\x88\x01\x01\x12\x10\n\x08\x66iles_id\x18\x04 \x03(\x04\x12\x11\n\x04hash\x18\x05 \x01(\tH\x01\x88\x01\x01\x12\x0c\n\x04igid\x18\x06 \x01(\t\x12\x0c\n\x04mark\x18\x07 \x01(\t\x12\x0f\n\x02ip\x18\x08 \x01(\tH\x02\x88\x01\x01\x12\x13\n\x0b\x63omments_id\x18\t \x03(\x04\x42\x06\n\x04_refB\x07\n\x05_hashB\x05\n\x03_ip*!\n\x06Status\x12\n\n\x06\x46\x61iled\x10\x00\x12\x0b\n\x07Success\x10\x01\x62\x06proto3')
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'niming_pb2', globals()) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'niming_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False: if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None DESCRIPTOR._options = None
_STATUS._serialized_start=513 _STATUS._serialized_start=440
_STATUS._serialized_end=546 _STATUS._serialized_end=473
_POST._serialized_start=16 _POST._serialized_start=16
_POST._serialized_end=80 _POST._serialized_end=80
_POSTRESPONSE._serialized_start=82 _POSTRESPONSE._serialized_start=82
_POSTRESPONSE._serialized_end=195 _POSTRESPONSE._serialized_end=195
_FETCHRESPONSE._serialized_start=198 _FETCHRESPONSE._serialized_start=198
_FETCHRESPONSE._serialized_end=511 _FETCHRESPONSE._serialized_end=438
_FETCHRESPONSE_MESSAGE._serialized_start=309 _FETCHRESPONSE_MESSAGE._serialized_start=255
_FETCHRESPONSE_MESSAGE._serialized_end=492 _FETCHRESPONSE_MESSAGE._serialized_end=438
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

View File

@ -1,11 +1,11 @@
from typing import Tuple, Dict, List from typing import Tuple, Dict, List
from flask import make_response, Response, jsonify from flask import make_response, Response, abort
from sqlalchemy.orm import sessionmaker, aliased from sqlalchemy.orm import sessionmaker, aliased
from sqlalchemy import desc, func, literal, and_ from sqlalchemy import desc, func, literal, and_
from utils import pgclass from utils import pgclass
from utils.misc import error, error_proto from utils.misc import error
from protobuf_files import niming_pb2 from protobuf_files import niming_pb2
class db: class db:
@ -23,7 +23,7 @@ class db:
# role (general) (owner) (admin) # role (general) (owner) (admin)
# 獲取單一文章 # 獲取單一文章
def solo_article_fetcher(role:str, key) -> Tuple[Dict | bytes, int]: # admin, owner, general def solo_article_fetcher(role:str, key) -> Tuple[Dict, int]: # admin, owner, general
table = pgclass.SQLarticle # main table = pgclass.SQLarticle # main
table2 = aliased(table) # comment table2 = aliased(table) # comment
with db.getsession() as session: with db.getsession() as session:
@ -51,7 +51,7 @@ def solo_article_fetcher(role:str, key) -> Tuple[Dict | bytes, int]: # admin, ow
res = res.group_by(table.id, table.content, table.reference, table.file_list, res = res.group_by(table.id, table.content, table.reference, table.file_list,
table.hash, table.igid, table.mark, table.ip).first() table.hash, table.igid, table.mark, table.ip).first()
if res is None: if res is None:
return error_proto("fetch", "Post not found"), 404 return abort(404)
# mapping # mapping
one = { one = {
@ -76,13 +76,11 @@ def solo_article_fetcher(role:str, key) -> Tuple[Dict | bytes, int]: # admin, ow
def multi_article_fetcher(role:str, page:str, count:int) -> Tuple[bytes, int]: # general, admin def multi_article_fetcher(role:str, page:str, count:int) -> Tuple[bytes, int]: # general, admin
# checker # checker
if page is None or not page.isdigit(): if page is None or not page.isdigit():
return error_proto("fetch", "Arguments error"), 400 return abort(400)
page = int(page)*count page = int(page)*count
table = pgclass.SQLarticle table = pgclass.SQLarticle
resfn = niming_pb2.FetchResponse( resfn = niming_pb2.FetchResponse()
status = niming_pb2.Status.Success
)
with db.getsession() as session: with db.getsession() as session:
# query # query
@ -112,7 +110,7 @@ def multi_article_fetcher(role:str, page:str, count:int) -> Tuple[bytes, int]: #
# 刪除文章 # 刪除文章
def solo_article_remover(role:str, hash:str=None, id:int=None) -> Tuple[Dict | bytes, int]: # admin, owner def solo_article_remover(role:str, hash:str=None, id:int=None) -> Tuple[Dict, int]: # admin, owner
key = None key = None
if role == "admin": key = id if role == "admin": key = id
elif role == "owner": key = (hash, id) elif role == "owner": key = (hash, id)
@ -125,7 +123,7 @@ def solo_article_remover(role:str, hash:str=None, id:int=None) -> Tuple[Dict | b
elif role == "owner": elif role == "owner":
res = session.query(table).filter(table.hash == key[0], table.id == key[1]).first() res = session.query(table).filter(table.hash == key[0], table.id == key[1]).first()
if res is None: # 檢查本體是否存在 if res is None: # 檢查本體是否存在
return error_proto("fetch", "Post not found!"), 404 return abort(404)
# 刪本體 # 刪本體
session.delete(res) session.delete(res)
session.commit() session.commit()

View File

@ -6,18 +6,6 @@ def error(message:str) -> Response:
return jsonify({"error":message}) return jsonify({"error":message})
def error_proto(type:str, message:str) -> Response:
if type == "post":
proto = niming_pb2.PostResponse()
proto.hash = ""
proto.id = 0
elif type == "fetch":
proto = niming_pb2.FetchResponse()
proto.status = niming_pb2.Status.Failed
proto.failed_message = message
return proto.SerializeToString()
def internal_json2protobuf(original:list|dict) -> bytes: def internal_json2protobuf(original:list|dict) -> bytes:
if isinstance(original, dict): if isinstance(original, dict):
original = [original] original = [original]