2024-02-02 01:51:03 +10:00
|
|
|
|
from flask import Flask, render_template, request, jsonify, make_response
|
2024-01-30 13:50:38 +10:00
|
|
|
|
|
2023-07-01 20:29:27 +10:00
|
|
|
|
from flask_assets import Bundle, Environment
|
2023-07-12 01:50:29 +10:00
|
|
|
|
from arango import ArangoClient
|
2023-07-20 01:28:34 +10:00
|
|
|
|
from minio import Minio
|
2023-07-20 01:24:15 +10:00
|
|
|
|
|
|
|
|
|
import socket, os
|
2023-07-01 20:29:27 +10:00
|
|
|
|
|
2023-07-03 23:02:48 +10:00
|
|
|
|
|
2023-09-28 14:56:29 +10:00
|
|
|
|
|
|
|
|
|
|
2023-07-01 20:29:27 +10:00
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
|
|
|
|
|
assets = Environment(app)
|
2023-07-03 23:28:41 +10:00
|
|
|
|
css = Bundle("src/*.css", output="dist/main.css")
|
2023-07-01 20:29:27 +10:00
|
|
|
|
|
|
|
|
|
# https://unpkg.com/htmx.org
|
2023-07-20 01:45:56 +10:00
|
|
|
|
#js = Bundle("src/*.js", output="dist/main.js")
|
2023-07-01 20:29:27 +10:00
|
|
|
|
|
2023-07-03 23:28:41 +10:00
|
|
|
|
assets.register("css", css)
|
2023-07-20 01:45:56 +10:00
|
|
|
|
#assets.register("js", js)
|
2023-07-03 23:28:41 +10:00
|
|
|
|
css.build()
|
2023-07-20 01:45:56 +10:00
|
|
|
|
#js.build()
|
2023-07-01 20:29:27 +10:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-07-14 01:52:00 +10:00
|
|
|
|
docker_short_id = socket.gethostname()
|
2023-07-12 01:43:59 +10:00
|
|
|
|
|
2023-07-17 12:56:15 +10:00
|
|
|
|
arango_client = ArangoClient(hosts='https://arango.guaranteedstruggle.host')
|
2024-08-04 12:53:06 +10:00
|
|
|
|
db = arango_client.db('board1', username='root', password='123-very-unsafe-way-to-protect-yourself321')
|
2023-09-28 14:56:29 +10:00
|
|
|
|
|
|
|
|
|
|
2023-07-12 01:50:29 +10:00
|
|
|
|
# предполагается что меняться список будет весьма редко, поэтому подхватываем при лишь при перезапуске
|
2024-02-02 18:59:34 +10:00
|
|
|
|
# # boards0 = db.collection('boards')
|
|
|
|
|
# # print(boards0)
|
|
|
|
|
# # board_list = [ k['_key'] for k in boards0]
|
2023-07-12 01:43:59 +10:00
|
|
|
|
|
2023-07-03 22:46:40 +10:00
|
|
|
|
|
2024-01-30 13:50:38 +10:00
|
|
|
|
|
|
|
|
|
@app.route("/get_my_ip")
|
|
|
|
|
def get_my_ip():
|
2024-01-30 13:51:23 +10:00
|
|
|
|
return jsonify({'ip': request.remote_addr,
|
|
|
|
|
'real-ip': request.environ.get('HTTP_X_REAL_IP', request.remote_addr)}), 200
|
2024-01-30 13:50:38 +10:00
|
|
|
|
|
|
|
|
|
|
2023-07-03 22:46:40 +10:00
|
|
|
|
@app.route('/liveness')
|
|
|
|
|
def healthx():
|
|
|
|
|
return "<h1><center>Liveness check completed</center><h1>"
|
|
|
|
|
|
|
|
|
|
@app.route('/readiness')
|
|
|
|
|
def healthz():
|
2023-09-28 14:56:29 +10:00
|
|
|
|
#### TODU return arango check
|
|
|
|
|
|
2023-07-03 22:46:40 +10:00
|
|
|
|
return "<h1><center>Readiness check completed</center><h1>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-07-01 20:29:27 +10:00
|
|
|
|
@app.route("/")
|
2024-01-30 01:49:36 +10:00
|
|
|
|
def homepage():
|
|
|
|
|
boards0 = db.collection('boards')
|
|
|
|
|
board_list = [ k['_key'] for k in boards0]
|
2023-07-03 23:02:48 +10:00
|
|
|
|
return render_template("main-page.html", host_id=docker_short_id, boards=board_list)
|
2023-07-03 22:41:49 +10:00
|
|
|
|
|
2024-02-01 03:26:12 +10:00
|
|
|
|
|
|
|
|
|
#### TODO если борды нет, то возвращать 404 мемную
|
|
|
|
|
#### TODO если треда нет, то возвращать 404 мемную
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### DONE route :: /{board}/
|
|
|
|
|
@app.route('/<board>')
|
|
|
|
|
def board_posts(board=None):
|
|
|
|
|
postos = db.collection('posts')
|
|
|
|
|
postos = [ p for p in postos if p.get('root_post') == True and p.get('board') == board ]
|
|
|
|
|
postos = sorted(postos, key=lambda posto: int(posto['_key']), reverse=False)
|
|
|
|
|
|
2024-02-02 18:59:34 +10:00
|
|
|
|
boards0 = db.collection('boards')
|
|
|
|
|
board_list = [ k['_key'] for k in boards0]
|
|
|
|
|
return render_template("board-posts.html", host_id=docker_short_id, postos=postos, board=board, target_post_id=None, boards=board_list)
|
2024-02-01 03:26:12 +10:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### TODO route :: /{board}/{thread}/
|
|
|
|
|
#### TODO убрать отсюда чужие рут-потсы
|
|
|
|
|
@app.route("/<board>/<int:target_post_id>")
|
|
|
|
|
def thread_posts(board=None, target_post_id=None):
|
|
|
|
|
|
|
|
|
|
## взять рут-пост
|
|
|
|
|
## взять всех его детей
|
|
|
|
|
|
|
|
|
|
# postos = db.collection('posts')
|
|
|
|
|
# postos = [ p for p in postos]
|
|
|
|
|
# postos = sorted(postos, key=lambda posto: int(posto['_key']), reverse=False)
|
|
|
|
|
|
|
|
|
|
cursor = db.aql.execute(
|
|
|
|
|
f"""FOR ppp IN posts
|
|
|
|
|
FILTER ppp.root_post == True and ppp._key == "{target_post_id}"
|
2024-02-02 18:59:34 +10:00
|
|
|
|
FOR v IN 1..9999 OUTBOUND ppp post_parents RETURN v"""
|
2024-02-01 03:26:12 +10:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
postos = [ ]
|
|
|
|
|
while not cursor.empty(): # Pop until nothing is left on the cursor.
|
|
|
|
|
postos.append(cursor.pop())
|
|
|
|
|
cursor = db.aql.execute(
|
|
|
|
|
f'RETURN DOCUMENT("posts/{target_post_id}")'
|
|
|
|
|
)
|
|
|
|
|
while not cursor.empty(): # Pop until nothing is left on the cursor.
|
|
|
|
|
postos.append(cursor.pop())
|
|
|
|
|
postos = [ p for p in postos ]
|
|
|
|
|
postos = sorted(postos, key=lambda posto: int(posto['_key']), reverse=False)
|
|
|
|
|
|
|
|
|
|
if not target_post_id:
|
|
|
|
|
target_post_id = postos[0]['_key']
|
|
|
|
|
|
2024-02-02 18:59:34 +10:00
|
|
|
|
|
|
|
|
|
boards0 = db.collection('boards')
|
|
|
|
|
board_list = [ k['_key'] for k in boards0]
|
|
|
|
|
return render_template("interactive-posts.html", board=board, host_id=docker_short_id, postos=postos, target_post_id=target_post_id, boards=board_list)
|
2024-02-01 03:26:12 +10:00
|
|
|
|
|
2024-02-02 01:51:03 +10:00
|
|
|
|
|
|
|
|
|
#### TODO route :: /{board}/create_thread/{target_post_id}
|
|
|
|
|
@app.route("/<board>/create-thread/<target_post_id>", methods=['POST'])
|
|
|
|
|
def create_thread(board=None, target_post_id=None):
|
|
|
|
|
|
|
|
|
|
postos = db.collection('posts')
|
|
|
|
|
data = request.form['send_this_text']
|
|
|
|
|
|
|
|
|
|
metadata = postos.insert({
|
|
|
|
|
'texto': data,
|
|
|
|
|
"root_post": True,
|
|
|
|
|
'board': board,
|
|
|
|
|
'images': [],
|
|
|
|
|
"children_num": 0,
|
|
|
|
|
"answers_num": 0,
|
|
|
|
|
"answers_list": [ [], [], [] ]
|
|
|
|
|
}, overwrite_mode='update')
|
|
|
|
|
|
|
|
|
|
response = make_response()
|
|
|
|
|
response.headers["HX-Redirect"] = f"/{board}/{metadata['_key']}"
|
|
|
|
|
response.status_code = 200
|
|
|
|
|
return response
|
|
|
|
|
|
2024-02-01 03:26:12 +10:00
|
|
|
|
|
|
|
|
|
#### TODO route :: /{board}/{thread}/answer_post/
|
|
|
|
|
|
|
|
|
|
#### TODO route :: /{board}/{thread}/post_to_another_post/
|
|
|
|
|
|
2023-07-03 23:18:37 +10:00
|
|
|
|
|
2024-02-02 18:59:34 +10:00
|
|
|
|
# @app.route('/db_posts')
|
|
|
|
|
# @app.route("/db_posts/<target_post_id>")
|
|
|
|
|
# def page_posts_from_db(target_post_id=None):
|
2023-07-13 19:50:45 +10:00
|
|
|
|
|
2024-02-02 18:59:34 +10:00
|
|
|
|
# postos = db.collection('posts')
|
|
|
|
|
# postos = [ p for p in postos]
|
|
|
|
|
# postos = sorted(postos, key=lambda posto: int(posto['_key']), reverse=False)
|
2023-07-18 23:59:10 +10:00
|
|
|
|
|
2024-02-01 03:26:12 +10:00
|
|
|
|
|
2024-02-02 18:59:34 +10:00
|
|
|
|
# for p in postos:
|
|
|
|
|
# #if p['root_post']:
|
|
|
|
|
# print(p)
|
2024-02-01 03:26:12 +10:00
|
|
|
|
|
2024-02-02 18:59:34 +10:00
|
|
|
|
# if not target_post_id:
|
|
|
|
|
# target_post_id = postos[0]['_key']
|
2023-07-18 23:59:10 +10:00
|
|
|
|
|
2024-02-02 18:59:34 +10:00
|
|
|
|
# return render_template("interactive-posts.html", host_id=docker_short_id, postos=postos, target_post_id=target_post_id)
|
2023-07-13 19:50:45 +10:00
|
|
|
|
|
2023-07-19 00:28:45 +10:00
|
|
|
|
|
2024-02-02 18:59:34 +10:00
|
|
|
|
@app.route("/<board>/answer_post/<target_post_id>", methods=['POST'])
|
|
|
|
|
def answer_post(board, target_post_id):
|
2023-07-19 00:28:45 +10:00
|
|
|
|
|
|
|
|
|
postos = db.collection('posts')
|
2024-02-01 03:26:12 +10:00
|
|
|
|
postos = [ p for p in postos ]
|
2024-01-26 19:05:33 +10:00
|
|
|
|
postos = sorted(postos, key=lambda posto: int(posto['_key']), reverse=False)
|
2023-07-19 00:28:45 +10:00
|
|
|
|
|
2024-02-02 18:59:34 +10:00
|
|
|
|
## ?? wut
|
2023-07-19 00:28:45 +10:00
|
|
|
|
if not target_post_id:
|
|
|
|
|
target_post_id = postos[0]['_key']
|
|
|
|
|
|
2024-02-02 18:59:34 +10:00
|
|
|
|
return render_template("answer-post.html", board=board, target_post_id=target_post_id)
|
2023-07-19 00:28:45 +10:00
|
|
|
|
|
|
|
|
|
|
2023-09-28 23:31:24 +10:00
|
|
|
|
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'mp4', 'webm', 'webp'}
|
|
|
|
|
def allowed_file(filename):
|
2024-01-31 23:53:00 +10:00
|
|
|
|
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
2023-07-19 00:28:45 +10:00
|
|
|
|
|
2024-02-02 18:59:34 +10:00
|
|
|
|
@app.route('/<board>/post_to_another_post/<post_key>', methods=['POST'])
|
|
|
|
|
def post_to_post(board, post_key):
|
2023-07-19 00:14:13 +10:00
|
|
|
|
|
2023-09-28 14:56:29 +10:00
|
|
|
|
|
2023-11-15 22:30:31 +10:00
|
|
|
|
#### TODO resize pics https://stackoverflow.com/questions/53337318/how-can-i-resize-image-with-pil-on-upload-and-serve-them-with-flask-cloudy
|
2023-09-28 14:56:29 +10:00
|
|
|
|
#### TODO allow only imgs, videos, and gifs
|
|
|
|
|
if 'file' in request.files:
|
2023-07-20 16:20:11 +10:00
|
|
|
|
|
|
|
|
|
minioClient = Minio( "static.guaranteedstruggle.host" )
|
|
|
|
|
bucket_name = "thread-pics"
|
|
|
|
|
|
2023-09-28 14:56:29 +10:00
|
|
|
|
files = request.files.getlist("file")
|
|
|
|
|
for file in files:
|
|
|
|
|
size = os.fstat(file.fileno()).st_size
|
2023-11-15 22:30:31 +10:00
|
|
|
|
#### работает ли??
|
2023-09-28 23:31:24 +10:00
|
|
|
|
if allowed_file(file.filename):
|
|
|
|
|
minioClient.put_object(
|
|
|
|
|
bucket_name, file.filename, file, size
|
|
|
|
|
)
|
2023-11-15 22:30:31 +10:00
|
|
|
|
|
2023-09-28 23:31:24 +10:00
|
|
|
|
else:
|
|
|
|
|
print(f'somebody tried to put this inside minio: {file.filename} size: {size}')
|
2023-07-20 16:20:11 +10:00
|
|
|
|
|
|
|
|
|
|
2024-02-02 01:51:03 +10:00
|
|
|
|
postos = db.collection('posts')
|
2023-07-19 00:14:13 +10:00
|
|
|
|
data = request.form['send_this_text']
|
|
|
|
|
|
2024-02-02 18:59:34 +10:00
|
|
|
|
|
|
|
|
|
cursor = db.aql.execute(
|
|
|
|
|
f'RETURN DOCUMENT("posts/{post_key}")'
|
|
|
|
|
)
|
|
|
|
|
p = cursor.pop()
|
|
|
|
|
|
|
|
|
|
if p.get('root_post') == True:
|
|
|
|
|
thread = p.get('_key')
|
|
|
|
|
elif not p.get('root_post'):
|
|
|
|
|
thread = p.get('thread')
|
|
|
|
|
else:
|
|
|
|
|
thread = 'ERROR'
|
|
|
|
|
|
|
|
|
|
print(p)
|
2023-07-19 00:14:13 +10:00
|
|
|
|
metadata = postos.insert({
|
2024-02-02 18:59:34 +10:00
|
|
|
|
'texto': data,
|
2024-01-30 00:02:38 +10:00
|
|
|
|
'parent_post': f'{post_key}',
|
2024-02-02 18:59:34 +10:00
|
|
|
|
'images': [],
|
|
|
|
|
"thread": thread
|
2023-07-19 00:14:13 +10:00
|
|
|
|
}, overwrite_mode='update')
|
|
|
|
|
|
|
|
|
|
metadata = db.collection('post_parents').insert({
|
|
|
|
|
'_from': f'posts/{post_key}',
|
|
|
|
|
'_to': f'posts/{metadata["_key"]}'
|
|
|
|
|
}, overwrite_mode='update')
|
|
|
|
|
|
|
|
|
|
|
2024-02-02 18:59:34 +10:00
|
|
|
|
#### TODO оптимайз для только тредовых штук
|
2023-07-19 00:14:13 +10:00
|
|
|
|
cursor = db.aql.execute(
|
|
|
|
|
"""FOR ppp IN posts
|
|
|
|
|
LET children = (FOR v IN 1..9999 OUTBOUND ppp post_parents RETURN v)
|
|
|
|
|
UPDATE ppp WITH { children_num : COUNT_DISTINCT( children[*]._key ) } IN posts"""
|
|
|
|
|
)
|
|
|
|
|
cursor = db.aql.execute(
|
|
|
|
|
"""FOR ppp IN posts
|
2023-07-19 01:36:02 +10:00
|
|
|
|
LET children = (FOR v IN 1 OUTBOUND ppp post_parents RETURN v)
|
2023-07-19 00:14:13 +10:00
|
|
|
|
UPDATE ppp WITH { answers_num : COUNT_DISTINCT( children[*]._key ) } IN posts"""
|
|
|
|
|
)
|
2023-07-19 01:07:42 +10:00
|
|
|
|
cursor = db.aql.execute(
|
|
|
|
|
"""FOR ppp IN posts
|
2023-07-19 01:36:02 +10:00
|
|
|
|
LET children0 = (FOR v IN 1 OUTBOUND ppp post_parents RETURN v)
|
|
|
|
|
LET children = (FOR c IN children0
|
|
|
|
|
SORT c._key DESC
|
|
|
|
|
RETURN c)
|
2023-07-19 01:26:52 +10:00
|
|
|
|
UPDATE ppp WITH { answers_list : [ children[*]._key, children[*].answers_num, children[*].children_num ] } IN posts"""
|
2023-07-19 01:07:42 +10:00
|
|
|
|
)
|
2023-07-19 00:14:13 +10:00
|
|
|
|
|
2024-01-26 19:05:33 +10:00
|
|
|
|
postos = db.collection('posts')
|
2024-02-02 18:59:34 +10:00
|
|
|
|
postos = [ p for p in postos if (not p.get('root_post')) and p.get('thread') == thread ]
|
|
|
|
|
cursor = db.aql.execute(
|
|
|
|
|
f'RETURN DOCUMENT("posts/{thread}")'
|
|
|
|
|
)
|
|
|
|
|
postos.append(cursor.pop())
|
|
|
|
|
|
2024-01-26 19:05:33 +10:00
|
|
|
|
postos = sorted(postos, key=lambda posto: int(posto['_key']), reverse=False)
|
2023-07-19 00:14:13 +10:00
|
|
|
|
|
2024-02-02 18:59:34 +10:00
|
|
|
|
return render_template("i-posts.html", board=board, host_id=docker_short_id, postos=postos)
|
2023-07-19 00:14:13 +10:00
|
|
|
|
|
|
|
|
|
|
2023-07-20 01:24:15 +10:00
|
|
|
|
|
2023-09-28 23:31:24 +10:00
|
|
|
|
#### TODO websockets
|
2024-01-31 23:53:00 +10:00
|
|
|
|
#### TODO sse
|
2023-09-28 23:31:24 +10:00
|
|
|
|
#### TODO kafka
|
2024-01-31 23:53:00 +10:00
|
|
|
|
#### TODO shards
|
2023-11-15 22:30:31 +10:00
|
|
|
|
#### TODO grpc
|
|
|
|
|
|
|
|
|
|
|
2023-07-01 20:29:27 +10:00
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2023-07-02 00:46:17 +10:00
|
|
|
|
app.run(debug=True, host='0.0.0.0')
|