from django.contrib.auth import logout

from rest_framework.views import APIView
from rest_framework import generics
from rest_framework import viewsets
from rest_framework import status
from rest_framework.response import Response
from rest_framework import permissions
from rest_framework.views import exception_handler

from .models import Book, Order
from .serializers import (BookSerializer, OrderSerializer, 
                          RegistrationSerializer, LoginSerializer, UserSerializer)
from .permissions import IsAdminOrReadOnly
from .renderers import UserJSONRenderer



# View - Register new User
class RegistrationAPIView(APIView):
    permission_classes = (permissions.AllowAny,)
    renderer_classes = (UserJSONRenderer,)
    serializer_class = RegistrationSerializer

    def post(self, request):
        # user = request.data.get('user', {})
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        return Response(serializer.data, status=status.HTTP_201_CREATED)


# View - Login
class LoginAPIView (APIView):
    permission_classes = (permissions.AllowAny,)
    renderer_classes = (UserJSONRenderer,)
    serializer_class = LoginSerializer

    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        return Response(serializer.data, status=status.HTTP_200_OK)


# View - Retrieve and Update User's Profile
class UserRetrieveUpdateAPIView(generics.RetrieveUpdateAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    renderer_classes = (UserJSONRenderer,)
    serializer_class = UserSerializer

    def retrieve (self, request, *args, **kwargs):
        serializer = self.serializer_class(request.user)
        return Response(serializer.data, status=status.HTTP_200_OK)
    
    def update (self, request, *args, **kwargs):
        serializer = self.serializer_class(request.user, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        return Response(serializer.data, status=status.HTTP_200_OK)

# View - Logout
class LogoutView(APIView):
    permission_classes = (permissions.IsAuthenticated,)

    def post(self, request):
        logout(request)

        return Response({}, status=status.HTTP_204_NO_CONTENT)



class BookListView (generics.ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = (IsAdminOrReadOnly,)

class BookDetailView (generics.RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = (IsAdminOrReadOnly, )

class OrderListView (viewsets.ModelViewSet):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer

    def get_permissions(self):
        if self.action == 'list':
            self.permission_classes = (permissions.IsAdminUser, )
        elif self.action == 'create':
            self.permission_classes = (permissions.IsAuthenticated,)
        return super().get_permissions()

class OrderDetailView (generics.RetrieveUpdateDestroyAPIView):
    permission_classes = (permissions.IsAuthenticated, )
    serializer_class = OrderSerializer
    queryset = Order.objects.all()

    def update (self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data)
        
        if serializer.is_valid():
            if (serializer.data['is_submit'] == True):
                list_books = serializer.data['list_books']
                for book_id in list_books:
                    book = Book.objects.get(id=book_id)
                    current_quantity = book.quantity
                    update_quantity = current_quantity - 1
                    book.quantity = update_quantity
                    book.save(update_fields=['quantity'])
            
            super(OrderDetailView, self).update(serializer, *args, **kwargs) 
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=400)



# Overriding EXCEPTIONN_HANDLER and NONE_FIELD_ERRORS_KEY
def core_exception_handler(exc, context):
    # If an exception is thrown that we don't explicitly handle here, we want
    # to delegate to the default exception handler offered by DRF. If we do
    # handle this exception type, we will still want access to the response
    # generated by DRF, so we get that response up front.
    response = exception_handler(exc, context)
    handlers = {
        'ValidationError': _handle_generic_error
    }
    # This is how we identify the type of the current exception. We will use
    # this in a moment to see whether we should handle this exception or let
    # Django REST Framework do its thing.
    exception_class = exc.__class__.__name__

    if exception_class in handlers:
        # If this exception is one that we can handle, handle it. Otherwise,
        # return the response generated earlier by the default exception 
        # handler.
        return handlers[exception_class](exc, context, response)

    return response

def _handle_generic_error(exc, context, response):
    # This is the most straightforward exception handler we can create.
    # We take the response generated by DRF and wrap it in the `errors` key.
    response.data = {
        'errors': response.data
    }

    return response
ec80634213d2a510454f549d0707d04fc861ebd2
<mask token>


class LogoutView(APIView):
    <mask token>

    def post(self, request):
        logout(request)
        return Response({}, status=status.HTTP_204_NO_CONTENT)


class BookListView(generics.ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = IsAdminOrReadOnly,


class BookDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = IsAdminOrReadOnly,


class OrderListView(viewsets.ModelViewSet):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer

    def get_permissions(self):
        if self.action == 'list':
            self.permission_classes = permissions.IsAdminUser,
        elif self.action == 'create':
            self.permission_classes = permissions.IsAuthenticated,
        return super().get_permissions()


class OrderDetailView(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = permissions.IsAuthenticated,
    serializer_class = OrderSerializer
    queryset = Order.objects.all()

    def update(self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            if serializer.data['is_submit'] == True:
                list_books = serializer.data['list_books']
                for book_id in list_books:
                    book = Book.objects.get(id=book_id)
                    current_quantity = book.quantity
                    update_quantity = current_quantity - 1
                    book.quantity = update_quantity
                    book.save(update_fields=['quantity'])
            super(OrderDetailView, self).update(serializer, *args, **kwargs)
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=400)


<mask token>

<mask token>


class UserRetrieveUpdateAPIView(generics.RetrieveUpdateAPIView):
    <mask token>
    <mask token>
    <mask token>

    def retrieve(self, request, *args, **kwargs):
        serializer = self.serializer_class(request.user)
        return Response(serializer.data, status=status.HTTP_200_OK)
    <mask token>


class LogoutView(APIView):
    permission_classes = permissions.IsAuthenticated,

    def post(self, request):
        logout(request)
        return Response({}, status=status.HTTP_204_NO_CONTENT)


class BookListView(generics.ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = IsAdminOrReadOnly,


class BookDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = IsAdminOrReadOnly,


class OrderListView(viewsets.ModelViewSet):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer

    def get_permissions(self):
        if self.action == 'list':
            self.permission_classes = permissions.IsAdminUser,
        elif self.action == 'create':
            self.permission_classes = permissions.IsAuthenticated,
        return super().get_permissions()


class OrderDetailView(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = permissions.IsAuthenticated,
    serializer_class = OrderSerializer
    queryset = Order.objects.all()

    def update(self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            if serializer.data['is_submit'] == True:
                list_books = serializer.data['list_books']
                for book_id in list_books:
                    book = Book.objects.get(id=book_id)
                    current_quantity = book.quantity
                    update_quantity = current_quantity - 1
                    book.quantity = update_quantity
                    book.save(update_fields=['quantity'])
            super(OrderDetailView, self).update(serializer, *args, **kwargs)
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=400)


<mask token>

<mask token>


class LoginAPIView(APIView):
    <mask token>
    <mask token>
    <mask token>
    <mask token>


class UserRetrieveUpdateAPIView(generics.RetrieveUpdateAPIView):
    permission_classes = permissions.IsAuthenticated,
    renderer_classes = UserJSONRenderer,
    serializer_class = UserSerializer

    def retrieve(self, request, *args, **kwargs):
        serializer = self.serializer_class(request.user)
        return Response(serializer.data, status=status.HTTP_200_OK)

    def update(self, request, *args, **kwargs):
        serializer = self.serializer_class(request.user, data=request.data,
            partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_200_OK)


class LogoutView(APIView):
    permission_classes = permissions.IsAuthenticated,

    def post(self, request):
        logout(request)
        return Response({}, status=status.HTTP_204_NO_CONTENT)


class BookListView(generics.ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = IsAdminOrReadOnly,


class BookDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = IsAdminOrReadOnly,


class OrderListView(viewsets.ModelViewSet):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer

    def get_permissions(self):
        if self.action == 'list':
            self.permission_classes = permissions.IsAdminUser,
        elif self.action == 'create':
            self.permission_classes = permissions.IsAuthenticated,
        return super().get_permissions()


class OrderDetailView(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = permissions.IsAuthenticated,
    serializer_class = OrderSerializer
    queryset = Order.objects.all()

    def update(self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            if serializer.data['is_submit'] == True:
                list_books = serializer.data['list_books']
                for book_id in list_books:
                    book = Book.objects.get(id=book_id)
                    current_quantity = book.quantity
                    update_quantity = current_quantity - 1
                    book.quantity = update_quantity
                    book.save(update_fields=['quantity'])
            super(OrderDetailView, self).update(serializer, *args, **kwargs)
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=400)


<mask token>

<mask token>


class RegistrationAPIView(APIView):
    <mask token>
    <mask token>
    <mask token>
    <mask token>


class LoginAPIView(APIView):
    permission_classes = permissions.AllowAny,
    renderer_classes = UserJSONRenderer,
    serializer_class = LoginSerializer

    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        return Response(serializer.data, status=status.HTTP_200_OK)


class UserRetrieveUpdateAPIView(generics.RetrieveUpdateAPIView):
    permission_classes = permissions.IsAuthenticated,
    renderer_classes = UserJSONRenderer,
    serializer_class = UserSerializer

    def retrieve(self, request, *args, **kwargs):
        serializer = self.serializer_class(request.user)
        return Response(serializer.data, status=status.HTTP_200_OK)

    def update(self, request, *args, **kwargs):
        serializer = self.serializer_class(request.user, data=request.data,
            partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_200_OK)


class LogoutView(APIView):
    permission_classes = permissions.IsAuthenticated,

    def post(self, request):
        logout(request)
        return Response({}, status=status.HTTP_204_NO_CONTENT)


class BookListView(generics.ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = IsAdminOrReadOnly,


class BookDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = IsAdminOrReadOnly,


class OrderListView(viewsets.ModelViewSet):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer

    def get_permissions(self):
        if self.action == 'list':
            self.permission_classes = permissions.IsAdminUser,
        elif self.action == 'create':
            self.permission_classes = permissions.IsAuthenticated,
        return super().get_permissions()


class OrderDetailView(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = permissions.IsAuthenticated,
    serializer_class = OrderSerializer
    queryset = Order.objects.all()

    def update(self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            if serializer.data['is_submit'] == True:
                list_books = serializer.data['list_books']
                for book_id in list_books:
                    book = Book.objects.get(id=book_id)
                    current_quantity = book.quantity
                    update_quantity = current_quantity - 1
                    book.quantity = update_quantity
                    book.save(update_fields=['quantity'])
            super(OrderDetailView, self).update(serializer, *args, **kwargs)
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=400)


<mask token>

from django.contrib.auth import logout

from rest_framework.views import APIView
from rest_framework import generics
from rest_framework import viewsets
from rest_framework import status
from rest_framework.response import Response
from rest_framework import permissions
from rest_framework.views import exception_handler

from .models import Book, Order
from .serializers import (BookSerializer, OrderSerializer, 
                          RegistrationSerializer, LoginSerializer, UserSerializer)
from .permissions import IsAdminOrReadOnly
from .renderers import UserJSONRenderer



# View - Register new User
class RegistrationAPIView(APIView):
    permission_classes = (permissions.AllowAny,)
    renderer_classes = (UserJSONRenderer,)
    serializer_class = RegistrationSerializer

    def post(self, request):
        # user = request.data.get('user', {})
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        return Response(serializer.data, status=status.HTTP_201_CREATED)


# View - Login
class LoginAPIView (APIView):
    permission_classes = (permissions.AllowAny,)
    renderer_classes = (UserJSONRenderer,)
    serializer_class = LoginSerializer

    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        return Response(serializer.data, status=status.HTTP_200_OK)


# View - Retrieve and Update User's Profile
class UserRetrieveUpdateAPIView(generics.RetrieveUpdateAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    renderer_classes = (UserJSONRenderer,)
    serializer_class = UserSerializer

    def retrieve (self, request, *args, **kwargs):
        serializer = self.serializer_class(request.user)
        return Response(serializer.data, status=status.HTTP_200_OK)
    
    def update (self, request, *args, **kwargs):
        serializer = self.serializer_class(request.user, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        return Response(serializer.data, status=status.HTTP_200_OK)

# View - Logout
class LogoutView(APIView):
    permission_classes = (permissions.IsAuthenticated,)

    def post(self, request):
        logout(request)

        return Response({}, status=status.HTTP_204_NO_CONTENT)



class BookListView (generics.ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = (IsAdminOrReadOnly,)

class BookDetailView (generics.RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = (IsAdminOrReadOnly, )

class OrderListView (viewsets.ModelViewSet):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer

    def get_permissions(self):
        if self.action == 'list':
            self.permission_classes = (permissions.IsAdminUser, )
        elif self.action == 'create':
            self.permission_classes = (permissions.IsAuthenticated,)
        return super().get_permissions()

class OrderDetailView (generics.RetrieveUpdateDestroyAPIView):
    permission_classes = (permissions.IsAuthenticated, )
    serializer_class = OrderSerializer
    queryset = Order.objects.all()

    def update (self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data)
        
        if serializer.is_valid():
            if (serializer.data['is_submit'] == True):
                list_books = serializer.data['list_books']
                for book_id in list_books:
                    book = Book.objects.get(id=book_id)
                    current_quantity = book.quantity
                    update_quantity = current_quantity - 1
                    book.quantity = update_quantity
                    book.save(update_fields=['quantity'])
            
            super(OrderDetailView, self).update(serializer, *args, **kwargs) 
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=400)



# Overriding EXCEPTIONN_HANDLER and NONE_FIELD_ERRORS_KEY
def core_exception_handler(exc, context):
    # If an exception is thrown that we don't explicitly handle here, we want
    # to delegate to the default exception handler offered by DRF. If we do
    # handle this exception type, we will still want access to the response
    # generated by DRF, so we get that response up front.
    response = exception_handler(exc, context)
    handlers = {
        'ValidationError': _handle_generic_error
    }
    # This is how we identify the type of the current exception. We will use
    # this in a moment to see whether we should handle this exception or let
    # Django REST Framework do its thing.
    exception_class = exc.__class__.__name__

    if exception_class in handlers:
        # If this exception is one that we can handle, handle it. Otherwise,
        # return the response generated earlier by the default exception 
        # handler.
        return handlers[exception_class](exc, context, response)

    return response

def _handle_generic_error(exc, context, response):
    # This is the most straightforward exception handler we can create.
    # We take the response generated by DRF and wrap it in the `errors` key.
    response.data = {
        'errors': response.data
    }

    return response