from django.shortcuts import render from rest_framework import status, viewsets from rest_framework.response import Response from .models import Connection, ConnectionType from .serializers import ConnectionSerializer from rest_framework.decorators import action, authentication_classes from rest_framework.decorators import permission_classes from qrtr_account.models import Account from rest_framework.permissions import IsAuthenticated, AllowAny import importlib import json from .serializers import ConnectionSerializer, ConnectionTypeSerializer from django.db import transaction from qrtr_account.mixins import OwnedAccountsMixin import traceback # Create your views here. class ConnectionTypeViewSet(viewsets.ModelViewSet): queryset = ConnectionType.objects.all() serializer_class = ConnectionTypeSerializer class ConnectionViewSet(viewsets.ModelViewSet, OwnedAccountsMixin): """API endpoint that allows connections to be seen or created """ permission_classes = [IsAuthenticated] queryset = Connection.objects.all() serializer_class = ConnectionSerializer # Make connections somewhat immutable from the users perspective http_method_names = [ 'get', 'post', 'delete', 'options'] def get_queryset(self): return Connection.objects.filter( account__in=self.accessible_accounts().values_list('id')) @action(detail=False, methods=['post'], url_path='plaid/exchange_public_token') def exchange_public_token(self, request): print(f"REQUEST: {request.data}") name = request.data.get("name", "dummyName") account_id = request.data.get("account") public_token = request.data.get("public_token") user = request.user if request.user.is_anonymous: accounts = (Account.objects.filter(pk=1)) else: accounts = (Account.objects.filter(pk=account_id, owner=user) | Account.objects.filter(pk=account_id, admin_users__in=[user])) if not accounts: return Response( status=status.HTTP_400_BAD_REQUEST, data="ERROR: Account ID not found") else: print(f"Account Found: {accounts[0]}") account = accounts[0] print(request) plaid_conn = importlib.import_module(f"connection.connections.plaid_client_v2") conn_type = ConnectionType.objects.get(name="Plaid") try: plaid_client = plaid_conn.Connection(request.data.dict(), account_id=account_id) token = plaid_client.get_auth_token(public_token) except ValueError: return Response(status=status.HTTP_503, data="ERROR: Invalid public_token") with transaction.atomic(): conn, created = Connection.objects \ .get_or_create(name=name, type=conn_type, defaults={ "credentials": request.data, "account": account }) conn.credentials = plaid_client.credentials print(f"CREDS: {plaid_client.credentials}") conn.save() serializer = self.get_serializer(conn, context={'request':request}) print("DATA:") print(serializer.data) return Response(serializer.data) @action(detail=False, methods=['post'], url_path='plaid') def authenticate(self, request): print(request.data) print(request.data.keys()) # public_token = request.data.get("public_token") name = request.data.get("name", "dummyName") account_id = request.data.get("account") print(f"Account ID Detected: {account_id}") # if public_token is None: # return Response( # status=status.HTTP_400_BAD_REQUEST, # data="ERROR: missing public_token") if account_id is None: return Response( status=status.HTTP_400_BAD_REQUEST, data="ERROR: missing account_id") user = request.user # Filter out any accounts with the right id, but the given user # is not an owner or admin on that account. if request.user.is_anonymous: accounts = (Account.objects.filter(pk=1)) else: accounts = (Account.objects.filter(pk=account_id, owner=user) | Account.objects.filter(pk=account_id, admin_users__in=[user])) if not accounts: return Response( status=status.HTTP_400_BAD_REQUEST, data="ERROR: Account ID not found") else: print(f"Account Found: {accounts[0]}") account = accounts[0] print(request) plaid_conn = importlib.import_module(f"connection.connections.plaid_client_v2") conn_type = ConnectionType.objects.get(name="Plaid") try: plaid_client = plaid_conn.Connection(request.data.dict(), account_id=account_id) plaid_client.generate_auth_request() except ValueError: return Response(status=status.HTTP_503, data="ERROR: Invalid public_token") except Exception as e: print(e) print(traceback.format_exc()) return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR, data="ERROR: Unable to contact Plaid") with transaction.atomic(): conn, created = Connection.objects \ .get_or_create(name=name, type=conn_type, defaults={ "credentials": request.data, "account": account }) conn.credentials = plaid_client.credentials print(f"CREDS: {plaid_client.credentials}") conn.save() return Response(plaid_client.credentials) @action(detail=False, methods=['post'], url_path='plaid-webhook', permission_classes=[AllowAny]) def plaid_webhook(self, request): print("Plaid Webhook Received!") print(request.data) return Response(200)