Commit 9b4ac5ab by Matt Drayer Committed by GitHub

Merge pull request #15142 from edx/mattdrayer/ENT-307-commerce

ENT-307: Consider waffle switch when selecting ecommerce workflow
parents 4785b269 a7f6e6a5
...@@ -96,6 +96,8 @@ from lms.envs.common import ( ...@@ -96,6 +96,8 @@ from lms.envs.common import (
SUPPORT_SITE_LINK, SUPPORT_SITE_LINK,
CONTACT_EMAIL, CONTACT_EMAIL,
DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH,
) )
from path import Path as path from path import Path as path
from warnings import simplefilter from warnings import simplefilter
......
""" Custom API permissions. """ """ Custom API permissions. """
from django.conf import settings
from django.contrib.auth.models import User
from rest_framework.permissions import BasePermission, DjangoModelPermissions from rest_framework.permissions import BasePermission, DjangoModelPermissions
from commerce.utils import is_account_activation_requirement_disabled
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.lib.api.permissions import ApiKeyHeaderPermission from openedx.core.lib.api.permissions import ApiKeyHeaderPermission
...@@ -10,3 +14,14 @@ class ApiKeyOrModelPermission(BasePermission): ...@@ -10,3 +14,14 @@ class ApiKeyOrModelPermission(BasePermission):
def has_permission(self, request, view): def has_permission(self, request, view):
return ApiKeyHeaderPermission().has_permission(request, view) or DjangoModelPermissions().has_permission( return ApiKeyHeaderPermission().has_permission(request, view) or DjangoModelPermissions().has_permission(
request, view) request, view)
class IsAuthenticatedOrActivationOverridden(BasePermission):
""" Considers the account activation override switch when determining the authentication status of the user """
def has_permission(self, request, view):
if not request.user.is_authenticated() and is_account_activation_requirement_disabled():
try:
request.user = User.objects.get(id=request.session._session_cache['_auth_user_id'])
except DoesNotExist:
pass
return request.user.is_authenticated()
""" API v1 views. """ """ API v1 views. """
import logging import logging
from django.conf import settings
from django.contrib.auth.models import User
from django.http import Http404 from django.http import Http404
from edx_rest_api_client import exceptions from edx_rest_api_client import exceptions
from rest_framework.authentication import SessionAuthentication from rest_framework.authentication import SessionAuthentication
...@@ -10,10 +12,12 @@ from rest_framework.permissions import IsAuthenticated ...@@ -10,10 +12,12 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework_oauth.authentication import OAuth2Authentication from rest_framework_oauth.authentication import OAuth2Authentication
from commerce.api.v1.models import Course from commerce.api.v1.models import Course
from commerce.api.v1.permissions import ApiKeyOrModelPermission from commerce.api.v1.permissions import ApiKeyOrModelPermission, IsAuthenticatedOrActivationOverridden
from commerce.api.v1.serializers import CourseSerializer from commerce.api.v1.serializers import CourseSerializer
from commerce.utils import is_account_activation_requirement_disabled
from course_modes.models import CourseMode from course_modes.models import CourseMode
from openedx.core.djangoapps.commerce.utils import ecommerce_api_client from openedx.core.djangoapps.commerce.utils import ecommerce_api_client
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.lib.api.mixins import PutAsCreateMixin from openedx.core.lib.api.mixins import PutAsCreateMixin
from util.json_request import JsonResponse from util.json_request import JsonResponse
...@@ -64,10 +68,17 @@ class OrderView(APIView): ...@@ -64,10 +68,17 @@ class OrderView(APIView):
""" Retrieve order details. """ """ Retrieve order details. """
authentication_classes = (SessionAuthentication,) authentication_classes = (SessionAuthentication,)
permission_classes = (IsAuthenticated,) permission_classes = (IsAuthenticatedOrActivationOverridden,)
def get(self, request, number): def get(self, request, number):
""" HTTP handler. """ """ HTTP handler. """
# If the account activation requirement is disabled for this installation, override the
# anonymous user object attached to the request with the actual user object (if it exists)
if not request.user.is_authenticated() and is_account_activation_requirement_disabled():
try:
request.user = User.objects.get(id=request.session._session_cache['_auth_user_id'])
except DoesNotExist:
return JsonResponse(status=403)
try: try:
order = ecommerce_api_client(request.user).orders(number).get() order = ecommerce_api_client(request.user).orders(number).get()
return JsonResponse(order) return JsonResponse(order)
......
...@@ -4,6 +4,7 @@ from django.test import TestCase ...@@ -4,6 +4,7 @@ from django.test import TestCase
from django.test.client import RequestFactory from django.test.client import RequestFactory
from django.test.utils import override_settings from django.test.utils import override_settings
from mock import patch from mock import patch
from waffle.testutils import override_switch
from commerce.models import CommerceConfiguration from commerce.models import CommerceConfiguration
from commerce.utils import EcommerceService from commerce.utils import EcommerceService
...@@ -55,6 +56,14 @@ class EcommerceServiceTests(TestCase): ...@@ -55,6 +56,14 @@ class EcommerceServiceTests(TestCase):
is_not_enabled = EcommerceService().is_enabled(self.user) is_not_enabled = EcommerceService().is_enabled(self.user)
self.assertFalse(is_not_enabled) self.assertFalse(is_not_enabled)
@override_switch(settings.DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH, active=True)
def test_is_enabled_activation_requirement_disabled(self):
"""Verify that is_enabled() returns True when ecomm checkout is enabled. """
self.user.is_active = False
self.user.save()
is_enabled = EcommerceService().is_enabled(self.user)
self.assertTrue(is_enabled)
@patch('openedx.core.djangoapps.theming.helpers.is_request_in_themed_site') @patch('openedx.core.djangoapps.theming.helpers.is_request_in_themed_site')
def test_is_enabled_for_microsites(self, is_microsite): def test_is_enabled_for_microsites(self, is_microsite):
"""Verify that is_enabled() returns True if used for a microsite.""" """Verify that is_enabled() returns True if used for a microsite."""
......
...@@ -2,11 +2,26 @@ ...@@ -2,11 +2,26 @@
from urlparse import urljoin from urlparse import urljoin
from django.conf import settings from django.conf import settings
import waffle
from commerce.models import CommerceConfiguration from commerce.models import CommerceConfiguration
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
def is_account_activation_requirement_disabled():
"""
Checks to see if the django-waffle switch for disabling the account activation requirement is active
Returns:
Boolean value representing switch status
"""
switch_name = configuration_helpers.get_value(
'DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH',
settings.DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH
)
return waffle.switch_is_active(switch_name)
class EcommerceService(object): class EcommerceService(object):
""" Helper class for ecommerce service integration. """ """ Helper class for ecommerce service integration. """
def __init__(self): def __init__(self):
...@@ -49,7 +64,8 @@ class EcommerceService(object): ...@@ -49,7 +64,8 @@ class EcommerceService(object):
Returns: Returns:
Boolean Boolean
""" """
allow_user = user.is_active or user.is_anonymous() user_is_active = user.is_active or is_account_activation_requirement_disabled()
allow_user = user_is_active or user.is_anonymous()
return allow_user and self.config.checkout_on_ecommerce_service return allow_user and self.config.checkout_on_ecommerce_service
def payment_page_url(self): def payment_page_url(self):
......
...@@ -53,7 +53,6 @@ from lms.djangoapps.verify_student.models import ( ...@@ -53,7 +53,6 @@ from lms.djangoapps.verify_student.models import (
) )
from lms.djangoapps.verify_student.views import ( from lms.djangoapps.verify_student.views import (
checkout_with_ecommerce_service, render_to_response, PayAndVerifyView, checkout_with_ecommerce_service, render_to_response, PayAndVerifyView,
DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH,
) )
...@@ -676,7 +675,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin): ...@@ -676,7 +675,7 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase, XssTestMixin):
PayAndVerifyView.WEBCAM_REQ, PayAndVerifyView.WEBCAM_REQ,
]) ])
@override_switch(DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH, active=True) @override_switch(settings.DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH, active=True)
@ddt.data("verify_student_start_flow", "verify_student_begin_flow") @ddt.data("verify_student_start_flow", "verify_student_begin_flow")
def test_disable_account_activation_requirement_flag_active(self, payment_flow): def test_disable_account_activation_requirement_flag_active(self, payment_flow):
""" """
......
...@@ -29,7 +29,7 @@ from opaque_keys import InvalidKeyError ...@@ -29,7 +29,7 @@ from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.keys import CourseKey
import waffle import waffle
from commerce.utils import EcommerceService from commerce.utils import EcommerceService, is_account_activation_requirement_disabled
from course_modes.models import CourseMode from course_modes.models import CourseMode
from edx_rest_api_client.exceptions import SlumberBaseException from edx_rest_api_client.exceptions import SlumberBaseException
from edxmako.shortcuts import render_to_response, render_to_string from edxmako.shortcuts import render_to_response, render_to_string
...@@ -57,8 +57,6 @@ from xmodule.modulestore.django import modulestore ...@@ -57,8 +57,6 @@ from xmodule.modulestore.django import modulestore
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH = 'verify_student_disable_account_activation_requirement'
class PayAndVerifyView(View): class PayAndVerifyView(View):
""" """
...@@ -205,10 +203,7 @@ class PayAndVerifyView(View): ...@@ -205,10 +203,7 @@ class PayAndVerifyView(View):
Arguments: Arguments:
user (User): Current user involved in the onboarding/verification flow user (User): Current user involved in the onboarding/verification flow
""" """
user_is_active = user.is_active return user.is_active or is_account_activation_requirement_disabled()
if waffle.switch_is_active(DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH):
user_is_active = True
return user_is_active
@method_decorator(login_required) @method_decorator(login_required)
def get( def get(
...@@ -614,7 +609,7 @@ class PayAndVerifyView(View): ...@@ -614,7 +609,7 @@ class PayAndVerifyView(View):
} }
# Remove the account activation requirement if disabled via waffle # Remove the account activation requirement if disabled via waffle
if waffle.switch_is_active(DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH): if is_account_activation_requirement_disabled():
all_requirements.pop(self.ACCOUNT_ACTIVATION_REQ) all_requirements.pop(self.ACCOUNT_ACTIVATION_REQ)
display_steps = set(step['name'] for step in display_steps) display_steps = set(step['name'] for step in display_steps)
......
...@@ -629,6 +629,10 @@ TRACKING_SEGMENTIO_SOURCE_MAP = ENV_TOKENS.get("TRACKING_SEGMENTIO_SOURCE_MAP", ...@@ -629,6 +629,10 @@ TRACKING_SEGMENTIO_SOURCE_MAP = ENV_TOKENS.get("TRACKING_SEGMENTIO_SOURCE_MAP",
# Student identity verification settings # Student identity verification settings
VERIFY_STUDENT = AUTH_TOKENS.get("VERIFY_STUDENT", VERIFY_STUDENT) VERIFY_STUDENT = AUTH_TOKENS.get("VERIFY_STUDENT", VERIFY_STUDENT)
DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH = ENV_TOKENS.get(
"DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH",
DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH
)
# Grades download # Grades download
GRADES_DOWNLOAD_ROUTING_KEY = ENV_TOKENS.get('GRADES_DOWNLOAD_ROUTING_KEY', HIGH_MEM_QUEUE) GRADES_DOWNLOAD_ROUTING_KEY = ENV_TOKENS.get('GRADES_DOWNLOAD_ROUTING_KEY', HIGH_MEM_QUEUE)
......
...@@ -2396,6 +2396,7 @@ VERIFY_STUDENT = { ...@@ -2396,6 +2396,7 @@ VERIFY_STUDENT = {
# The variable represents the window within which a verification is considered to be "expiring soon." # The variable represents the window within which a verification is considered to be "expiring soon."
"EXPIRING_SOON_WINDOW": 28, "EXPIRING_SOON_WINDOW": 28,
} }
DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH = "verify_student_disable_account_activation_requirement"
### This enables the Metrics tab for the Instructor dashboard ########### ### This enables the Metrics tab for the Instructor dashboard ###########
FEATURES['CLASS_DASHBOARD'] = False FEATURES['CLASS_DASHBOARD'] = False
......
...@@ -199,6 +199,7 @@ VERIFY_STUDENT["SOFTWARE_SECURE"] = { ...@@ -199,6 +199,7 @@ VERIFY_STUDENT["SOFTWARE_SECURE"] = {
"API_ACCESS_KEY": "BBBBBBBBBBBBBBBBBBBB", "API_ACCESS_KEY": "BBBBBBBBBBBBBBBBBBBB",
"API_SECRET_KEY": "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", "API_SECRET_KEY": "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC",
} }
DISABLE_ACCOUNT_ACTIVATION_REQUIREMENT_SWITCH = "verify_student_disable_account_activation_requirement"
# Skip enrollment start date filtering # Skip enrollment start date filtering
SEARCH_SKIP_ENROLLMENT_START_DATE_FILTERING = True SEARCH_SKIP_ENROLLMENT_START_DATE_FILTERING = True
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment