Spaces:
Sleeping
Sleeping
Commit ·
39bbebf
1
Parent(s): 1215efd
made it faster and added color picker
Browse files
app/routes/analytics.py
CHANGED
|
@@ -34,13 +34,13 @@ class TrackEventRequest(BaseModel):
|
|
| 34 |
@router.post("/public/forms/{token}/track")
|
| 35 |
async def track_public_event(
|
| 36 |
token: str,
|
| 37 |
-
payload: TrackEventRequest,
|
| 38 |
request: Request,
|
| 39 |
db: Session = Depends(get_db)
|
| 40 |
):
|
| 41 |
"""
|
| 42 |
Public endpoint for client-side analytics tracking.
|
| 43 |
-
No authentication required.
|
| 44 |
"""
|
| 45 |
# Find public form by token
|
| 46 |
public_form = db.query(PublicForm).filter(
|
|
|
|
| 34 |
@router.post("/public/forms/{token}/track")
|
| 35 |
async def track_public_event(
|
| 36 |
token: str,
|
| 37 |
+
payload: TrackEventRequest, # Expects JSON body with event_type, session_id, question_id, time_spent
|
| 38 |
request: Request,
|
| 39 |
db: Session = Depends(get_db)
|
| 40 |
):
|
| 41 |
"""
|
| 42 |
Public endpoint for client-side analytics tracking.
|
| 43 |
+
No authentication required. Accepts JSON body with tracking data.
|
| 44 |
"""
|
| 45 |
# Find public form by token
|
| 46 |
public_form = db.query(PublicForm).filter(
|
app/services/analytics_service.py
CHANGED
|
@@ -226,18 +226,18 @@ class AnalyticsService:
|
|
| 226 |
|
| 227 |
base_filter = and_(*filters)
|
| 228 |
|
| 229 |
-
# Count
|
| 230 |
-
total_views = db.query(func.count(FormAnalyticsEvent.
|
| 231 |
base_filter,
|
| 232 |
FormAnalyticsEvent.event_type == AnalyticsEventType.FORM_VIEWED.value
|
| 233 |
).scalar() or 0
|
| 234 |
|
| 235 |
-
total_starts = db.query(func.count(FormAnalyticsEvent.
|
| 236 |
base_filter,
|
| 237 |
FormAnalyticsEvent.event_type == AnalyticsEventType.FORM_STARTED.value
|
| 238 |
).scalar() or 0
|
| 239 |
|
| 240 |
-
total_completes = db.query(func.count(FormAnalyticsEvent.
|
| 241 |
base_filter,
|
| 242 |
FormAnalyticsEvent.event_type == AnalyticsEventType.FORM_SUBMITTED_COMPLETE.value
|
| 243 |
).scalar() or 0
|
|
@@ -253,19 +253,20 @@ class AnalyticsService:
|
|
| 253 |
# Build question funnel
|
| 254 |
question_funnel = []
|
| 255 |
for question in sorted(form.questions, key=lambda q: q.question_order):
|
| 256 |
-
viewed
|
|
|
|
| 257 |
base_filter,
|
| 258 |
FormAnalyticsEvent.question_id == question.id,
|
| 259 |
FormAnalyticsEvent.event_type == AnalyticsEventType.QUESTION_VIEWED.value
|
| 260 |
).scalar() or 0
|
| 261 |
|
| 262 |
-
answered = db.query(func.count(FormAnalyticsEvent.
|
| 263 |
base_filter,
|
| 264 |
FormAnalyticsEvent.question_id == question.id,
|
| 265 |
FormAnalyticsEvent.event_type == AnalyticsEventType.QUESTION_ANSWERED.value
|
| 266 |
).scalar() or 0
|
| 267 |
|
| 268 |
-
skipped = db.query(func.count(FormAnalyticsEvent.
|
| 269 |
base_filter,
|
| 270 |
FormAnalyticsEvent.question_id == question.id,
|
| 271 |
FormAnalyticsEvent.event_type == AnalyticsEventType.QUESTION_SKIPPED.value
|
|
|
|
| 226 |
|
| 227 |
base_filter = and_(*filters)
|
| 228 |
|
| 229 |
+
# Count UNIQUE SESSIONS by event type (not total events)
|
| 230 |
+
total_views = db.query(func.count(func.distinct(FormAnalyticsEvent.session_id))).filter(
|
| 231 |
base_filter,
|
| 232 |
FormAnalyticsEvent.event_type == AnalyticsEventType.FORM_VIEWED.value
|
| 233 |
).scalar() or 0
|
| 234 |
|
| 235 |
+
total_starts = db.query(func.count(func.distinct(FormAnalyticsEvent.session_id))).filter(
|
| 236 |
base_filter,
|
| 237 |
FormAnalyticsEvent.event_type == AnalyticsEventType.FORM_STARTED.value
|
| 238 |
).scalar() or 0
|
| 239 |
|
| 240 |
+
total_completes = db.query(func.count(func.distinct(FormAnalyticsEvent.session_id))).filter(
|
| 241 |
base_filter,
|
| 242 |
FormAnalyticsEvent.event_type == AnalyticsEventType.FORM_SUBMITTED_COMPLETE.value
|
| 243 |
).scalar() or 0
|
|
|
|
| 253 |
# Build question funnel
|
| 254 |
question_funnel = []
|
| 255 |
for question in sorted(form.questions, key=lambda q: q.question_order):
|
| 256 |
+
# Count UNIQUE SESSIONS that viewed/answered/skipped each question
|
| 257 |
+
viewed = db.query(func.count(func.distinct(FormAnalyticsEvent.session_id))).filter(
|
| 258 |
base_filter,
|
| 259 |
FormAnalyticsEvent.question_id == question.id,
|
| 260 |
FormAnalyticsEvent.event_type == AnalyticsEventType.QUESTION_VIEWED.value
|
| 261 |
).scalar() or 0
|
| 262 |
|
| 263 |
+
answered = db.query(func.count(func.distinct(FormAnalyticsEvent.session_id))).filter(
|
| 264 |
base_filter,
|
| 265 |
FormAnalyticsEvent.question_id == question.id,
|
| 266 |
FormAnalyticsEvent.event_type == AnalyticsEventType.QUESTION_ANSWERED.value
|
| 267 |
).scalar() or 0
|
| 268 |
|
| 269 |
+
skipped = db.query(func.count(func.distinct(FormAnalyticsEvent.session_id))).filter(
|
| 270 |
base_filter,
|
| 271 |
FormAnalyticsEvent.question_id == question.id,
|
| 272 |
FormAnalyticsEvent.event_type == AnalyticsEventType.QUESTION_SKIPPED.value
|