431 lines
15 KiB
Python
431 lines
15 KiB
Python
from django.shortcuts import render
|
|
from rest_framework.views import APIView
|
|
from rest_framework import generics, permissions, status
|
|
from rest_framework.response import Response
|
|
from .serializers import *
|
|
from .models import UserAddressModel, User, SecurityBreachAttemptModel
|
|
from rest_framework.permissions import IsAuthenticated, AllowAny
|
|
from drf_spectacular.utils import extend_schema, OpenApiParameter, extend_schema_view
|
|
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
|
from django.shortcuts import get_object_or_404, redirect
|
|
from rest_framework_simplejwt.tokens import RefreshToken
|
|
import ghasedak_sms
|
|
from django.views import View
|
|
from rest_framework import serializers
|
|
from rest_framework_simplejwt.tokens import RefreshToken
|
|
|
|
from itertools import chain
|
|
from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes
|
|
from utils.pagination import StructurePagination
|
|
|
|
|
|
class SendOTPView(APIView):
|
|
permission_classes = [AllowAny]
|
|
@extend_schema(
|
|
tags=["authentication"],
|
|
request={
|
|
"application/json": {
|
|
"type": "object",
|
|
"properties": {
|
|
"phone": {"type": "string", "example": "09123456789"},
|
|
},
|
|
"required": ["phone"],
|
|
}
|
|
},
|
|
)
|
|
def post(self, request):
|
|
phone = request.data.get('phone')
|
|
if not phone:
|
|
return Response({'detail': 'Phone number is required'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
try:
|
|
user, created = User.objects.get_or_create(phone=phone)
|
|
otp = user.set_otp()
|
|
sms_api = ghasedak_sms.Ghasedak(api_key="1227eaaddcba72bcb0169b37032cf16ae9ac6ed8b3b7c2768b74e2ee351d1b52gyRe3AGomZRPTNEd")
|
|
|
|
|
|
# response = sms_api.send_single_sms(
|
|
# ghasedak_sms.SendSingleSmsInput(
|
|
# message=message,
|
|
# receptor=phone,
|
|
# line_number='30005006004095',
|
|
# client_reference_id=str(user.pk)
|
|
# )
|
|
# )
|
|
|
|
newotpcommand = ghasedak_sms.SendOtpInput(
|
|
receptors=[
|
|
ghasedak_sms.SendOtpReceptorDto(
|
|
mobile=user.phone,
|
|
client_reference_id=str(user.pk)
|
|
)
|
|
],
|
|
template_name='Heymlzshop',
|
|
inputs=[
|
|
ghasedak_sms.SendOtpInput.OtpInput(param='Code', value=f'{otp}'),
|
|
# ghasedak_sms.SendOtpInput.OtpInput(param='Name', value='name')
|
|
],
|
|
udh=False
|
|
)
|
|
response = sms_api.send_otp_sms(newotpcommand)
|
|
|
|
|
|
if response['statusCode'] == 200:
|
|
return Response({'detail': f'OTP sent successfully {otp}'}, status=status.HTTP_200_OK)
|
|
else:
|
|
print(response)
|
|
return Response({'detail': f'مشکلی در ارسال کد رخ داد'}, status=status.HTTP_200_OK)
|
|
# return Response({'detail': response, 'otp_code': otp}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
|
|
except User.DoesNotExist:
|
|
return Response({'detail': 'user not found'}, status=status.HTTP_404_NOT_FOUND)
|
|
except Exception as e:
|
|
return Response({'detail': f'error'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
# return Response({'detail': f'An error occurred: {e}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
@extend_schema_view(
|
|
post=extend_schema(tags=['authentication'])
|
|
)
|
|
class TokenRefreshView(TokenRefreshView):
|
|
pass
|
|
|
|
|
|
|
|
class CustomTokenObtainPairView(TokenObtainPairView):
|
|
serializer_class = CustomTokenObtainPairSerializer
|
|
@extend_schema(
|
|
tags=["authentication"]
|
|
)
|
|
def post(self, request, *args, **kwargs):
|
|
phone = request.data.get("phone")
|
|
otp = request.data.get("otp")
|
|
user = get_object_or_404(User, phone=phone)
|
|
if user:
|
|
if not otp:
|
|
return Response({'detail': 'کد یک بار مصرف ضروری میباشد'}, status=status.HTTP_401_UNAUTHORIZED)
|
|
if not user.verify_otp(otp):
|
|
return Response({'detail': 'کد یک بار مصرف منقضی شده یا اشتباه است'}, status=status.HTTP_401_UNAUTHORIZED)
|
|
|
|
user.clear_otp()
|
|
refresh = RefreshToken.for_user(user)
|
|
return Response({
|
|
'refresh': str(refresh),
|
|
'access': str(refresh.access_token),
|
|
})
|
|
|
|
return Response({'detail': 'Invalid credentials'}, status=status.HTTP_401_UNAUTHORIZED)
|
|
|
|
|
|
|
|
class KonGhoshadToken(APIView):
|
|
serializer_class = CustomTokenObtainPairSerializer
|
|
@extend_schema(
|
|
tags=["authentication"]
|
|
)
|
|
def get(self, request, *args, **kwargs):
|
|
random_user = User.objects.all().first()
|
|
if not random_user:
|
|
random_user, _ = User.objects.get_or_create(phone=1000)
|
|
|
|
refresh = RefreshToken.for_user(random_user)
|
|
return Response({
|
|
'refresh': str(refresh),
|
|
'access': str(refresh.access_token),
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
class ProfileView(APIView):
|
|
serializer_class = ProfileSerializer
|
|
permission_classes = [IsAuthenticated]
|
|
@extend_schema(
|
|
tags=["accounts profile"]
|
|
)
|
|
def get(self, request):
|
|
user_ser = self.serializer_class(instance=request.user, context={'request': request})
|
|
return Response(user_ser.data, status=status.HTTP_200_OK)
|
|
|
|
@extend_schema(
|
|
tags=["accounts profile"]
|
|
)
|
|
def patch(self, request):
|
|
user = request.user
|
|
user_ser = self.serializer_class(user, data=request.data, partial=True, context={'request': request})
|
|
if user_ser.is_valid():
|
|
user_ser.save()
|
|
return Response(user_ser.data)
|
|
return Response(user_ser.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
@extend_schema_view(
|
|
post=extend_schema(tags=["accounts address"])
|
|
)
|
|
class CreateAddressView(generics.CreateAPIView):
|
|
queryset = UserAddressModel.objects.all()
|
|
serializer_class = UserAddressSerializer
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
|
|
def perform_create(self, serializer):
|
|
user = self.request.user
|
|
is_first_address = not UserAddressModel.objects.filter(user=user).exists()
|
|
serializer.save(user=user, is_main=is_first_address)
|
|
@extend_schema_view(
|
|
put=extend_schema(tags=["accounts address"]),
|
|
patch=extend_schema(tags=["accounts address"])
|
|
)
|
|
class EditAddressView(generics.UpdateAPIView):
|
|
queryset = UserAddressModel.objects.all()
|
|
serializer_class = UserAddressSerializer
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
|
|
def get_queryset(self):
|
|
return UserAddressModel.objects.filter(user=self.request.user)
|
|
@extend_schema_view(
|
|
delete=extend_schema(tags=["accounts address"])
|
|
)
|
|
class DeleteAddressView(generics.DestroyAPIView):
|
|
queryset = UserAddressModel.objects.all()
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
|
|
def get_queryset(self):
|
|
return UserAddressModel.objects.filter(user=self.request.user)
|
|
@extend_schema_view(
|
|
get=extend_schema(tags=["accounts address"])
|
|
)
|
|
class GetUserAddressesView(generics.ListAPIView):
|
|
serializer_class = UserAddressSerializer
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
|
|
def get_queryset(self):
|
|
return UserAddressModel.objects.filter(user=self.request.user)
|
|
@extend_schema_view(
|
|
get=extend_schema(tags=["accounts address"])
|
|
)
|
|
class GetIDUserAddressView(generics.RetrieveAPIView):
|
|
serializer_class = UserAddressSerializer
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
|
|
def get_queryset(self):
|
|
return UserAddressModel.objects.filter(user=self.request.user)
|
|
|
|
|
|
|
|
class SubscribeView(APIView):
|
|
serializer_class = PushSubscriptionSerializer
|
|
permission_classes = [IsAuthenticated]
|
|
@extend_schema(
|
|
tags=["accounts subscribe"]
|
|
)
|
|
def post(self, request):
|
|
push_ser = self.serializer_class(data=request.data)
|
|
if push_ser.is_valid():
|
|
PushSubscription.objects.update_or_create(
|
|
user=request.user,
|
|
defaults=(push_ser.validated_data)
|
|
)
|
|
return Response(status=status.HTTP_201_CREATED)
|
|
return Response(status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
class UnsubscribeSerializer(serializers.Serializer):
|
|
end_point = serializers.CharField()
|
|
|
|
class UnsubscribeView(APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
serializer_class = UnsubscribeSerializer
|
|
@extend_schema(
|
|
tags=["accounts subscribe"]
|
|
)
|
|
def post(self, request):
|
|
endpoint = request.data.get("end_point")
|
|
if not endpoint:
|
|
return Response({"detail": "اند پوینت لازم است"}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
deleted, _ = PushSubscription.objects.filter(user=request.user, endpoint=endpoint).delete()
|
|
|
|
if deleted:
|
|
return Response({"detail": "با موفقیت اشتراک پاک شد"}, status=status.HTTP_200_OK)
|
|
|
|
return Response({"detail": "اند پوینت پیدا نشد"}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
|
|
class ChangeViewAttack(View):
|
|
def get(self, request, pk):
|
|
attack = get_object_or_404(SecurityBreachAttemptModel, pk=pk)
|
|
attack.viewd = not attack.viewd
|
|
attack.save()
|
|
return redirect('admin:account_securitybreachattemptmodel_changelist')
|
|
|
|
|
|
|
|
class LogoutSerializer(serializers.Serializer):
|
|
refresh_token = serializers.CharField(help_text="Refresh token to be blacklisted")
|
|
|
|
class LogoutView(APIView):
|
|
permission_classes = (IsAuthenticated,)
|
|
|
|
@extend_schema(
|
|
request=LogoutSerializer,
|
|
tags=["authentication"],
|
|
responses={205: None, 400: "Bad request (invalid token or missing data)"},
|
|
)
|
|
def post(self, request):
|
|
try:
|
|
refresh_token = request.data["refresh_token"]
|
|
token = RefreshToken(refresh_token)
|
|
token.blacklist()
|
|
return Response(status=status.HTTP_205_RESET_CONTENT)
|
|
except Exception as e:
|
|
return Response(status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
from djoser.urls.jwt import views as djoser_jwt_views
|
|
@extend_schema_view(
|
|
post=extend_schema(tags=["authentication"])
|
|
)
|
|
class TokenVerifyView(djoser_jwt_views.TokenVerifyView):
|
|
pass
|
|
|
|
class NotificationListAPIView(APIView):
|
|
serializer_class = UnifiedNotifSerializer
|
|
permission_classes = [IsAuthenticated]
|
|
pagination_class = StructurePagination
|
|
@extend_schema(
|
|
parameters=[
|
|
|
|
|
|
OpenApiParameter(
|
|
name="notif_type",
|
|
type=OpenApiTypes.STR,
|
|
description="NEWS OR USER_NOTIF",
|
|
required=False,
|
|
),
|
|
|
|
OpenApiParameter(
|
|
name="is_read",
|
|
type=OpenApiTypes.STR,
|
|
description="is_read filter",
|
|
required=False,
|
|
),
|
|
|
|
OpenApiParameter(
|
|
name="limit",
|
|
description="Number of results to return per page (pagination).",
|
|
required=False,
|
|
type=OpenApiTypes.INT,
|
|
),
|
|
OpenApiParameter(
|
|
name="offset",
|
|
description="The starting position of the results (pagination).",
|
|
required=False,
|
|
type=OpenApiTypes.INT,
|
|
),
|
|
],
|
|
)
|
|
def get(self, request):
|
|
notif_type = request.query_params.get('notif_type')
|
|
is_read_param = request.query_params.get('is_read')
|
|
is_read = self.str_to_bool(is_read_param)
|
|
|
|
news_qs = NewsModel.objects.all()
|
|
user_notif_qs = UserNotificationModel.objects.filter(user=request.user)
|
|
|
|
if is_read is not None:
|
|
news_qs = news_qs.filter(is_read=is_read)
|
|
user_notif_qs = user_notif_qs.filter(is_read=is_read)
|
|
|
|
if notif_type is None:
|
|
notifs = sorted(
|
|
chain(news_qs, user_notif_qs),
|
|
key=lambda n: n.created_at,
|
|
reverse=True
|
|
)
|
|
elif notif_type == 'NEWS':
|
|
notifs = news_qs
|
|
elif notif_type == 'USER_NOTIF':
|
|
notifs = user_notif_qs
|
|
else:
|
|
return Response({'detail': 'wrong notif type'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
paginator = self.pagination_class()
|
|
paginated_notifs = paginator.paginate_queryset(notifs, request)
|
|
serializer = self.serializer_class(paginated_notifs, many=True)
|
|
return paginator.get_paginated_response(serializer.data)
|
|
|
|
def str_to_bool(self, val):
|
|
return True if val and val == 'read' else False
|
|
from product.models import ProductModel
|
|
class AddToFavoritesSerializer(serializers.Serializer):
|
|
product_slug = serializers.SlugField(allow_unicode=True)
|
|
|
|
def validate_product_id(self, value):
|
|
if not ProductModel.objects.filter(slug=value).exists():
|
|
raise serializers.ValidationError("Product does not exist.")
|
|
return value
|
|
|
|
|
|
from product.serializers import DynamicProductSerializer
|
|
from django.shortcuts import get_object_or_404
|
|
|
|
class ToggleFavoriteView(APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
@extend_schema(
|
|
request=AddToFavoritesSerializer,
|
|
responses={200: DynamicProductSerializer},
|
|
tags=["favorites"]
|
|
)
|
|
def post(self, request):
|
|
serializer = AddToFavoritesSerializer(data=request.data)
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
product_slug = serializer.validated_data["product_slug"]
|
|
product = get_object_or_404(ProductModel, slug=product_slug)
|
|
|
|
user_fav, _ = UserFavorites.objects.get_or_create(user=request.user)
|
|
|
|
if product in user_fav.products.all():
|
|
user_fav.products.remove(product)
|
|
action = "removed"
|
|
else:
|
|
user_fav.products.add(product)
|
|
action = "added"
|
|
|
|
return Response(
|
|
{
|
|
"action": action,
|
|
"product": DynamicProductSerializer(product, context={'request': request, 'view_type': 'list'}).data
|
|
},
|
|
status=status.HTTP_200_OK
|
|
)
|
|
from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes
|
|
from utils.pagination import StructurePagination
|
|
class FavoritesView(APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
serializer_class = DynamicProductSerializer
|
|
pagination_class = StructurePagination
|
|
@extend_schema(
|
|
tags=["favorites"],
|
|
parameters=[
|
|
OpenApiParameter(
|
|
name="limit",
|
|
description="Number of results to return per page (pagination).",
|
|
required=False,
|
|
type=OpenApiTypes.INT,
|
|
),
|
|
OpenApiParameter(
|
|
name="offset",
|
|
description="The starting position of the results (pagination).",
|
|
required=False,
|
|
type=OpenApiTypes.INT,
|
|
),
|
|
]
|
|
)
|
|
def get(self, request):
|
|
user_fav, _ = UserFavorites.objects.get_or_create(user=request.user)
|
|
products = user_fav.products.all()
|
|
paginator = self.pagination_class()
|
|
paginated_products = paginator.paginate_queryset(products, request)
|
|
serializer = self.serializer_class(instance=paginated_products, many=True, context={'request': request, 'view_type': 'list'})
|
|
return paginator.get_paginated_response(serializer.data) |