last commit

This commit is contained in:
Sayyid Hamid Mahdavi 2025-10-14 20:49:31 +03:30
parent 491670200c
commit e30005021d
7 changed files with 106 additions and 50 deletions

View file

@ -2,11 +2,11 @@ from functools import update_wrapper
from django.contrib import admin from django.contrib import admin
from .models import Promotion, Plan, Event, Recipient from .models import Promotion, Plan, Event, Recipient, EventSaver
admin.site.register(Plan) admin.site.register(Plan)
admin.site.register(Promotion) admin.site.register(Promotion)
admin.site.register(Event) admin.site.register(Event)
admin.site.register(EventSaver)
admin.site.register(Recipient) admin.site.register(Recipient)

View file

@ -0,0 +1,32 @@
# Generated by Django 5.1.7 on 2025-10-14 16:49
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('promotions', '0010_remove_plan_max_amount_remove_plan_min_amount_and_more'),
]
operations = [
migrations.CreateModel(
name='EventSaver',
fields=[
('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('created_at', models.DateTimeField(auto_now_add=True, db_index=True)),
('updated_at', models.DateTimeField(auto_now=True, db_index=True)),
('title', models.CharField(max_length=255, verbose_name='title')),
('event_label', models.CharField(db_index=True, max_length=255, unique=True, verbose_name='label')),
('save_once', models.BooleanField(default=False, verbose_name='save once')),
],
options={
'abstract': False,
},
),
migrations.RemoveField(
model_name='recipient',
name='wallet_uuid',
),
]

View file

@ -5,14 +5,47 @@ from django.utils import timezone
from oauth2_provider.settings import oauth2_settings from oauth2_provider.settings import oauth2_settings
from apps.promotions import handlers from apps.promotions import handlers
from apps.promotions.handlers import PromotionTypeChoices, BasePromotionHandler from apps.promotions.handlers import PromotionTypeChoices, BasePromotionHandler
from apps.users.models import User from apps.users.models import User
from utils.models import BaseModel from utils.models import BaseModel
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
class EventSaverQuerySet(models.QuerySet):
pass
class EventSaver(BaseModel):
title = models.CharField(_('title'), max_length=255)
event_label = models.CharField(_('label'), max_length=255, unique=True, db_index=True)
save_once = models.BooleanField(_('save once'), default=False)
objects = EventSaverQuerySet.as_manager()
def save_event(self, **kwargs):
user = kwargs.get('user')
application = kwargs.get('application')
label = kwargs.get('label')
data = kwargs.get('data')
if self.save_once:
event, created = Event.objects.get_or_create(user=user, application=application, label=label, defaults={"data": data})
if created:
return event
else:
raise Exception(_('already saved'))
else:
event = Event.objects.create(user=user, application=application, label=label, defaults={"date": date})
return event
class EventQuerySet(models.QuerySet): class EventQuerySet(models.QuerySet):
pass pass
@ -63,20 +96,6 @@ class Plan(BaseModel):
def __str__(self): def __str__(self):
return self.title return self.title
# @property
# def handler(self):
# if self.promotion_type == PromotionTypeChoices.PERCENTAGE.name:
# return handlers.PercentageHandler(self)
#
# elif self.promotion_type == PromotionTypeChoices.REFERRAL.name:
# return handlers.ReferralHandler(self)
#
# elif self.promotion_type == PromotionTypeChoices.OTHERS.name:
# return handlers.OtherHandler(self)
#
# else:
# raise NotImplementedError()
def process_event(self, event=None): def process_event(self, event=None):
self.promote(event=event) self.promote(event=event)
@ -155,7 +174,6 @@ class Recipient(BaseModel):
raise raise
class PromotionQuerySet(models.QuerySet): class PromotionQuerySet(models.QuerySet):
def used(self, user): def used(self, user):
return self.filter(user=user, state__in=[Promotion.StateChoices.CREATED]) return self.filter(user=user, state__in=[Promotion.StateChoices.CREATED])

View file

@ -30,13 +30,14 @@ class EventSerializer(serializers.ModelSerializer):
) )
read_only_fields = ('user', 'application') read_only_fields = ('user', 'application')
class PlanSerializer(serializers.ModelSerializer): class PlanSerializer(serializers.ModelSerializer):
base_amount = serializers.IntegerField(required=True) base_amount = serializers.IntegerField(required=True)
promotion_amount = serializers.IntegerField(read_only=True) promotion_amount = serializers.IntegerField(read_only=True)
class Meta: class Meta:
model = Plan model = Plan
fields = ( fields = ("label"
"title", "title",
"description", "description",
"base_amount", "base_amount",
@ -58,4 +59,3 @@ class PlanPromotSerializer(serializers.ModelSerializer):
"application", "application",
) )
read_only_fields = ('user', 'application') read_only_fields = ('user', 'application')

