From 286e61db2d7a97065cd479d47a0ac6ca9bef484c Mon Sep 17 00:00:00 2001 From: Sayyid Hamid Mahdavi Date: Sat, 20 Sep 2025 16:23:25 +0330 Subject: [PATCH] event api --- .../0008_event_application_event_user.py | 28 ++++++++++ apps/promotions/models.py | 3 ++ apps/promotions/serializers.py | 14 ++++- apps/promotions/tasks.py | 7 +-- apps/promotions/views.py | 51 ++++++++++--------- 5 files changed, 74 insertions(+), 29 deletions(-) create mode 100644 apps/promotions/migrations/0008_event_application_event_user.py diff --git a/apps/promotions/migrations/0008_event_application_event_user.py b/apps/promotions/migrations/0008_event_application_event_user.py new file mode 100644 index 0000000..f5de80d --- /dev/null +++ b/apps/promotions/migrations/0008_event_application_event_user.py @@ -0,0 +1,28 @@ +# Generated by Django 5.2.6 on 2025-09-20 12:52 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('promotions', '0007_plan_max_amount_plan_min_amount_and_more'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + migrations.swappable_dependency(settings.OAUTH2_PROVIDER_APPLICATION_MODEL), + ] + + operations = [ + migrations.AddField( + model_name='event', + name='application', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL), + ), + migrations.AddField( + model_name='event', + name='user', + field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + preserve_default=False, + ), + ] diff --git a/apps/promotions/models.py b/apps/promotions/models.py index 8108e91..4bea0f7 100644 --- a/apps/promotions/models.py +++ b/apps/promotions/models.py @@ -17,6 +17,9 @@ class EventQuerySet(models.QuerySet): class Event(BaseModel): + user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT) + application = models.ForeignKey(oauth2_settings.APPLICATION_MODEL, on_delete=models.PROTECT, + related_name='+', null=True, blank=True) label = models.CharField(max_length=255, db_index=True) data = models.JSONField() # from to amount application user etc diff --git a/apps/promotions/serializers.py b/apps/promotions/serializers.py index aa7d5d5..a8d5318 100644 --- a/apps/promotions/serializers.py +++ b/apps/promotions/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from .models import Promotion, Plan +from .models import Promotion, Plan, Event class PromotionSerializer(serializers.ModelSerializer): @@ -18,6 +18,18 @@ class PromotionSerializer(serializers.ModelSerializer): ) read_only_fields = ('user','application', "promotion_amount",) + +class EventSerializer(serializers.ModelSerializer): + class Meta: + model = Event + fields = ( + "label", + "data", + "user", + "application", + ) + read_only_fields = ('user','application') + class PlanSerializer(serializers.ModelSerializer): base_amount = serializers.IntegerField(required=True) promotion_amount = serializers.IntegerField(read_only=True) diff --git a/apps/promotions/tasks.py b/apps/promotions/tasks.py index 3a55344..943be9e 100644 --- a/apps/promotions/tasks.py +++ b/apps/promotions/tasks.py @@ -1,7 +1,8 @@ +from apps.promotions.models import Event from main import celery_app @celery_app.task -def sample_application_task(sample_uuid): - from .models import Sample - sample = Sample.objects.get(uuid=sample_uuid) +def analyze_event_task(event_uuid): + event = Event.objects.get(uuid=event_uuid) + event.analyze() diff --git a/apps/promotions/views.py b/apps/promotions/views.py index 451bd7c..4e3adfd 100644 --- a/apps/promotions/views.py +++ b/apps/promotions/views.py @@ -1,35 +1,13 @@ -from django.shortcuts import render - -from django.http import Http404 -from django.shortcuts import render from drf_spectacular.utils import extend_schema -from oauth2_provider.contrib.rest_framework import TokenMatchesOASRequirements -from rest_framework import viewsets, mixins +from rest_framework import mixins from rest_framework.decorators import action -from rest_framework.generics import get_object_or_404 from rest_framework.viewsets import GenericViewSet -from .models import Promotion, Plan -from .serializers import PlanSerializer, PromotionSerializer -from apps.gooyal_oauth2.models import Application from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRequirements from apps.gooyal_oauth2.utils import get_application -from ..users.models import User - -from django.shortcuts import render - -from django.http import Http404 -from django.shortcuts import render -from django.urls import reverse -from oauth2_provider.contrib.rest_framework import TokenMatchesOASRequirements -from rest_framework import viewsets, mixins -from rest_framework.generics import get_object_or_404 -from rest_framework.viewsets import GenericViewSet - from .models import Plan, Promotion -from apps.gooyal_oauth2.models import Application -from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRequirements -from apps.gooyal_oauth2.utils import get_application +from .serializers import PlanSerializer, PromotionSerializer, EventSerializer +from .tasks import analyze_event_task from ..users.models import User @@ -85,6 +63,29 @@ class ApplicationPromotionViewSet( promotion.promote(**promotion_args) +class ApplicationEventViewSet( + mixins.CreateModelMixin, + GenericViewSet +): + serializer_class = EventSerializer + + permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements] + required_alternate_scopes = { + "POST": [["promotions.application.event:submit"]], + } + + def perform_create(self, serializer): + if hasattr(self.request, 'user'): + user = self.request.user + else: + user = None + + application = get_application(self.request) + event = serializer.save(user=user, application=application) + analyze_event_task.delay(event.uuid) + + +