Compare commits

..

20 Commits

Author SHA1 Message Date
Simple_Not
701c5cc6ff upd drone mst
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-16 17:06:19 +10:00
Simple_Not
07b6992295 upd drone oir-stili 2023-11-16 17:05:32 +10:00
Simple_Not
510c19b194 upd drone oir-stili 2023-11-16 17:02:50 +10:00
Simple_Not
45cd3a1d59 upd drone oir-stili 2023-11-16 16:55:12 +10:00
Simple_Not
ca8f8aa510 upd drone oir-stili 2023-11-16 16:43:05 +10:00
Simple_Not
a935aea926 check many hexes
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-18 23:03:27 +10:00
Simple_Not
0768ff5d0e check many hexes
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-18 21:17:26 +10:00
Simple_Not
8cc52a2d2e check many hexes
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-18 21:16:29 +10:00
Simple_Not
5fda9d5444 check many hexes
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-18 21:14:21 +10:00
Simple_Not
af4a8f5b20 check many hexes
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-18 21:13:37 +10:00
Simple_Not
e08d767ded check many hexes
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-18 21:12:25 +10:00
Simple_Not
cf33c91651 check many hexes
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-18 21:11:07 +10:00
Simple_Not
2560ab3d51 check many hexes
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-18 21:09:28 +10:00
Simple_Not
0c3272cac8 check many hexes
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-18 20:19:38 +10:00
Simple_Not
4eb461e0e1 sin fix
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-18 20:05:24 +10:00
Simple_Not
2714b49ea9 sin fix
Some checks failed
continuous-integration/drone/push Build is failing
2023-07-18 20:03:33 +10:00
Simple_Not
0b3e534d63 sin fix
Some checks failed
continuous-integration/drone/push Build is failing
2023-07-18 19:59:14 +10:00
Simple_Not
813a769871 remake many certs
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-17 12:55:47 +10:00
Simple_Not
9d1889232e rm styles
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-16 02:35:06 +10:00
Simple_Not
5afeefa0ba rm styles
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-16 02:32:19 +10:00
25 changed files with 4165 additions and 564 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
__pycache__ __pycache__
static/.webassets_cache

View File

@ -214,3 +214,4 @@ stateDiagram-v2
``` ```

237
app.py
View File

