From 019688a87cde630e985febb60a9cabc8a7f3ea3f Mon Sep 17 00:00:00 2001 From: pictures2333 Date: Tue, 12 Nov 2024 21:12:23 +0800 Subject: [PATCH] =?UTF-8?q?postgresqlv2=EF=BC=8C=E5=81=B7=E5=81=B7?= =?UTF-8?q?=E5=91=8A=E8=A8=B4=E4=BD=A0=EF=BC=8C1005=E6=98=AF10=E6=9C=8805?= =?UTF-8?q?=E6=97=A5=EF=BC=8C=E6=98=AF=E7=99=BD=E4=B8=8A=E7=8B=90=E5=BC=A7?= =?UTF-8?q?=E7=9A=84=E7=94=9F=E6=97=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 89 ++++++++++++++---------------------- blueprints/article.py | 103 ++++++++++++++++++++++++++++++++++++++++++ pgclass.py | 17 +++++++ requirements.txt | 5 +- supaclient.py | 29 ------------ 5 files changed, 157 insertions(+), 86 deletions(-) create mode 100644 blueprints/article.py create mode 100644 pgclass.py delete mode 100644 supaclient.py diff --git a/app.py b/app.py index 40aa6dc..d41add8 100644 --- a/app.py +++ b/app.py @@ -1,65 +1,44 @@ -from flask import Flask, request, Response -import os, requests, time -from hashlib import sha256 -from supaclient import logger +from flask import Flask from dotenv import load_dotenv -from supabase import Client, create_client load_dotenv() +import os +from sqlalchemy import create_engine +from pgclass import Base, SQLarticle +# blueprints +from blueprints.article import article -# supabase -URL = os.getenv("SUPABASE_IP") + "/" -KEY = os.getenv("SUPABASE_KEY") -supabase = create_client(URL, KEY) +# Global Variables +PG_HOST = os.getenv("PG_HOST") +PG_PORT = os.getenv("PG_PORT") +PG_NAME = os.getenv("PG_NAME") +PG_USER = os.getenv("PG_USER") +PG_PASS = os.getenv("PG_PASS") +JWT_KEY = os.getenv("JWT_KEY") -# app +# Postgresql +engine = create_engine('postgresql+psycopg2://%s:%s@%s:%s/%s'%(PG_USER, PG_PASS, PG_HOST, PG_PORT, PG_NAME)) +Base.metadata.create_all(engine) + +# shared class +class shared(): + def __init__(self, engine): + self.engine = engine + self.SQLarticle = SQLarticle +sh = shared(engine) + +# flask app app = Flask(__name__) app.config["SECRET_KEY"] = os.urandom(64) +app.shared_resource = sh -# main -@app.route("/") -def index(): return "Hello, world!" +# register blueprints +app.register_blueprint(article, url_prefix = "/article") -# reverse proxy -@app.route('/r/',methods=['GET', 'POST']) -def proxy(path): - headers = request.headers +# index +@app.route("/", methods = ["GET", "POST"]) +def index(): + return "Hello, World!" - # process - if request.method == 'GET': - resp = requests.get(f'{URL}{path}', headers = headers) # forward - elif request.method=='POST': - # get items - json_ctx = request.get_json() - # flags - logger_args = [] - # edit request - if path == "rest/v1/niming_posts": # niming post - # hash - hash = sha256( (json_ctx["content"] + str(time.time())).encode() ).hexdigest() - - # ig posting - igid = None - - # set logger - logger_args.append("newpost") - logger_args.append(hash) - - # edit payload - json_ctx["hash"] = hash - json_ctx["igid"] = igid - - # forward - resp = requests.post(f'{URL}{path}',json=json_ctx, headers = headers) - - # logger - logger_res = logger(supabase, logger_args) - - # make response - excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection'] - headers = [(name, value) for (name, value) in resp.raw.headers.items() if name.lower() not in excluded_headers] - response = Response(resp.content, resp.status_code, headers) - return response - -# run +# app run if __name__ == "__main__": - app.run(host = "0.0.0.0", port = 8000, debug = False) \ No newline at end of file + app.run(host="0.0.0.0", port=5000, debug=False) \ No newline at end of file diff --git a/blueprints/article.py b/blueprints/article.py new file mode 100644 index 0000000..3921bb6 --- /dev/null +++ b/blueprints/article.py @@ -0,0 +1,103 @@ +from flask import Blueprint, current_app, request, jsonify +import hashlib +import time +from sqlalchemy.orm import sessionmaker +from sqlalchemy import desc + +article = Blueprint('article', __name__) + +# 匿名文列表 +@article.route('/list', methods = ["GET"]) +def listing(): + # variables + rst = int(request.args.get("start")) + count = int(request.args.get("count")) + + # db + db = current_app.shared_resource.engine + Session = sessionmaker(bind=db) + session = Session() + + # get ctx + table = current_app.shared_resource.SQLarticle + res = session.query(table.id, table.ctx, table.igid, table.created_at, table.mark).order_by(desc(table.id)).filter(table.mark == 'visible').offset(rst).limit(count).all() + + # mapping + res = [ {"id":r[0], "ctx":r[1], "igid":r[2], "created_at":r[3], "mark":r[4]} for r in res ] + + return jsonify(res) + +# 獲取指定文章 +@article.route("/get/", methods = ["GET"]) +def getarticle(id:int): + db = current_app.shared_resource.engine + Session = sessionmaker(bind=db) + session = Session() + + # get ctx + table = current_app.shared_resource.SQLarticle + res = session.query(table.id, table.ctx, table.igid, table.created_at, table.mark).filter(table.id == id).filter(table.mark == 'visible').all() + + # mapping + res = [ {"id":r[0], "ctx":r[1], "igid":r[2], "created_at":r[3], "mark":r[4]} for r in res ] + + return jsonify(res) + +# 上傳文章 +@article.route("/post", methods = ["POST"]) +def posting(): + db = current_app.shared_resource.engine + Session = sessionmaker(bind=db) + session = Session() + + # content + ctx = str(request.json["ctx"]) + if ctx is None: return "No brain no content" + + # hash + seed = ctx + str(time.time()) + hash = hashlib.sha256(seed.encode()).hexdigest() + + # file processing + + # ig posting + igid = None + + # mark + mark = "visible" + + # pg commit + table = current_app.shared_resource.SQLarticle + data = table(hash = hash, ctx = ctx, igid = igid, mark = mark) + session.add(data) + session.commit() + + # pg getdata + res = session.query(table.id, table.ctx, table.igid, table.created_at, table.mark).filter(table.hash == hash).all() + res = [ {"id":r[0], "ctx":r[1], "igid":r[2], "created_at":r[3], "mark":r[4]} for r in res ] + + session.close() + return jsonify(res) + +# 只有發文者可以看到的獲取指定文章 +# 只有發文者可以做到的刪除文章 +@article.route("/own/", methods = ["GET", "DELETE"]) +def owner_getarticle(sha256:str): + db = current_app.shared_resource.engine + Session = sessionmaker(bind=db) + session = Session() + table = current_app.shared_resource.SQLarticle + + # 獲取指定文章 + if request.method == "GET": + res = session.query(table.id, table.ctx, table.igid, table.created_at, table.mark, table.hash).filter(table.hash == sha256).all() + res = [ {"id":r[0], "ctx":r[1], "igid":r[2], "created_at":r[3], "mark":r[4], "hash":r[5]} for r in res ] + return jsonify(res) + # 刪除指定文章 + elif request.method == "DELETE": + res = session.query(table).filter(table.hash == sha256).first() + session.delete(res) + session.commit() + return "OK", 200 + + session.close() \ No newline at end of file diff --git a/pgclass.py b/pgclass.py new file mode 100644 index 0000000..d54d911 --- /dev/null +++ b/pgclass.py @@ -0,0 +1,17 @@ +from sqlalchemy import Column, Integer, String, TIMESTAMP, func +from sqlalchemy.ext.declarative import declarative_base + +Base = declarative_base() + +class SQLarticle(Base): + __tablename__ = 'posts' + + id = Column(Integer, primary_key=True) + created_at = Column(TIMESTAMP(timezone=True), server_default=func.now()) + hash = Column(String) + ctx = Column(String) + igid = Column(String) + mark = Column(String) + + def __repr__(self): + return f"" \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 2bf9f7d..90de530 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +sqlalchemy flask -python-dotenv -supabase \ No newline at end of file +pyjwt +psycopg2 \ No newline at end of file diff --git a/supaclient.py b/supaclient.py deleted file mode 100644 index e10d880..0000000 --- a/supaclient.py +++ /dev/null @@ -1,29 +0,0 @@ -from supabase import Client, create_client -from dotenv import load_dotenv -import os - -load_dotenv() - -# service url -URL = os.getenv("SUPABASE_IP") -# service key -KEY = os.getenv("SUPABASE_KEY") - -class supaClient: - def __init__(self): - self.client = create_client(URL, KEY) - -# logger -def logger(dbclient: Client, args: list): - if len(args) == 2 and args[0] == "newpost": - hash:str = args[1] - pres = dbclient.table("niming_posts").select("id, hash").eq("hash", hash).execute() - id = int(pres.data[0]["id"]) - - dbres = dbclient.table("niming_log").insert({ - "message": "[id=%d] new post"%id, - "source": "client" - }).execute() - - return dbres - return None \ No newline at end of file