set permissions to membership actions

This commit is contained in:
2025-05-29 14:42:23 +03:00
parent e30eb10d7d
commit be27f5ee97
3 changed files with 65 additions and 12 deletions

View File

@@ -9,17 +9,20 @@ from django.core.validators import validate_email
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.db.models import Q from django.db.models import Q
from datetime import datetime, timedelta from datetime import timedelta
from django.utils import timezone from rest_framework.exceptions import PermissionDenied
from django.utils.timezone import now as timezone_now
from .serializers import RouteSerializer, CreateRouteSerializer, CitySerializer, CountrySerializer, PlanChangeSerializer, PricingSerializer, LeadSerializer, LeadResponseSerializer from .serializers import RouteSerializer, CreateRouteSerializer, CitySerializer, CountrySerializer, PlanChangeSerializer, PricingSerializer, LeadSerializer, LeadResponseSerializer
from api.auth.serializers import UserResponseSerializer from api.auth.serializers import UserResponseSerializer
from api.models import UserProfile from api.models import UserProfile
from routes.models import Route, City, Country, Leads from routes.models import Route, City, Country, Leads
from sitemanagement.models import Pricing from sitemanagement.models import Pricing, RoutePromotionLog
from api.utils.decorators import handle_exceptions from api.utils.decorators import handle_exceptions
from api.utils.emailSender import send_email from api.utils.emailSender import send_email
from api.utils.permissionChecker import check_monthly_limit
class UserDataView(ViewSet): class UserDataView(ViewSet):
"""Эндпоинт для наполнения стора фронта данными""" """Эндпоинт для наполнения стора фронта данными"""
@@ -314,32 +317,54 @@ class LeadViewSet(ViewSet):
) )
class PremiumMembershipActionsView(ViewSet): class PremiumMembershipActionsView(ViewSet):
"""Выделение объявления""" """Выделение и поднятие объявления"""
@action(detail=False, methods=['patch']) @action(detail=False, methods=['patch'])
@handle_exceptions @handle_exceptions
def highlight_route(self, request): def highlight_route(self, request):
"""Выделяем объявление""" """Выделяем объявление"""
route_id = request.data.get('route_id') route_id = request.data.get('route_id')
route = get_object_or_404(Route, id=route_id) route = get_object_or_404(Route, id=route_id)
if not check_monthly_limit(request.user, route, 'highlight'):
raise PermissionDenied("Превышен лимит выделений за месяц")
# подсвечиваем объявление на 24 часа # подсвечиваем объявление на 24 часа
now = timezone.now() now = timezone_now()
route.highlight_end_DT = now + timedelta(days=1) route.highlight_end_DT = now + timedelta(days=1)
route.is_highlighted = True route.is_highlighted = True
route.save() route.save()
# логируем действие
RoutePromotionLog.objects.create(
user=request.user,
route=route,
action_type='highlight'
)
return Response({ return Response({
"message": "Объявление выделено", "message": "Объявление выделено",
"is_highlighted": route.is_highlighted "is_highlighted": route.is_highlighted
}, status=status.HTTP_200_OK) }, status=status.HTTP_200_OK)
@action(detail=False, methods=['patch']) @action(detail=False, methods=['patch'])
@handle_exceptions @handle_exceptions
def upper_route(self, request): def upper_route(self, request):
"""Поднимаем объявление""" """Поднимаем объявление"""
route_id = request.data.get('route_id') route_id = request.data.get('route_id')
route = get_object_or_404(Route, id=route_id) route = get_object_or_404(Route, id=route_id)
route.rising_DT = datetime.now()
if not check_monthly_limit(request.user, route, 'rising'):
raise PermissionDenied("Превышен лимит поднятий за месяц")
route.rising_DT = timezone_now()
route.save() route.save()
return Response({"message": "Объявление поднято"}, status=status.HTTP_200_OK)
# логируем действие
RoutePromotionLog.objects.create(
user=request.user,
route=route,
action_type='rising'
)
return Response({"message": "Объявление поднято"}, status=status.HTTP_200_OK)

View File

@@ -0,0 +1,14 @@
from django.utils.timezone import now
from datetime import timedelta
from sitemanagement.models import RoutePromotionLog
MAX_ACTIONS_PER_MONTH = 5
def check_monthly_limit(user, route, action_type):
month_ago = now() - timedelta(days=30)
return RoutePromotionLog.objects.filter(
user=user,
route=route,
action_type=action_type,
created_at__gte=month_ago
).count() < MAX_ACTIONS_PER_MONTH

View File

@@ -7,6 +7,7 @@ from django.dispatch import receiver
from transliterate import translit from transliterate import translit
from routes.constants.account_types import account_types from routes.constants.account_types import account_types
from django.contrib.auth.models import User from django.contrib.auth.models import User
from routes.models import Route
class FAQ (models.Model): class FAQ (models.Model):
title = models.CharField(max_length=250) title = models.CharField(max_length=250)
@@ -89,4 +90,17 @@ class Transactions(models.Model):
def __str__(self): def __str__(self):
return f'{self.user} - {self.amount}' return f'{self.user} - {self.amount}'
class RoutePromotionLog(models.Model):
ACTION_CHOICES = [
('highlight', 'Выделение'),
('rising', 'Поднятие'),
]
route = models.ForeignKey(Route, on_delete=models.CASCADE, related_name='promotion_logs')
user = models.ForeignKey(User, on_delete=models.CASCADE)
action_type = models.CharField(max_length=20, choices=ACTION_CHOICES)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.user} - {self.action_type} for route {self.route.id} at {self.created_at}"