@ -1,13 +1,12 @@
from flask import Flask, render_template, request, jsonify, make_response from flask import Flask, render_template, request
from flask_assets import Bundle, Environment from flask_assets import Bundle, Environment
from todo import todos
#from boards import board_list
from threads import threads_lists
from threads_with_posts import open_threads
from arango import ArangoClient from arango import ArangoClient
from minio import Minio
import socket, os
import socket
app = Flask(__name__) app = Flask(__name__)
@ -15,32 +14,24 @@ assets = Environment(app)
css = Bundle("src/*.css", output="dist/main.css") css = Bundle("src/*.css", output="dist/main.css")
# https://unpkg.com/htmx.org # https://unpkg.com/htmx.org
#js = Bundle("src/*.js", output="dist/main.js") js = Bundle("src/*.js", output="dist/main.js")
assets.register("css", css) assets.register("css", css)
#assets.register("js", js) assets.register("js", js)
css.build() css.build()
#js.build() js.build()
docker_short_id = socket.gethostname() docker_short_id = socket.gethostname()
arango_client = ArangoClient(hosts='https://arango.guaranteedstruggle.host') arango_client = ArangoClient(hosts='https://arango.guaranteedstruggle.host')
db = arango_client.db('board1', username='root', password='123-very-unsafe-way-to-protect-yourself321') db = arango_client.db('board1', username='root', password='stolendick527')
# предполагается что меняться список будет весьма редко, поэтому подхватываем при лишь при перезапуске # предполагается что меняться список будет весьма редко, поэтому подхватываем при лишь при перезапуске
# # boards0 = db.collection('boards') boards0 = db.collection('boards')
# # print(boards0) board_list = [ k['_key'] for k in boards0]
# # board_list = [ k['_key'] for k in boards0]
@app.route("/get_my_ip")
def get_my_ip():
return jsonify({'ip': request.remote_addr,
'real-ip': request.environ.get('HTTP_X_REAL_IP', request.remote_addr)}), 200
@app.route('/liveness') @app.route('/liveness')
@ -49,8 +40,6 @@ def healthx():
@app.route('/readiness') @app.route('/readiness')
def healthz(): def healthz():
#### TODU return arango check
return "<h1><center>Readiness check completed</center><h1>" return "<h1><center>Readiness check completed</center><h1>"
@ -58,185 +47,40 @@ def healthz():
@app.route("/") @app.route("/")
def homepage(): def homepage():
boards0 = db.collection('boards')
board_list = [ k['_key'] for k in boards0]
return render_template("main-page.html", host_id=docker_short_id, boards=board_list) return render_template("main-page.html", host_id=docker_short_id, boards=board_list)
#### TODO если борды нет, то возвращать 404 мемную @app.route("/db_posts")
#### TODO если треда нет, то возвращать 404 мемную def page_posts_from_db():
#### DONE route :: /{board}/
@app.route('/<board>')
def board_posts(board=None):
postos = db.collection('posts') postos = db.collection('posts')
postos = [ p for p in postos if p.get('root_post') == True and p.get('board') == board ] postos = [ p for p in postos]
postos = sorted(postos, key=lambda posto: int(posto['_key']), reverse=False) postos = sorted(postos, key=lambda posto: posto['_key'], reverse=False)
boards0 = db.collection('boards') return render_template("interactive-posts.html", host_id=docker_short_id, postos=postos)
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)
#### TODO route :: /{board}/{thread}/ @app.route('/post_my_post/<post_key>', methods=['POST'])
#### TODO убрать отсюда чужие рут-потсы def post_a_post(post_key):
@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}"
FOR v IN 1..9999 OUTBOUND ppp post_parents RETURN v"""
)
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']
boards0 = db.collection('boards') postos = db.collection('posts')
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)
#### TODO route :: /{board}/create_thread/{target_post_id} #### TODO проверить как-то по-умному что мы таки его добавили
@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({ metadata = postos.insert({
'texto': data, 'texto': 'next post is this',
"root_post": True, 'parent_post': f'{post_key}'
'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
#### TODO route :: /{board}/{thread}/answer_post/
#### TODO route :: /{board}/{thread}/post_to_another_post/
# @app.route('/db_posts')
# @app.route("/db_posts/<target_post_id>")
# def page_posts_from_db(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)
# for p in postos:
# #if p['root_post']:
# print(p)
# if not target_post_id:
# target_post_id = postos[0]['_key']
# return render_template("interactive-posts.html", host_id=docker_short_id, postos=postos, target_post_id=target_post_id)
@app.route("/<board>/answer_post/<target_post_id>", methods=['POST'])
def answer_post(board, target_post_id):
postos = db.collection('posts')
postos = [ p for p in postos ]
postos = sorted(postos, key=lambda posto: int(posto['_key']), reverse=False)
## ?? wut
if not target_post_id:
target_post_id = postos[0]['_key']
return render_template("answer-post.html", board=board, target_post_id=target_post_id)
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'mp4', 'webm', 'webp'}
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/<board>/post_to_another_post/<post_key>', methods=['POST'])
def post_to_post(board, post_key):
#### TODO resize pics https://stackoverflow.com/questions/53337318/how-can-i-resize-image-with-pil-on-upload-and-serve-them-with-flask-cloudy
#### TODO allow only imgs, videos, and gifs
if 'file' in request.files:
minioClient = Minio( "static.guaranteedstruggle.host" )
bucket_name = "thread-pics"
files = request.files.getlist("file")
for file in files:
size = os.fstat(file.fileno()).st_size
#### работает ли??
if allowed_file(file.filename):
minioClient.put_object(
bucket_name, file.filename, file, size
)
else:
print(f'somebody tried to put this inside minio: {file.filename} size: {size}')
postos = db.collection('posts')
data = request.form['send_this_text']
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)
metadata = postos.insert({
'texto': data,
'parent_post': f'{post_key}',
'images': [],
"thread": thread
}, overwrite_mode='update') }, overwrite_mode='update')
metadata = db.collection('post_parents').insert({ metadata = db.collection('post_parents').insert({
# '_key': post_key,
'_from': f'posts/{post_key}', '_from': f'posts/{post_key}',
'_to': f'posts/{metadata["_key"]}' '_to': f'posts/{metadata["_key"]}'
}, overwrite_mode='update') }, overwrite_mode='update')
#### TODO оптимайз для только тредовых штук
cursor = db.aql.execute( cursor = db.aql.execute(
"""FOR ppp IN posts """FOR ppp IN posts
LET children = (FOR v IN 1..9999 OUTBOUND ppp post_parents RETURN v) LET children = (FOR v IN 1..9999 OUTBOUND ppp post_parents RETURN v)
@ -244,36 +88,19 @@ def post_to_post(board, post_key):
) )
cursor = db.aql.execute( cursor = db.aql.execute(
"""FOR ppp IN posts """FOR ppp IN posts
LET children = (FOR v IN 1 OUTBOUND ppp post_parents RETURN v) LET children = (FOR v IN 1OUTBOUND ppp post_parents RETURN v)
UPDATE ppp WITH { answers_num : COUNT_DISTINCT( children[*]._key ) } IN posts""" UPDATE ppp WITH { answers_num : COUNT_DISTINCT( children[*]._key ) } IN posts"""
) )
cursor = db.aql.execute(
"""FOR ppp IN posts
LET children0 = (FOR v IN 1 OUTBOUND ppp post_parents RETURN v)
LET children = (FOR c IN children0
SORT c._key DESC
RETURN c)
UPDATE ppp WITH { answers_list : [ children[*]._key, children[*].answers_num, children[*].children_num ] } IN posts"""
)
postos = db.collection('posts') postos = db.collection('posts')
postos = [ p for p in postos if (not p.get('root_post')) and p.get('thread') == thread ] postos = sorted(postos, key=lambda posto: posto['_key'], reverse=False)
cursor = db.aql.execute(
f'RETURN DOCUMENT("posts/{thread}")'
)
postos.append(cursor.pop())
postos = sorted(postos, key=lambda posto: int(posto['_key']), reverse=False) return render_template("i-posts.html", host_id=docker_short_id, postos=postos)
return render_template("i-posts.html", board=board, host_id=docker_short_id, postos=postos)
# @app.route('/post_my_file', method=['POST'])
#### TODO websockets # def post_a_file():
#### TODO sse # pass
#### TODO kafka
#### TODO shards
#### TODO grpc

3
boards.py Normal file
View File

@ -0,0 +1,3 @@
board_list = [
'b','a','d'
]

View File

@ -1,4 +1,3 @@
flask flask
flask-assets flask-assets
python-arango python-arango
minio

41
static/dist/main.css vendored
View File

@ -1,41 +0,0 @@
/* украдено здесь https://css-tricks.com/hexagons-and-beyond-flexible-responsive-grid-patterns-sans-media-queries/ */
.hex-main {
display:flex;
--s: 100px; /* size */
--m: 4px; /* margin */
--f: calc(1.732 * var(--s) + 4 * var(--m) - 1px);
max-width: 440px;
margin: 15px;
}
.hex-container {
font-size: 0; /*disable white space between inline block element */
}
.hex-container img {
width: var(--s);
margin: var(--m);
height: calc(var(--s)*1.1547);
display: inline-block;
font-size:initial;
clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);
background: transparent;
margin-bottom: calc(var(--m) - var(--s)*0.2885);
}
.hex-container img:nth-child(odd) {
background: transparent;
}
.hex-container::before {
content: "";
width: calc(var(--s)/2 + var(--m));
float: left;
height: 120%;
shape-outside: repeating-linear-gradient(
#0000 0 calc(var(--f) - 3px),
#000 0 var(--f));
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@
--s: 100px; /* size */ --s: 100px; /* size */
--m: 4px; /* margin */ --m: 4px; /* margin */
--f: calc(1.732 * var(--s) + 4 * var(--m) - 1px); --f: calc(1.732 * var(--s) + 4 * var(--m) - 1px);
max-width: 440px; max-width: 330px;
margin: 15px; margin: 15px;
} }

View File

@ -1,69 +0,0 @@
<div class="card">
<form
hx-encoding='multipart/form-data'
_='on htmx:xhr:progress(loaded, total) set #progress.value to (loaded/total)*100'
hx-on::after-request="this.reset()"
>
<div class="card-content">
<div class="row">
<span class="card-title">Ты отвечаешь: <a href="#post-{{ target_post_id }}">>>{{ target_post_id }}</a></span>
</div>
<div class="row">
<a class="btn-floating halfway-fab waves-effect waves-light red" href="#post-{{ target_post_id }}"><i class="material-icons">>>{{ target_post_id }}</i></a>
</div>
<div class="row">
<div class="input-field col s6">
<input id="send_this_text" name="send_this_text" type="text" >
<label for="send_this_text">Печатать сюда</label>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<div class="file-field input-field">
<div class="btn">
<span>File</span>
<input id="file" name="file" type="file" multiple>
</div>
<div class="file-path-wrapper">
<input class="file-path validate" type="text" placeholder="Upload one or more files">
<progress id='progress' value='0' max='100'></progress>
</div>
<!-- <div class="file-progress">
</div> -->
</div>
</div>
</div>
</div>
<div class="card-action">
<a href="#answer-post">
<button class="btn waves-effect waves-light"
type="submit" name="action" hx-encoding='multipart/form-data'
_='on htmx:xhr:progress(loaded, total) set #progress.value to (loaded/total)*100'
hx-post="/{{board}}/post_to_another_post/{{ target_post_id }}"
hx-target="#neu-posts"
hx-include="[name='send_this_text'], [name='file']"
>
Отправить!!
<i class="material-icons right">send</i>
</button>
</a>
</div>
</form>
<!-- <div class="row">
<form hx-encoding='multipart/form-data' hx-post='/send_dudes'
_='on htmx:xhr:progress(loaded, total) set #progress.value to (loaded/total)*100'>
<input type='file' name='file'>
<button>
Upload
</button>
<progress id='progress' value='0' max='100'></progress>
</form>
</div> -->
<!-- <h1>Загрузить картинку:</h1>
<input type="file" #file placeholder="Загрузить картинку" (change)="sendPic($event)" style="display:none;">
<button type="button" class="btn btn-success" (click)="file.click()">Загрузить картинку</button>
<div *ngFor="let singlePic of inputImages" >Картинка: {{singlePic}}</div>
<p>
<button (click)="eraseData()" >Убрать картинку</button>
</p> -->
</div>

View File

@ -5,15 +5,6 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Compiled and minified CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<!-- Compiled and minified JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script src="https://unpkg.com/htmx.org@1.9.3" integrity="sha384-lVb3Rd/Ca0AxaoZg5sACe8FJKF0tnUgR2Kd7ehUOG5GCcROv5uBIZsOqovBAcWua" crossorigin="anonymous"></script>
<script src="https://unpkg.com/hyperscript.org@0.9.9"></script>
{% assets 'css' %} {% assets 'css' %}
<link rel="stylesheet" href="{{ ASSET_URL }}"> <link rel="stylesheet" href="{{ ASSET_URL }}">
{% endassets %} {% endassets %}
@ -25,7 +16,7 @@
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.png') }}"> <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.png') }}">
<title>Board++</title> <title>Board++</title>
</head> </head>
<body class="bg-blue-100"> <body class=" ">
<div id="multi-bg"> <div id="multi-bg">
{% block content %} {% block content %}

View File

@ -1,23 +0,0 @@
{% extends "base.html" %}
{% block content %}
{% include 'navbar.html' %}
<div class="row" >
{% include 'create-thread.html' %}
</div>
<div class="row" >
<div class="col s6 m5" id="op-posts">
{% include 'op-posts.html' %}
</div>
<!-- <div class="col s6 m5" id="thread-viz">
<iframe src="https://thread-visualizah-dev.board.vdk2ch.ru/" scrolling="no" frameborder="0" style="position: relative; height: 600px; width: 100%; margin:10px;"></iframe>
</div> -->
</div>
{% endblock content %}

View File

@ -1,48 +0,0 @@
<div class="card">
<form
hx-encoding='multipart/form-data'
_='on htmx:xhr:progress(loaded, total) set #progress.value to (loaded/total)*100'
hx-on::after-request="this.reset()"
>
<div class="card-content">
<div class="row">
<span class="card-title">Создавай тред уже!</span>
</div>
<div class="row">
<div class="input-field col s6">
<input id="send_this_text" name="send_this_text" type="text" >
<label for="send_this_text">Печатать сюда</label>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<div class="file-field input-field">
<div class="btn">
<span>File</span>
<input id="file" name="file" type="file" multiple>
</div>
<div class="file-path-wrapper">
<input class="file-path validate" type="text" placeholder="Upload one or more files">
<progress id='progress' value='0' max='100'></progress>
</div>
<!-- <div class="file-progress">
</div> -->
</div>
</div>
</div>
</div>
<div class="card-action">
<a href="/{{board}}/create-thread/{{ target_post_id }}">
<button class="btn waves-effect waves-light"
type="submit" name="action" hx-encoding='multipart/form-data'
_='on htmx:xhr:progress(loaded, total) set #progress.value to (loaded/total)*100'
hx-post="/{{board}}/create-thread/{{ target_post_id }}"
hx-include="[name='send_this_text'], [name='file']"
>
Отправить!!
<i class="material-icons right">send</i>
</button>
</a>
</div>
</form>
</div>

View File

@ -1,92 +1,40 @@
{% if postos | length > 0 %} {% if postos | length > 0 %}
{% for posto in postos %} {% for posto in postos %}
<div class="row"> <div class=" ">
{% if posto.root_post %} {% if posto.root_post %}
<div class="card s5 deep-orange accent-4 darken-1"> <div class=" ">
{% else %} {% else %}
<div class="card s5 blue-grey darken-1"> <div class=" ">
{% endif %} {% endif %}
<div class=" " id="post-{{ posto._key }}">
<div class="card-content white-text"> <div class=" ">
<span class="new badge yellow" data-badge-caption=""> <div class="">
<a class="purple-text" href="#post-{{ posto._key }}"> #{{ posto._key }} </a> <div class="hex-main">
</span>
<span class="new badge blue" data-badge-caption="">Ответов: {{ posto.answers_num }}</span>
<span class="new badge red" data-badge-caption="">Длина треда: {{ posto.children_num }}</span>
</div>
<div class="row" id="post-{{ posto._key }}">
{% if posto.images | length > 0 %}
<div class="col s12">
<!-- <div class="hex-main">
<div class="hex-container"> <div class="hex-container">
<a href="https://loremflickr.com/g/320/240/paris" target="_blank" "> <a href="https://loremflickr.com/g/320/240/paris" target="_blank" ">
<img src="https://loremflickr.com/g/320/240/paris"> <img src="https://loremflickr.com/g/320/240/paris">
</a> </a>
</div> </div>
</div> -->
<div class="nav-wrapper">
<ul id="nav-mobile" class="right hide-on-med-and-down">
<li>
<a href="https://static.guaranteedstruggle.host/thread-pics/photo_2023-05-16_00-49-34.jpg" target="_blank" ">
<img src="https://static.guaranteedstruggle.host/thread-pics/photo_2023-05-16_00-49-34.jpg" width="300px">
</a>
<span class=" "><a class="" href="https://static.guaranteedstruggle.host/thread-pics/photo_2023-05-16_00-49-34.jpg" target="_blank"> photo_2023-05-16_00-49-34.jpg </a> </span>
</li>
<li>
<a href="https://static.guaranteedstruggle.host/thread-pics/109.png" target="_blank" ">
<img src="https://static.guaranteedstruggle.host/thread-pics/109.png" width="300px">
</a>
<span class=" "><a class="" href="https://static.guaranteedstruggle.host/thread-pics/109.png" target="_blank"> 109.png </a> </span>
</li>
</ul>
</div>
</div>
</div>
</div> </div>
{% endif %} <div class=" ">
<!-- <div class="col s8"> <div class=" ">
<div class="card-content white-text"> <span class=" e">#{{ posto._key }}
<span class="card-title">#{{ posto._key }} <span class=" " data-badge-caption="">Ответов: {{ posto.answers_num }}</span>
<span class="new badge blue" data-badge-caption="">Ответов: {{ posto.answers_num }}</span> <span class=" " data-badge-caption="">Длина треда: {{ posto.children_num }}</span>
<span class="new badge red" data-badge-caption="">Длина треда: {{ posto.children_num }}</span>
</span> </span>
{% if posto.parent_post %} {% if posto.parent_post %}
<a class="link orange-text purple" href="#post-{{ posto.parent_post }}"> >>{{ posto.parent_post }} </a> <a class=" " href="#post-{{ posto.parent_post }}"> >>{{ posto.parent_post }} </a>
{% endif %} {% endif %}
<p>{{ posto.texto }}</p> <p>{{ posto.texto }}</p>
</div> </div>
</div> -->
<div class="col s12 card-content white-text">
{% if posto.parent_post %}
<a class="link orange-text purple" href="#post-{{ posto.parent_post }}"> >>{{ posto.parent_post }} </a>
{% endif %}
<p>{{ posto.texto }}</p>
</div> </div>
<div class="col s12 card-action white-text"> <div class=" ">
<div class="right"> <div class=" ">
<!-- <a href="#" hx-post="/post_my_post/{{ posto._key }}" hx-target="#neu-posts" >Answer me!</a> --> <a href="#" hx-post="/post_my_post/{{ posto._key }}" hx-target="#neu-posts" >Answer me!</a>
<a href="#answer-post" hx-post="/{{board}}/answer_post/{{ posto._key }}" hx-target="#answer-post" >Ответить этому.</a>
</div>
</div>
<div class="col s12 card-content white-text">
<!-- TODO !подгрузка следующего поста в конец треда без перезагрузки всего треда! -->
<div class="left">
<!-- <a href="#" hx-post="/post_my_post/{{ posto._key }}" hx-target="#neu-posts" >Answer me!</a> -->
{% if posto.answers_list[0] | length > 0 %}
<p>Ответы:</p>
{% for ans in posto.answers_list[0] %}
{% if (posto.answers_list[1])[loop.index-1] > 0 %}
{% if (posto.answers_list[2])[loop.index-1] > 0 %}
<a href="#post-{{ (posto.answers_list[0])[loop.index-1] }}" class="lime-text red collection-item" style="padding: 2px 2px;">>>{{ (posto.answers_list[0])[loop.index-1] }} (ответов {{ (posto.answers_list[1])[loop.index-1] }}, длина {{ (posto.answers_list[2])[loop.index-1] }})</a>
{% else %}
<a href="#post-{{ (posto.answers_list[0])[loop.index-1] }}" class="lime-text red collection-item" style="padding: 2px 2px;">>>{{ (posto.answers_list[0])[loop.index-1] }} (ответов {{ (posto.answers_list[1])[loop.index-1] }})</a>
{% endif %}
{% else %}
<a href="#post-{{ (posto.answers_list[0])[loop.index-1] }}" class="lime-text red collection-item" style="padding: 2px 2px;">>>{{ (posto.answers_list[0])[loop.index-1] }}</a>
{% endif %}
{% endfor %}
{% endif %}
</div> </div>
</div> </div>
</div> </div>

View File

@ -5,21 +5,12 @@
{% include 'navbar.html' %} {% include 'navbar.html' %}
<div class="row" >
<div class="col s6 m5" id="neu-posts"> <div class=" " >
<div class=" " id="neu-posts">
{% include 'i-posts.html' %} {% include 'i-posts.html' %}
</div> </div>
<div class="col s6 m5" id="thread-viz">
<iframe src="https://thread-visualizah-dev.board.vdk2ch.ru/" scrolling="no" frameborder="0" style="position: relative; height: 600px; width: 100%; margin:10px;"></iframe>
</div>
</div> </div>
<div class="row">
<div class="col s3 m3 " id="aa"></div>
<div class="col s7 m6 " id="answer-post">
{% include 'answer-post.html' %}
</div>
</div>
{% endblock content %} {% endblock content %}

View File

@ -3,15 +3,17 @@
{% block content %} {% block content %}
{% include 'navbar.html' %} {% include 'navbar.html' %}
<div class="container"> <div class=" ">
<div class="row"> <div class=" ">
<div class="col s4 center"> <div class=" ">
<div class="card"> <div class=" ">
<div class="card-image"> <div class=" ">
<img class="img-responsive" src="https://static.guaranteedstruggle.host/test-public/sin.jpg" height="400px" width="320px"> <img class=" " src="https://static.guaranteedstruggle.host/test-public/sin.jpg" height="400px" width="320px">
</div> </div>
<div class="card-content"> <div class=" ">
<p> Dobro pozhalovat. AGAIN. </p> <p>
Dobro pozhalovat. AGAIN.
</p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,16 +1,11 @@
<nav> <nav>
<div class="nav-wrapper purple darken-3"> <div class=" ">
<ul id="nav-mobile" class="left "> <ul id="nav-mobile" class="left ">
<li> <a href="/">glavnaya</a> </li> <li> <a href="/">glavnaya</a> </li>
<li><a href="/db_posts"><span class=" " data-badge-caption="">here we go</span></a> </li>
{% if boards | length > 0 %}
{% for board in boards %}
<li><a href="/{{board}}"><span class="new badge red" data-badge-caption="">{{board}}</span></a> </li>
{% endfor %}
{% endif %}
<li> <li>
<a href="#">Вас закинуло сюда: <span class="new badge blue" data-badge-caption="">{{host_id}}</span></a> <a href="#">Вас закинуло сюда: <span class=" " data-badge-caption="">{{host_id}}</span></a>
</li> </li>
</ul> </ul>
</div> </div>

View File

@ -1,53 +0,0 @@
{% if postos | length > 0 %}
{% for posto in postos %}
<div class="row">
{% if posto.root_post %}
<div class="card s5 deep-orange accent-4 darken-1">
{% else %}
<div class="card s5 blue-grey darken-1">
{% endif %}
<div class="card-content white-text">
<span class="new badge yellow" data-badge-caption="">
<a class="purple-text" href="/{{board}}/{{ posto._key }}"> #{{ posto._key }} </a>
</span>
<span class="new badge blue" data-badge-caption="">Ответов: {{ posto.answers_num }}</span>
<span class="new badge red" data-badge-caption="">Длина треда: {{ posto.children_num }}</span>
</div>
<div class="row" id="post-{{ posto._key }}">
{% if posto.images | length > 0 %}
<div class="col s12">
<!-- <div class="nav-wrapper">
<ul id="nav-mobile" class="right hide-on-med-and-down">
<li>
<a href="https://static.guaranteedstruggle.host/thread-pics/photo_2023-05-16_00-49-34.jpg" target="_blank" ">
<img src="https://static.guaranteedstruggle.host/thread-pics/photo_2023-05-16_00-49-34.jpg" width="300px">
</a>
<span class=" "><a class="" href="https://static.guaranteedstruggle.host/thread-pics/photo_2023-05-16_00-49-34.jpg" target="_blank"> photo_2023-05-16_00-49-34.jpg </a> </span>
</li>
<li>
<a href="https://static.guaranteedstruggle.host/thread-pics/109.png" target="_blank" ">
<img src="https://static.guaranteedstruggle.host/thread-pics/109.png" width="300px">
</a>
<span class=" "><a class="" href="https://static.guaranteedstruggle.host/thread-pics/109.png" target="_blank"> 109.png </a> </span>
</li>
</ul>
</div> -->
</div>
{% endif %}
<div class="col s12 card-content white-text">
<p>{{ posto.texto }}</p>
</div>
<div class="col s12 card-action white-text">
<div class="right">
<!-- <a href="#" hx-post="/post_my_post/{{ posto._key }}" hx-target="#neu-posts" >Answer me!</a> -->
<a href="/{{board}}/{{ posto._key }}" >В тред!</a>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
{% endif %}

11
threads.py Normal file
View File

@ -0,0 +1,11 @@
threads_lists = {
'b': {
'123','124'
},
'a': {
'1'
},
'd': {
'44','99','1230'
}
}

45
threads_with_posts.py Normal file
View File

@ -0,0 +1,45 @@
# <id>: {<post_num>, <pic_links>, <texto>, <name>}
open_threads = {
'123': {
'thread_num': '123',
'post_num': '9999',
'pic_links': ['16216445863900.jpg'],
'txt': 'фыва',
'name': 'anonius'
},
'124': {
'thread_num': '124',
'post_num': '456',
'pic_linkss': ['16672846165910.png'],
'txt': 'Test',
'name': 'anonius'
},
'1': {
'thread_num': '123',
'post_num': '1',
'pic_links': ['16211265989190.jpg'],
'txt': 'фыва',
'name': 'anonius'
},
'44': {
'thread_num': '44',
'post_num': '12',
'pic_links': ['15937598937440.png'],
'txt': 'I hate my brother-nation..',
'name': 'Владимир Владимирович'
},
'99': {
'thread_num': '99',
'post_num': '55',
'pic_links': ['Экран-смерти.jpg','Экран-смерти.jpg','Экран-смерти.jpg','Экран-смерти.jpg','15937598937440.png','Экран-смерти.jpg','Экран-смерти.jpg'],
'txt': 'фыва',
'name': 'anonius'
},
'1230': {
'thread_num': '1230',
'post_num': '1234',
'pic_links': ['15906018690140.png'],
'txt': '33333!',
'name': 'SIRNA'
}
}

457
todo.py Normal file
View File

@ -0,0 +1,457 @@
todos = [
{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": False},
{
"userId": 1,
"id": 2,
"title": "quis ut nam facilis et officia qui",
"completed": False,
},
{"userId": 1, "id": 3, "title": "fugiat veniam minus", "completed": False},
{"userId": 1, "id": 4, "title": "et porro tempora", "completed": True},
{
"userId": 1,
"id": 5,
"title": "laboriosam mollitia et enim quasi adipisci quia provident illum",
"completed": False,
},
{
"userId": 1,
"id": 6,
"title": "qui ullam ratione quibusdam voluptatem quia omnis",
"completed": False,
},
{
"userId": 1,
"id": 7,
"title": "illo expedita consequatur quia in",
"completed": False,
},
{"userId": 1, "id": 8, "title": "quo adipisci enim quam ut ab", "completed": True},
{"userId": 1, "id": 9, "title": "molestiae perspiciatis ipsa", "completed": False},
{
"userId": 1,
"id": 10,
"title": "illo est ratione doloremque quia maiores aut",
"completed": True,
},
{"userId": 1, "id": 11, "title": "vero rerum temporibus dolor", "completed": True},
{"userId": 1, "id": 12, "title": "ipsa repellendus fugit nisi", "completed": True},
{"userId": 1, "id": 13, "title": "et doloremque nulla", "completed": False},
{
"userId": 1,
"id": 14,
"title": "repellendus sunt dolores architecto voluptatum",
"completed": True,
},
{"userId": 1, "id": 15, "title": "ab voluptatum amet voluptas", "completed": True},
{
"userId": 1,
"id": 16,
"title": "accusamus eos facilis sint et aut voluptatem",
"completed": True,
},
{
"userId": 1,
"id": 17,
"title": "quo laboriosam deleniti aut qui",
"completed": True,
},
{
"userId": 1,
"id": 18,
"title": "dolorum est consequatur ea mollitia in culpa",
"completed": False,
},
{
"userId": 1,
"id": 19,
"title": "molestiae ipsa aut voluptatibus pariatur dolor nihil",
"completed": True,
},
{
"userId": 1,
"id": 20,
"title": "ullam nobis libero sapiente ad optio sint",
"completed": True,
},
{
"userId": 2,
"id": 21,
"title": "suscipit repellat esse quibusdam voluptatem incidunt",
"completed": False,
},
{
"userId": 2,
"id": 22,
"title": "distinctio vitae autem nihil ut molestias quo",
"completed": True,
},
{
"userId": 2,
"id": 23,
"title": "et itaque necessitatibus maxime molestiae qui quas velit",
"completed": False,
},
{
"userId": 2,
"id": 24,
"title": "adipisci non ad dicta qui amet quaerat doloribus ea",
"completed": False,
},
{
"userId": 2,
"id": 25,
"title": "voluptas quo tenetur perspiciatis explicabo natus",
"completed": True,
},
{"userId": 2, "id": 26, "title": "aliquam aut quasi", "completed": True},
{"userId": 2, "id": 27, "title": "veritatis pariatur delectus", "completed": True},
{
"userId": 2,
"id": 28,
"title": "nesciunt totam sit blanditiis sit",
"completed": False,
},
{"userId": 2, "id": 29, "title": "laborum aut in quam", "completed": False},
{
"userId": 2,
"id": 30,
"title": "nemo perspiciatis repellat ut dolor libero commodi blanditiis omnis",
"completed": True,
},
{
"userId": 2,
"id": 31,
"title": "repudiandae totam in est sint facere fuga",
"completed": False,
},
{
"userId": 2,
"id": 32,
"title": "earum doloribus ea doloremque quis",
"completed": False,
},
{"userId": 2, "id": 33, "title": "sint sit aut vero", "completed": False},
{
"userId": 2,
"id": 34,
"title": "porro aut necessitatibus eaque distinctio",
"completed": False,
},
{
"userId": 2,
"id": 35,
"title": "repellendus veritatis molestias dicta incidunt",
"completed": True,
},
{
"userId": 2,
"id": 36,
"title": "excepturi deleniti adipisci voluptatem et neque optio illum ad",
"completed": True,
},
{"userId": 2, "id": 37, "title": "sunt cum tempora", "completed": False},
{"userId": 2, "id": 38, "title": "totam quia non", "completed": False},
{
"userId": 2,
"id": 39,
"title": "doloremque quibusdam asperiores libero corrupti illum qui omnis",
"completed": False,
},
{"userId": 2, "id": 40, "title": "totam atque quo nesciunt", "completed": True},
{
"userId": 3,
"id": 41,
"title": "aliquid amet impedit consequatur aspernatur placeat eaque fugiat suscipit",
"completed": False,
},
{
"userId": 3,
"id": 42,
"title": "rerum perferendis error quia ut eveniet",
"completed": False,
},
{
"userId": 3,
"id": 43,
"title": "tempore ut sint quis recusandae",
"completed": True,
},
{
"userId": 3,
"id": 44,
"title": "cum debitis quis accusamus doloremque ipsa natus sapiente omnis",
"completed": True,
},
{
"userId": 3,
"id": 45,
"title": "velit soluta adipisci molestias reiciendis harum",
"completed": False,
},
{
"userId": 3,
"id": 46,
"title": "vel voluptatem repellat nihil placeat corporis",
"completed": False,
},
{
"userId": 3,
"id": 47,
"title": "nam qui rerum fugiat accusamus",
"completed": False,
},
{
"userId": 3,
"id": 48,
"title": "sit reprehenderit omnis quia",
"completed": False,
},
{
"userId": 3,
"id": 49,
"title": "ut necessitatibus aut maiores debitis officia blanditiis velit et",
"completed": False,
},
{
"userId": 3,
"id": 50,
"title": "cupiditate necessitatibus ullam aut quis dolor voluptate",
"completed": True,
},
{
"userId": 3,
"id": 51,
"title": "distinctio exercitationem ab doloribus",
"completed": False,
},
{
"userId": 3,
"id": 52,
"title": "nesciunt dolorum quis recusandae ad pariatur ratione",
"completed": False,
},
{
"userId": 3,
"id": 53,
"title": "qui labore est occaecati recusandae aliquid quam",
"completed": False,
},
{
"userId": 3,
"id": 54,
"title": "quis et est ut voluptate quam dolor",
"completed": True,
},
{
"userId": 3,
"id": 55,
"title": "voluptatum omnis minima qui occaecati provident nulla voluptatem ratione",
"completed": True,
},
{"userId": 3, "id": 56, "title": "deleniti ea temporibus enim", "completed": True},
{
"userId": 3,
"id": 57,
"title": "pariatur et magnam ea doloribus similique voluptatem rerum quia",
"completed": False,
},
{
"userId": 3,
"id": 58,
"title": "est dicta totam qui explicabo doloribus qui dignissimos",
"completed": False,
},
{
"userId": 3,
"id": 59,
"title": "perspiciatis velit id laborum placeat iusto et aliquam odio",
"completed": False,
},
{
"userId": 3,
"id": 60,
"title": "et sequi qui architecto ut adipisci",
"completed": True,
},
{"userId": 4, "id": 61, "title": "odit optio omnis qui sunt", "completed": True},
{
"userId": 4,
"id": 62,
"title": "et placeat et tempore aspernatur sint numquam",
"completed": False,
},
{
"userId": 4,
"id": 63,
"title": "doloremque aut dolores quidem fuga qui nulla",
"completed": True,
},
{
"userId": 4,
"id": 64,
"title": "voluptas consequatur qui ut quia magnam nemo esse",
"completed": False,
},
{
"userId": 4,
"id": 65,
"title": "fugiat pariatur ratione ut asperiores necessitatibus magni",
"completed": False,
},
{
"userId": 4,
"id": 66,
"title": "rerum eum molestias autem voluptatum sit optio",
"completed": False,
},
{
"userId": 4,
"id": 67,
"title": "quia voluptatibus voluptatem quos similique maiores repellat",
"completed": False,
},
{
"userId": 4,
"id": 68,
"title": "aut id perspiciatis voluptatem iusto",
"completed": False,
},
{
"userId": 4,
"id": 69,
"title": "doloribus sint dolorum ab adipisci itaque dignissimos aliquam suscipit",
"completed": False,
},
{
"userId": 4,
"id": 70,
"title": "ut sequi accusantium et mollitia delectus sunt",
"completed": False,
},
{"userId": 4, "id": 71, "title": "aut velit saepe ullam", "completed": False},
{
"userId": 4,
"id": 72,
"title": "praesentium facilis facere quis harum voluptatibus voluptatem eum",
"completed": False,
},
{
"userId": 4,
"id": 73,
"title": "sint amet quia totam corporis qui exercitationem commodi",
"completed": True,
},
{
"userId": 4,
"id": 74,
"title": "expedita tempore nobis eveniet laborum maiores",
"completed": False,
},
{
"userId": 4,
"id": 75,
"title": "occaecati adipisci est possimus totam",
"completed": False,
},
{"userId": 4, "id": 76, "title": "sequi dolorem sed", "completed": True},
{
"userId": 4,
"id": 77,
"title": "maiores aut nesciunt delectus exercitationem vel assumenda eligendi at",
"completed": False,
},
{
"userId": 4,
"id": 78,
"title": "reiciendis est magnam amet nemo iste recusandae impedit quaerat",
"completed": False,
},
{"userId": 4, "id": 79, "title": "eum ipsa maxime ut", "completed": True},
{
"userId": 4,
"id": 80,
"title": "tempore molestias dolores rerum sequi voluptates ipsum consequatur",
"completed": True,
},
{"userId": 5, "id": 81, "title": "suscipit qui totam", "completed": True},
{
"userId": 5,
"id": 82,
"title": "voluptates eum voluptas et dicta",
"completed": False,
},
{
"userId": 5,
"id": 83,
"title": "quidem at rerum quis ex aut sit quam",
"completed": True,
},
{"userId": 5, "id": 84, "title": "sunt veritatis ut voluptate", "completed": False},
{"userId": 5, "id": 85, "title": "et quia ad iste a", "completed": True},
{"userId": 5, "id": 86, "title": "incidunt ut saepe autem", "completed": True},
{
"userId": 5,
"id": 87,
"title": "laudantium quae eligendi consequatur quia et vero autem",
"completed": True,
},
{
"userId": 5,
"id": 88,
"title": "vitae aut excepturi laboriosam sint aliquam et et accusantium",
"completed": False,
},
{"userId": 5, "id": 89, "title": "sequi ut omnis et", "completed": True},
{
"userId": 5,
"id": 90,
"title": "molestiae nisi accusantium tenetur dolorem et",
"completed": True,
},
{
"userId": 5,
"id": 91,
"title": "nulla quis consequatur saepe qui id expedita",
"completed": True,
},
{"userId": 5, "id": 92, "title": "in omnis laboriosam", "completed": True},
{
"userId": 5,
"id": 93,
"title": "odio iure consequatur molestiae quibusdam necessitatibus quia sint",
"completed": True,
},
{"userId": 5, "id": 94, "title": "facilis modi saepe mollitia", "completed": False},
{
"userId": 5,
"id": 95,
"title": "vel nihil et molestiae iusto assumenda nemo quo ut",
"completed": True,
},
{
"userId": 5,
"id": 96,
"title": "nobis suscipit ducimus enim asperiores voluptas",
"completed": False,
},
{
"userId": 5,
"id": 97,
"title": "dolorum laboriosam eos qui iure aliquam",
"completed": False,
},
{
"userId": 5,
"id": 98,
"title": "debitis accusantium ut quo facilis nihil quis sapiente necessitatibus",
"completed": True,
},
{"userId": 5, "id": 99, "title": "neque voluptates ratione", "completed": False},
{
"userId": 5,
"id": 100,
"title": "excepturi a et neque qui expedita vel voluptate",
"completed": False,
},
]