From c32d9b75c2edebc31b5af4c1333d01812a77aba0 Mon Sep 17 00:00:00 2001 From: sahama Date: Wed, 7 Aug 2024 16:36:28 +0330 Subject: [PATCH] bugfix for oidc --- apps/gooyal_oauth2/settings.py | 33 ++- apps/gooyal_oauth2/validators.py | 3 + apps/wallet/__init__.py | 0 apps/wallet/admin.py | 21 -- apps/wallet/apps.py | 6 - apps/wallet/constans.py | 12 - apps/wallet/forms.py | 8 - apps/wallet/migrations/0001_initial.py | 33 --- ...nsaction_application_client_id_and_more.py | 25 -- apps/wallet/migrations/__init__.py | 0 apps/wallet/models.py | 164 ------------- apps/wallet/serializers.py | 108 --------- apps/wallet/tests.py | 3 - apps/wallet/urls.py | 24 -- apps/wallet/views.py | 218 ------------------ templates/base.html | 14 +- 16 files changed, 42 insertions(+), 630 deletions(-) delete mode 100755 apps/wallet/__init__.py delete mode 100755 apps/wallet/admin.py delete mode 100755 apps/wallet/apps.py delete mode 100644 apps/wallet/constans.py delete mode 100644 apps/wallet/forms.py delete mode 100644 apps/wallet/migrations/0001_initial.py delete mode 100644 apps/wallet/migrations/0002_remove_transaction_application_client_id_and_more.py delete mode 100755 apps/wallet/migrations/__init__.py delete mode 100755 apps/wallet/models.py delete mode 100755 apps/wallet/serializers.py delete mode 100755 apps/wallet/tests.py delete mode 100644 apps/wallet/urls.py delete mode 100755 apps/wallet/views.py diff --git a/apps/gooyal_oauth2/settings.py b/apps/gooyal_oauth2/settings.py index 7aa7128..57c7d22 100644 --- a/apps/gooyal_oauth2/settings.py +++ b/apps/gooyal_oauth2/settings.py @@ -1,4 +1,33 @@ -from oauth2_provider.settings import OAuth2ProviderSettings, USER_SETTINGS, DEFAULTS, IMPORT_STRINGS, MANDATORY +from oauth2_provider.settings import OAuth2ProviderSettings, USER_SETTINGS, DEFAULTS, IMPORT_STRINGS, MANDATORY, \ + _PhonyHttpRequest + +from django.http import HttpRequest +from django.urls import reverse +from oauthlib.common import Request + + +class GooyalOAuth2Settings(OAuth2ProviderSettings): + def oidc_issuer(self, request): + """ + Helper function to get the OIDC issuer URL, either from the settings + or constructing it from the passed request. + + If only an oauthlib request is available, a dummy django request is + built from that and used to generate the URL. + """ + if self.OIDC_ISS_ENDPOINT: + return self.OIDC_ISS_ENDPOINT + if isinstance(request, HttpRequest): + django_request = request + elif isinstance(request, Request): + django_request = _PhonyHttpRequest() + django_request.META = request.headers + if request.headers.get("X_DJANGO_OAUTH_TOOLKIT_SECURE", False): + django_request._scheme = "https" + else: + raise TypeError("request must be a django or oauthlib request: got %r" % request) + abs_url = django_request.build_absolute_uri(reverse("gooyal_oauth2:oidc-connect-discovery-info")) + return abs_url[: -len("/.well-known/openid-configuration")] GOOYAL_DEFAULTS = { # Resource Server with Token Introspection additions @@ -17,4 +46,4 @@ DEFAULTS.update(GOOYAL_DEFAULTS) IMPORT_STRINGS = IMPORT_STRINGS + GOOYAL_IMPORT_STRINGS MANDATORY = MANDATORY + GOOYAL_MANDATORY -oauth2_settings = OAuth2ProviderSettings(USER_SETTINGS, DEFAULTS, IMPORT_STRINGS, MANDATORY) +oauth2_settings = GooyalOAuth2Settings(USER_SETTINGS, DEFAULTS, IMPORT_STRINGS, MANDATORY) diff --git a/apps/gooyal_oauth2/validators.py b/apps/gooyal_oauth2/validators.py index 1914361..797cddf 100755 --- a/apps/gooyal_oauth2/validators.py +++ b/apps/gooyal_oauth2/validators.py @@ -74,3 +74,6 @@ class OAuth2Validator(BaseOAuth2Validator): # pylint: disable=w0223 claims.update(add) return claims + + def get_oidc_issuer_endpoint(self, request): + return oauth2_settings.oidc_issuer(request) diff --git a/apps/wallet/__init__.py b/apps/wallet/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/apps/wallet/admin.py b/apps/wallet/admin.py deleted file mode 100755 index 1c59e67..0000000 --- a/apps/wallet/admin.py +++ /dev/null @@ -1,21 +0,0 @@ -from django.contrib import admin -from .models import Transaction - - -class TransactionAdmin(admin.ModelAdmin): - fields = [ - 'uuid', - 'amount', - 'payer', - 'payee', - 'create', - 'last_update', - 'state', - 'delay', - 'detail_id', - 'application' - ] - readonly_fields = ['uuid', 'last_update', 'create', 'detail_id', 'application'] - - -admin.site.register(Transaction, TransactionAdmin) diff --git a/apps/wallet/apps.py b/apps/wallet/apps.py deleted file mode 100755 index ebb7c40..0000000 --- a/apps/wallet/apps.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.apps import AppConfig - - -class WalletConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' - name = 'apps.wallet' diff --git a/apps/wallet/constans.py b/apps/wallet/constans.py deleted file mode 100644 index b35bba6..0000000 --- a/apps/wallet/constans.py +++ /dev/null @@ -1,12 +0,0 @@ -from django.db.models import IntegerChoices -from django.utils.translation import gettext_lazy as _ - - -class StateChoices(IntegerChoices): - CREATED = 1 , _('created') - DELAYED = 2 , _('delayed') # delayed as user wish - PENDING = 3 , _('pending') # wait for external service response - INCOMPLETE = 4 , _('incomplete') # started and wait for internal progress to complete - SUCCESS = 5 , _('success') - FAILED = 6 , _('failed') - EXPECTED_FAILURE = 7 , _('expected_failure') # no exact data available but guessed to be failed diff --git a/apps/wallet/forms.py b/apps/wallet/forms.py deleted file mode 100644 index 6fdae3a..0000000 --- a/apps/wallet/forms.py +++ /dev/null @@ -1,8 +0,0 @@ -from django import forms -from .models import Transaction - - -class TransactionActionForm(forms.ModelForm): - class Meta: - model = Transaction - fields = [] diff --git a/apps/wallet/migrations/0001_initial.py b/apps/wallet/migrations/0001_initial.py deleted file mode 100644 index 6e02dfd..0000000 --- a/apps/wallet/migrations/0001_initial.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 4.1 on 2022-09-04 12:55 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion -import uuid - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='Transaction', - fields=[ - ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), - ('amount', models.IntegerField(verbose_name='amount')), - ('delay', models.IntegerField(blank=True, default=0)), - ('state', models.IntegerField(choices=[(1, 'created'), (2, 'delayed'), (3, 'pending'), (4, 'incomplete'), (5, 'success'), (6, 'failed'), (7, 'expected_failure')], default=1)), - ('create', models.DateTimeField(auto_now=True, null=True, verbose_name='create')), - ('last_update', models.DateTimeField(auto_now=True, null=True, verbose_name='last update')), - ('application_client_id', models.CharField(db_index=True, max_length=100, null=True)), - ('detail_id', models.IntegerField(blank=True, null=True)), - ('payee', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='receipts', to=settings.AUTH_USER_MODEL)), - ('payer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='payments', to=settings.AUTH_USER_MODEL)), - ], - ), - ] diff --git a/apps/wallet/migrations/0002_remove_transaction_application_client_id_and_more.py b/apps/wallet/migrations/0002_remove_transaction_application_client_id_and_more.py deleted file mode 100644 index 13fb061..0000000 --- a/apps/wallet/migrations/0002_remove_transaction_application_client_id_and_more.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.1 on 2022-09-08 12:16 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.OAUTH2_PROVIDER_APPLICATION_MODEL), - ('wallet', '0001_initial'), - ] - - operations = [ - migrations.RemoveField( - model_name='transaction', - name='application_client_id', - ), - migrations.AddField( - model_name='transaction', - name='application', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='transactions', to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL), - ), - ] diff --git a/apps/wallet/migrations/__init__.py b/apps/wallet/migrations/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/apps/wallet/models.py b/apps/wallet/models.py deleted file mode 100755 index 0b6b83f..0000000 --- a/apps/wallet/models.py +++ /dev/null @@ -1,164 +0,0 @@ -import datetime -import uuid - -from django.db import models -from django.db import transaction -from django.db.models import F -from django.utils.translation import gettext_lazy as _ -from rest_framework.exceptions import APIException, ValidationError -from django.conf import settings -from .constans import StateChoices -from apps.users.models import User - - -class TransactionManager(models.Manager): - def create_transaction( - self, - amount, - payee: User, - payer: User = None, - delay=0, - # detail_id=None, - application=None, - # state=None, - uuid=None - ): - if not (isinstance(payer, User) or payer is None): - raise ValidationError('payer type not valid') - if not isinstance(payee, User): - raise ValidationError('payee type not valid') - if not amount > 0: - raise ValidationError('amount should be greater than zero') - if not delay >= 0: - raise ValidationError('delay should be greater than equal zero') - - transaction = self.model( - uuid=uuid, - payer=payer, - payee=payee, - amount=amount, - delay=delay, - # detail_id=detail_id, - application=application - ) - # if state: - # transaction.state = state - - transaction.save() - return transaction - - -class Transaction(models.Model): - uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4, unique=True, - db_index=True) # reserve_code - amount = models.IntegerField(_('amount'), blank=False) - delay = models.IntegerField(default=0, blank=True) # number of days for delayed payments - payer = models.ForeignKey(User, on_delete=models.PROTECT, related_name='payments', blank=True, null=True) - payee = models.ForeignKey(User, on_delete=models.PROTECT, related_name='receipts') - state = models.IntegerField(choices=StateChoices.choices, default=StateChoices.CREATED) - create = models.DateTimeField(_('create'), blank=True, null=True, auto_now=True) - last_update = models.DateTimeField(_('last update'), blank=True, null=True, auto_now=True) - application = models.ForeignKey(settings.OAUTH2_PROVIDER_APPLICATION_MODEL, on_delete=models.PROTECT, - related_name='transactions', null=True) - detail_id = models.IntegerField(null=True, blank=True) # TODO: or better detail url - - objects = TransactionManager() - - # class Meta: - # unique_together = ('application', 'detail_id',) - - def pay(self, payer=None): - if not self.payer and not payer: - raise APIException('payer identification error') - - if self.payer and payer and not self.payer == payer: - raise APIException('payer identification error') - - # TODO: check bundry conditions - if not self.state == StateChoices.CREATED: - raise APIException('this transaction is not ready to pay') - - if not self.payer: - self.payer = payer - - with transaction.atomic(): - self.last_update = datetime.datetime.now() - - if self.payer.balance < self.amount: - raise APIException('not enough balance') - - self.payer.balance = F('balance') - self.amount - self.payer.save(update_fields=['balance']) - - self.payer.refresh_from_db() - if self.payer.balance < 0: - raise APIException('not enough balance') - - if self.delay: - self.state = StateChoices.DELAYED - self.save() - - else: - self.payee.balance = F('balance') + self.amount - self.payee.save(update_fields=['balance']) - - self.state = StateChoices.SUCCESS - self.save() - - self.save() - return self - - def receipt(self): - # TODO: check bundry conditions - if not self.state == StateChoices.DELAYED: - raise APIException('this transaction is not delayed') - - with transaction.atomic(): - self.last_update = datetime.datetime.now() - self.payee.balance = F('balance') + self.amount - self.state = StateChoices.SUCCESS - self.payee.save() - self.save() - - def submit(self): - if not self.payer: - raise APIException('payer identification error') - - if not self.payee: - raise APIException('payee identification error') - - # TODO: check bundry conditions - if not self.state == StateChoices.CREATED: - raise APIException('this transaction is not ready to pay') - - with transaction.atomic(): - self.last_update = datetime.datetime.now() - - if self.payer.balance < self.amount: - raise APIException('not enough balance') - - self.payer.balance = F('balance') - self.amount - self.payer.save(update_fields=['balance']) - - self.payer.refresh_from_db() - self.state = StateChoices.PENDING - if self.payer.balance < 0: - raise APIException('not enough balance') - - self.save() - return self - - def verify(self): - # TODO: check bundry conditions - if not self.state == StateChoices.PENDING: - raise APIException('this transaction is not pending') - - with transaction.atomic(): - self.last_update = datetime.datetime.now() - self.payee.balance = F('balance') + self.amount - self.state = StateChoices.SUCCESS - self.payee.save() - self.save() - - def __str__(self): - return f"{self.payer} -> {self.payee} ({self.uuid}): {self.amount}" diff --git a/apps/wallet/serializers.py b/apps/wallet/serializers.py deleted file mode 100755 index c714718..0000000 --- a/apps/wallet/serializers.py +++ /dev/null @@ -1,108 +0,0 @@ -from django.db import IntegrityError -from django.db.transaction import atomic -from rest_framework import serializers -from rest_framework.exceptions import APIException - -from apps.users.serializers import PublicUserSerializer -from .models import Transaction -from ..users.models import User - - -class TransactionSerializer(serializers.ModelSerializer): - payer = PublicUserSerializer(required=False) - payee = PublicUserSerializer(required=False, read_only=True) - - class Meta: - model = Transaction - fields = ('uuid', - 'payer', - 'payee', - "create", - "state", - 'amount', - 'delay', - 'last_update', - # 'detail_id', - ) - - read_only_fields = ['uuid', 'last_update', 'state', 'create'] # , 'detail_id'] - - def create(self, validated_data): - # payer = validated_data.get('payer') - # request = self.context.get('request') - # user = request.user if request else payer - - # if user == payer: - # with atomic(): - # transaction = Transaction.objects.create_transaction(**validated_data) - # transaction.pay() - # - # else: - transaction = Transaction.objects.create_transaction(**validated_data) - return transaction - - -class DepositSerializer(serializers.ModelSerializer): - uuid = serializers.UUIDField(required=True) - - class Meta: - model = Transaction - fields = ( - 'uuid', - 'payer', - 'payee', - "create", - "state", - 'amount', - 'delay', - 'last_update', - # 'detail_id', - ) - - read_only_fields = ['last_update', 'state', 'create', 'payer'] # , 'detail_id'] - - def create(self, validated_data): - with atomic(): - try: - transaction = Transaction.objects.create_transaction(**validated_data) - transaction.submit() - except IntegrityError as e: - raise APIException('duplicate uuid') - - return transaction - - -class WithdrawSerializer(serializers.ModelSerializer): - uuid = serializers.UUIDField(required=True) - - class Meta: - model = Transaction - fields = ( - 'uuid', - 'payer', - 'payee', - "create", - "state", - 'amount', - 'delay', - 'last_update', - # 'detail_id', - ) - - read_only_fields = ['last_update', 'state', 'create', 'payee'] # , 'detail_id'] - - def create(self, validated_data): - with atomic(): - try: - transaction = Transaction.objects.create_transaction(**validated_data) - transaction.submit() - except IntegrityError as e: - raise APIException('duplicate uuid') - - return transaction - - -class WalletSerializer(serializers.ModelSerializer): - class Meta: - model=User - fields = ['balance'] diff --git a/apps/wallet/tests.py b/apps/wallet/tests.py deleted file mode 100755 index 7ce503c..0000000 --- a/apps/wallet/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/apps/wallet/urls.py b/apps/wallet/urls.py deleted file mode 100644 index 68434cd..0000000 --- a/apps/wallet/urls.py +++ /dev/null @@ -1,24 +0,0 @@ -from django.urls import path -from .views import TransactionList, TransactionDetail, TransactionPay, TransactionReceipt, \ - WithdrawVerify, WithdrawSubmit, DepositSubmit, DepositVerify, TransactionListView, TransactionDetailView, \ - DefaultWalletBalanceView - -app_name = "wallet" - -urlpatterns = [ - path('transactions/', TransactionListView.as_view(), name='transaction_list'), - path('transactions/', TransactionDetailView.as_view(), name='transaction_detail'), - - path('api/wallet/default/balance', DefaultWalletBalanceView.as_view(), name='default_wallet_balance_api'), - - path('api/transactions/', TransactionList.as_view(), name='transaction_list_api'), - path('api/transactions/', TransactionDetail.as_view(), name='transaction_detail_api'), - path('api/transactions//pay', TransactionPay.as_view(), name='transaction_pay_api'), - path('api/transactions//receipt', TransactionReceipt.as_view(), name='transaction_receipt_api'), - # - path('api/deposit/', DepositSubmit.as_view(), name='deposit_submit_api'), - path('api/deposit//verify', DepositVerify.as_view(), name='deposit_verify_api'), - # - path('api/withdraw/', WithdrawSubmit.as_view(), name='withdraw_submit_api'), - path('api/withdraw//verify', WithdrawVerify.as_view(), name='withdraw_verify_api'), -] \ No newline at end of file diff --git a/apps/wallet/views.py b/apps/wallet/views.py deleted file mode 100755 index c2f26de..0000000 --- a/apps/wallet/views.py +++ /dev/null @@ -1,218 +0,0 @@ -from django.contrib import messages -from django.contrib.auth.decorators import login_required -from django.db.models import Q -from django.urls import reverse -from django.utils.decorators import method_decorator -from django.views.generic import DetailView, ListView, UpdateView - -from oauth2_provider.contrib.rest_framework import TokenHasScope, IsAuthenticatedOrTokenHasScope -from rest_framework import generics, permissions -from rest_framework.response import Response - -from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRequirements -from apps.wallet.models import Transaction -from apps.wallet.serializers import TransactionSerializer, DepositSerializer, WithdrawSerializer, WalletSerializer -from .constans import StateChoices -from .forms import TransactionActionForm - -from django.utils.translation import gettext_lazy as _ - - -def get_application(request): - try: - application = request.auth.application - except: - application = None - return application - - -class DefaultWalletBalanceView(generics.RetrieveAPIView): - permission_classes = [permissions.IsAuthenticated, IsAuthenticatedOrTokenHasScope] - serializer_class = WalletSerializer - required_scopes = ['wallet.wallet:get_balance'] - - def get_object(self): - return self.request.user - - -# TODO: this is user invoice create view -# class TransactionList(generics.ListCreateAPIView): -# permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements] -# serializer_class = TransactionSerializer -# required_alternate_scopes = { -# "GET": [['wallet.transaction:list']], -# "POST": [['wallet.invoice:create']], -# } -# -# def get_queryset(self): -# user = self.request.user -# return Transaction.objects.filter(Q(payee=user) | Q(payer=user)).all() -# -# def perform_create(self, serializer): -# user = self.request.user -# serializer.save(payee=user, application=get_application(self.request)) - - -# this is application create invoice view -class TransactionList(generics.ListCreateAPIView): - permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements] - serializer_class = TransactionSerializer - required_alternate_scopes = { - "GET": [['wallet.transaction:list']], - "POST": [['wallet.invoice:create']], - } - - def get_queryset(self): - user = self.request.user - return Transaction.objects.filter(Q(payee=user) | Q(payer=user)).all() - - def perform_create(self, serializer): - payer = self.request.user - payee = self.request.auth.application.user - serializer.save(payer=payer, payee=payee, application=get_application(self.request)) - - -class TransactionDetail(generics.RetrieveAPIView): - permission_classes = [permissions.IsAuthenticated, IsAuthenticatedOrTokenHasScope] - serializer_class = TransactionSerializer - lookup_field = 'uuid' - required_scopes = ['wallet.transaction:retrieve'] - - def get_queryset(self): - user = self.request.user - return Transaction.objects.filter(Q(payee=user) | Q(payer=user) | Q(payer__isnull=True)).all() - - -class TransactionPay(generics.RetrieveAPIView): - permission_classes = [permissions.IsAuthenticated, IsAuthenticatedOrTokenHasScope] - serializer_class = TransactionSerializer - lookup_field = 'uuid' - required_scopes = ['wallet.invoice:pay'] - - def get_queryset(self): - user = self.request.user - return Transaction.objects.filter(Q(payer=user) | Q(payer__isnull=True)).all() - - def retrieve(self, request, *args, **kwargs): - instance = self.get_object() - instance.pay(payer=self.request.user) - serializer = self.get_serializer(instance) - return Response(serializer.data) - - -class TransactionReceipt(generics.RetrieveAPIView): - permission_classes = [permissions.IsAuthenticated, IsAuthenticatedOrTokenHasScope] - serializer_class = TransactionSerializer - lookup_field = 'uuid' - required_scopes = ['wallet.invoice:receipt'] - - def get_queryset(self): - user = self.request.user - return Transaction.objects.filter(payer=user).all() - - def retrieve(self, request, *args, **kwargs): - instance = self.get_object() - instance.receipt() - serializer = self.get_serializer(instance) - return Response(serializer.data) - - -class DepositSubmit(generics.CreateAPIView): - permission_classes = [TokenHasScope] - serializer_class = DepositSerializer - required_scopes = ['wallet.deposit:submit'] - - def get_queryset(self): - application = get_application(self.request) - return Transaction.objects.filter(application=application).all() - - def perform_create(self, serializer): - payer = self.request.auth.application.user - serializer.save(payer=payer, application=get_application(self.request)) - - -class DepositVerify(generics.RetrieveAPIView): - permission_classes = [TokenHasScope] - serializer_class = DepositSerializer - lookup_field = 'uuid' - required_scopes = ['wallet.deposit:verify'] - - def get_queryset(self): - application = get_application(self.request) - return Transaction.objects.filter(application=application).all() - - def retrieve(self, request, *args, **kwargs): - instance = self.get_object() - if instance.state == StateChoices.PENDING: - instance.verify() - - serializer = self.get_serializer(instance) - return Response(serializer.data) - - -class WithdrawSubmit(generics.CreateAPIView): - permission_classes = [TokenHasScope] - serializer_class = WithdrawSerializer - required_scopes = ['wallet.withdraw:submit'] - - def get_queryset(self): - application = get_application(self.request) - return Transaction.objects.filter(application=application).all() - - def perform_create(self, serializer): - payee = self.request.auth.application.user - serializer.save(payee=payee, application=get_application(self.request)) - - -class WithdrawVerify(generics.RetrieveAPIView): - permission_classes = [TokenHasScope] - serializer_class = WithdrawSerializer - lookup_field = 'uuid' - required_scopes = ['wallet.withdraw:verify'] - - def get_queryset(self): - application = get_application(self.request) - return Transaction.objects.filter(application=application).all() - - def retrieve(self, request, *args, **kwargs): - instance = self.get_object() - if instance.state == StateChoices.PENDING: - instance.verify() - - serializer = self.get_serializer(instance) - return Response(serializer.data) - - -@method_decorator(login_required, name='dispatch') -class TransactionListView(ListView): - model = Transaction - template_name = 'wallet/transaction_list.html' - - def get_queryset(self): - user = self.request.user - return Transaction.objects.filter(Q(payee=user) | Q(payer=user)).all() - - -@method_decorator(login_required, name='dispatch') -class TransactionDetailView(UpdateView): - model = Transaction - form_class = TransactionActionForm - template_name = 'wallet/transaction_detail.html' - - def get_queryset(self): - user = self.request.user - return Transaction.objects.filter(Q(payee=user) | Q(payer=user) | Q(payer__isnull=True)).all() - - def get_success_url(self): - return reverse('wallet:transaction_detail', kwargs={'pk': self.get_object().pk}) - - def form_valid(self, form): - transaction: Transaction = form.instance - if 'pay' in self.request.POST: - result = transaction.pay(payer=self.request.user) - messages.error(self.request, _('success.')) - if 'receipt' in self.request.POST: - result = transaction.receipt() - messages.error(self.request, _('success.')) - return super().form_valid(form) - diff --git a/templates/base.html b/templates/base.html index 972b2d9..f92e504 100644 --- a/templates/base.html +++ b/templates/base.html @@ -13,7 +13,8 @@ - + @@ -42,8 +43,9 @@
{# {% include "include/sidebar.html" %}#}
+
-
+
{% include "include/top_bar.html" %} {% include "include/messages.html" %} {# {% block breadcrumbs %}#} @@ -101,10 +103,10 @@