diff --git a/apps/gooyal_oauth2/validators.py b/apps/gooyal_oauth2/validators.py index 95926a7..a2ce9b6 100755 --- a/apps/gooyal_oauth2/validators.py +++ b/apps/gooyal_oauth2/validators.py @@ -150,15 +150,18 @@ class OAuth2Validator(BaseOAuth2Validator): # pylint: disable=w0223 expires, timezone=get_timezone(oauth2_settings.AUTHENTICATION_SERVER_EXP_TIME_ZONE) ) - # TODO: get application owner and put it here + application, _created = Application.objects.get_or_create( client_id=content["client_id"], - uuid=application_introspection_content["uuid"] + uuid=application_introspection_content["uuid"], + defaults={ + "user": owner # TODO: JUST FOR WALLET + } ) access_token, _created = AccessToken.objects.update_or_create( token=token, defaults={ - "user": user, + "user": user , # TODO: JUST FOR WALLET "client_id": content["client_id"], "application_owner": owner, "application_id": application_uuid, diff --git a/apps/wallet/application_views.py b/apps/wallet/application_views.py new file mode 100755 index 0000000..ede6018 --- /dev/null +++ b/apps/wallet/application_views.py @@ -0,0 +1,74 @@ +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, mixins +from rest_framework.permissions import AllowAny +from rest_framework.response import Response +from rest_framework.viewsets import GenericViewSet, ModelViewSet + +from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRequirements, \ + IsAuthenticatedOrActionMatchesOASRequirements +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 ApplicationWalletBalanceView(generics.RetrieveAPIView): + ''' + API for getting authenticated user balance. + ''' + permission_classes = [TokenHasScope] + serializer_class = WalletSerializer + required_scopes = ['wallet.application:get_balance'] + + def get_object(self): + return self.request.user + + def retrieve(self, request, *args, **kwargs): + return super().retrieve(request, *args, **kwargs) + + +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) + + diff --git a/apps/wallet/models.py b/apps/wallet/models.py index b4fe69c..2c68398 100755 --- a/apps/wallet/models.py +++ b/apps/wallet/models.py @@ -1,6 +1,7 @@ import datetime import uuid +from django.core.validators import MinValueValidator from django.db import models from django.db import transaction from django.db.models import F @@ -14,45 +15,40 @@ from ..gooyal_oauth2.models import Application # TODO: move DRF functionalities to view or serializers -class TransactionManager(models.Manager): - def create_transaction( - self, - amount, - payee, - payee_type, - payer=None, - payer_type=None, - delay=0, - detail=None, - application=None, - uuid=None - ): - if amount <= 0: - raise ValidationError('amount should be greater than zero') - if delay < 0: - raise ValidationError('delay should be greater than equal zero') - - transaction = self.model( - uuid=uuid, - payer=payer, - payer_type=payer_type, - payee=payee, - payee_type=payee_type, - amount=amount, - delay=delay, - application=application, - detail=detail - ) - - transaction.save() - return transaction +# class TransactionManager(models.Manager): +# def create_transaction( +# self, +# amount, +# payee_id, +# payee_type, +# payer_id=None, +# payer_type=None, +# delay=0, +# detail=None, +# application=None, +# uuid=None +# ): +# tr = self.model( +# uuid=uuid, +# payer_id=payer_id, +# payer_type=payer_type, +# payee_id=payee_id, +# payee_type=payee_type, +# amount=amount, +# delay=delay, +# application=application, +# detail=detail +# ) +# +# tr.save() +# return tr 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 + amount = models.PositiveBigIntegerField(_('amount'), blank=False, validators=[MinValueValidator(1)]) + delay = models.PositiveIntegerField(default=0, blank=True) # number of days for delayed payments payer_id = models.UUIDField(blank=True, null=True) payer_type = models.IntegerField(choices=TypeChoices.choices, blank=True, null=True) payee_id = models.UUIDField() @@ -62,9 +58,9 @@ class Transaction(models.Model): updated_at = models.DateTimeField(auto_now=True, null=True) application = models.ForeignKey(oauth2_settings.APPLICATION_MODEL, on_delete=models.PROTECT, related_name='transactions', null=True) - detail = models.JSONField(null=True, blank=True, default={}) + details = models.JSONField(null=True, blank=True, default=dict) - objects = TransactionManager() + # objects = TransactionManager() # class Meta: # unique_together = ('application', 'detail_id',) diff --git a/apps/wallet/serializers.py b/apps/wallet/serializers.py index 6256806..b9cd5ae 100755 --- a/apps/wallet/serializers.py +++ b/apps/wallet/serializers.py @@ -8,35 +8,28 @@ from ..users.models import User class TransactionSerializer(serializers.ModelSerializer): - payee = serializers.UUIDField(read_only=True) + payee_id = serializers.UUIDField(read_only=True) + payee_type = serializers.UUIDField(read_only=True) class Meta: model = Transaction fields = ('uuid', - 'payer', - 'payee', + 'payer_id', + 'payer_type', + 'payee_id', + 'payee_type', "created_at", "state", 'amount', 'delay', 'updated_at', - # 'detail_id', + 'details', ) - read_only_fields = ['uuid', 'updated_at', 'state', 'created_at'] # , 'detail_id'] + read_only_fields = ['uuid', 'updated_at', 'state', 'created_at', 'details'] - 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 + # def create(self, validated_data): + # transaction = Transaction.objects.create_transaction(**validated_data) + # return transaction class DepositSerializer(serializers.ModelSerializer): diff --git a/apps/wallet/urls.py b/apps/wallet/urls.py index 0005e2b..f780ed9 100644 --- a/apps/wallet/urls.py +++ b/apps/wallet/urls.py @@ -1,4 +1,6 @@ from django.urls import path + +from .application_views import ApplicationWalletBalanceView from .views import TransactionList, TransactionDetail, TransactionPay, TransactionReceipt, \ WithdrawVerify, WithdrawSubmit, DepositSubmit, DepositVerify, TransactionListView, TransactionDetailView, \ WalletBalanceView @@ -21,4 +23,6 @@ urlpatterns = [ # path('api/withdraw/', WithdrawSubmit.as_view(), name='withdraw_submit_api'), path('api/withdraw//verify', WithdrawVerify.as_view(), name='withdraw_verify_api'), + + path('api/get_balance/', ApplicationWalletBalanceView.as_view(), name='wallet_balance'), ] \ No newline at end of file diff --git a/apps/wallet/views.py b/apps/wallet/views.py index aff32eb..caabc83 100755 --- a/apps/wallet/views.py +++ b/apps/wallet/views.py @@ -7,6 +7,7 @@ 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.permissions import AllowAny from rest_framework.response import Response from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRequirements @@ -30,32 +31,14 @@ class WalletBalanceView(generics.RetrieveAPIView): ''' API for getting authenticated user balance. ''' - permission_classes = [permissions.IsAuthenticated, IsAuthenticatedOrTokenHasScope] + permission_classes = [AllowAny, permissions.IsAuthenticated, IsAuthenticatedOrTokenHasScope] serializer_class = WalletSerializer - required_scopes = ['wallet.wallet:get_balance'] + required_scopes = ['wallet.application: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): ''' diff --git a/wallet/settings.py b/wallet/settings.py index 69828b9..6a938c1 100644 --- a/wallet/settings.py +++ b/wallet/settings.py @@ -144,7 +144,7 @@ TEMPLATES = [ AUTHENTICATION_BACKENDS = ( 'oauth2_provider.backends.OAuth2Backend', - 'django.contrib.auth.backends.ModelBackend', + # 'django.contrib.auth.backends.ModelBackend', ) WSGI_APPLICATION = 'wallet.wsgi.application'