# management/views.py # -*- coding: utf-8 -*- from django.utils import timezone from rest_framework import generics, viewsets, status from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated, IsAdminUser from rest_framework.views import APIView from rest_framework_simplejwt.views import TokenObtainPairView from rest_framework_simplejwt.tokens import RefreshToken import datetime from .models import ( CustomUser, Panel, MarzbanAdmin, License, SecurityToken, Plan, Subscription, Payment, EndUser, PaymentMethod, PaymentSetting, PaymentDetail, TelegramUser ) from .serializers import ( PanelSerializer, LicenseSerializer, MarzbanAdminSerializer, CustomUserSerializer, SecurityTokenSerializer, PlanSerializer, SubscriptionSerializer, ReceiptUploadSerializer, PaymentMethodSerializer, PaymentDetailSerializer, EndUserPaymentDetailSerializer, AdminLevel3SubscriptionSerializer, PurchaseSubscriptionForUserSerializer, ) from .tasks import ( send_telegram_message, send_payment_receipt_to_admin, send_payment_confirmation_to_user, ) # --- Authentication Views --- class CustomTokenObtainPairView(TokenObtainPairView): def post(self, request, *args, **kwargs): response = super().post(request, *args, **kwargs) if response.status_code == 200: user = CustomUser.objects.get(username=request.data['username']) response.data['user_role'] = user.role return response class LogoutAPIView(APIView): permission_classes = [IsAuthenticated] def post(self, request): try: refresh_token = request.data["refresh_token"] token = RefreshToken(refresh_token) token.blacklist() return Response({"message": "Successfully logged out."}, status=status.HTTP_200_OK) except Exception as e: return Response({"error": "Invalid token or other error."}, status=status.HTTP_400_BAD_REQUEST) # --- ADDED: Missing ViewSets --- class PanelViewSet(viewsets.ModelViewSet): serializer_class = PanelSerializer permission_classes = [IsAuthenticated] def get_queryset(self): return Panel.objects.filter(owner=self.request.user) def perform_create(self, serializer): serializer.save(owner=self.request.user) class LicenseViewSet(viewsets.ModelViewSet): serializer_class = LicenseSerializer permission_classes = [IsAuthenticated] def get_queryset(self): user = self.request.user if user.is_super_admin(): return License.objects.all() return License.objects.filter(owner=user) class MarzbanAdminViewSet(viewsets.ModelViewSet): serializer_class = MarzbanAdminSerializer permission_classes = [IsAuthenticated] def get_queryset(self): try: panel = Panel.objects.get(owner=self.request.user) return MarzbanAdmin.objects.filter(panel=panel) except Panel.DoesNotExist: return MarzbanAdmin.objects.none() class PlanViewSet(viewsets.ModelViewSet): serializer_class = PlanSerializer permission_classes = [IsAuthenticated] def get_queryset(self): try: panel = Panel.objects.get(owner=self.request.user) return Plan.objects.filter(panel=panel) except Panel.DoesNotExist: return Plan.objects.none() def perform_create(self, serializer): try: panel = Panel.objects.get(owner=self.request.user) serializer.save(panel=panel) except Panel.DoesNotExist: return Response({"error": "You do not own a panel."}, status=status.HTTP_403_FORBIDDEN) class EndUserViewSet(viewsets.ModelViewSet): serializer_class = SubscriptionSerializer # A better serializer can be created for EndUser permission_classes = [IsAuthenticated] def get_queryset(self): if self.request.user.role == 'AdminLevel3': try: panel = Panel.objects.get(owner=self.request.user) return EndUser.objects.filter(panel=panel) except Panel.DoesNotExist: return EndUser.objects.none() return EndUser.objects.none() class SubscriptionViewSet(viewsets.ModelViewSet): serializer_class = SubscriptionSerializer permission_classes = [IsAuthenticated] def get_queryset(self): user = self.request.user if user.role == 'AdminLevel3': try: panel = Panel.objects.get(owner=user) return Subscription.objects.filter(panel=panel) except Panel.DoesNotExist: return Subscription.objects.none() elif user.role == 'EndUser': try: end_user = EndUser.objects.get(username=user.username) return Subscription.objects.filter(end_user=end_user) except EndUser.DoesNotExist: return Subscription.objects.none() return Subscription.objects.none() class PaymentViewSet(viewsets.ModelViewSet): serializer_class = ReceiptUploadSerializer # A better serializer can be created for listing permission_classes = [IsAuthenticated] def get_queryset(self): user = self.request.user if user.is_admin_level_3(): return Payment.objects.filter(admin=user) return Payment.objects.none() # --- Payment System Views --- class PaymentMethodViewSet(viewsets.ModelViewSet): queryset = PaymentMethod.objects.all() serializer_class = PaymentMethodSerializer permission_classes = [IsAuthenticated] http_method_names = ['get', 'patch', 'put'] def get_queryset(self): if self.request.user.is_authenticated and self.request.user.is_admin_level_2(): return PaymentMethod.objects.all() return PaymentMethod.objects.none() class PaymentDetailAPIView(APIView): permission_classes = [IsAuthenticated] def get(self, request): if not request.user.is_admin_level_3(): return Response({'error': 'Permission denied.'}, status=status.HTTP_403_FORBIDDEN) details, _ = PaymentDetail.objects.get_or_create(admin_level_3=request.user) serializer = PaymentDetailSerializer(details) return Response(serializer.data) def put(self, request): if not request.user.is_admin_level_3(): return Response({'error': 'Permission denied.'}, status=status.HTTP_403_FORBIDDEN) details, _ = PaymentDetail.objects.get_or_create(admin_level_3=request.user) serializer = PaymentDetailSerializer(details, data=request.data, partial=True) if serializer.is_valid(): serializer.save() return Response(serializer.data) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class EndUserPaymentOptionsAPIView(APIView): permission_classes = [IsAuthenticated] def get(self, request): if not request.user.role == 'EndUser': return Response({'error': 'Permission denied.'}, status=status.HTTP_403_FORBIDDEN) try: end_user = EndUser.objects.get(username=request.user.username) admin_level_3_user = end_user.panel.owner payment_settings = PaymentSetting.objects.filter(admin_level_3=admin_level_3_user, is_active=True) serializer = EndUserPaymentDetailSerializer(payment_settings, many=True) return Response(serializer.data) except EndUser.DoesNotExist: return Response({'error': 'User not found.'}, status=status.HTTP_404_NOT_FOUND) # --- Subscription Management --- class AdminLevel3SubscriptionViewSet(viewsets.ModelViewSet): serializer_class = AdminLevel3SubscriptionSerializer permission_classes = [IsAuthenticated] def get_queryset(self): if self.request.user.is_authenticated and self.request.user.role == 'AdminLevel3': try: return Subscription.objects.filter(panel__owner=self.request.user) except Panel.DoesNotExist: return Subscription.objects.none() return Subscription.objects.none() def perform_create(self, serializer): serializer.save() # FIXED: Logic for purchasing subscription class PurchaseSubscriptionForUserAPIView(APIView): serializer_class = PurchaseSubscriptionForUserSerializer permission_classes = [IsAuthenticated] def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) data = serializer.validated_data end_user_username = data.get('end_user_username') plan_id = data.get('plan_id') amount = data.get('amount') try: # The user making the request must be an EndUser if request.user.role != 'EndUser': return Response({'error': 'Only EndUsers can purchase subscriptions.'}, status=status.HTTP_403_FORBIDDEN) # Get the panel of the user making the request requester_end_user = EndUser.objects.get(username=request.user.username) panel = requester_end_user.panel admin_level_3_user = panel.owner plan = Plan.objects.get(id=plan_id, panel=panel) # Get or create the target end user within the same panel target_end_user, _ = EndUser.objects.get_or_create( username=end_user_username, defaults={'panel': panel} ) subscription = Subscription.objects.create( end_user=target_end_user, plan=plan, panel=panel, status='pending', ) payment = Payment.objects.create( subscription=subscription, admin=admin_level_3_user, amount=amount, status='pending', ) return Response({ "message": "Subscription request created successfully. Please upload the receipt.", "subscription_id": subscription.id, "payment_token": payment.payment_token }, status=status.HTTP_201_CREATED) except EndUser.DoesNotExist: return Response({'error': 'Requesting user profile not found.'}, status=status.HTTP_404_NOT_FOUND) except Plan.DoesNotExist: return Response({'error': 'Plan not found for your panel.'}, status=status.HTTP_404_NOT_FOUND) except Exception as e: return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) # --- Other Views --- # ADDED: PaymentReceiptUploadAPIView (was missing) class PaymentReceiptUploadAPIView(APIView): permission_classes = [IsAuthenticated] serializer_class = ReceiptUploadSerializer def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) try: payment = Payment.objects.get(payment_token=serializer.validated_data['payment_token']) # Update payment with receipt details payment.receipt_image = serializer.validated_data.get('receipt_image') payment.receipt_text = serializer.validated_data.get('receipt_text') payment.save() # Trigger celery task to notify admin send_payment_receipt_to_admin.delay(payment.id) return Response({"message": "Receipt uploaded successfully. Please wait for admin approval."}, status=status.HTTP_200_OK) except Payment.DoesNotExist: return Response({"error": "Invalid payment token."}, status=status.HTTP_404_NOT_FOUND) # ADDED: GenerateTelegramTokenAPIView (was missing) class GenerateTelegramTokenAPIView(APIView): permission_classes = [IsAuthenticated] def post(self, request): user = request.user expiration = timezone.now() + datetime.timedelta(minutes=5) # This assumes a direct relation between CustomUser and a Marzban Admin ID if not user.marzban_admin_id: return Response({'error': 'User is not linked to a Marzban admin.'}, status=status.HTTP_400_BAD_REQUEST) token, _ = SecurityToken.objects.update_or_create( admin_id=str(user.marzban_admin_id), defaults={'expiration_date': expiration} ) return Response({'token': token.token}) class VerifyTelegramTokenAPIView(APIView): # This view is for unauthenticated users (the bot) to verify a token permission_classes = [] def post(self, request): token_value = request.data.get('token') chat_id = request.data.get('chat_id') if not token_value or not chat_id: return Response({'error': 'Token and chat_id are required.'}, status=status.HTTP_400_BAD_REQUEST) try: token = SecurityToken.objects.get(token=token_value, expiration_date__gt=timezone.now()) # Logic to find the main DB CustomUser and update their telegram_chat_id user = CustomUser.objects.get(marzban_admin_id=token.admin_id) # Assuming AdminLevel3 has a telegram_chat_id field if hasattr(user, 'admin_level_3'): user.admin_level_3.telegram_chat_id = chat_id user.admin_level_3.save() token.delete() # One-time use token return Response({'message': 'Telegram account linked successfully.'}) except (SecurityToken.DoesNotExist, CustomUser.DoesNotExist): return Response({'error': 'Invalid or expired token.'}, status=status.HTTP_400_BAD_REQUEST) class PushSubscriptionAPIView(APIView): permission_classes = [IsAuthenticated] def post(self, request, *args, **kwargs): # Implementation needed return Response({'message': 'Subscription created successfully.'}) # ADDED: TelegramWebhookView (was in urls.py but missing here) class TelegramWebhookView(APIView): permission_classes = [] def post(self, request, bot_token): # Your telegram bot logic here # print(request.data) return Response({'status': 'ok'})