from django.contrib.auth import get_user_model from django.contrib.auth.decorators import login_required from django.contrib.auth.views import LoginView from django.http import Http404 from django.shortcuts import render, redirect from django.urls import reverse from django.utils import timezone from django.utils.decorators import method_decorator from django.views.generic import DetailView, UpdateView from django_filters.rest_framework import DjangoFilterBackend from oauth2_provider.contrib.rest_framework import IsAuthenticatedOrTokenHasScope from rest_framework import generics, status, permissions from rest_framework.permissions import AllowAny from rest_framework.response import Response from rest_framework.views import APIView from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRequirements from apps.users.filters import UserFilter from apps.users.forms import OTPAuthenticationForm, ProfileUpdateForm from apps.users.models import User from apps.users.provinces_and_cities import State from apps.users.serializers import PublicUserSerializer, AccountSerializer, RequestOTPSerializer, RequestOTTSerializer, \ ChangePasswordSerializer, UserInquirySerializer, SessionSerializer from utils.throttles import RequestOTPDayRateThrottle, RequestOTPMinRateThrottle, NumberedRequestOTPDayRateThrottle, NumberedRequestOTPMinRateThrottle UserModel = get_user_model() class UserListView(generics.ListAPIView): permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements] queryset = User.objects.all() serializer_class = PublicUserSerializer filter_backends = (DjangoFilterBackend,) filterset_class = UserFilter required_alternate_scopes = { "GET": [["accounts.profile:list"]], } class UserPublicRetrieveView(generics.RetrieveAPIView): permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements] queryset = User.objects.all() serializer_class = PublicUserSerializer lookup_field = 'uuid' required_alternate_scopes = { "GET": [["accounts.profile:retrieve"]], } class UserDetailedRetrieveView(generics.RetrieveAPIView): permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements] queryset = User.objects.all() serializer_class = AccountSerializer lookup_field = 'uuid' required_alternate_scopes = { "GET": [["accounts.profile:detailed_retrieve"]], } class UserCurrentAvatarUrlView(generics.RetrieveAPIView): permission_classes = [AllowAny] queryset = User.objects.all() lookup_field = 'uuid' def retrieve(self, request, *args, **kwargs): user: User = self.get_object() if user.avatar: return redirect(user.avatar.url) else: raise Http404() class AccountView(generics.RetrieveUpdateAPIView): serializer_class = AccountSerializer permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements] required_alternate_scopes = { "GET": [["accounts.account:retrieve"]], "POST": [["accounts.account:update"]], "PUT": [["accounts.account:update"]], "PATCH": [["accounts.account:update"]], } def get_object(self): return self.request.user def perform_update(self, serializer): serializer.save(last_update=timezone.now()) class RequestOTPView(generics.CreateAPIView): permission_classes = [] serializer_class = RequestOTPSerializer required_scopes = [] throttle_classes = [RequestOTPMinRateThrottle, RequestOTPDayRateThrottle, NumberedRequestOTPDayRateThrottle, NumberedRequestOTPMinRateThrottle] class RequestOTTView(generics.CreateAPIView): permission_classes = [IsAuthenticatedOrTokenHasScope] required_scopes = ['accounts.account:request_ott'] serializer_class = RequestOTTSerializer def get_object(self): return self.request.user def create(self, request, *args, **kwargs): instance: User = self.get_object() serializer = self.get_serializer(instance, data=request.data) serializer.is_valid(raise_exception=True) instance.set_ott() instance.save() return Response(serializer.data) class UserInquiryView(generics.CreateAPIView): serializer_class = UserInquirySerializer permission_classes = [IsAuthenticatedOrTokenHasScope] required_scopes = ['accounts.profile:inquiry'] class ChangePasswordView(generics.UpdateAPIView): permission_classes = [IsAuthenticatedOrTokenHasScope] serializer_class = ChangePasswordSerializer required_scopes = ["accounts.account:change_password"] model = User def get_object(self, queryset=None): obj = self.request.user return obj def update(self, request, *args, **kwargs): self.object = self.get_object() serializer = self.get_serializer(data=request.data) if serializer.is_valid(): pass_field = serializer.data.get("old_password_field") old_password = serializer.data.get("old_password") new_password = serializer.data.get("new_password") if not self.object.check_auth(pass_field, old_password): return Response({"old_password": ["Wrong password/otp."]}, status=status.HTTP_400_BAD_REQUEST) self.object.set_password(new_password) self.object.last_update = timezone.now() self.object.save() return Response({"state": 'success'}, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class OTPLoginView(LoginView): template_name = 'users/login.html' """ Display the login form and handle the login action. """ form_class = OTPAuthenticationForm def post(self, request, *args, **kwargs): return super().post(request, *args, **kwargs) @method_decorator(login_required, name='dispatch') class ProfileDetailView(DetailView): model = User template_name = 'users/profile_detail.html' pk_url_kwarg = 'uuid' def get_object(self, queryset=None): return self.request.user @method_decorator(login_required, name='dispatch') class ProfileUpdateView(UpdateView): model = User template_name = 'users/profile_update.html' pk_url_kwarg = 'uuid' form_class = ProfileUpdateForm def get_success_url(self): return reverse('users:profile_update') def get_object(self, queryset=None): return self.request.user def form_valid(self, form): return super().form_valid(form) class UserSessionListView(generics.ListAPIView): permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements] serializer_class = SessionSerializer filter_backends = (DjangoFilterBackend,) max_allowed_session = 0 required_alternate_scopes = { "GET": [["accounts.account:retrieve"]], } def get_queryset(self): from apps.gooyal_oauth2.models import AccessToken return AccessToken.objects.filter(user=self.request.user).all()