feat: added desktop sso endpoints

This commit is contained in:
2026-05-28 16:05:47 -07:00
parent 91a376ac0a
commit bf6171a667
11 changed files with 1077 additions and 5 deletions

View File

@@ -0,0 +1,61 @@
import logging
from rest_framework import serializers
logger = logging.getLogger(__name__)
class VibnAttributionCaptureMixin:
"""
A Django REST Framework ViewSet/APIView mixin that automatically
extracts marketing attribution fields (UTMs, referrer) from incoming
request payloads or HTTP headers and binds them to the saving object.
Compatible with any Django REST Framework serializer.
"""
def extract_attribution_data(self, request):
"""
Extracts UTM and referrer keys from request data, falling back
to request headers if required.
"""
# Try request payload first
data = request.data or {}
utm_source = data.get("utm_source")
utm_medium = data.get("utm_medium")
utm_campaign = data.get("utm_campaign")
utm_content = data.get("utm_content")
utm_term = data.get("utm_term")
# Capture Referrer from payload or fallback to HTTP headers
referrer = data.get("referrer")
if not referrer:
referrer = request.META.get("HTTP_REFERER")
return {
"utm_source": utm_source,
"utm_medium": utm_medium,
"utm_campaign": utm_campaign,
"utm_content": utm_content,
"utm_term": utm_term,
"referrer": referrer,
}
def perform_create(self, serializer):
"""
In DRF ViewSets, overrides perform_create to automatically inject
attribution fields directly into the saved model instance.
"""
attrib_data = self.extract_attribution_data(self.request)
# Save serializer with attribution params injected as overrides
instance = serializer.save(
**{k: v for k, v in attrib_data.items() if v is not None}
)
logger.info(
f"VibnTracker: Saved attribution data to {instance.__class__.__name__} "
f"(Source: {attrib_data['utm_source']}, Campaign: {attrib_data['utm_campaign']})"
)
return instance

View File

@@ -0,0 +1,164 @@
from django.db import models
class VibnAbstractAttributionModel(models.Model):
"""
An abstract Django model that adds standard marketing attribution
(first-touch UTM parameters & referrers) to any model (e.g. User, APIClient, Customer).
To implement:
class APIClient(VibnAbstractAttributionModel):
name = models.CharField(max_length=255)
# ... other fields ...
"""
utm_source = models.CharField(
max_length=255,
null=True,
blank=True,
help_text="Marketing channel source (e.g. twitter, google, newsletter)",
)
utm_medium = models.CharField(
max_length=255,
null=True,
blank=True,
help_text="Marketing medium (e.g. cpc, social, organic, email)",
)
utm_campaign = models.CharField(
max_length=255,
null=True,
blank=True,
help_text="Marketing campaign name (e.g. mcp-launch, spring-discount)",
)
utm_content = models.CharField(
max_length=255,
null=True,
blank=True,
help_text="Specific content links or ad identifiers clicked",
)
utm_term = models.CharField(
max_length=255,
null=True,
blank=True,
help_text="Keywords searched or paid terms clicked",
)
referrer = models.CharField(
max_length=1000,
null=True,
blank=True,
help_text="First-touch browser referrer URL (e.g. https://t.co/, https://google.com)",
)
class Meta:
abstract = True
def save_attribution(
self,
utm_source,
utm_medium=None,
utm_campaign=None,
utm_content=None,
utm_term=None,
referrer=None,
overwrite=False,
):
"""
Helper method to securely save marketing attribution data if it hasn't been set yet.
"""
if overwrite or not self.utm_source:
self.utm_source = utm_source
self.utm_medium = utm_medium
self.utm_campaign = utm_campaign
self.utm_content = utm_content
self.utm_term = utm_term
self.referrer = referrer
self.save(
update_fields=[
"utm_source",
"utm_medium",
"utm_campaign",
"utm_content",
"utm_term",
"referrer",
]
if self.pk
else None
)
class VibnPageview(models.Model):
"""
Vibn Pageview Tracking Model.
Tracks active user interactions and page loads in real-time,
providing fully dynamic traffic data and click timelines.
"""
user = models.ForeignKey(
"UserProfile", # Replace with your custom User model name
on_delete=models.CASCADE,
related_name="pageviews",
null=True,
blank=True,
)
session_id = models.CharField(
max_length=255, db_index=True, help_text="Unique browser session tracker ID"
)
url_path = models.CharField(
max_length=500, db_index=True, help_text="Tracked page path, e.g. /pricing"
)
referrer = models.CharField(
max_length=1000, null=True, blank=True, help_text="Traffic referrer URL"
)
# Captured UTM variables
utm_source = models.CharField(max_length=255, null=True, blank=True)
utm_medium = models.CharField(max_length=255, null=True, blank=True)
utm_campaign = models.CharField(max_length=255, null=True, blank=True)
utm_content = models.CharField(max_length=255, null=True, blank=True)
utm_term = models.CharField(max_length=255, null=True, blank=True)
# Device/Geo details
device = models.CharField(max_length=100, default="desktop")
browser = models.CharField(max_length=100, default="chrome")
country = models.CharField(max_length=100, default="US")
created_at = models.DateTimeField(auto_now_add=True, db_index=True)
class Meta:
db_table = "vibn_pageview"
verbose_name = "Vibn Pageview"
verbose_name_plural = "Vibn Pageviews"
ordering = ["-created_at"]
class VibnEvent(models.Model):
"""
Vibn Product Event Tracking Model.
Tracks custom user conversion events (e.g. signup, connect_channel, create_campaign)
and binds them to their sessions and profiles.
"""
user = models.ForeignKey(
"UserProfile", # Replace with your custom User model name
on_delete=models.CASCADE,
related_name="events",
null=True,
blank=True,
)
session_id = models.CharField(max_length=255, db_index=True)
event_name = models.CharField(
max_length=255,
db_index=True,
help_text="Custom event name, e.g. connect_social",
)
properties = models.JSONField(
default=dict, blank=True, help_text="Custom event properties JSON"
)
created_at = models.DateTimeField(auto_now_add=True, db_index=True)
class Meta:
db_table = "vibn_event"
verbose_name = "Vibn Event"
verbose_name_plural = "Vibn Events"
ordering = ["-created_at"]