Commit d8c07ce2 by Clinton Blackburn

Extracted Apple Pay view and processor code out of CyberSource module

The Apple Pay code is not all CyberSource-specific. Extracting it allows it to be used with other payment processors.
parent c3615196
......@@ -5,6 +5,7 @@ from collections import namedtuple
import waffle
from django.conf import settings
from django.utils.functional import cached_property
from oscar.core.loading import get_model
PaymentProcessorResponse = get_model('payment', 'PaymentProcessorResponse')
......@@ -146,3 +147,15 @@ class BaseClientSidePaymentProcessor(BasePaymentProcessor): # pylint: disable=a
str
"""
return 'payment/{}.html'.format(self.NAME)
class ApplePayMixin(object):
@cached_property
def apple_pay_merchant_id_domain_association(self):
""" Returns the Apple Pay merchant domain association contents that will be served at
/.well-known/apple-developer-merchantid-domain-association.
Returns:
str
"""
return (self.configuration.get('apple_pay_merchant_id_domain_association') or '').strip()
......@@ -29,7 +29,11 @@ from ecommerce.extensions.payment.exceptions import (
ProcessorMisconfiguredError
)
from ecommerce.extensions.payment.helpers import sign
from ecommerce.extensions.payment.processors import BaseClientSidePaymentProcessor, HandledProcessorResponse
from ecommerce.extensions.payment.processors import (
ApplePayMixin,
BaseClientSidePaymentProcessor,
HandledProcessorResponse
)
from ecommerce.extensions.payment.utils import clean_field_value
logger = logging.getLogger(__name__)
......@@ -37,13 +41,14 @@ logger = logging.getLogger(__name__)
OrderNumberGenerator = get_class('order.utils', 'OrderNumberGenerator')
class Cybersource(BaseClientSidePaymentProcessor):
class Cybersource(ApplePayMixin, BaseClientSidePaymentProcessor):
"""
CyberSource Secure Acceptance Web/Mobile (February 2015)
For reference, see
http://apps.cybersource.com/library/documentation/dev_guides/Secure_Acceptance_WM/Secure_Acceptance_WM.pdf.
"""
NAME = 'cybersource'
PCI_FIELDS = ('card_cvn', 'card_expiry_date', 'card_number', 'card_type',)
......@@ -87,8 +92,6 @@ class Cybersource(BaseClientSidePaymentProcessor):
# Apple Pay configuration
self.apple_pay_enabled = self.site.siteconfiguration.enable_apple_pay
self.apple_pay_merchant_identifier = configuration.get('apple_pay_merchant_identifier', '')
self.apple_pay_merchant_id_domain_association = configuration.get(
'apple_pay_merchant_id_domain_association', '').strip()
self.apple_pay_merchant_id_certificate_path = configuration.get('apple_pay_merchant_id_certificate_path', '')
self.apple_pay_country_code = configuration.get('apple_pay_country_code', '')
......
from django.conf import settings
from django.test import override_settings
from django.urls import reverse
from ecommerce.extensions.payment.tests.views.test_cybersource import LoginMixin
from ecommerce.tests.testcases import TestCase
class ApplePayMerchantDomainAssociationViewTests(LoginMixin, TestCase):
url = reverse('apple_pay_domain_association')
def setUp(self):
super(ApplePayMerchantDomainAssociationViewTests, self).setUp()
self.site_configuration.client_side_payment_processor = 'cybersource'
self.site_configuration.save()
def set_apple_pay_merchant_id_domain_association(self, value):
key = 'apple_pay_merchant_id_domain_association'
partner_code = self.site_configuration.partner.short_code
processor_name = self.site_configuration.client_side_payment_processor
settings.PAYMENT_PROCESSOR_CONFIG[partner_code][processor_name][key] = value
def assert_response_matches(self, response, expected_status_code, expected_content):
self.assertEqual(response.status_code, expected_status_code)
self.assertEqual(response.content, expected_content)
self.assertEqual(response['Content-Type'], 'text/plain')
@override_settings()
def test_get(self):
""" The view should return the the merchant domain association verification data. """
expected = 'fake-value'
self.set_apple_pay_merchant_id_domain_association(expected)
response = self.client.get(self.url)
self.assert_response_matches(response, 200, expected)
@override_settings()
def test_get_with_configuration_error(self):
""" The view should return HTTP 501 if Apple Pay is not properly configured. """
self.set_apple_pay_merchant_id_domain_association(None)
response = self.client.get(self.url)
content = 'Apple Pay is not configured for [{}].'.format(self.site.domain)
self.assert_response_matches(response, 501, content)
......@@ -254,29 +254,6 @@ class CybersourceInterstitialViewTests(CybersourceNotificationTestsMixin, TestCa
self.assertRedirects(response, self.get_full_url(path=reverse('payment_error')), status_code=302)
class ApplePayMerchantDomainAssociationViewTests(LoginMixin, TestCase):
url = reverse('apple_pay_domain_association')
def assert_response_matches(self, response, expected_status_code, expected_content):
self.assertEqual(response.status_code, expected_status_code)
self.assertEqual(response.content, expected_content)
self.assertEqual(response['Content-Type'], 'text/plain')
def test_get(self):
""" The view should return the the merchant domain association verification data. """
response = self.client.get(self.url)
self.assert_response_matches(response, 200, settings.PAYMENT_PROCESSOR_CONFIG['edx']['cybersource'][
'apple_pay_merchant_id_domain_association'])
def test_get_with_configuration_error(self):
""" The view should return HTTP 501 if Apple Pay is not properly configured. """
settings.PAYMENT_PROCESSOR_CONFIG['edx']['cybersource'][
'apple_pay_merchant_id_domain_association'] = ''
response = self.client.get(self.url)
content = 'Apple Pay is not configured for [{}].'.format(self.site.domain)
self.assert_response_matches(response, 501, content)
@ddt.ddt
class ApplePayStartSessionViewTests(LoginMixin, TestCase):
url = reverse('cybersource:apple_pay:start_session')
......
import logging
from django.http import HttpResponse
from django.views import View
logger = logging.getLogger(__name__)
class ApplePayMerchantDomainAssociationView(View):
def get(self, request, *args, **kwargs): # pylint: disable=unused-argument
site_configuration = self.request.site.siteconfiguration
payment_processor_class = site_configuration.get_client_side_payment_processor_class()
payment_processor = payment_processor_class(self.request.site)
content = payment_processor.apple_pay_merchant_id_domain_association
status_code = 200
if not content:
content = 'Apple Pay is not configured for [{}].'.format(request.site.domain)
# 501 Not Implemented -- https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.2
status_code = 501
logger.warning(content)
return HttpResponse(content, content_type='text/plain', status=status_code)
......@@ -10,7 +10,7 @@ from django.contrib.auth.decorators import login_required
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.db import transaction
from django.http import HttpResponse, JsonResponse
from django.http import JsonResponse
from django.shortcuts import redirect
from django.utils.decorators import method_decorator
from django.utils.functional import cached_property
......@@ -390,20 +390,6 @@ class CybersourceInterstitialView(CybersourceNotificationMixin, View):
return redirect(receipt_page_url)
class ApplePayMerchantDomainAssociationView(CyberSourceProcessorMixin, View):
def get(self, request, *args, **kwargs): # pylint: disable=unused-argument
content = self.payment_processor.apple_pay_merchant_id_domain_association
status_code = 200
if not content:
content = 'Apple Pay is not configured for [{}].'.format(request.site.domain)
# 501 Not Implemented -- https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.2
status_code = 501
logger.warning(content)
return HttpResponse(content, content_type='text/plain', status=status_code)
class ApplePayStartSessionView(CyberSourceProcessorMixin, APIView):
permission_classes = (permissions.IsAuthenticated,)
......
......@@ -15,7 +15,7 @@ from rest_framework.documentation import include_docs_urls
from ecommerce.core import views as core_views
from ecommerce.core.url_utils import get_lms_dashboard_url
from ecommerce.core.views import LogoutView
from ecommerce.extensions.payment.views.cybersource import ApplePayMerchantDomainAssociationView
from ecommerce.extensions.payment.views.apple_pay import ApplePayMerchantDomainAssociationView
from ecommerce.extensions.urls import urlpatterns as extensions_patterns
......
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