Implement generic rest_dispatch method for new API.

(imported from commit 912ee803db03098f195d18648ab98401915fead6)
This commit is contained in:
Luke Faraone
2013-03-21 12:15:27 -07:00
parent 0c0f99ccc6
commit a49c37917a
3 changed files with 62 additions and 4 deletions

View File

@@ -1,7 +1,7 @@
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from zephyr.models import UserProfile, UserActivity, get_client from zephyr.models import UserProfile, UserActivity, get_client
from zephyr.lib.response import json_success, json_error from zephyr.lib.response import json_success, json_error, HttpResponseUnauthorized
from django.utils.timezone import now from django.utils.timezone import now
from django.db import transaction, IntegrityError from django.db import transaction, IntegrityError
from django.conf import settings from django.conf import settings
@@ -13,6 +13,7 @@ from zephyr.lib.cache import user_profile_by_email_cache_key, \
user_profile_by_user_cache_key user_profile_by_user_cache_key
from functools import wraps from functools import wraps
import base64
class _RespondAsynchronously(object): class _RespondAsynchronously(object):
pass pass
@@ -90,6 +91,35 @@ def authenticated_api_view(view_func):
return view_func(request, user_profile, *args, **kwargs) return view_func(request, user_profile, *args, **kwargs)
return _wrapped_view_func return _wrapped_view_func
def authenticated_rest_api_view(view_func):
@csrf_exempt
@wraps(view_func)
def _wrapped_view_func(request, *args, **kwargs):
# First try block attempts to get the credentials we need to do authentication
try:
# Grab the base64-encoded authentication string, decode it, and split it into
# the email and API key
auth_type, encoded_value = request.META['HTTP_AUTHORIZATION'].split()
# case insensitive per RFC 1945
if auth_type.lower() != "basic":
return json_error("Only Basic authentication is supported.")
email, api_key = base64.b64decode(encoded_value).split(":")
except ValueError:
return json_error("Invalid authorization header for basic auth")
except KeyError:
return HttpResponseUnauthorized("humbug")
# Now we try to do authentication or die
try:
user_profile = validate_api_key(email, api_key)
except JsonableError, e:
resp = HttpResponseUnauthorized("humbug")
resp.content = e.error
return resp
process_client(request, user_profile)
return view_func(request, user_profile, *args, **kwargs)
return _wrapped_view_func
def authenticate_log_and_execute_json(request, client, view_func, *args, **kwargs): def authenticate_log_and_execute_json(request, client, view_func, *args, **kwargs):
if not request.user.is_authenticated(): if not request.user.is_authenticated():
return json_error("Not logged in", status=401) return json_error("Not logged in", status=401)

View File

@@ -1,6 +1,20 @@
from django.http import HttpResponse from django.http import HttpResponse, HttpResponseNotAllowed
import simplejson import simplejson
class HttpResponseUnauthorized(HttpResponse):
status_code = 401
def __init__(self, realm):
HttpResponse.__init__(self)
self["WWW-Authenticate"] = 'Basic realm="%s"' % realm
def json_method_not_allowed(methods):
resp = HttpResponseNotAllowed(methods)
resp.content = simplejson.dumps({"result": "error",
"msg": "Method Not Allowed",
"allowed_methods": methods})
return resp
def json_response(res_type="success", msg="", data={}, status=200): def json_response(res_type="success", msg="", data={}, status=200):
content = {"result": res_type, "msg": msg} content = {"result": res_type, "msg": msg}
content.update(data) content.update(data)

View File

@@ -34,10 +34,10 @@ from zephyr.decorator import require_post, \
has_request_variables, POST, authenticated_json_view, \ has_request_variables, POST, authenticated_json_view, \
to_non_negative_int, json_to_dict, json_to_list, json_to_bool, \ to_non_negative_int, json_to_dict, json_to_list, json_to_bool, \
JsonableError, RequestVariableMissingError, get_user_profile_by_email, \ JsonableError, RequestVariableMissingError, get_user_profile_by_email, \
get_user_profile_by_user_id get_user_profile_by_user_id, authenticated_rest_api_view, \
from zephyr.lib.query import last_n from zephyr.lib.query import last_n
from zephyr.lib.avatar import gravatar_hash from zephyr.lib.avatar import gravatar_hash
from zephyr.lib.response import json_success, json_error, json_response from zephyr.lib.response import json_success, json_error, json_response, json_method_not_allowed
from zephyr.lib.timestamp import timestamp_to_datetime, datetime_to_timestamp from zephyr.lib.timestamp import timestamp_to_datetime, datetime_to_timestamp
from zephyr.lib.cache import cache_with_key from zephyr.lib.cache import cache_with_key
@@ -150,6 +150,20 @@ def principal_to_user_profile(agent, principal):
return principal_user_profile return principal_user_profile
METHODS = ('GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'PATCH')
@authenticated_rest_api_view
def rest_dispatch(request, user_profile, **kwargs):
supported_methods = {}
# duplicate kwargs so we can mutate the original as we go
for arg in list(kwargs):
if arg in METHODS:
supported_methods[arg] = kwargs[arg]
del kwargs[arg]
if request.method in supported_methods.keys():
return globals()[supported_methods[request.method]](request, user_profile, **kwargs)
return json_method_not_allowed(supported_methods.keys())
@require_post @require_post
def accounts_register(request): def accounts_register(request):
key = request.POST['key'] key = request.POST['key']