##// END OF EJS Templates
New backend for fav threads. Now only last post ids are saved, no thread ids
New backend for fav threads. Now only last post ids are saved, no thread ids

File last commit:

r2044:227641ed default
r2044:227641ed default
Show More
api.py
329 lines | 9.8 KiB | text/x-python | PythonLexer
import json
import logging
from django.core import serializers
from django.db import transaction
from django.db.models import Q
from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import get_object_or_404
from django.views.decorators.csrf import csrf_protect
from boards.abstracts.settingsmanager import get_settings_manager
from boards.forms import PostForm, PlainErrorList, ThreadForm
from boards.mdx_neboard import Parser
from boards.models import Post, Thread, Tag, TagAlias
from boards.models.attachment import AttachmentSticker
from boards.models.thread import STATUS_ARCHIVE
from boards.models.user import Notification
from boards.utils import datetime_to_epoch
__author__ = 'neko259'
PARAMETER_TRUNCATED = 'truncated'
PARAMETER_TAG = 'tag'
PARAMETER_OFFSET = 'offset'
PARAMETER_DIFF_TYPE = 'type'
PARAMETER_POST = 'post'
PARAMETER_UPDATED = 'updated'
PARAMETER_LAST_UPDATE = 'last_update'
PARAMETER_THREAD = 'thread'
PARAMETER_UIDS = 'uids'
PARAMETER_SUBSCRIBED = 'subscribed'
DIFF_TYPE_HTML = 'html'
DIFF_TYPE_JSON = 'json'
STATUS_OK = 'ok'
STATUS_ERROR = 'error'
logger = logging.getLogger(__name__)
@transaction.atomic
def api_get_threaddiff(request):
"""
Gets posts that were changed or added since time
"""
thread_id = request.POST.get(PARAMETER_THREAD)
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(' ')
opening_post = get_object_or_404(Post, id=thread_id)
thread = opening_post.get_thread()
json_data = {
PARAMETER_UPDATED: [],
PARAMETER_LAST_UPDATE: None, # TODO Maybe this can be removed already?
}
posts = Post.objects.filter(thread=thread).exclude(uid__in=uids)
diff_type = request.GET.get(PARAMETER_DIFF_TYPE, DIFF_TYPE_HTML)
for post in posts:
json_data[PARAMETER_UPDATED].append(post.get_post_data(
format_type=diff_type, request=request))
json_data[PARAMETER_LAST_UPDATE] = str(thread.last_edit_time)
settings_manager = get_settings_manager(request)
json_data[PARAMETER_SUBSCRIBED] = str(settings_manager.thread_is_fav(opening_post))
# 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)
return HttpResponse(content=json.dumps(json_data))
@csrf_protect
def api_add_post(request, opening_post_id=None):
"""
Adds a post and return the JSON response for it
"""
if opening_post_id:
opening_post = get_object_or_404(Post, id=opening_post_id)
else:
opening_post = None
status = STATUS_OK
errors = []
post = None
if request.method == 'POST':
if opening_post:
form = PostForm(request.POST, request.FILES, error_class=PlainErrorList)
else:
form = ThreadForm(request.POST, request.FILES, error_class=PlainErrorList)
form.session = request.session
if form.need_to_ban:
# Ban user because he is suspected to be a bot
# _ban_current_user(request)
status = STATUS_ERROR
if form.is_valid():
post = Post.objects.create_from_form(request, form, opening_post,
html_response=False)
if not post:
status = STATUS_ERROR
else:
logger.info('Added post #%d via api.' % post.id)
else:
status = STATUS_ERROR
errors = form.as_json_errors()
else:
status = STATUS_ERROR
response = {
'status': status,
'errors': errors,
}
if post:
response['post_id'] = post.id
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()
return HttpResponse(content=json.dumps(response))
def get_post(request, post_id):
"""
Gets the html of a post. Used for popups. Post can be truncated if used
in threads list with 'truncated' get parameter.
"""
post = get_object_or_404(Post, id=post_id)
truncated = PARAMETER_TRUNCATED in request.GET
return HttpResponse(content=post.get_view(truncated=truncated, need_op_data=True))
def api_get_threads(request, count):
"""
Gets the JSON thread opening posts list.
Parameters that can be used for filtering:
tag, offset (from which thread to get results)
"""
if PARAMETER_TAG in request.GET:
tag_name = request.GET[PARAMETER_TAG]
if tag_name is not None:
tag = get_object_or_404(Tag, name=tag_name)
threads = tag.get_threads().exclude(status=STATUS_ARCHIVE)
else:
threads = Thread.objects.exclude(status=STATUS_ARCHIVE)
if PARAMETER_OFFSET in request.GET:
offset = request.GET[PARAMETER_OFFSET]
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()
# TODO Add tags, replies and images count
post_data = opening_post.get_post_data(include_last_update=True)
post_data['status'] = thread.get_status()
opening_posts.append(post_data)
return HttpResponse(content=json.dumps(opening_posts))
# TODO Test this
def api_get_tags(request):
"""
Gets all tags or user tags.
"""
# TODO Get favorite tags for the given user ID
tags = TagAlias.objects.all()
term = request.GET.get('term')
if term is not None:
tags = tags.filter(name__contains=term)
tag_names = [tag.name for tag in tags]
return HttpResponse(content=json.dumps(tag_names))
def api_get_stickers(request):
term = request.GET.get('term')
if not term:
return HttpResponseBadRequest()
global_stickers = AttachmentSticker.objects.filter(Q(name__icontains=term) | Q(stickerpack__name__icontains=term))
local_stickers = [sticker for sticker in get_settings_manager(request).get_stickers() if term in sticker.name]
stickers = list(global_stickers) + local_stickers
image_dict = [{'thumb': sticker.attachment.get_thumb_url(),
'alias': str(sticker)}
for sticker in stickers]
return HttpResponse(content=json.dumps(image_dict))
# TODO The result can be cached by the thread last update time
# TODO Test this
def api_get_thread_posts(request, opening_post_id):
"""
Gets the JSON array of thread posts
"""
opening_post = get_object_or_404(Post, id=opening_post_id)
thread = opening_post.get_thread()
posts = thread.get_replies()
json_data = {
'posts': [],
'last_update': None,
}
json_post_list = []
for post in posts:
json_post_list.append(post.get_post_data())
json_data['last_update'] = datetime_to_epoch(thread.last_edit_time)
json_data['posts'] = json_post_list
return HttpResponse(content=json.dumps(json_data))
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
posts = Notification.objects.get_notification_posts(usernames=[username],
last=last_id)
json_post_list = []
for post in posts:
json_post_list.append(post.get_post_data())
return HttpResponse(content=json.dumps(json_post_list))
def api_get_post(request, post_id):
"""
Gets the JSON of a post. This can be
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)
def api_get_preview(request):
raw_text = request.POST['raw_text']
parser = Parser()
return HttpResponse(content=parser.parse(parser.preparse(raw_text)))
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)
last_posts = settings_manager.get_last_posts()
if include_posts:
new_post_threads = Thread.objects.get_new_posts(last_posts)
if new_post_threads:
thread_ids = {thread.id: thread for thread in new_post_threads}
else:
thread_ids = dict()
for post in last_posts:
fav_thread_dict = dict()
thread = post.get_thread()
op = thread.get_opening_post()
if thread.id in thread_ids:
thread = thread_ids[thread.id]
new_post_count = thread.new_post_count
fav_thread_dict['newest_post_link'] = thread.get_replies()\
.filter(id__gt=post.id)\
.first().get_absolute_url(thread=thread)
else:
new_post_count = 0
fav_thread_dict['new_post_count'] = new_post_count
fav_thread_dict['id'] = op.id
fav_thread_dict['post_url'] = op.get_link_view()
fav_thread_dict['title'] = op.title
posts.append(fav_thread_dict)
else:
fav_thread_dict = dict()
fav_thread_dict['new_post_count'] = \
Thread.objects.get_new_post_count(last_posts)
posts.append(fav_thread_dict)
return HttpResponse(content=json.dumps(posts))