re-add api route
This commit is contained in:
		@@ -76,11 +76,13 @@ def create_app():
 | 
			
		||||
    from app.routes.threads import bp as threads_bp
 | 
			
		||||
    from app.routes.users import bp as users_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(topics_bp)
 | 
			
		||||
    app.register_blueprint(threads_bp)
 | 
			
		||||
    app.register_blueprint(users_bp)
 | 
			
		||||
    app.register_blueprint(mod_bp)
 | 
			
		||||
    app.register_blueprint(api_bp)
 | 
			
		||||
 | 
			
		||||
    app.config['SESSION_COOKIE_SECURE'] = True
 | 
			
		||||
 | 
			
		||||
@@ -88,11 +90,12 @@ def create_app():
 | 
			
		||||
    def make_session_permanent():
 | 
			
		||||
        session.permanent = True
 | 
			
		||||
 | 
			
		||||
    commit = ""
 | 
			
		||||
    with open('.git/refs/heads/main') as f:
 | 
			
		||||
        commit = f.read().strip()
 | 
			
		||||
 | 
			
		||||
    @app.context_processor
 | 
			
		||||
    def inject_constants():
 | 
			
		||||
        commit = ""
 | 
			
		||||
        with open('.git/refs/heads/main') as f:
 | 
			
		||||
            commit = f.read().strip()
 | 
			
		||||
        return {
 | 
			
		||||
            "InfoboxIcons": InfoboxIcons,
 | 
			
		||||
            "InfoboxHTMLClass": InfoboxHTMLClass,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
from .db import Model, db
 | 
			
		||||
from .constants import PermissionLevel
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
class Users(Model):
 | 
			
		||||
    table = "users"
 | 
			
		||||
@@ -219,3 +220,27 @@ class Avatars(Model):
 | 
			
		||||
 | 
			
		||||
class Subscriptions(Model):
 | 
			
		||||
    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>
 | 
			
		||||
  </div>
 | 
			
		||||
</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>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user