-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
215 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# Generated by Django 4.2.5 on 2024-07-13 14:45 | ||
|
||
from django.conf import settings | ||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
|
||
|
||
class Migration(migrations.Migration): | ||
initial = True | ||
|
||
dependencies = [ | ||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||
("opportunity", "0044_opportunityverificationflags"), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name="Event", | ||
fields=[ | ||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), | ||
("date_created", models.DateTimeField(auto_now_add=True, db_index=True)), | ||
( | ||
"event_type", | ||
models.CharField( | ||
choices=[ | ||
("invite_sent", "Invite Sent"), | ||
("records_approved", "Records Approved"), | ||
("records_flagged", "Records Flagged"), | ||
("records_rejected", "Records Rejected"), | ||
("payment_approved", "Payment Approved"), | ||
("payment_accrued", "Payment Accrued"), | ||
("payment_transferred", "Payment Transferred"), | ||
("notifications_sent", "Notifications Sent"), | ||
("additional_budget_added", "Additional Budget Added"), | ||
], | ||
max_length=40, | ||
), | ||
), | ||
( | ||
"opportunity", | ||
models.ForeignKey( | ||
null=True, on_delete=django.db.models.deletion.PROTECT, to="opportunity.opportunity" | ||
), | ||
), | ||
( | ||
"user", | ||
models.ForeignKey( | ||
null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL | ||
), | ||
), | ||
], | ||
), | ||
] |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
from rest_framework.test import APIClient | ||
|
||
from commcare_connect.opportunity.models import Opportunity | ||
from commcare_connect.users.models import User | ||
|
||
from .models import Event | ||
from .tasks import EventQueue, process_events_batch | ||
|
||
|
||
def test_post_events(mobile_user_with_connect_link: User, api_client: APIClient, opportunity: Opportunity): | ||
api_client.force_authenticate(mobile_user_with_connect_link) | ||
response = api_client.post( | ||
"/api/events/", | ||
data=[ | ||
{ | ||
"event_type": "invalid_event_name", | ||
"user": mobile_user_with_connect_link.pk, | ||
"opportunity": opportunity.pk, | ||
} | ||
], | ||
format="json", | ||
) | ||
assert response.status_code == 400 | ||
assert Event.objects.count() == 0 | ||
response = api_client.post( | ||
"/api/events/", | ||
data=[ | ||
{ | ||
"event_type": Event.Type.INVITE_SENT, | ||
"user": mobile_user_with_connect_link.pk, | ||
"opportunity": opportunity.pk, | ||
}, | ||
{ | ||
"event_type": Event.Type.RECORDS_APPROVED, | ||
"user": mobile_user_with_connect_link.pk, | ||
"opportunity": opportunity.pk, | ||
}, | ||
], | ||
format="json", | ||
) | ||
assert response.status_code == 201 | ||
assert Event.objects.count() == 2 | ||
|
||
|
||
def test_event_queue(mobile_user_with_connect_link: User, opportunity: Opportunity): | ||
event_queue = EventQueue() | ||
assert event_queue.pop() == [] | ||
|
||
# queue the event | ||
event = Event(event_type=Event.Type.INVITE_SENT, user=mobile_user_with_connect_link, opportunity=opportunity) | ||
event.track() | ||
queued_events = event_queue.pop() | ||
process_events_batch() | ||
assert len(queued_events) == 1 | ||
assert Event.objects.count() == 0 | ||
# process the batch | ||
event.track() | ||
process_events_batch() | ||
assert Event.objects.count() == 1 | ||
assert Event.objects.first().user == event.user |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
from django.utils.translation import gettext as _ | ||
|
||
# Server/Web events | ||
INVITE_SENT = "invite_sent" | ||
RECORDS_APPROVED = "records_approved" | ||
RECORDS_REJECTED = "records_rejected" | ||
PAYMENT_APPROVED = "payment_approved" | ||
PAYMENT_ACCRUED = "payment_accrued" | ||
PAYMENT_TRANSFERRED = "payment_transferred" | ||
NOTIFICATIONS_SENT = "notifications_sent" | ||
ADDITIONAL_BUDGET_ADDED = "additional_budget_added" | ||
|
||
EVENT_TYPES = { | ||
INVITE_SENT: _("Invite Sent"), | ||
RECORDS_APPROVED: _("Records Approved"), | ||
RECORDS_REJECTED: _("Records Rejected"), | ||
PAYMENT_APPROVED: _("Payment Approved"), | ||
PAYMENT_ACCRUED: _("Payment Accrued"), | ||
PAYMENT_TRANSFERRED: _("Payment Transferred"), | ||
NOTIFICATIONS_SENT: _("Notifications Sent"), | ||
ADDITIONAL_BUDGET_ADDED: _("Additional Budget Added"), | ||
} | ||
|
||
EVENT_TYPE_CHOICES = list(EVENT_TYPES.items()) | ||
|
||
|
||
# Inferred Events | ||
RECORDS_FLAGGED = "records_flagged" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from django.utils.decorators import method_decorator | ||
from django.views.decorators.csrf import csrf_exempt | ||
from rest_framework import serializers, status | ||
from rest_framework.generics import ListCreateAPIView | ||
from rest_framework.permissions import IsAuthenticated | ||
from rest_framework.response import Response | ||
|
||
from .models import Event | ||
|
||
|
||
class EventSerializer(serializers.ModelSerializer): | ||
class Meta: | ||
model = Event | ||
fields = ["date_created", "event_type", "user", "opportunity"] | ||
|
||
|
||
@method_decorator(csrf_exempt, name="dispatch") | ||
class EventListCreateView(ListCreateAPIView): | ||
queryset = Event.objects.all() | ||
serializer_class = EventSerializer | ||
permission_classes = [IsAuthenticated] | ||
|
||
def create(self, request, *args, **kwargs): | ||
if not isinstance(request.data, list): | ||
return Response({"error": "Expected a list of items"}, status=status.HTTP_400_BAD_REQUEST) | ||
|
||
serializer = self.get_serializer(data=request.data, many=True) | ||
serializer.is_valid(raise_exception=True) | ||
|
||
event_objects = [Event(**item) for item in serializer.validated_data] | ||
Event.objects.bulk_create(event_objects) | ||
|
||
headers = self.get_success_headers(serializer.data) | ||
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters