Projet

Général

Profil

0003-lingo-handle-empty-payload-in-ReturnView-42581.patch

Valentin Deniaud, 08 juin 2020 14:22

Télécharger (5,88 ko)

Voir les différences:

Subject: [PATCH 3/3] lingo: handle empty payload in ReturnView (#42581)

 combo/apps/lingo/views.py   | 23 +++++++++++++++++-----
 tests/test_lingo_payment.py | 39 +++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+), 5 deletions(-)
combo/apps/lingo/views.py
554 554
        payment = get_eopayment_object(request, payment_backend)
555 555
        logger = logging.getLogger(__name__)
556 556
        logger.info(u'received payment response: %r', backend_response)
557
        extra_info = kwargs.pop('payment_extra_info', {})
557 558
        try:
558
            payment_response = payment.response(backend_response)
559
            payment_response = payment.response(backend_response, **extra_info)
559 560
        except eopayment.PaymentException as e:
560 561
            logger.error(u'failed to process payment response: %s', e,
561 562
                         extra={'eopayment_raw_response': repr(backend_response)})
......
678 679
        return super(ReturnView, self).dispatch(*args, **kwargs)
679 680

  
680 681
    def get(self, request, *args, **kwargs):
681
        if not request.environ['QUERY_STRING']:
682
            return HttpResponseBadRequest('Missing query string')
683 682
        return self.handle_return(request, request.environ['QUERY_STRING'], **kwargs)
684 683

  
685 684
    def post(self, request, *args, **kwargs):
686 685
        return self.handle_return(request, force_text(request.body) or request.environ['QUERY_STRING'], **kwargs)
687 686

  
688 687
    def handle_return(self, request, backend_response, **kwargs):
688
        payment_extra_info = {'redirect': True}
689

  
689 690
        transaction = None
690 691
        transaction_id = kwargs.get('transaction_signature')
691 692
        if transaction_id:
692 693
            try:
693 694
                transaction_id = signing_loads(transaction_id)
694 695
            except signing.BadSignature:
696
                transaction_id = None
697

  
698
        if transaction_id:
699
            # retrieve info about previously known state
700
            try:
701
                current_transaction = Transaction.objects.get(pk=transaction_id)
702
            except Transaction.DoesNotExist:
695 703
                pass
704
            else:
705
                payment_extra_info['order_id_hint'] = current_transaction.order_id
706
                payment_extra_info['order_status_hint'] = current_transaction.status
707

  
696 708
        try:
697
            transaction = self.handle_response(request, backend_response, **kwargs)
709
            transaction = self.handle_response(
710
                request, backend_response, payment_extra_info=payment_extra_info, **kwargs
711
            )
698 712
        except UnsignedPaymentException as e:
699 713
            # some payment backends do not sign return URLs, don't mark this as
700 714
            # an error, they will provide a notification to the callback
......
702 716
            if transaction_id:
703 717
                return HttpResponseRedirect(get_payment_status_view(transaction_id))
704 718
            return HttpResponseRedirect(get_basket_url())
705

  
706 719
        except PaymentException as e:
707 720
            messages.error(request, _('We are sorry but the payment service '
708 721
                                      'failed to provide a correct answer.'))
tests/test_lingo_payment.py
766 766
    assert data['amount'] == '11.50'
767 767

  
768 768

  
769
@pytest.mark.parametrize('with_payment_backend', [False, True])
770
def test_payment_return_without_query_string(app, basket_page, regie, user, with_payment_backend):
771
    page = Page(title='xxx', slug='index', template_name='standard')
772
    page.save()
773
    item = BasketItem.objects.create(user=user, regie=regie,
774
                        subject='test_item', amount='10.5',
775
                        source_url='http://example.org/testitem/')
776
    resp = login(app).get(basket_page.get_online_url())
777
    resp = resp.form.submit()
778
    assert resp.status_code == 302
779
    location = resp.location
780
    parsed = urlparse.urlparse(location)
781
    qs = urlparse.parse_qs(parsed.query)
782
    return_url = qs['return_url'][0]
783
    transaction_id = qs['transaction_id'][0]
784
    data = {'transaction_id': transaction_id, 'signed': True,
785
            'amount': qs['amount'][0], 'ok': True}
786

  
787
    # payment status is obtained through callback
788
    callback_url = get_url(with_payment_backend, 'lingo-callback', regie)
789
    with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request:
790
        get_resp = app.get(callback_url, params=data)
791
    transaction = Transaction.objects.get(order_id=transaction_id)
792
    assert transaction.status == 3
793

  
794
    # then return view is called without any data, which should be expected by the backend
795
    with mock.patch.object(eopayment.dummy.Payment, 'response', autospec=True) as mock_response:
796
        mock_response.return_value = eopayment.common.PaymentResponse(result=transaction.status,
797
                                                                      order_id=transaction.order_id)
798
        get_resp = app.get(return_url)
799
        mock_response.assert_called_once_with(
800
            mock.ANY, '', redirect=True, order_id_hint=transaction.order_id,
801
            order_status_hint=transaction.status
802
        )
803
    assert get_resp.status_code == 302
804
    resp = app.get(get_resp['Location'])
805
    assert 'Your payment has been succesfully registered.' in resp.text
806

  
807

  
769 808
@pytest.mark.parametrize('with_payment_backend', [False, True])
770 809
def test_nonexisting_transaction(app, regie, user, with_payment_backend):
771 810
    app = login(app)
772
-