accounts/apps/users/views.py
Sayyid Hamid Mahdavi 7ad52c59a4 test
2026-07-11 09:53:07 +03:30

278 lines
9.6 KiB
Python

from django.conf import settings
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, mixins
from rest_framework.decorators import action
from rest_framework.generics import get_object_or_404
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.viewsets import GenericViewSet
from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRequirements, TokenMatchesViewSetActions
from apps.gooyal_oauth2.throttling import get_application
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, ReferralSetSerializer
from utils.throttles import RequestOTPDayRateThrottle, RequestOTPMinRateThrottle, NumberedRequestOTPDayRateThrottle, NumberedRequestOTPMinRateThrottle
from utils.clients.promotions_client import promote_user
from utils.throttles import RequestOTPDayRateThrottle, RequestOTPMinRateThrottle
from utils import exceptions
UserModel = get_user_model()
class BaseUserListView(generics.ListAPIView):
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
queryset = User.objects.all()
serializer_class = PublicUserSerializer
filter_backends = (DjangoFilterBackend,)
# Make filterset_class abstract - must be defined in subclasses
filterset_class = None
class UserProfileView(BaseUserListView):
filterset_class = UserFilter
required_alternate_scopes = {
"GET": [["accounts.profile:list"]],
}
class UserListView(BaseUserListView):
# filterset_class = UserFilter
required_alternate_scopes = {
"GET": [["accounts.users: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()
class UserViewSet(
# mixins.CreateModelMixin,
GenericViewSet
):
serializer_class = AccountSerializer
permission_classes = [TokenMatchesViewSetActions]
required_action_scopes = {
"submit_referral": [["accounts.users.user:submit_referral"]],
}
# TODO: better solution
# this is a proxy api for submit event in promotion service
@action(detail=False, methods=['POST'], serializer_class=ReferralSetSerializer)
def submit_referral(self, request, *args, **kwargs):
user = self.request.user
application = get_application(self.request)
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
referral = serializer.validated_data.get("referral")
if referral == self.request.user.pk:
raise exceptions.Conflict('SAME AS USER')
referral_user = get_object_or_404(User.objects.all(), pk=referral)
data = {
"referral": referral,
"application": application.pk,
"user": user.pk,
}
plan = settings.PROMOTIONS_REFERRAL_PLAN
result = promote_user(user, plan, 'accounts::submit_referral', data)
# result_json = {
# "promotions": [
# {
# "uuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
# "event": {
# "label": "string",
# "data": "string",
# "user": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
# "application": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
# },
# "promotion_amount": 2147483647,
# "state": 1,
# "user": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
# }
# ]
# }
if not result:
raise exceptions.Conflict('can not set referral')
return Response(serializer.validated_data)