99 lines
3.2 KiB
Python
99 lines
3.2 KiB
Python
from flask import Blueprint, request, url_for
|
|
from ..lib.babycode import babycode_to_html
|
|
from ..constants import REACTION_EMOJI
|
|
from .users import is_logged_in, get_active_user
|
|
from ..models import APIRateLimits, Threads, Reactions
|
|
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}
|
|
|
|
|
|
@bp.post('/add-reaction/<post_id>')
|
|
def add_reaction(post_id):
|
|
if not is_logged_in():
|
|
return {'error': 'not authorized', 'error_code': 401}, 401
|
|
user = get_active_user()
|
|
reaction_text = request.json.get('emoji')
|
|
if not reaction_text or not isinstance(reaction_text, str):
|
|
return {'error': 'emoji field missing or invalid type', 'error_code': 400}, 400
|
|
if reaction_text not in REACTION_EMOJI:
|
|
return {'error': 'unsupported reaction', 'error_code': 400}, 400
|
|
|
|
reaction = Reactions.find({
|
|
'user_id': user.id,
|
|
'post_id': int(post_id),
|
|
'reaction_text': reaction_text,
|
|
})
|
|
|
|
if reaction:
|
|
return {'error': 'reaction already exists', 'error_code': 409}, 409
|
|
|
|
reaction = Reactions.create({
|
|
'user_id': user.id,
|
|
'post_id': int(post_id),
|
|
'reaction_text': reaction_text,
|
|
})
|
|
|
|
return {'status': 'added'}
|
|
|
|
|
|
@bp.post('/remove-reaction/<post_id>')
|
|
def remove_reaction(post_id):
|
|
if not is_logged_in():
|
|
return {'error': 'not authorized'}, 401
|
|
user = get_active_user()
|
|
reaction_text = request.json.get('emoji')
|
|
if not reaction_text or not isinstance(reaction_text, str):
|
|
return {'error': 'emoji field missing or invalid type'}, 400
|
|
if reaction_text not in REACTION_EMOJI:
|
|
return {'error': 'unsupported reaction'}, 400
|
|
|
|
reaction = Reactions.find({
|
|
'user_id': user.id,
|
|
'post_id': int(post_id),
|
|
'reaction_text': reaction_text,
|
|
})
|
|
|
|
if not reaction:
|
|
return {'error': 'reaction does not exist'}, 404
|
|
|
|
reaction.delete()
|
|
|
|
return {'status': 'removed'}
|