Projet

Général

Profil

0003-lingo-add-an-intermediate-page-on-external-redirect-.patch

Benjamin Dauvergne, 12 avril 2019 20:40

Télécharger (6,09 ko)

Voir les différences:

Subject: [PATCH 3/3] lingo: add an intermediate page on external redirect
 (#32239)

 .../lingo/templates/lingo/payment-error.html  | 10 ++++
 combo/apps/lingo/views.py                     | 47 ++++++++++++++++++-
 tests/test_lingo_payment.py                   | 15 +++++-
 3 files changed, 69 insertions(+), 3 deletions(-)
 create mode 100644 combo/apps/lingo/templates/lingo/payment-error.html
combo/apps/lingo/templates/lingo/payment-error.html
1
{% extends "combo/page_template.html" %}
2
{% load i18n %}
3

  
4
{% block combo-content %}
5
 <div>
6
  <p>
7
   <a href="{{ location }}">{% trans "Continue" %}</a>
8
  </p>
9
 </div>
10
{% endblock %}
combo/apps/lingo/views.py
35 35
from django.utils.translation import ugettext_lazy as _
36 36
from django.db.transaction import atomic
37 37
from django.utils.encoding import smart_text
38
from django.shortcuts import render
38 39

  
39 40
import eopayment
40 41

  
42
from combo.public.views import publish_page
41 43
from combo.data.models import Page
42 44
from combo.utils import check_request_signature, aes_hex_decrypt, DecryptionError
43 45
from combo.profile.utils import get_user_from_name_id
46
from combo.utils.urls import same_origin
44 47

  
45 48
from .models import (Regie, BasketItem, Transaction, TransactionOperation,
46 49
        LingoBasketCell, SelfDeclaredInvoicePayment)
......
67 70
    return check_request_signature(request, keys=keys)
68 71

  
69 72

  
73
def payment_error(request, location, *args, **kwargs):
74
    try:
75
        page = Page.objects.get(slug='payment-error')
76
        template_name = None
77
    except Page.DoesNotExist:
78
        page = Page()
79
        page.template_name = 'standard'
80
        template_name = 'lingo/payment-error.html'
81
    request.extra_context_data = {'location': location}
82
    return publish_page(request, page, template_name=template_name)
83

  
84

  
85
class ShowMessageOnExternalRedirectMixin(object):
86
    def dispatch(self, request, *args, **kwargs):
87
        response = super(ShowMessageOnExternalRedirectMixin, self).dispatch(request, *args, **kwargs)
88
        if self.is_external_redirect(request, response) and self.has_messages(request):
89
            return payment_error(request, response['Location'], *args, **kwargs)
90
        return response
91

  
92
    def has_messages(self, request):
93
        storage = messages.get_messages(request)
94
        if not storage:
95
            return False
96
        return bool(len(storage))
97

  
98
    def is_external_redirect(self, request, response):
99
        if not isinstance(response, HttpResponseRedirect):
100
            return False
101
        return not self.is_same_origin(request, response)
102

  
103
    def is_same_origin(self, request, response):
104
        local_url = request.build_absolute_uri()
105
        redirect_url = response['Location']
106
        if (not redirect_url
107
                or (redirect_url[0] == '/'
108
                    and (len(redirect_url) == 1 or redirect_url[1] != '/'))):
109
                return True
110
        return same_origin(local_url, redirect_url)
111

  
112

  
70 113
class RegiesApiView(ListView):
71 114
    model = Regie
72 115

  
......
403 446
        return self.handle_payment(request, regie, items, remote_items, next_url, email)
404 447

  
405 448

  
406
class BasketItemPayView(PayMixin, View):
449
class BasketItemPayView(ShowMessageOnExternalRedirectMixin, PayMixin, View):
407 450
    def get(self, request, *args, **kwargs):
408 451
        next_url = request.GET.get('next_url') or '/'
409 452
        if not (request.user and request.user.is_authenticated()):
......
545 588
        return super(CallbackView, self).dispatch(*args, **kwargs)
546 589

  
547 590

  
548
class ReturnView(PaymentView):
591
class ReturnView(ShowMessageOnExternalRedirectMixin, PaymentView):
549 592
    @csrf_exempt
550 593
    def dispatch(self, *args, **kwargs):
551 594
        return super(ReturnView, self).dispatch(*args, **kwargs)
tests/test_lingo_payment.py
317 317
    assert 'No item payment allowed for anonymous users.' in resp.text
318 318

  
319 319
    login(app, username='john.doe', password='john.doe')
320

  
320 321
    resp = app.get(payment_url, status=403)
321 322
    assert 'Wrong item: payment not allowed.' in resp.text
322 323

  
......
331 332
    regie.extra_fees_ws_url = ''
332 333
    regie.save()
333 334

  
335
    regie.payment_min_amount = 100
336
    regie.save()
337

  
334 338
    resp = app.get(payment_url, params={'next_url': 'http://example.net/form/id/'})
339
    assert 'Continue' in resp.text
340
    assert 'http://example.net/form/id/' in resp.text
335 341

  
342
    regie.payment_min_amount = 0
343
    regie.save()
344

  
345
    resp = app.get(payment_url, params={'next_url': 'http://example.net/form/id/'})
336 346
    # make sure the redirection is done to the payment backend
337 347
    assert resp.location.startswith('http://dummy-payment.demo.entrouvert.com/')
338 348
    qs = urlparse.parse_qs(urlparse.urlparse(resp.location).query)
......
347 357
    # check that item is paid
348 358
    assert BasketItem.objects.filter(regie=regie, amount=amount, payment_date__isnull=False).exists()
349 359
    # check that user is redirected to the next_url passed previously
350
    assert resp.location == 'http://example.net/form/id/'
360
    assert 'Continue' in resp.text
361
    assert 'Your payment has been succesfully registered' in resp.text
362
    assert 'http://example.net/form/id/' in resp.text
363

  
351 364

  
352 365
def test_pay_multiple_regies(app, key, regie, user):
353 366
    test_add_amount_to_basket(app, key, regie, user)
354
-