From 32642a29f05a9d69cd570aaf9e62b908aaa9b973 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO <ynerant@crans.org> Date: Sat, 19 Jun 2021 11:42:51 +0200 Subject: [PATCH] Authorize user rather than Crans to use Note Kfet --- billing/admin.py | 7 -- billing/forms.py | 23 +------ billing/models/payment_methods.py | 26 +++----- billing/urls.py | 1 - billing/views/__init__.py | 5 +- billing/views/note_kfet.py | 107 ++++++++++-------------------- billing/views/purchase.py | 2 +- constellation/settings.py | 2 +- 8 files changed, 52 insertions(+), 121 deletions(-) diff --git a/billing/admin.py b/billing/admin.py index 3701a95..bc7b253 100644 --- a/billing/admin.py +++ b/billing/admin.py @@ -1,9 +1,7 @@ from django import forms -from django.conf import settings from django.contrib import admin from django.db import models -from django.shortcuts import redirect from django.urls import reverse_lazy from django.utils.safestring import mark_safe from django.utils.text import capfirst @@ -228,11 +226,6 @@ class NoteKfetPaymentMethodAdmin(PolymorphicChildModelAdmin): list_display = ('__str__', 'visible',) list_filter = ('visible',) - def add_view(self, request, form_url='', extra_context=None): - return redirect(settings.NOTE_KFET_URL + "o/authorize/?client_id=" + settings.NOTE_KFET_CLIENT_ID - + "&response_type=code&scope=" + settings.NOTE_KFET_SCOPES + "&state=toto" - + f"&redirect_uri={request.scheme}://{request.get_host()}{reverse_lazy('billing:note_auth')}") - @admin.register(Invoice) class InvoiceAdmin(admin.ModelAdmin): diff --git a/billing/forms.py b/billing/forms.py index 889cff1..8286b8b 100644 --- a/billing/forms.py +++ b/billing/forms.py @@ -1,9 +1,6 @@ -import requests from django import forms -from django.conf import settings -from django.utils.translation import gettext_lazy as _ -from .models import Entry, Invoice, NoteKfetPaymentMethod, Product +from .models import Entry, Invoice, Product class EntryForm(forms.ModelForm): @@ -22,21 +19,3 @@ class ProductForm(forms.ModelForm): class Meta: model = Product fields = ('name',) - - -class NoteKfetForm(forms.Form): - alias = forms.CharField(max_length=255) - - def clean(self): - cleaned_data = super().clean() - - alias = cleaned_data['alias'] - access_token = NoteKfetPaymentMethod.objects.get().access_token - resp = requests.get(settings.NOTE_KFET_URL + "api/note/alias/?name=" + alias, - headers={"Authorization": f"Bearer {access_token}"}).json() - if resp['count'] != 1: - self.add_error('alias', _("No user was found with this alias.")) - else: - cleaned_data['note_id'] = resp['results'][0]['id'] - - return cleaned_data diff --git a/billing/models/payment_methods.py b/billing/models/payment_methods.py index 217ed97..7394ce6 100644 --- a/billing/models/payment_methods.py +++ b/billing/models/payment_methods.py @@ -1,3 +1,5 @@ +from django.conf import settings +from django.contrib.sites.models import Site from django.db import models from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ @@ -17,7 +19,7 @@ class PaymentMethod(PolymorphicModel): help_text=_("if enabled, all members will see this payment method."), ) - def get_payment_url(self, invoice): + def get_payment_url(self, invoice, request=None): """ URL where the user should be redirected after purchase. By default, the invoice stays invalid and we are redirected to the invoice list. @@ -34,7 +36,7 @@ class PaymentMethod(PolymorphicModel): class ComnpayPaymentMethod(PaymentMethod): - def get_payment_url(self, invoice): + def get_payment_url(self, invoice, request=None): return reverse_lazy('billing:comnpay_redirect', args=(invoice.pk,)) class Meta: @@ -43,7 +45,7 @@ class ComnpayPaymentMethod(PaymentMethod): class StripePaymentMethod(PaymentMethod): - def get_payment_url(self, invoice): + def get_payment_url(self, invoice, request=None): return reverse_lazy('billing:stripe_redirect', args=(invoice.pk,)) class Meta: @@ -52,18 +54,12 @@ class StripePaymentMethod(PaymentMethod): class NoteKfetPaymentMethod(PaymentMethod): - access_token = models.CharField( - max_length=64, - verbose_name=_("access token"), - ) - - refresh_token = models.CharField( - max_length=64, - verbose_name=_("refresh token"), - ) - - def get_payment_url(self, invoice): - return reverse_lazy('billing:note_pay', args=(invoice.pk,)) + def get_payment_url(self, invoice, request=None): + scheme = request.scheme if request else "https" + host = request.get_host() if request else Site.objects.first().domain + return settings.NOTE_KFET_URL + "o/authorize/?client_id=" + settings.NOTE_KFET_CLIENT_ID \ + + "&response_type=code&scope=" + settings.NOTE_KFET_SCOPES + "&state=" + str(invoice.pk) \ + + f"&redirect_uri={scheme}://{host}{reverse_lazy('billing:note_auth')}" class Meta: verbose_name = _("Note Kfet payment method") diff --git a/billing/urls.py b/billing/urls.py index a69fcda..3315ef1 100644 --- a/billing/urls.py +++ b/billing/urls.py @@ -19,5 +19,4 @@ urlpatterns = [ path('stripe/fail/', views.StripeFailView.as_view(), name='stripe_fail'), path('note/authorize/', views.NoteKfetAuthorizeView.as_view(), name='note_auth'), - path('note/pay/<int:pk>/', views.NoteKfetPayView.as_view(), name='note_pay'), ] diff --git a/billing/views/__init__.py b/billing/views/__init__.py index 28983f8..9d6ee45 100644 --- a/billing/views/__init__.py +++ b/billing/views/__init__.py @@ -1,11 +1,10 @@ from .comnpay import ComnpayFailView, ComnpaySuccessView, IPNComnpayView, RedirectComnpayView -from .note_kfet import NoteKfetAuthorizeView, NoteKfetPayView +from .note_kfet import NoteKfetAuthorizeView from .purchase import InvoiceListView, PurchaseView, RenderInvoiceView from .stripe import StripeFailView, StripeSuccessView, RedirectStripeView __all__ = [ - "ComnpayFailView", "ComnpaySuccessView", "InvoiceListView", "IPNComnpayView", - "NoteKfetAuthorizeView", "NoteKfetPayView", + "ComnpayFailView", "ComnpaySuccessView", "InvoiceListView", "IPNComnpayView", "NoteKfetAuthorizeView", "PurchaseView", "RedirectComnpayView", "RedirectStripeView", "RenderInvoiceView", "StripeFailView", "StripeSuccessView", ] diff --git a/billing/views/note_kfet.py b/billing/views/note_kfet.py index 854fa7b..0026976 100644 --- a/billing/views/note_kfet.py +++ b/billing/views/note_kfet.py @@ -1,25 +1,28 @@ import requests from django.conf import settings from django.contrib import messages -from django.contrib.auth.mixins import LoginRequiredMixin from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ -from django.views.generic import DetailView, FormView, RedirectView +from django.views.generic import RedirectView -from ..forms import NoteKfetForm -from ..models import NoteKfetPaymentMethod, Invoice +from ..models import Invoice class NoteKfetAuthorizeView(RedirectView): + url = reverse_lazy('index') + def get(self, request, *args, **kwargs): if 'code' not in request.GET or 'state' not in request.GET: messages.error(request, _("Bad request")) return super().get(request, *args, **kwargs) - if request.GET['state'] != 'toto': # FIXME use better state code - messages.error(request, _("Invalid state code")) + invoice_id = request.GET['state'] + if not Invoice.objects.filter(pk=invoice_id).exists(): + messages.error(request, _("Bad request")) return super().get(request, *args, **kwargs) + invoice = Invoice.objects.get(pk=invoice_id) + code = request.GET['code'] response = requests.post(settings.NOTE_KFET_URL + "o/token/", data={ @@ -33,73 +36,35 @@ class NoteKfetAuthorizeView(RedirectView): if 'error' not in resp_json: resp_json = response.json() access_token = resp_json['access_token'] - refresh_token = resp_json['refresh_token'] - payment_method, created = NoteKfetPaymentMethod.objects.get_or_create() - if created: - payment_method.name = "Note Kfet" - payment_method.access_token = access_token - payment_method.refresh_token = refresh_token - payment_method.save() - - self.payment_method = payment_method - messages.success(request, _("Authorization succeed")) + note = requests.get(settings.NOTE_KFET_URL + "api/note/note/", + headers={"Authorization": f"Bearer {access_token}"}).json()['results'][0] + + response = requests.post( + settings.NOTE_KFET_URL + "api/note/transaction/transaction/", + json={ + 'source_alias': note['name'], + 'destination_alias': 'Crans', + 'quantity': 1, + 'amount': invoice.price, + 'reason': f'Facture n°{invoice.id}', + 'valid': True, + 'polymorphic_ctype': 26, + 'source': note['id'], + 'destination': 2088, + 'resourcetype': 'Transaction', + + }, + headers={"Authorization": f"Bearer {access_token}"}, + ) + + if response.status_code == 201: + messages.success(request, _("Payment succeed!")) + invoice.valid = True + invoice.save() + else: + messages.error(request, _("Error:") + " " + str(response.json())) else: messages.error(request, _("Error:") + " " + str(resp_json)) return super().get(request, *args, **kwargs) - - def get_redirect_url(self, *args, **kwargs): - if hasattr(self, 'payment_method'): - return reverse_lazy('admin:billing_paymentmethod_change', args=(self.payment_method.pk,)) - else: - return reverse_lazy('admin:billing_paymentmethod_changelist') - - -class NoteKfetPayView(LoginRequiredMixin, FormView, DetailView): - model = Invoice - # Don't pay validated invoices - queryset = Invoice.objects.filter(valid=False, payment_method__notekfetpaymentmethod__isnull=False) - form_class = NoteKfetForm - template_name = "billing/note_kfet_pay.html" - - def post(self, request, *args, **kwargs): - self.object = self.get_object() - return super().post(request, *args, **kwargs) - - def form_valid(self, form): - alias = form.cleaned_data['alias'] - note_id = form.cleaned_data['note_id'] - access_token = NoteKfetPaymentMethod.objects.get().access_token - invoice = self.get_object() - - response = requests.post( - settings.NOTE_KFET_URL + "api/note/transaction/transaction/", - json={ - 'source_alias': alias, - 'destination_alias': 'Crans', - 'quantity': 1, - 'amount': invoice.price, - 'reason': f'Facture n°{invoice.id}', - 'valid': True, - 'polymorphic_ctype': 26, - 'source': note_id, - 'destination': 2088, - 'resourcetype': 'Transaction', - - }, - headers={"Authorization": f"Bearer {access_token}"}, - ) - - if response.status_code == 201: - messages.success(self.request, _("Payment succeed!")) - invoice.valid = True - invoice.save() - else: - messages.error(self.request, str(response.json())) - return super().form_invalid(form) - - return super().form_valid(form) - - def get_success_url(self): - return reverse_lazy('index') diff --git a/billing/views/purchase.py b/billing/views/purchase.py index a78c289..50ef9e8 100644 --- a/billing/views/purchase.py +++ b/billing/views/purchase.py @@ -85,7 +85,7 @@ class PurchaseView(LoginRequiredMixin, CreateView): return super().form_valid(form) def get_success_url(self): - return self.object.payment_method.get_payment_url(self.object) + return self.object.payment_method.get_payment_url(self.object, self.request) class InvoiceListView(LoginRequiredMixin, SingleTableView): diff --git a/constellation/settings.py b/constellation/settings.py index d49454c..4f31b9c 100644 --- a/constellation/settings.py +++ b/constellation/settings.py @@ -250,7 +250,7 @@ STRIPE_PRIVATE_KEY = "CHANGEME" NOTE_KFET_URL = "https://note.crans.org/" NOTE_KFET_CLIENT_ID = "CHANGEME" NOTE_KFET_CLIENT_SECRET = "CHANGEME" -NOTE_KFET_SCOPES = "6_1 20_23" # View aliases, make a transaction between a user and Crans +NOTE_KFET_SCOPES = "3_1 17_1" # View own note, create transaction from our own note try: from .settings_local import * # noqa: F401, F403& -- GitLab