app/soc/views/helper/decorators.py
author Sverre Rabbelier <srabbelier@gmail.com>
Sun, 01 Mar 2009 20:39:21 +0000
changeset 1585 06fb5950cb03
parent 1582 f2f352ad193f
child 1592 4465cda55182
permissions -rw-r--r--
Make it possible to put the site in maintenance mode By specifying the UTC date from which the maintenance shoulds start, developers can put the site in 'maintenance' mode. Also redirect to /maintenance if we get a CapabilityDisabledError. Patch by: Sverre Rabbelier

#!/usr/bin/python2.5
#
# Copyright 2008 the Melange authors.
#
# 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.

"""Views decorators.
"""

__authors__ = [
  '"Pawel Solyga" <pawel.solyga@gmail.com>',
  '"Sverre Rabbelier" <sverre@rabbelier.nl>',
  ]


import logging

from functools import wraps

from google.appengine.api import users
from google.appengine.runtime import DeadlineExceededError
from google.appengine.runtime.apiproxy_errors import CapabilityDisabledError


from django import http

from soc.logic import dicts


class Error(Exception):
  pass


def view(func):
  """Decorator that insists that exceptions are handled by view.
  """

  from soc.logic.helper import timeline
  from soc.logic.models.site import logic as site_logic

  @wraps(func)
  def view_wrapper(request, *args, **kwds):
    site = site_logic.getSingleton()

    # don't redirect admins, or if we're at /maintenance already
    no_redirect = users.is_current_user_admin() or request.path == '/maintenance'

    if (not no_redirect) and timeline.isAfterEvent(site, 'maintenance_start'):
      return http.HttpResponseRedirect('/maintenance')

    try:
      return func(request, *args, **kwds)
    except DeadlineExceededError, e:
      logging.exception(e)
      return http.HttpResponseRedirect('/soc/content/deadline_exceeded.html')
    except CapabilityDisabledError, e:
      logging.exception(e)
      # assume the site is in maintenance if we get CDE
      return http.HttpResponseRedirect('/maintenance')
    except MemoryError, e:
      logging.exception(e)
      return http.HttpResponseRedirect('/soc/content/memory_error.html')
    except AssertionError, e:
      logging.exception(e)
      return http.HttpResponseRedirect('/soc/content/assertion_error.html')

  return view_wrapper


def merge_params(func):
  """Decorator that merges 'params' with self._params.
  """

  @wraps(func)
  def wrapper(self, *args, **kwargs):
    params = kwargs.get('params', {})
    kwargs['params'] = dicts.merge(params, self._params)
    return func(self, *args, **kwargs)

  return wrapper


def check_access(func):
  """This decorator does access checks for the specified view method.

  The rights dictionary is extracted from 'params', or, if either 'params' or
  'rights' do not exist, from self._params['rights'].
  """

  # Do not pollute helper.decorators with access specific imports
  from soc.views import out_of_band
  from soc.views import helper
  from soc.views.helper import access
  from soc.views.helper import responses

  @wraps(func)
  def wrapper(self, request, access_type, *args, **kwargs):
    params = kwargs.get('params', {})

    # Try to extract rights
    if 'rights' in params:
      rights = params['rights']
    else:
      rights = self._params['rights']

    check_kwargs = kwargs.copy()
    context = responses.getUniversalContext(request)
    responses.useJavaScript(context, self._params['js_uses_all'])

    id = context['account']
    user = context['user']

    check_kwargs['GET'] = request.GET
    check_kwargs['POST'] = request.POST
    check_kwargs['context'] = context

    # reset and pre-fill the Checker's cache
    rights.setCurrentUser(id, user)

    # Do the access check dance
    try:
      rights.checkAccess(access_type, check_kwargs)
    except out_of_band.Error, error:
      return helper.responses.errorResponse(error, request)
    return func(self, request, access_type, *args, **kwargs)

  return wrapper