it/itf/api/views.py

407 lines
12 KiB
Python

# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division
import os.path
from os.path import join
import re
from datetime import datetime
from urllib2 import unquote
import mimetypes
from django import forms
from django.core.paginator import Paginator
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.db.models import Q, Avg, Count, Sum
from django.http import HttpResponse, Http404
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404, redirect
from django.template import RequestContext
from django.conf import settings
from django.contrib.comments.forms import CommentForm
from django.contrib.comments.models import Comment
from django.contrib.comments.signals import comment_will_be_posted, comment_was_posted
from django.contrib.contenttypes.models import ContentType
from ox.utils import json
from ox.django.decorators import login_required_json
from ox.django.shortcuts import render_to_json_response, get_object_or_404_json, json_response
from ox.django.http import HttpFileResponse
import ox
from actions import actions
from user.models import get_user_json
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def api(request):
if request.META['REQUEST_METHOD'] == "OPTIONS":
response = render_to_json_response({'status': {'code': 200,
'text': 'use POST'}})
response['Access-Control-Allow-Origin'] = '*'
return response
if not 'action' in request.POST:
methods = actions.keys()
api = []
for f in sorted(methods):
api.append({'name': f,
'doc': actions.doc(f).replace('\n', '<br>\n')})
context = RequestContext(request, {'api': api,
'sitename': settings.SITENAME})
return render_to_response('api.html', context)
function = request.POST['action']
#FIXME: possible to do this in f
#data = json.loads(request.POST['data'])
f = actions.get(function, None)
if f:
response = f(request)
else:
response = render_to_json_response(json_response(status=400,
text='Unknown function %s' % function))
response['Access-Control-Allow-Origin'] = '*'
return response
#def api_api(request):
# '''
# returns list of all known api action
# return {'status': {'code': int, 'text': string},
# 'data': {actions: ['api', 'hello', ...]}}
# '''
# actions = globals().keys()
# actions = map(lambda a: a[4:], filter(lambda a: a.startswith('api_'), actions))
# actions.sort()
# ret = {}
# #FIXME: set cache to False for login, logout, etc.
# for a in actions:
# ret[a] = {
# 'cache': True
# }
# return render_to_json_response(json_response({'actions': ret}))
#def api_apidoc(request):
# '''
# returns array of actions with documentation
# '''
# actions = globals().keys()
# actions = map(lambda a: a[4:], filter(lambda a: a.startswith('api_'), actions))
# actions.sort()
# docs = {}
# for f in actions:
# docs[f] = get_api_doc(f)
# return render_to_json_response(json_response({'actions': docs}))
def init(request):
'''
return {'status': {'code': int, 'text': string},
'data': {user: object}}
'''
#data = json.loads(request.POST['data'])
response = json_response({})
if request.user.is_authenticated():
response['data']['user'] = get_user_json(request.user)
else:
response['data']['user'] = {'name': 'Guest', 'group': 'guest', 'level': 'guest', 'preferences': {}}
#FIXME: Get config definition out of here.
response['data']['config'] = {
'site': {
'name': 'India Theatre Forum'
}
}
return render_to_json_response(response)
actions.register(init)
def error(request):
'''
trows 503 error
'''
success = error_is_success
return render_to_json_response({})
actions.register(error)
def find(request):
data = json.loads(request.POST['data'])
# print json.dumps(data)
model = getModel(data)
response = json_response({})
l = model.get_list(data)
if data.has_key('ids'):
ids = data['ids']
else:
ids = []
if data.has_key('range'):
response['data']['items'] = l
else:
response['data']['items'] = len(l)
response['data']['positions'] = _get_positions(ids, l)
response['status'] = {'code': 200}
return render_to_json_response(response)
actions.register(find)
def _get_positions(ids, l):
ret = {}
i = 0
for id in ids:
for obj in l:
if obj['id'] == id:
ret[id] = i
break
i += 1
return ret
def preview(request):
data = json.loads(request.POST['data'])
if not data.has_key('id'):
return render_to_json_response({'status': {'code': 404}})
id = int(data['id'])
model = getModel(data)
response = json_response({})
response['status'] = {'code': 200}
obj = get_object_or_404(model, pk=id)
response['data'] = obj.preview_dict()
response['template'] = getTemplate(data, "preview")
return render_to_json_response(response)
actions.register(preview)
#FIXME: Generalize based on these two functions being the same.
def info(request):
'''
id: object id
model: string, name of model
module: string, name of module
'''
data = json.loads(request.POST['data'])
id = int(data['id'])
model = getModel(data)
response = json_response({})
response['status'] = {'code': 200}
obj = get_object_or_404(model, pk=id)
if model.hasComments:
response['commentForm'] = _get_comment_form_initial(request, obj)
response['comments'] = _get_comments(obj)
response['data'] = obj.info_dict()
response['template'] = getTemplate(data, "info")
return render_to_json_response(response)
actions.register(info)
#obj: Django model instance - object for which to get comment form for.
#Returns dict with content_type, object_id, security_hash, etc.
#FIXME: put comments stuff somewhere
def _get_comment_form_initial(request, obj):
c = CommentForm(obj)
return c.initial
def _get_comments(obj):
ret = []
content_type = ContentType.objects.get_for_model(obj)
object_id = obj.id
qset = Comment.objects.filter(content_type=content_type, object_pk=object_id)
for q in qset:
ret.append({
'name': q.name,
# 'date': q.submit_date,
'comment': q.comment
})
return ret
@login_required_json
def addComment(request):
'''
id
module
model
comment
content_type
email
name
object_pk
security_hash
timestamp
'''
data = json.loads(request.POST['data'])
data.update({
'name': request.user.username,
'email': request.user.email
})
id = int(data['object_pk'])
model = getModel(data)
obj = get_object_or_404_json(model, pk=id)
cf = CommentForm(obj, data=data)
ret = json_response({})
if cf.is_valid():
comment = cf.get_comment_object()
comment.user = request.user
# Signal that the comment is about to be saved
responses = comment_will_be_posted.send(
sender = comment.__class__,
comment = comment,
request = request
)
for (receiver, response) in responses:
if response == False:
return CommentPostBadRequest(
"comment_will_be_posted receiver %r killed the comment" % receiver.__name__)
# Save the comment and signal that it was saved
comment.save()
comment_was_posted.send(
sender = comment.__class__,
comment = comment,
request = request
)
ret['data'] = {
id: comment.id
}
ret['status'] = {'code': 200}
else:
ret['status'] = {'code': 200}
ret['errors'] = cf.errors
return render_to_json_response(ret)
actions.register(addComment)
widgetMap = {
'TextInput': 'text',
'Textarea': 'textarea',
'Select': 'select'
}
def getAddItemForm(request):
response = json_response({})
data = json.loads(request.POST['data'])
model = getModel(data)
# import pdb; pdb.set_trace()
form = getForm(data)
form_fields = []
for field in form.base_fields:
name = field
this = form.base_fields[field]
widget = this.widget
widgetClassName = type(widget).__name__
if hasattr(widget, "choices"):
choices = []
for c in widget.choices:
if c[0] == '':
id = 0
else:
id = c[0]
choices.append({
'id': id,
'title': c[1]
})
else:
choices = False
js_widget = widgetMap.get(widgetClassName, "text")
form_fields.append({
'name': name,
'widget': js_widget,
'label': this.label,
'choices': choices
})
response['data']['form'] = form_fields
return render_to_json_response(response)
actions.register(getAddItemForm)
@login_required_json
def addItem(request):
response = json_response({})
data = json.loads(request.POST['data'])
model = getModel(data)
form = getForm(data)
if form.is_valid():
m = model()
for field in form.base_fields:
m.__setattr__(field, form.cleaned_data[field])
m.save()
response['data'] = {'id': m.id}
else:
response['errors'] = form.errors
return render_to_json_response(response)
actions.register(addItem)
def getTemplate(data, tmpl_name):
path = join(settings.PROJECT_PATH, "templates", data['module'], data['model'], tmpl_name + ".html")
return open(path).read().strip()
def getModel(data):
module = __import__(data['module'])
return module.models.__getattribute__(data['model'])
#FIXME: BAAD Hack
def getForm(data):
module = __import__(data['module'] + ".forms")
model = getModel(data)
formStr = model.add_form
return module.forms.__getattribute__(formStr)
def get_api_doc(f):
f = 'api_' + f
import sys
def trim(docstring):
if not docstring:
return ''
# Convert tabs to spaces (following the normal Python rules)
# and split into a list of lines:
lines = docstring.expandtabs().splitlines()
# Determine minimum indentation (first line doesn't count):
indent = sys.maxint
for line in lines[1:]:
stripped = line.lstrip()
if stripped:
indent = min(indent, len(line) - len(stripped))
# Remove indentation (first line is special):
trimmed = [lines[0].strip()]
if indent < sys.maxint:
for line in lines[1:]:
trimmed.append(line[indent:].rstrip())
# Strip off trailing and leading blank lines:
while trimmed and not trimmed[-1]:
trimmed.pop()
while trimmed and not trimmed[0]:
trimmed.pop(0)
# Return a single string:
return '\n'.join(trimmed)
return trim(globals()[f].__doc__)
def apidoc(request):
'''
this is used for online documentation at http://127.0.0.1:8000/api/
'''
functions = filter(lambda x: x.startswith('api_'), globals().keys())
api = []
for f in sorted(functions):
api.append({
'name': f[4:],
'doc': get_api_doc(f[4:]).replace('\n', '<br>\n')
})
context = RequestContext(request, {'api': api,
'sitename': settings.SITENAME,})
return render_to_response('api.html', context)
def jsdoc(request):
'''
Used to document OxUI JS Widgets
'''
context = RequestContext(request, {})
return render_to_response("jsdoc.html", context)
'''
ajax html snapshots
http://code.google.com/web/ajaxcrawling/docs/html-snapshot.html
'''
def html_snapshot(request):
fragment = unquote(request.GET['_escaped_fragment_'])
url = request.build_absolute_uri('/ra')
url = 'http://'+settings.URL
response = HttpResponse('sorry, server side rendering for %s!#%s not yet implemented'%(url, fragment))
return response