api.py
246 lines
| 6.9 KiB
| text/x-python
|
PythonLexer
neko259
|
r450 | import json | ||
neko259
|
r639 | import logging | ||
neko259
|
r1117 | |||
neko259
|
r450 | from django.db import transaction | ||
from django.http import HttpResponse | ||||
neko259
|
r1117 | from django.shortcuts import get_object_or_404 | ||
neko259
|
r564 | from django.core import serializers | ||
neko259
|
r533 | from boards.forms import PostForm, PlainErrorList | ||
neko259
|
r499 | from boards.models import Post, Thread, Tag | ||
neko259
|
r542 | from boards.utils import datetime_to_epoch | ||
from boards.views.thread import ThreadView | ||||
neko259
|
r994 | from boards.models.user import Notification | ||
neko259
|
r450 | |||
neko259
|
r1117 | |||
neko259
|
r450 | __author__ = 'neko259' | ||
neko259
|
r501 | PARAMETER_TRUNCATED = 'truncated' | ||
PARAMETER_TAG = 'tag' | ||||
PARAMETER_OFFSET = 'offset' | ||||
neko259
|
r524 | PARAMETER_DIFF_TYPE = 'type' | ||
neko259
|
r1075 | PARAMETER_POST = 'post' | ||
neko259
|
r1076 | PARAMETER_UPDATED = 'updated' | ||
neko259
|
r1086 | PARAMETER_LAST_UPDATE = 'last_update' | ||
neko259
|
r1119 | PARAMETER_THREAD = 'thread' | ||
PARAMETER_UIDS = 'uids' | ||||
neko259
|
r524 | |||
DIFF_TYPE_HTML = 'html' | ||||
DIFF_TYPE_JSON = 'json' | ||||
neko259
|
r501 | |||
neko259
|
r533 | STATUS_OK = 'ok' | ||
STATUS_ERROR = 'error' | ||||
neko259
|
r639 | logger = logging.getLogger(__name__) | ||
neko259
|
r450 | |||
@transaction.atomic | ||||
neko259
|
r1086 | def api_get_threaddiff(request): | ||
neko259
|
r627 | """ | ||
Gets posts that were changed or added since time | ||||
""" | ||||
neko259
|
r450 | |||
neko259
|
r1119 | thread_id = request.GET.get(PARAMETER_THREAD) | ||
uids_str = request.POST.get(PARAMETER_UIDS).strip() | ||||
neko259
|
r1118 | uids = uids_str.split(' ') | ||
neko259
|
r639 | |||
neko259
|
r1086 | thread = get_object_or_404(Post, id=thread_id).get_thread() | ||
neko259
|
r450 | |||
json_data = { | ||||
neko259
|
r1076 | PARAMETER_UPDATED: [], | ||
neko259
|
r1119 | PARAMETER_LAST_UPDATE: None, # TODO Maybe this can be removed already? | ||
neko259
|
r504 | } | ||
neko259
|
r1118 | posts = Post.objects.filter(threads__in=[thread]).exclude(uid__in=uids) | ||
neko259
|
r524 | |||
neko259
|
r917 | diff_type = request.GET.get(PARAMETER_DIFF_TYPE, DIFF_TYPE_HTML) | ||
neko259
|
r524 | |||
neko259
|
r1118 | for post in posts: | ||
neko259
|
r1076 | json_data[PARAMETER_UPDATED].append(get_post_data(post.id, diff_type, request)) | ||
neko259
|
r1086 | json_data[PARAMETER_LAST_UPDATE] = str(thread.last_edit_time) | ||
neko259
|
r450 | |||
return HttpResponse(content=json.dumps(json_data)) | ||||
neko259
|
r533 | def api_add_post(request, opening_post_id): | ||
""" | ||||
neko259
|
r627 | Adds a post and return the JSON response for it | ||
neko259
|
r533 | """ | ||
opening_post = get_object_or_404(Post, id=opening_post_id) | ||||
neko259
|
r640 | logger.info('Adding post via api...') | ||
neko259
|
r533 | status = STATUS_OK | ||
errors = [] | ||||
if request.method == 'POST': | ||||
neko259
|
r640 | form = PostForm(request.POST, request.FILES, error_class=PlainErrorList) | ||
neko259
|
r533 | form.session = request.session | ||
neko259
|
r638 | if form.need_to_ban: | ||
# Ban user because he is suspected to be a bot | ||||
# _ban_current_user(request) | ||||
status = STATUS_ERROR | ||||
neko259
|
r533 | if form.is_valid(): | ||
neko259
|
r640 | post = ThreadView().new_post(request, form, opening_post, | ||
neko259
|
r690 | html_response=False) | ||
neko259
|
r640 | if not post: | ||
neko259
|
r638 | status = STATUS_ERROR | ||
neko259
|
r640 | else: | ||
logger.info('Added post #%d via api.' % post.id) | ||||
neko259
|
r533 | else: | ||
status = STATUS_ERROR | ||||
errors = form.as_json_errors() | ||||
response = { | ||||
'status': status, | ||||
'errors': errors, | ||||
} | ||||
return HttpResponse(content=json.dumps(response)) | ||||
neko259
|
r499 | |||
neko259
|
r491 | def get_post(request, post_id): | ||
neko259
|
r499 | """ | ||
neko259
|
r627 | Gets the html of a post. Used for popups. Post can be truncated if used | ||
neko259
|
r499 | in threads list with 'truncated' get parameter. | ||
""" | ||||
neko259
|
r491 | |||
post = get_object_or_404(Post, id=post_id) | ||||
neko259
|
r1110 | truncated = PARAMETER_TRUNCATED in request.GET | ||
neko259
|
r491 | |||
neko259
|
r1110 | return HttpResponse(content=post.get_view(truncated=truncated)) | ||
neko259
|
r499 | |||
def api_get_threads(request, count): | ||||
""" | ||||
neko259
|
r627 | Gets the JSON thread opening posts list. | ||
neko259
|
r499 | Parameters that can be used for filtering: | ||
tag, offset (from which thread to get results) | ||||
""" | ||||
neko259
|
r501 | if PARAMETER_TAG in request.GET: | ||
tag_name = request.GET[PARAMETER_TAG] | ||||
neko259
|
r499 | if tag_name is not None: | ||
tag = get_object_or_404(Tag, name=tag_name) | ||||
neko259
|
r908 | threads = tag.get_threads().filter(archived=False) | ||
neko259
|
r499 | else: | ||
threads = Thread.objects.filter(archived=False) | ||||
neko259
|
r501 | if PARAMETER_OFFSET in request.GET: | ||
offset = request.GET[PARAMETER_OFFSET] | ||||
neko259
|
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
|
r524 | # TODO Add tags, replies and images count | ||
neko259
|
r976 | post_data = get_post_data(opening_post.id, include_last_update=True) | ||
post_data['bumpable'] = thread.can_bump() | ||||
post_data['archived'] = thread.archived | ||||
opening_posts.append(post_data) | ||||
neko259
|
r499 | |||
return HttpResponse(content=json.dumps(opening_posts)) | ||||
neko259
|
r500 | |||
neko259
|
r502 | # TODO Test this | ||
neko259
|
r500 | def api_get_tags(request): | ||
""" | ||||
neko259
|
r627 | Gets all tags or user tags. | ||
neko259
|
r500 | """ | ||
# TODO Get favorite tags for the given user ID | ||||
tags = Tag.objects.get_not_empty_tags() | ||||
neko259
|
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
|
r500 | |||
return HttpResponse(content=json.dumps(tag_names)) | ||||
neko259
|
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
|
r627 | Gets the JSON array of thread posts | ||
neko259
|
r502 | """ | ||
opening_post = get_object_or_404(Post, id=opening_post_id) | ||||
neko259
|
r627 | thread = opening_post.get_thread() | ||
neko259
|
r502 | posts = thread.get_replies() | ||
neko259
|
r525 | json_data = { | ||
'posts': [], | ||||
'last_update': None, | ||||
} | ||||
neko259
|
r502 | json_post_list = [] | ||
for post in posts: | ||||
neko259
|
r853 | json_post_list.append(get_post_data(post.id)) | ||
neko259
|
r542 | json_data['last_update'] = datetime_to_epoch(thread.last_edit_time) | ||
neko259
|
r525 | json_data['posts'] = json_post_list | ||
neko259
|
r524 | |||
neko259
|
r525 | return HttpResponse(content=json.dumps(json_data)) | ||
neko259
|
r524 | |||
neko259
|
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 | ||||
posts = Notification.objects.get_notification_posts(username=username, | ||||
neko259
|
r1117 | last=last_id) | ||
neko259
|
r994 | |||
json_post_list = [] | ||||
for post in posts: | ||||
json_post_list.append(get_post_data(post.id)) | ||||
return HttpResponse(content=json.dumps(json_post_list)) | ||||
neko259
|
r564 | def api_get_post(request, post_id): | ||
""" | ||||
neko259
|
r627 | Gets the JSON of a post. This can be | ||
neko259
|
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
|
r853 | # TODO Remove this method and use post method directly | ||
def get_post_data(post_id, format_type=DIFF_TYPE_JSON, request=None, | ||||
include_last_update=False): | ||||
post = get_object_or_404(Post, id=post_id) | ||||
return post.get_post_data(format_type=format_type, request=request, | ||||
include_last_update=include_last_update) | ||||
neko259
|
r1144 | |||
# TODO Make a separate module for sync API methods | ||||
def sync_pull(request): | ||||
""" | ||||
Return 'get' request response for all posts. | ||||
""" | ||||
request_xml = request.get('xml') | ||||
if request_xml is None: | ||||
posts = Post.objects.all() | ||||
else: | ||||
pass # TODO Parse the XML and get filters from it | ||||
xml = Post.objects.generate_response_get(posts) | ||||
return HttpResponse(content=xml) | ||||