aboutsummaryrefslogtreecommitdiffstats
path: root/rest_framework
diff options
context:
space:
mode:
authorEric Buehl2014-03-06 20:19:21 +0000
committerEric Buehl2014-03-06 20:21:44 +0000
commit34887ed75625a58d00c986b3ea5526877f4724b2 (patch)
tree9550083d51dce99acf2e744e85d891dd803d645c /rest_framework
parent86375f2d9506bcd3c95cb9901d2237672a47da3f (diff)
downloaddjango-rest-framework-34887ed75625a58d00c986b3ea5526877f4724b2.tar.bz2
it's safe to import scope and constants
Diffstat (limited to 'rest_framework')
-rw-r--r--rest_framework/compat.py4
-rw-r--r--rest_framework/permissions.py7
-rw-r--r--rest_framework/tests/test_authentication.py6
3 files changed, 11 insertions, 6 deletions
diff --git a/rest_framework/compat.py b/rest_framework/compat.py
index f60a180d..d155f554 100644
--- a/rest_framework/compat.py
+++ b/rest_framework/compat.py
@@ -551,6 +551,8 @@ except (ImportError, ImproperlyConfigured):
# OAuth 2 support is optional
try:
import provider as oauth2_provider
+ from provider import scope as oauth2_provider_scope
+ from provider import constants as oauth2_constants
if oauth2_provider.__version__ in ('0.2.3', '0.2.4'):
# 0.2.3 and 0.2.4 are supported version that do not support
# timezone aware datetimes
@@ -561,6 +563,8 @@ try:
from django.utils.timezone import now as provider_now
except ImportError:
oauth2_provider = None
+ oauth2_provider_scope = None
+ oauth2_constants = None
provider_now = None
# Handle lazy strings
diff --git a/rest_framework/permissions.py b/rest_framework/permissions.py
index 6460056a..f24a5123 100644
--- a/rest_framework/permissions.py
+++ b/rest_framework/permissions.py
@@ -8,7 +8,8 @@ import warnings
SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS']
from django.http import Http404
-from rest_framework.compat import (get_model_name, oauth2_provider)
+from rest_framework.compat import (get_model_name, oauth2_provider_scope,
+ oauth2_constants)
class BasePermission(object):
@@ -218,8 +219,8 @@ class TokenHasReadWriteScope(BasePermission):
if hasattr(token, 'resource'): # OAuth 1
return read_only or not request.auth.resource.is_readonly
elif hasattr(token, 'scope'): # OAuth 2
- required = oauth2_provider.constants.READ if read_only else oauth2_provider.constants.WRITE
- return oauth2_provider.scope.check(required, request.auth.scope)
+ required = oauth2_constants.READ if read_only else oauth2_constants.WRITE
+ return oauth2_provider_scope.check(required, request.auth.scope)
assert False, ('TokenHasReadWriteScope requires either the'
'`OAuthAuthentication` or `OAuth2Authentication` authentication '
diff --git a/rest_framework/tests/test_authentication.py b/rest_framework/tests/test_authentication.py
index 90383eef..8caeb081 100644
--- a/rest_framework/tests/test_authentication.py
+++ b/rest_framework/tests/test_authentication.py
@@ -19,7 +19,7 @@ from rest_framework.authentication import (
)
from rest_framework.authtoken.models import Token
from rest_framework.compat import patterns, url, include
-from rest_framework.compat import oauth2_provider
+from rest_framework.compat import oauth2_provider, oauth2_provider_scope
from rest_framework.compat import oauth, oauth_provider
from rest_framework.test import APIRequestFactory, APIClient
from rest_framework.views import APIView
@@ -581,7 +581,7 @@ class OAuth2Tests(TestCase):
def test_post_form_with_invalid_scope_failing_auth(self):
"""Ensure POSTing with a readonly scope instead of a write scope fails"""
read_only_access_token = self.access_token
- read_only_access_token.scope = oauth2_provider.scope.SCOPE_NAME_DICT['read']
+ read_only_access_token.scope = oauth2_provider_scope.SCOPE_NAME_DICT['read']
read_only_access_token.save()
auth = self._create_authorization_header(token=read_only_access_token.token)
response = self.csrf_client.get('/oauth2-with-scope-test/', HTTP_AUTHORIZATION=auth)
@@ -593,7 +593,7 @@ class OAuth2Tests(TestCase):
def test_post_form_with_valid_scope_passing_auth(self):
"""Ensure POSTing with a write scope succeed"""
read_write_access_token = self.access_token
- read_write_access_token.scope = oauth2_provider.scope.SCOPE_NAME_DICT['write']
+ read_write_access_token.scope = oauth2_provider_scope.SCOPE_NAME_DICT['write']
read_write_access_token.save()
auth = self._create_authorization_header(token=read_write_access_token.token)
response = self.csrf_client.post('/oauth2-with-scope-test/', HTTP_AUTHORIZATION=auth)
ref='#n343'>343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
'use strict';

/**
 * @ngdoc widget
 * @name angular.widget.select
 *
 * @description
 * HTML `SELECT` element with angular data-binding.
 *
 * # `ng:options`
 *
 * Optionally `ng:options` attribute can be used to dynamically generate a list of `<option>`
 * elements for a `<select>` element using an array or an object obtained by evaluating the
 * `ng:options` expression.
 *
 * When an item in the select menu is select, the value of array element or object property
 * represented by the selected option will be bound to the model identified by the `name` attribute
 * of the parent select element.
 *
 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
 * be nested into the `<select>` element. This element will then represent `null` or "not selected"
 * option. See example below for demonstration.
 *
 * Note: `ng:options` provides iterator facility for `<option>` element which must be used instead
 * of {@link angular.widget.@ng:repeat ng:repeat}. `ng:repeat` is not suitable for use with
 * `<option>` element because of the following reasons:
 *
 *   * value attribute of the option element that we need to bind to requires a string, but the
 *     source of data for the iteration might be in a form of array containing objects instead of
 *     strings
 *   * {@link angular.widget.@ng:repeat ng:repeat} unrolls after the select binds causing
 *     incorect rendering on most browsers.
 *   * binding to a value not in list confuses most browsers.
 *
 * @param {string} name assignable expression to data-bind to.
 * @param {string=} required The widget is considered valid only if value is entered.
 * @param {comprehension_expression=} ng:options in one of the following forms:
 *
 *   * for array data sources:
 *     * `label` **`for`** `value` **`in`** `array`
 *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
 *     * `label`  **`group by`** `group` **`for`** `value` **`in`** `array`
 *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array`
 *   * for object data sources:
 *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
 *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
 *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
 *     * `select` **`as`** `label` **`group by`** `group`
 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
 *
 * Where:
 *
 *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
 *   * `value`: local variable which will refer to each item in the `array` or each property value
 *      of `object` during iteration.
 *   * `key`: local variable which will refer to a property name in `object` during iteration.
 *   * `label`: The result of this expression will be the label for `<option>` element. The
 *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
 *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
 *      element. If not specified, `select` expression will default to `value`.
 *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
 *      DOM element.
 *
 * @example
    <doc:example>
      <doc:source>
        <script>
        function MyCntrl() {
          this.colors = [
            {name:'black', shade:'dark'},
            {name:'white', shade:'light'},
            {name:'red', shade:'dark'},
            {name:'blue', shade:'dark'},
            {name:'yellow', shade:'light'}
          ];
          this.color = this.colors[2]; // red
        }
        </script>
        <div ng:controller="MyCntrl">
          <ul>
            <li ng:repeat="color in colors">
              Name: <input ng:model="color.name">
              [<a href ng:click="colors.$remove(color)">X</a>]
            </li>
            <li>
              [<a href ng:click="colors.push({})">add</a>]
            </li>
          </ul>
          <hr/>
          Color (null not allowed):
          <select ng:model="color" ng:options="c.name for c in colors"></select><br>

          Color (null allowed):
          <div  class="nullable">
            <select ng:model="color" ng:options="c.name for c in colors">
              <option value="">-- chose color --</option>
            </select>
          </div><br/>

          Color grouped by shade:
          <select ng:model="color" ng:options="c.name group by c.shade for c in colors">
          </select><br/>


          Select <a href ng:click="color={name:'not in list'}">bogus</a>.<br>
          <hr/>
          Currently selected: {{ {selected_color:color}  }}
          <div style="border:solid 1px black; height:20px"
               ng:style="{'background-color':color.name}">
          </div>
        </div>
      </doc:source>
      <doc:scenario>
         it('should check ng:options', function() {
           expect(binding('color')).toMatch('red');
           select('color').option('0');
           expect(binding('color')).toMatch('black');
           using('.nullable').select('color').option('');
           expect(binding('color')).toMatch('null');
         });
      </doc:scenario>
    </doc:example>
 */


                       //00001111100000000000222200000000000000000000003333000000000000044444444444444444000000000555555555555555550000000666666666666666660000000000000007777
var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/;


angularWidget('select', function(element){
  this.directives(true);
  this.descend(true);
  return element.attr('ng:model') && annotate('$formFactory', function($formFactory, selectElement){
    var modelScope = this,
        match,
        form = $formFactory.forElement(selectElement),
        multiple = selectElement.attr('multiple'),
        optionsExp = selectElement.attr('ng:options'),
        modelExp = selectElement.attr('ng:model'),
        widget = form.$createWidget({
          scope: this,
          model: modelExp,
          onChange: selectElement.attr('ng:change'),
          alias: selectElement.attr('name'),
          controller: optionsExp ? Options : (multiple ? Multiple : Single)});

    selectElement.bind('$destroy', function() { widget.$destroy(); });

    widget.$pristine = !(widget.$dirty = false);

    watchElementProperty(modelScope, widget, 'required', selectElement);
    watchElementProperty(modelScope, widget, 'readonly', selectElement);
    watchElementProperty(modelScope, widget, 'disabled', selectElement);

    widget.$on('$validate', function() {
      var valid = !widget.$required || !!widget.$modelValue;
      if (valid && multiple && widget.$required) valid = !!widget.$modelValue.length;
      if (valid !== !widget.$error.REQUIRED) {
        widget.$emit(valid ? '$valid' : '$invalid', 'REQUIRED');
      }
    });

    widget.$on('$viewChange', function() {
      widget.$pristine = !(widget.$dirty = true);
    });

    forEach(['valid', 'invalid', 'pristine', 'dirty'], function(name) {
      widget.$watch('$' + name, function(scope, value) {
        selectElement[value ? 'addClass' : 'removeClass']('ng-' + name);
      });
    });

    ////////////////////////////

    function Multiple() {
      var widget = this;

      this.$render = function() {
        var items = new HashMap(this.$viewValue);
        forEach(selectElement.children(), function(option){
          option.selected = isDefined(items.get(option.value));
        });
      };

      selectElement.bind('change', function() {
        widget.$apply(function() {
          var array = [];
          forEach(selectElement.children(), function(option){
            if (option.selected) {
              array.push(option.value);
            }
          });
          widget.$emit('$viewChange', array);
        });
      });

    }

    function Single() {
      var widget = this;

      widget.$render = function() {
        selectElement.val(widget.$viewValue);
      };

      selectElement.bind('change', function() {
        widget.$apply(function() {
          widget.$emit('$viewChange', selectElement.val());
        });
      });

      widget.$viewValue = selectElement.val();
    }

    function Options() {
      var widget = this,
          match;

      if (! (match = optionsExp.match(NG_OPTIONS_REGEXP))) {
        throw Error(
          "Expected ng:options in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
          " but got '" + optionsExp + "'.");
      }

      var widgetScope = this,
          displayFn = expressionCompile(match[2] || match[1]),
          valueName = match[4] || match[6],
          keyName = match[5],
          groupByFn = expressionCompile(match[3] || ''),
          valueFn = expressionCompile(match[2] ? match[1] : valueName),
          valuesFn = expressionCompile(match[7]),
          // we can't just jqLite('<option>') since jqLite is not smart enough
          // to create it in <select> and IE barfs otherwise.
          optionTemplate = jqLite(document.createElement('option')),
          optGroupTemplate = jqLite(document.createElement('optgroup')),
          nullOption = false, // if false then user will not be able to select it
          // This is an array of array of existing option groups in DOM. We try to reuse these if possible
          // optionGroupsCache[0] is the options with no option group
          // optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
          optionGroupsCache = [[{element: selectElement, label:''}]],
          inChangeEvent;

      // find existing special options
      forEach(selectElement.children(), function(option){
        if (option.value == '')
          // User is allowed to select the null.
          nullOption = {label:jqLite(option).text(), id:''};
      });
      selectElement.html(''); // clear contents

      selectElement.bind('change', function() {
        widgetScope.$apply(function() {
          var optionGroup,
              collection = valuesFn(modelScope) || [],
              key = selectElement.val(),
              tempScope = inherit(modelScope),
              value, optionElement, index, groupIndex, length, groupLength;

          if (multiple) {
            value = [];
            for (groupIndex = 0, groupLength = optionGroupsCache.length;
            groupIndex < groupLength;
            groupIndex++) {
              // list of options for that group. (first item has the parent)