#!/usr/bin/python2.4
#
# Copyright (C) 2009 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Filter and decorator to wave enable django sites.

If you want to require wave authentication for every handler, just add
WaveOAuthMiddleware to your middleware. If you only want to require
authentication for specific handlers, decorate those with @waveoauth.

In any wave authenticated handler the request object should have a
waveservice field that can be used to talk to wave.

You can specify the following in your settings:
WAVE_CONSUMER_KEY: the consumer key passed to the waveservice. defaults to
    anonymous if not set.
WAVE_CONSUMER_SECRET: the consumer key passed to the waveservice. defaults to
    anonymous if not set.
WAVE_USE_SANDBOX: whether to use the sandbox for this app. Defaults to false.
"""

from django.conf import settings
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth import authenticate

import base64
import logging
from functools import wraps

import waveservice


class WaveOAuthMiddleware(object):
  """Wave middleware to authenticate all requests at this site."""
  def process_request(self, request):
    return _oauth_helper(request)


def waveoauth(func):
  """Decorator used to specify that a handler requires wave authentication."""
  @wraps(func)
  def inner(request, *args, **kwargs):
    result = _oauth_helper(request)
    if result is not None:
      return result
    return func(request, *args, **kwargs)
  return inner


def _oauth_helper(request):
  "Check if we're authenticated and if not, execute the oauth dance."

  consumer_key = getattr(settings, 'WAVE_CONSUMER_KEY', 'anonymous')
  consumer_secret = getattr(settings, 'WAVE_CONSUMER_SECRET', 'anonymous')
  use_sandbox = getattr(settings, 'WAVE_USE_SANDBOX', False)

  service = waveservice.WaveService(
      consumer_key=consumer_key, consumer_secret=consumer_secret, use_sandbox=use_sandbox)

  access_token = request.COOKIES.get('WAVE_ACCESS_TOKEN')
  if access_token:
    service.set_access_token(access_token)
    request.waveservice = service
    return None

  # no access token. dance monkey dance.
  oauth_token = request.GET.get('oauth_token')
  verifier = request.GET.get('oauth_verifier')
  request_token = request.COOKIES.get('WAVE_REQUEST_TOKEN')
  meta = request.META

  # you'd think there would be something better than this madness:
  this_url = meta.get('HTTP_HOST')
  if not this_url:
    this_url = meta.get('SERVER_NAME')
    port = meta.get('SEVER_PORT')
    if port:
      this_url += ':' + port
  this_url += request.path
  schema = meta.get('wsgi.url_scheme', 'http')
  this_url = schema + '://' + this_url

  if not oauth_token or not verifier or not request_token:
    # we're here not returning from a callback. Start.
    request_token = service.fetch_request_token(callback=this_url)
    auth_url = service.generate_authorization_url()
    response = HttpResponseRedirect(auth_url)
    # set a session cookie
    response.set_cookie('WAVE_REQUEST_TOKEN', request_token.to_string())
    return response
  else:
    logging.info('upgrading to access token')
    access_token = service.upgrade_to_access_token(request_token=request_token,
                                                   verifier=verifier)
    # This redirect could be avoided if the caller would set the cookie. This way
    # however we keep the cgi arguments clean.
    response = HttpResponseRedirect(this_url)
    response.set_cookie('WAVE_ACCESS_TOKEN', access_token.to_string(), max_age=24*3600*365)
    return response
