From 5ad95523250a0a9e377d53f6f614e21df3547e4d Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO <ynerant@crans.org> Date: Fri, 18 Jun 2021 23:54:17 +0200 Subject: [PATCH] Grant Constellation to use Note Kfet --- billing/admin.py | 37 +++++++++++++++++++-- billing/models/__init__.py | 4 +-- billing/models/payment_methods.py | 20 ++++++++++++ billing/urls.py | 2 ++ billing/views/__init__.py | 3 +- billing/views/note_kfet.py | 54 +++++++++++++++++++++++++++++++ constellation/settings.py | 5 +++ 7 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 billing/views/note_kfet.py diff --git a/billing/admin.py b/billing/admin.py index 8bc7e2c..3701a95 100644 --- a/billing/admin.py +++ b/billing/admin.py @@ -1,7 +1,9 @@ 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 @@ -10,7 +12,8 @@ from django.utils.dateparse import parse_duration from polymorphic.admin import PolymorphicChildModelAdmin, PolymorphicParentModelAdmin from .models import ComnpayPaymentMethod, Entry, Invoice, \ - MembershipProduct, MembershipPurchase, PaymentMethod, Product + MembershipProduct, MembershipPurchase, NoteKfetPaymentMethod, \ + PaymentMethod, Product, StripePaymentMethod from .templatetags.pretty_money import pretty_money import datetime @@ -181,7 +184,7 @@ class PaymentMethodAdmin(PolymorphicParentModelAdmin): """ Manage different payment methods. """ - child_models = [PaymentMethod, ComnpayPaymentMethod] + child_models = [PaymentMethod, ComnpayPaymentMethod, NoteKfetPaymentMethod, StripePaymentMethod] list_display = ('__str__', 'visible', 'payment_type',) list_filter = ('visible',) @@ -201,6 +204,36 @@ class ComnpayPaymentMethodAdmin(PolymorphicChildModelAdmin): list_filter = ('visible',) +@admin.register(StripePaymentMethod) +class StripePaymentMethodAdmin(PolymorphicChildModelAdmin): + """ + Manage Stripe payment methods. + + In normal cases, there should be at most one object in this table. + """ + list_display = ('__str__', 'visible',) + list_filter = ('visible',) + + +@admin.register(NoteKfetPaymentMethod) +class NoteKfetPaymentMethodAdmin(PolymorphicChildModelAdmin): + """ + Manage Note Kfet payment methods. + + In normal cases, there should be at most one object in this table. + + This stores the current access and refresh tokens, which + should not be updated manually. + """ + 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/models/__init__.py b/billing/models/__init__.py index 25bc93e..1b24aee 100644 --- a/billing/models/__init__.py +++ b/billing/models/__init__.py @@ -1,9 +1,9 @@ from .invoices import Entry, Invoice, Product from .memberships import MembershipProduct, MembershipPurchase -from .payment_methods import ComnpayPaymentMethod, PaymentMethod, StripePaymentMethod +from .payment_methods import ComnpayPaymentMethod, NoteKfetPaymentMethod, PaymentMethod, StripePaymentMethod __all__ = [ 'Entry', 'Invoice', 'Product', - 'PaymentMethod', 'ComnpayPaymentMethod', 'StripePaymentMethod', + 'PaymentMethod', 'ComnpayPaymentMethod', 'NoteKfetPaymentMethod', 'StripePaymentMethod', 'MembershipProduct', 'MembershipPurchase', ] diff --git a/billing/models/payment_methods.py b/billing/models/payment_methods.py index a0f0f1e..c19ad4b 100644 --- a/billing/models/payment_methods.py +++ b/billing/models/payment_methods.py @@ -12,6 +12,7 @@ class PaymentMethod(PolymorphicModel): ) visible = models.BooleanField( + default=False, verbose_name=_("visible"), help_text=_("if enabled, all members will see this payment method."), ) @@ -48,3 +49,22 @@ class StripePaymentMethod(PaymentMethod): class Meta: verbose_name = _("stripe payment method") verbose_name_plural = _("stripe payment methods") + + +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', args=(invoice.pk,)) + + class Meta: + verbose_name = _("Note Kfet payment method") + verbose_name_plural = _("Note Kfet payment methods") diff --git a/billing/urls.py b/billing/urls.py index 9b5a4b5..3315ef1 100644 --- a/billing/urls.py +++ b/billing/urls.py @@ -17,4 +17,6 @@ urlpatterns = [ path('stripe/redirect/<int:pk>/', views.RedirectStripeView.as_view(), name='stripe_redirect'), path('stripe/success/', views.StripeSuccessView.as_view(), name='stripe_success'), path('stripe/fail/', views.StripeFailView.as_view(), name='stripe_fail'), + + path('note/authorize/', views.NoteKfetAuthorizeView.as_view(), name='note_auth'), ] diff --git a/billing/views/__init__.py b/billing/views/__init__.py index 623dffe..9d6ee45 100644 --- a/billing/views/__init__.py +++ b/billing/views/__init__.py @@ -1,9 +1,10 @@ from .comnpay import ComnpayFailView, ComnpaySuccessView, IPNComnpayView, RedirectComnpayView +from .note_kfet import NoteKfetAuthorizeView from .purchase import InvoiceListView, PurchaseView, RenderInvoiceView from .stripe import StripeFailView, StripeSuccessView, RedirectStripeView __all__ = [ - "ComnpayFailView", "ComnpaySuccessView", "InvoiceListView", "IPNComnpayView", + "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 new file mode 100644 index 0000000..2620aa6 --- /dev/null +++ b/billing/views/note_kfet.py @@ -0,0 +1,54 @@ +import requests +from django.conf import settings +from django.contrib import messages +from django.urls import reverse_lazy +from django.utils.translation import gettext_lazy as _ +from django.views.generic import RedirectView + +from billing.models import NoteKfetPaymentMethod + + +class NoteKfetAuthorizeView(RedirectView): + 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")) + return super().get(request, *args, **kwargs) + + code = request.GET['code'] + + response = requests.post(settings.NOTE_KFET_URL + "o/token/", data={ + 'client_id': settings.NOTE_KFET_CLIENT_ID, + 'client_secret': settings.NOTE_KFET_CLIENT_SECRET, + 'grant_type': 'authorization_code', + 'code': code, + }) + resp_json = response.json() + + 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")) + 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') diff --git a/constellation/settings.py b/constellation/settings.py index 4e1105a..d49454c 100644 --- a/constellation/settings.py +++ b/constellation/settings.py @@ -247,6 +247,11 @@ COMNPAY_SECRET_KEY = 'CHANGEME' STRIPE_PUBLIC_KEY = "CHANGEME" 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 + try: from .settings_local import * # noqa: F401, F403& except ImportError: -- GitLab