Spaces:
Running
Running
# 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'}) | |