##// END OF EJS Templates
Prevent zalgo inside posts
Prevent zalgo inside posts

File last commit:

r2069:f3964896 default
r2076:062b2b13 default
Show More
api.py
329 lines | 9.8 KiB | text/x-python | PythonLexer
neko259
Removed hiding the form row with CSS as it causes problems with error rows
r450 import json
neko259
Added some logging
r639 import logging
neko259
Fixed issue in rendering post without having a request
r1117
neko259
Merged with default branch
r1441 from django.core import serializers
neko259
Removed hiding the form row with CSS as it causes problems with error rows
r450 from django.db import transaction
neko259
Added sticker pack functionality
r1951 from django.db.models import Q
neko259
Added sticker as a separate entity for the attachment aliases
r1937 from django.http import HttpResponse, HttpResponseBadRequest
neko259
Fixed issue in rendering post without having a request
r1117 from django.shortcuts import get_object_or_404
neko259
Use CSRF protection
r1422 from django.views.decorators.csrf import csrf_protect
neko259
Merged with default branch
r1441 from boards.abstracts.settingsmanager import get_settings_manager
neko259
AJAX-based thread creation
r1998 from boards.forms import PostForm, PlainErrorList, ThreadForm
neko259
Merged with default branch
r1441 from boards.mdx_neboard import Parser
neko259
Removed unused imports
r1946 from boards.models import Post, Thread, Tag, TagAlias
neko259
Added sticker as a separate entity for the attachment aliases
r1937 from boards.models.attachment import AttachmentSticker
neko259
Thread status field instead of bumpable and archived fields (per BB-73)
r1414 from boards.models.thread import STATUS_ARCHIVE
neko259
Merged with default branch
r1441 from boards.models.user import Notification
neko259
Rewriting views to class-based
r542 from boards.utils import datetime_to_epoch
neko259
Fixed issue in rendering post without having a request
r1117
neko259
Removed hiding the form row with CSS as it causes problems with error rows
r450 __author__ = 'neko259'
neko259
Api module refactoring, moved some values to the module scope
r501 PARAMETER_TRUNCATED = 'truncated'
PARAMETER_TAG = 'tag'
PARAMETER_OFFSET = 'offset'
neko259
Added api for thread update in json
r524 PARAMETER_DIFF_TYPE = 'type'
neko259
Use dict instead of context instance in post view API
r1075 PARAMETER_POST = 'post'
neko259
Move attribute names in api to constants
r1076 PARAMETER_UPDATED = 'updated'
neko259
Updated API to use a new timestamp format for getting updated posts and get...
r1086 PARAMETER_LAST_UPDATE = 'last_update'
neko259
Cosmetic changes in the api view
r1119 PARAMETER_THREAD = 'thread'
PARAMETER_UIDS = 'uids'
neko259
Checkbox to subscribe replied or created thread
r1625 PARAMETER_SUBSCRIBED = 'subscribed'
neko259
Added api for thread update in json
r524
DIFF_TYPE_HTML = 'html'
DIFF_TYPE_JSON = 'json'
neko259
Api module refactoring, moved some values to the module scope
r501
neko259
Added posting over ajax
r533 STATUS_OK = 'ok'
STATUS_ERROR = 'error'
neko259
Added some logging
r639 logger = logging.getLogger(__name__)
neko259
Removed hiding the form row with CSS as it causes problems with error rows
r450
@transaction.atomic
neko259
Updated API to use a new timestamp format for getting updated posts and get...
r1086 def api_get_threaddiff(request):
neko259
Small changes to the docstrings of the api module
r627 """
Gets posts that were changed or added since time
"""
neko259
Removed hiding the form row with CSS as it causes problems with error rows
r450
neko259
Put thread id parameter into POST body instead of GET param when getting a...
r1191 thread_id = request.POST.get(PARAMETER_THREAD)
neko259
If trying to get thread diff from a GET request, send a message instead of failing with exception
r1425 uids_str = request.POST.get(PARAMETER_UIDS)
if not thread_id or not uids_str:
return HttpResponse(content='Invalid request.')
uids = uids_str.strip().split(' ')
neko259
Added some logging
r639
neko259
Favorite threads with new posts counter
r1323 opening_post = get_object_or_404(Post, id=thread_id)
thread = opening_post.get_thread()
neko259
Removed hiding the form row with CSS as it causes problems with error rows
r450
json_data = {
neko259
Move attribute names in api to constants
r1076 PARAMETER_UPDATED: [],
neko259
Cosmetic changes in the api view
r1119 PARAMETER_LAST_UPDATE: None, # TODO Maybe this can be removed already?
neko259
Style cleanup in api module
r504 }
neko259
Removed multitread posts 'feature'
r1704 posts = Post.objects.filter(thread=thread).exclude(uid__in=uids)
neko259
Added api for thread update in json
r524
neko259
Refactoring
r917 diff_type = request.GET.get(PARAMETER_DIFF_TYPE, DIFF_TYPE_HTML)
neko259
Added api for thread update in json
r524
neko259
Store UUID for posts and get thread diff by UUIDs instead of update time or...
r1118 for post in posts:
neko259
Added favorite thread popup
r1340 json_data[PARAMETER_UPDATED].append(post.get_post_data(
format_type=diff_type, request=request))
neko259
Updated API to use a new timestamp format for getting updated posts and get...
r1086 json_data[PARAMETER_LAST_UPDATE] = str(thread.last_edit_time)
neko259
Removed hiding the form row with CSS as it causes problems with error rows
r450
neko259
Checkbox to subscribe replied or created thread
r1625 settings_manager = get_settings_manager(request)
json_data[PARAMETER_SUBSCRIBED] = str(settings_manager.thread_is_fav(opening_post))
neko259
Favorite threads with new posts counter
r1323 # If the tag is favorite, update the counter
settings_manager = get_settings_manager(request)
favorite = settings_manager.thread_is_fav(opening_post)
if favorite:
settings_manager.add_or_read_fav_thread(opening_post)
neko259
Removed hiding the form row with CSS as it causes problems with error rows
r450 return HttpResponse(content=json.dumps(json_data))
neko259
Use CSRF protection
r1422 @csrf_protect
neko259
AJAX-based thread creation
r1998 def api_add_post(request, opening_post_id=None):
neko259
Added posting over ajax
r533 """
neko259
Small changes to the docstrings of the api module
r627 Adds a post and return the JSON response for it
neko259
Added posting over ajax
r533 """
neko259
AJAX-based thread creation
r1998 if opening_post_id:
opening_post = get_object_or_404(Post, id=opening_post_id)
else:
opening_post = None
neko259
Added posting over ajax
r533
status = STATUS_OK
errors = []
neko259
Return id of the post created via API
r1996 post = None
neko259
Added posting over ajax
r533 if request.method == 'POST':
neko259
AJAX-based thread creation
r1998 if opening_post:
neko259
Specify session in the form constructor
r2069 form_class = PostForm
neko259
AJAX-based thread creation
r1998 else:
neko259
Specify session in the form constructor
r2069 form_class = ThreadForm
form = form_class(request.POST, request.FILES,
error_class=PlainErrorList, session=request.session)
neko259
Added posting over ajax
r533
neko259
Make status an error if the user is banned in api_add_post
r638 if form.need_to_ban:
# Ban user because he is suspected to be a bot
# _ban_current_user(request)
status = STATUS_ERROR
neko259
Added posting over ajax
r533 if form.is_valid():
neko259
Unify thread and post creation into one method inside post manager, that can be called from almost anywhere (one step closer to ajax thread creation)
r1997 post = Post.objects.create_from_form(request, form, opening_post,
html_response=False)
neko259
Tweaked API logging
r640 if not post:
neko259
Make status an error if the user is banned in api_add_post
r638 status = STATUS_ERROR
neko259
Tweaked API logging
r640 else:
logger.info('Added post #%d via api.' % post.id)
neko259
Added posting over ajax
r533 else:
status = STATUS_ERROR
errors = form.as_json_errors()
neko259
Return id of the post created via API
r1996 else:
status = STATUS_ERROR
neko259
Added posting over ajax
r533
response = {
'status': status,
'errors': errors,
}
neko259
Return id of the post created via API
r1996 if post:
response['post_id'] = post.id
neko259
AJAX-based thread creation
r1998 if not opening_post:
# FIXME For now we include URL only for threads to navigate to them.
# This needs to become something universal, just not yet sure how.
response['url'] = post.get_absolute_url()
neko259
Return id of the post created via API
r1996
neko259
Added posting over ajax
r533 return HttpResponse(content=json.dumps(response))
neko259
Added api for getting thread list
r499
neko259
Moved get_post to an API views module
r491 def get_post(request, post_id):
neko259
Added api for getting thread list
r499 """
neko259
Small changes to the docstrings of the api module
r627 Gets the html of a post. Used for popups. Post can be truncated if used
neko259
Added api for getting thread list
r499 in threads list with 'truncated' get parameter.
"""
neko259
Moved get_post to an API views module
r491
post = get_object_or_404(Post, id=post_id)
neko259
Remove usage of broken and arbitrary api_post template in get_post view
r1110 truncated = PARAMETER_TRUNCATED in request.GET
neko259
Moved get_post to an API views module
r491
neko259
Show OP name in post preview popup
r1413 return HttpResponse(content=post.get_view(truncated=truncated, need_op_data=True))
neko259
Added api for getting thread list
r499
def api_get_threads(request, count):
"""
neko259
Small changes to the docstrings of the api module
r627 Gets the JSON thread opening posts list.
neko259
Added api for getting thread list
r499 Parameters that can be used for filtering:
tag, offset (from which thread to get results)
"""
neko259
Api module refactoring, moved some values to the module scope
r501 if PARAMETER_TAG in request.GET:
tag_name = request.GET[PARAMETER_TAG]
neko259
Added api for getting thread list
r499 if tag_name is not None:
tag = get_object_or_404(Tag, name=tag_name)
neko259
Thread status field instead of bumpable and archived fields (per BB-73)
r1414 threads = tag.get_threads().exclude(status=STATUS_ARCHIVE)
neko259
Added api for getting thread list
r499 else:
neko259
Thread status field instead of bumpable and archived fields (per BB-73)
r1414 threads = Thread.objects.exclude(status=STATUS_ARCHIVE)
neko259
Added api for getting thread list
r499
neko259
Api module refactoring, moved some values to the module scope
r501 if PARAMETER_OFFSET in request.GET:
offset = request.GET[PARAMETER_OFFSET]
neko259
Added api for getting thread list
r499 offset = int(offset) if offset is not None else 0
else:
offset = 0
threads = threads.order_by('-bump_time')
threads = threads[offset:offset + int(count)]
opening_posts = []
for thread in threads:
opening_post = thread.get_opening_post()
neko259
Added api for thread update in json
r524 # TODO Add tags, replies and images count
neko259
Added favorite thread popup
r1340 post_data = opening_post.get_post_data(include_last_update=True)
neko259
Thread status field instead of bumpable and archived fields (per BB-73)
r1414 post_data['status'] = thread.get_status()
neko259
Added bumpable and archived attributes to the thread API output
r976
opening_posts.append(post_data)
neko259
Added api for getting thread list
r499
return HttpResponse(content=json.dumps(opening_posts))
neko259
Added api for the tags list
r500
neko259
Added api for getting thread posts
r502 # TODO Test this
neko259
Added api for the tags list
r500 def api_get_tags(request):
"""
neko259
Small changes to the docstrings of the api module
r627 Gets all tags or user tags.
neko259
Added api for the tags list
r500 """
# TODO Get favorite tags for the given user ID
neko259
Tag name is now stored in the alias with default locale
r1874 tags = TagAlias.objects.all()
neko259
Added tags autocompletion to the thread creation form
r1115
term = request.GET.get('term')
if term is not None:
tags = tags.filter(name__contains=term)
tag_names = [tag.name for tag in tags]
neko259
Added api for the tags list
r500
return HttpResponse(content=json.dumps(tag_names))
neko259
Added api for getting thread posts
r502
neko259
Image alias autocomplete
r1702 def api_get_stickers(request):
neko259
Added sticker as a separate entity for the attachment aliases
r1937 term = request.GET.get('term')
if not term:
return HttpResponseBadRequest()
neko259
Added sticker pack functionality
r1951 global_stickers = AttachmentSticker.objects.filter(Q(name__icontains=term) | Q(stickerpack__name__icontains=term))
neko259
Added local stickers feature
r1940 local_stickers = [sticker for sticker in get_settings_manager(request).get_stickers() if term in sticker.name]
stickers = list(global_stickers) + local_stickers
neko259
Image alias autocomplete
r1702
neko259
Added sticker as a separate entity for the attachment aliases
r1937 image_dict = [{'thumb': sticker.attachment.get_thumb_url(),
neko259
Added sticker pack functionality
r1951 'alias': str(sticker)}
neko259
Added sticker as a separate entity for the attachment aliases
r1937 for sticker in stickers]
neko259
Image alias autocomplete
r1702
return HttpResponse(content=json.dumps(image_dict))
neko259
Added api for getting thread posts
r502 # TODO The result can be cached by the thread last update time
# TODO Test this
def api_get_thread_posts(request, opening_post_id):
"""
neko259
Small changes to the docstrings of the api module
r627 Gets the JSON array of thread posts
neko259
Added api for getting thread posts
r502 """
opening_post = get_object_or_404(Post, id=opening_post_id)
neko259
Small changes to the docstrings of the api module
r627 thread = opening_post.get_thread()
neko259
Added api for getting thread posts
r502 posts = thread.get_replies()
neko259
Added last update time to the initial thread result in api
r525 json_data = {
'posts': [],
'last_update': None,
}
neko259
Added api for getting thread posts
r502 json_post_list = []
for post in posts:
neko259
Added favorite thread popup
r1340 json_post_list.append(post.get_post_data())
neko259
Rewriting views to class-based
r542 json_data['last_update'] = datetime_to_epoch(thread.last_edit_time)
neko259
Added last update time to the initial thread result in api
r525 json_data['posts'] = json_post_list
neko259
Added api for thread update in json
r524
neko259
Added last update time to the initial thread result in api
r525 return HttpResponse(content=json.dumps(json_data))
neko259
Added api for thread update in json
r524
neko259
Added notification API
r994 def api_get_notifications(request, username):
last_notification_id_str = request.GET.get('last', None)
last_id = int(last_notification_id_str) if last_notification_id_str is not None else None
neko259
Fixed notifications API
r1445 posts = Notification.objects.get_notification_posts(usernames=[username],
neko259
Fixed issue in rendering post without having a request
r1117 last=last_id)
neko259
Added notification API
r994
json_post_list = []
for post in posts:
neko259
Added favorite thread popup
r1340 json_post_list.append(post.get_post_data())
neko259
Added notification API
r994 return HttpResponse(content=json.dumps(json_post_list))
neko259
Fixed tests failing with error 404 handler not imported
r564 def api_get_post(request, post_id):
"""
neko259
Small changes to the docstrings of the api module
r627 Gets the JSON of a post. This can be
neko259
Fixed tests failing with error 404 handler not imported
r564 used as and API for external clients.
"""
post = get_object_or_404(Post, id=post_id)
json = serializers.serialize("json", [post], fields=(
"pub_time", "_text_rendered", "title", "text", "image",
"image_width", "image_height", "replies", "tags"
))
return HttpResponse(content=json)
neko259
Added AJAX text preview to the form.
r1217 def api_get_preview(request):
raw_text = request.POST['raw_text']
parser = Parser()
return HttpResponse(content=parser.parse(parser.preparse(raw_text)))
neko259
Added favorite thread popup
r1340
def api_get_new_posts(request):
"""
Gets favorite threads and unread posts count.
"""
posts = list()
include_posts = 'include_posts' in request.GET
settings_manager = get_settings_manager(request)
neko259
New backend for fav threads. Now only last post ids are saved, no thread ids
r2044 last_posts = settings_manager.get_last_posts()
neko259
Faster way of obtaining new post count
r1345 if include_posts:
neko259
New backend for fav threads. Now only last post ids are saved, no thread ids
r2044 new_post_threads = Thread.objects.get_new_posts(last_posts)
neko259
Fixed last post link in new favorite posts api
r1346 if new_post_threads:
thread_ids = {thread.id: thread for thread in new_post_threads}
else:
thread_ids = dict()
neko259
Faster way of obtaining new post count
r1345
neko259
New backend for fav threads. Now only last post ids are saved, no thread ids
r2044 for post in last_posts:
neko259
Faster way of obtaining new post count
r1345 fav_thread_dict = dict()
neko259
Don't check new posts in the archived threads
r1344
neko259
New backend for fav threads. Now only last post ids are saved, no thread ids
r2044 thread = post.get_thread()
op = thread.get_opening_post()
if thread.id in thread_ids:
thread = thread_ids[thread.id]
neko259
Faster way of obtaining new post count
r1345 new_post_count = thread.new_post_count
neko259
Fixed last post link in new favorite posts api
r1346 fav_thread_dict['newest_post_link'] = thread.get_replies()\
neko259
New backend for fav threads. Now only last post ids are saved, no thread ids
r2044 .filter(id__gt=post.id)\
neko259
Show updated thread's link in favorite's new multipost
r1365 .first().get_absolute_url(thread=thread)
neko259
Faster way of obtaining new post count
r1345 else:
new_post_count = 0
fav_thread_dict['new_post_count'] = new_post_count
neko259
Don't check new posts in the archived threads
r1344
neko259
Faster way of obtaining new post count
r1345 fav_thread_dict['id'] = op.id
neko259
Added favorite thread popup
r1340
neko259
Speed up loading favorite list. Add reflinks to the list to see favorite...
r1343 fav_thread_dict['post_url'] = op.get_link_view()
fav_thread_dict['title'] = op.title
neko259
Added favorite thread popup
r1340
neko259
Faster way of obtaining new post count
r1345 posts.append(fav_thread_dict)
else:
fav_thread_dict = dict()
fav_thread_dict['new_post_count'] = \
neko259
New backend for fav threads. Now only last post ids are saved, no thread ids
r2044 Thread.objects.get_new_post_count(last_posts)
neko259
Added favorite thread popup
r1340 posts.append(fav_thread_dict)
return HttpResponse(content=json.dumps(posts))