Skip to content

Commit

Permalink
Added Lead API (#4)
Browse files Browse the repository at this point in the history
* Fix Workflow
* Added tests
* Added Lead API
* Fix Already Scanned
* Modified Response
* Modified the response for already scanned case to include attendee name
and email
* Added Option for Tags
* Updated Exhibitors to have Booth with ID and Name
* Modifications on the settings page
* isort Fixes
* Add Modification for Booth ID
  • Loading branch information
Sak1012 authored Nov 11, 2024
1 parent fcbea7d commit f3e3ecb
Show file tree
Hide file tree
Showing 21 changed files with 743 additions and 141 deletions.
239 changes: 231 additions & 8 deletions exhibitors/api.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,34 @@
from rest_framework import viewsets, views, status
from rest_framework.response import Response
from django.shortcuts import get_object_or_404

from django.utils import timezone
from pretix.api.serializers.i18n import I18nAwareModelSerializer
from pretix.api.serializers.order import CompatibleJSONField
from pretix.base.models import OrderPosition
from rest_framework import status, views, viewsets
from rest_framework.response import Response

from .models import ExhibitorInfo, ExhibitorItem
from .models import ExhibitorInfo, ExhibitorItem,ExhibitorSettings , ExhibitorTag, Lead


class ExhibitorAuthView(views.APIView):
def post(self, request, *args, **kwargs):
email = request.data.get('email')
key = request.data.get('key')

if not email or not key:
if not key:
return Response(
{'detail': 'Missing parameters'},
status=status.HTTP_400_BAD_REQUEST
)

try:
exhibitor = ExhibitorInfo.objects.get(email=email, key=key)
exhibitor = ExhibitorInfo.objects.get(key=key)
return Response(
{'success': True, 'exhibitor_id': exhibitor.id},
{
'success': True,
'exhibitor_id': exhibitor.id,
'exhibitor_name': exhibitor.name,
'booth_id': exhibitor.booth_id,
'booth_name': exhibitor.booth_name,
},
status=status.HTTP_200_OK
)
except ExhibitorInfo.DoesNotExist:
Expand Down Expand Up @@ -65,3 +71,220 @@ class ExhibitorItemViewSet(viewsets.ReadOnlyModelViewSet):

def get_queryset(self):
return ExhibitorItem.objects.filter(item__event=self.request.event)


class LeadCreateView(views.APIView):
def get_allowed_attendee_data(self, order_position, settings, exhibitor):
"""Helper method to get allowed attendee data based on settings"""
# Get all allowed fields including defaults
allowed_fields = settings.all_allowed_fields
print(allowed_fields)
print(order_position)
attendee_data = {
'name': order_position.attendee_name, # Always included
'email': order_position.attendee_email, # Always included
'company': order_position.company if 'attendee_company' in allowed_fields else None,
'city': order_position.city if 'attendee_city' in allowed_fields else None,
'country': str(order_position.country) if 'attendee_country' in allowed_fields else None,
'note': '',
'tags': []
}

return {k: v for k, v in attendee_data.items() if v is not None}

def post(self, request, *args, **kwargs):
# Extract parameters from the request
pseudonymization_id = request.data.get('lead')
scanned = request.data.get('scanned')
scan_type = request.data.get('scan_type')
device_name = request.data.get('device_name')
key = request.headers.get('Exhibitor')

if not all([pseudonymization_id, scanned, scan_type, device_name]):
return Response(
{'detail': 'Missing parameters'},
status=status.HTTP_400_BAD_REQUEST
)

# Authenticate the exhibitor
try:
exhibitor = ExhibitorInfo.objects.get(key=key)
settings = ExhibitorSettings.objects.get(event=exhibitor.event)
except (ExhibitorInfo.DoesNotExist, ExhibitorSettings.DoesNotExist):
return Response(
{'success': False, 'error': 'Invalid exhibitor key'},
status=status.HTTP_401_UNAUTHORIZED
)

# Get attendee details
try:
order_position = OrderPosition.objects.get(
pseudonymization_id=pseudonymization_id
)
except OrderPosition.DoesNotExist:
return Response(
{'success': False, 'error': 'Attendee not found'},
status=status.HTTP_404_NOT_FOUND
)

# Check for duplicate scan
if Lead.objects.filter(
exhibitor=exhibitor,
pseudonymization_id=pseudonymization_id
).exists():
attendee_data = self.get_allowed_attendee_data(
order_position,
settings,
exhibitor
)
return Response(
{
'success': False,
'error': 'Lead already scanned',
'attendee': attendee_data
},
status=status.HTTP_409_CONFLICT
)

# Get allowed attendee data based on settings
attendee_data = self.get_allowed_attendee_data(
order_position,
settings,
exhibitor
)
print(attendee_data)
# Create the lead entry
lead = Lead.objects.create(
exhibitor=exhibitor,
exhibitor_name=exhibitor.name,
pseudonymization_id=pseudonymization_id,
scanned=timezone.now(),
scan_type=scan_type,
device_name=device_name,
booth_id=exhibitor.booth_id,
booth_name=exhibitor.booth_name,
attendee=attendee_data
)

return Response(
{
'success': True,
'lead_id': lead.id,
'attendee': attendee_data
},
status=status.HTTP_201_CREATED
)


class LeadRetrieveView(views.APIView):
def get(self, request, *args, **kwargs):
# Authenticate the exhibitor using the key
key = request.headers.get('Exhibitor')
try:
exhibitor = ExhibitorInfo.objects.get(key=key)
except ExhibitorInfo.DoesNotExist:
return Response(
{
'success': False,
'error': 'Invalid exhibitor key'
},
status=status.HTTP_401_UNAUTHORIZED
)

# Fetch all leads associated with the exhibitor
leads = Lead.objects.filter(exhibitor=exhibitor).values(
'id',
'pseudonymization_id',
'exhibitor_name',
'scanned',
'scan_type',
'device_name',
'booth_id',
'booth_name',
'attendee'
)

return Response(
{
'success': True,
'leads': list(leads)
},
status=status.HTTP_200_OK
)


class TagListView(views.APIView):
def get(self, request, organizer, event, *args, **kwargs):
key = request.headers.get('Exhibitor')
try:
exhibitor = ExhibitorInfo.objects.get(key=key)
tags = ExhibitorTag.objects.filter(exhibitor=exhibitor)
return Response({
'success': True,
'tags': [tag.name for tag in tags]
})
except ExhibitorInfo.DoesNotExist:
return Response(
{
'success': False,
'error': 'Invalid exhibitor key'
},
status=status.HTTP_401_UNAUTHORIZED
)

class LeadUpdateView(views.APIView):
def post(self, request, organizer, event, lead_id, *args, **kwargs):
key = request.headers.get('Exhibitor')
note = request.data.get('note')
tags = request.data.get('tags', [])

try:
exhibitor = ExhibitorInfo.objects.get(key=key)
except ExhibitorInfo.DoesNotExist:
return Response(
{
'success': False,
'error': 'Invalid exhibitor key'
},
status=status.HTTP_401_UNAUTHORIZED
)

try:
lead = Lead.objects.get(pseudonymization_id=lead_id, exhibitor=exhibitor)
except Lead.DoesNotExist:
return Response(
{
'success': False,
'error': 'Lead not found'
},
status=status.HTTP_404_NOT_FOUND
)

# Update lead's attendee info
attendee_data = lead.attendee or {}
if note is not None:
attendee_data['note'] = note
if tags is not None:
attendee_data['tags'] = tags

# Update tag usage counts and create new tags
for tag_name in tags:
tag, created = ExhibitorTag.objects.get_or_create(
exhibitor=exhibitor,
name=tag_name
)
if not created:
tag.use_count += 1
tag.save()

lead.attendee = attendee_data
lead.save()

return Response(
{
'success': True,
'lead_id': lead.id,
'attendee': lead.attendee
},
status=status.HTTP_200_OK
)
55 changes: 19 additions & 36 deletions exhibitors/forms.py
Original file line number Diff line number Diff line change
@@ -1,49 +1,32 @@
from django import forms
from django.utils.translation import gettext, gettext_lazy as _

from pretix.base.forms import SettingsForm
from .models import ExhibitorInfo

from .models import ExhibitorInfo

class ExhibitorSettingForm(SettingsForm):
exhibitor_url = forms.URLField(
label=_("Exhibitor URL"),
required=False,
)

exhibitor_name = forms.CharField(
label=_("Exhibitor Name"),
required=True,
)

exhibitor_description = forms.CharField(
label=_("Exhibitor Description"),
required=False,
)

exhibitor_logo = forms.ImageField(
label=_("Exhibitor Logo"),
required=False,
)
lead_scanning_enabled = forms.BooleanField(
label=_("Lead Scanning Enabled"),
required=False,
initial=True,
class ExhibitorInfoForm(forms.ModelForm):
allow_voucher_access = forms.BooleanField(required=False)
allow_lead_access = forms.BooleanField(required=False)
lead_scanning_scope_by_device = forms.BooleanField(required=False)
comment = forms.CharField(
widget=forms.Textarea(attrs={'rows': 10}),
required=False
)
booth_id = forms.CharField(required=False)

def __init__(self, *args, **kwargs):
self.obj = kwargs.get('obj')
super().__init__(*args, **kwargs)

def clean(self):
data = super().clean()
return data


class ExhibitorInfoForm(forms.ModelForm):
class Meta:
model = ExhibitorInfo
fields = ['name', 'description', 'url', 'email', 'logo']
fields = [
'name',
'description',
'url',
'email',
'logo',
'booth_id',
'booth_name',
'lead_scanning_enabled'
]
widgets = {
'description': forms.Textarea(attrs={'rows': 4}),
}
3 changes: 2 additions & 1 deletion exhibitors/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Generated by Django 4.2.14 on 2024-09-02 09:37

from django.db import migrations, models
import django.db.models.deletion
from django.db import migrations, models

import exhibitors.models


Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Generated by Django 4.2.14 on 2024-09-16 05:42

from django.db import migrations, models
import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):
Expand Down
26 changes: 26 additions & 0 deletions exhibitors/migrations/0003_lead.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 4.2.14 on 2024-10-14 10:02

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('exhibitors', '0002_alter_exhibitorinfo_lead_scanning_enabled_and_more'),
]

operations = [
migrations.CreateModel(
name='Lead',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
('pseudonymization_id', models.CharField(max_length=190)),
('scanned', models.DateTimeField()),
('scan_type', models.CharField(max_length=50)),
('device_name', models.CharField(max_length=50)),
('attendee', models.JSONField(null=True)),
('exhibitor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='exhibitors.exhibitorinfo')),
],
),
]
Loading

0 comments on commit f3e3ecb

Please sign in to comment.