re-add api route
This commit is contained in:
parent
3c3837b3f2
commit
64e18f16dd
@ -76,11 +76,13 @@ def create_app():
|
|||||||
from app.routes.threads import bp as threads_bp
|
from app.routes.threads import bp as threads_bp
|
||||||
from app.routes.users import bp as users_bp
|
from app.routes.users import bp as users_bp
|
||||||
from app.routes.mod import bp as mod_bp
|
from app.routes.mod import bp as mod_bp
|
||||||
|
from app.routes.api import bp as api_bp
|
||||||
app.register_blueprint(app_bp)
|
app.register_blueprint(app_bp)
|
||||||
app.register_blueprint(topics_bp)
|
app.register_blueprint(topics_bp)
|
||||||
app.register_blueprint(threads_bp)
|
app.register_blueprint(threads_bp)
|
||||||
app.register_blueprint(users_bp)
|
app.register_blueprint(users_bp)
|
||||||
app.register_blueprint(mod_bp)
|
app.register_blueprint(mod_bp)
|
||||||
|
app.register_blueprint(api_bp)
|
||||||
|
|
||||||
app.config['SESSION_COOKIE_SECURE'] = True
|
app.config['SESSION_COOKIE_SECURE'] = True
|
||||||
|
|
||||||
@ -88,11 +90,12 @@ def create_app():
|
|||||||
def make_session_permanent():
|
def make_session_permanent():
|
||||||
session.permanent = True
|
session.permanent = True
|
||||||
|
|
||||||
@app.context_processor
|
|
||||||
def inject_constants():
|
|
||||||
commit = ""
|
commit = ""
|
||||||
with open('.git/refs/heads/main') as f:
|
with open('.git/refs/heads/main') as f:
|
||||||
commit = f.read().strip()
|
commit = f.read().strip()
|
||||||
|
|
||||||
|
@app.context_processor
|
||||||
|
def inject_constants():
|
||||||
return {
|
return {
|
||||||
"InfoboxIcons": InfoboxIcons,
|
"InfoboxIcons": InfoboxIcons,
|
||||||
"InfoboxHTMLClass": InfoboxHTMLClass,
|
"InfoboxHTMLClass": InfoboxHTMLClass,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from .db import Model, db
|
from .db import Model, db
|
||||||
from .constants import PermissionLevel
|
from .constants import PermissionLevel
|
||||||
|
import time
|
||||||
|
|
||||||
class Users(Model):
|
class Users(Model):
|
||||||
table = "users"
|
table = "users"
|
||||||
@ -219,3 +220,27 @@ class Avatars(Model):
|
|||||||
|
|
||||||
class Subscriptions(Model):
|
class Subscriptions(Model):
|
||||||
table = "subscriptions"
|
table = "subscriptions"
|
||||||
|
|
||||||
|
class APIRateLimits(Model):
|
||||||
|
table = 'api_rate_limits'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_allowed(cls, user_id, method, seconds):
|
||||||
|
q = """
|
||||||
|
SELECT logged_at FROM api_rate_limits
|
||||||
|
WHERE user_id = ? AND method = ?
|
||||||
|
ORDER BY logged_at DESC LIMIT 1"""
|
||||||
|
last_call = db.fetch_one(q, user_id, method)
|
||||||
|
if last_call is None or (int(time.time()) - int(last_call['logged_at']) >= seconds):
|
||||||
|
with db.transaction():
|
||||||
|
db.query(
|
||||||
|
'DELETE FROM api_rate_limits WHERE user_id = ? AND method = ?',
|
||||||
|
user_id, method
|
||||||
|
)
|
||||||
|
db.query(
|
||||||
|
'INSERT INTO api_rate_limits (user_id, method) VALUES (?, ?)',
|
||||||
|
user_id, method
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
43
app/routes/api.py
Normal file
43
app/routes/api.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
from flask import Blueprint, request, url_for
|
||||||
|
from ..lib.babycode import babycode_to_html
|
||||||
|
from .users import is_logged_in, get_active_user
|
||||||
|
from ..models import APIRateLimits, Threads
|
||||||
|
from ..db import db
|
||||||
|
|
||||||
|
bp = Blueprint("api", __name__, url_prefix="/api/")
|
||||||
|
|
||||||
|
|
||||||
|
@bp.post('/thread-updates/<thread_id>')
|
||||||
|
def thread_updates(thread_id):
|
||||||
|
thread = Threads.find({'id': thread_id})
|
||||||
|
if not thread:
|
||||||
|
return {'error': 'no such thread'}, 404
|
||||||
|
target_time = request.json.get('since')
|
||||||
|
if not target_time:
|
||||||
|
return {'error': 'missing parameter "since"'}, 400
|
||||||
|
try:
|
||||||
|
target_time = int(target_time)
|
||||||
|
except:
|
||||||
|
return {'error': 'parameter "since" is not/cannot be converted to a number'}, 400
|
||||||
|
|
||||||
|
q = 'SELECT id FROM posts WHERE thread_id = ? AND posts.created_at > ? ORDER BY posts.created_at ASC LIMIT 1'
|
||||||
|
new_post = db.fetch_one(q, thread_id, target_time)
|
||||||
|
if not new_post:
|
||||||
|
return {'status': 'none'}
|
||||||
|
|
||||||
|
url = url_for('threads.thread', slug=thread.slug, after=new_post['id'], _anchor=f'post-{new_post['id']}')
|
||||||
|
return {'status': 'new_post', 'url': url}
|
||||||
|
|
||||||
|
|
||||||
|
@bp.post('/babycode-preview')
|
||||||
|
def babycode_preview():
|
||||||
|
if not is_logged_in():
|
||||||
|
return {'error': 'not authorized'}, 401
|
||||||
|
user = get_active_user()
|
||||||
|
if not APIRateLimits.is_allowed(user.id, 'babycode_preview', 5):
|
||||||
|
return {'error': 'too many requests'}, 429
|
||||||
|
markup = request.json.get('markup')
|
||||||
|
if not markup or not isinstance(markup, str):
|
||||||
|
return {'error': 'markup field missing or invalid type'}, 400
|
||||||
|
rendered = babycode_to_html(markup)
|
||||||
|
return {'html': rendered}
|
@ -72,5 +72,16 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
<input type='hidden' id='thread-subscribe-endpoint' value='{{ url_for('api.thread_updates', thread_id=thread.id) }}'>
|
||||||
|
<div id="new-post-notification" class="new-concept-notification hidden">
|
||||||
|
<div class="new-notification-content">
|
||||||
|
<p>New post in thread!</p>
|
||||||
|
<span class="notification-buttons">
|
||||||
|
<button id="dismiss-new-post-button">Dismiss</button>
|
||||||
|
<a class="linkbutton" id="go-to-new-post-button">View post</a>
|
||||||
|
<button id="unsub-new-post-button">Stop updates</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<script src="/static/js/thread.js?v=1"></script>
|
<script src="/static/js/thread.js?v=1"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
Loading…
Reference in New Issue
Block a user