View file

@ -1,11 +1,12 @@
from drf_spectacular.utils import extend_schema from drf_spectacular.utils import extend_schema
from rest_framework import mixins from rest_framework import mixins
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework import exceptions
from rest_framework.viewsets import GenericViewSet from rest_framework.viewsets import GenericViewSet
from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRequirements from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRequirements
from apps.gooyal_oauth2.utils import get_application from apps.gooyal_oauth2.utils import get_application
from .models import Plan, Promotion from .models import Plan, Promotion, EventSaver
from .serializers import PlanSerializer, PromotionSerializer, EventSerializer from .serializers import PlanSerializer, PromotionSerializer, EventSerializer
from .tasks import analyze_event_task from .tasks import analyze_event_task
from ..users.models import User from ..users.models import User
@ -74,14 +75,20 @@ class ApplicationEventViewSet(
"POST": [["promotions.application.event:submit"]], "POST": [["promotions.application.event:submit"]],
} }
def perform_create(self, serializer): def perform_create(self, serializer: EventSerializer):
if hasattr(self.request, 'user'): if hasattr(self.request, 'user'):
user = self.request.user user = self.request.user
else: else:
user = None user = None
application = get_application(self.request) application = get_application(self.request)
event = serializer.save(user=user, application=application) # EventSaver.objects.first(event_label=serializer.validated_data['event_label'], valid_application__contains=application.uuid)
event_saver: EventSaver = EventSaver.objects.filter(event_label=serializer.validated_data['label']).first()
try:
event = event_saver.save_event(user=user, application=application, **serializer.validated_data)
except Exception as e:
raise exceptions.ValidationError(str(e))
analyze_event_task.delay(event.uuid) analyze_event_task.delay(event.uuid)

View file

@ -188,7 +188,7 @@ REST_FRAMEWORK = {
# 'otp_min': '1/min', # 'otp_min': '1/min',
# 'otp_day': '20/day', # 'otp_day': '20/day',
}, },
'EXCEPTION_HANDLER': 'utils.exceptions.ExceptionHandler', 'EXCEPTION_HANDLER': 'utils.exceptions.exception_handler',
} }
AUTHENTICATION_BACKENDS = ( AUTHENTICATION_BACKENDS = (

View file

@ -5,10 +5,8 @@ from rest_framework.views import exception_handler as drf_exception_handler
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class ExceptionHandler:
@classmethod def exception_handler(exc, context):
def __call__(cls, exc, context):
# پاسخ پیش‌فرض DRF را دریافت می‌کنیم # پاسخ پیش‌فرض DRF را دریافت می‌کنیم
response = drf_exception_handler(exc, context) response = drf_exception_handler(exc, context)
@ -33,6 +31,7 @@ class ExceptionHandler:
# در فایل middleware.py # در فایل middleware.py
from django.http import JsonResponse from django.http import JsonResponse
class ErrorMiddleware: class ErrorMiddleware:
def __init__(self, get_response): def __init__(self, get_response):
self.get_response = get_response self.get_response = get_response