feat: HOME-007 — server-side event title/description search (q param)
This commit is contained in:
@@ -13,9 +13,83 @@ from datetime import datetime, timedelta
|
||||
import calendar
|
||||
import math
|
||||
from mobile_api.utils import validate_token_and_get_user
|
||||
from accounts.models import User
|
||||
from eventify_logger.services import log
|
||||
|
||||
|
||||
def _resolve_contributor(identifier):
|
||||
"""Resolve an eventifyId or email to a contributor dict. Returns None on miss."""
|
||||
if not identifier:
|
||||
return None
|
||||
try:
|
||||
user = User.objects.filter(
|
||||
Q(eventify_id=identifier) | Q(email=identifier)
|
||||
).first()
|
||||
if not user:
|
||||
return None
|
||||
|
||||
# Count events this user contributed
|
||||
events_count = Event.objects.filter(
|
||||
Q(contributed_by=user.eventify_id) | Q(contributed_by=user.email)
|
||||
).filter(
|
||||
event_status__in=['published', 'live', 'completed']
|
||||
).count()
|
||||
|
||||
full_name = user.get_full_name() or user.username or ''
|
||||
avatar = ''
|
||||
if user.profile_picture and hasattr(user.profile_picture, 'url'):
|
||||
try:
|
||||
avatar = user.profile_picture.url
|
||||
except Exception:
|
||||
avatar = ''
|
||||
|
||||
return {
|
||||
'name': full_name,
|
||||
'email': user.email,
|
||||
'eventify_id': user.eventify_id or '',
|
||||
'avatar': avatar,
|
||||
'member_since': user.date_joined.strftime('%b %Y') if user.date_joined else '',
|
||||
'events_contributed': events_count,
|
||||
'location': ', '.join(filter(None, [user.place or '', user.district or '', user.state or ''])),
|
||||
}
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _serialize_event_for_contributor(event):
|
||||
"""Lightweight event serializer for contributor profile listings."""
|
||||
primary_img = ''
|
||||
try:
|
||||
img = EventImages.objects.filter(event=event, is_primary=True).first()
|
||||
if not img:
|
||||
img = EventImages.objects.filter(event=event).first()
|
||||
if img and img.event_image:
|
||||
primary_img = img.event_image.url
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return {
|
||||
'id': event.id,
|
||||
'name': event.name or event.title or '',
|
||||
'title': event.title or event.name or '',
|
||||
'start_date': event.start_date.isoformat() if event.start_date else '',
|
||||
'end_date': event.end_date.isoformat() if event.end_date else '',
|
||||
'start_time': str(event.start_time or ''),
|
||||
'end_time': str(event.end_time or ''),
|
||||
'image': primary_img,
|
||||
'venue_name': event.venue_name or '',
|
||||
'place': event.place or '',
|
||||
'district': event.district or '',
|
||||
'state': event.state or '',
|
||||
'pincode': event.pincode or '',
|
||||
'latitude': str(event.latitude) if event.latitude else '',
|
||||
'longitude': str(event.longitude) if event.longitude else '',
|
||||
'event_type': event.event_type_id,
|
||||
'event_status': event.event_status or '',
|
||||
'source': event.source or '',
|
||||
}
|
||||
|
||||
|
||||
def _haversine_km(lat1, lon1, lat2, lon2):
|
||||
"""Great-circle distance between two points in km."""
|
||||
R = 6371.0
|
||||
@@ -92,6 +166,7 @@ class EventListAPI(APIView):
|
||||
page = int(data.get("page", 1))
|
||||
page_size = int(data.get("page_size", 50))
|
||||
per_type = int(data.get("per_type", 0))
|
||||
q = data.get("q", "").strip()
|
||||
|
||||
# New optional geo params
|
||||
user_lat = data.get("latitude")
|
||||
@@ -169,6 +244,10 @@ class EventListAPI(APIView):
|
||||
if pincode_qs.count() >= MIN_EVENTS_THRESHOLD:
|
||||
qs = pincode_qs
|
||||
|
||||
# Priority 3: Full-text search on title / description
|
||||
if q:
|
||||
qs = qs.filter(Q(title__icontains=q) | Q(description__icontains=q))
|
||||
|
||||
if per_type > 0 and page == 1:
|
||||
type_ids = list(qs.values_list('event_type_id', flat=True).distinct())
|
||||
events_page = []
|
||||
@@ -225,6 +304,14 @@ class EventDetailAPI(APIView):
|
||||
event_img['image'] = ei.event_image.url
|
||||
event_images_list.append(event_img)
|
||||
event_data["images"] = event_images_list
|
||||
|
||||
# Resolve contributor from contributed_by field
|
||||
contributed_by = getattr(events, 'contributed_by', None)
|
||||
if contributed_by:
|
||||
contributor = _resolve_contributor(contributed_by)
|
||||
if contributor:
|
||||
event_data["contributor"] = contributor
|
||||
|
||||
return JsonResponse(event_data)
|
||||
except Exception as e:
|
||||
log("error", "EventDetailAPI exception", request=request, logger_data={"error": str(e)})
|
||||
@@ -542,3 +629,55 @@ class TopEventsAPI(APIView):
|
||||
except Exception as e:
|
||||
log("error", "TopEventsAPI exception", request=request, logger_data={"error": str(e)})
|
||||
return JsonResponse({"status": "error", "message": "An unexpected server error occurred."})
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name='dispatch')
|
||||
class ContributorProfileAPI(APIView):
|
||||
"""
|
||||
Public API to fetch a contributor's profile and their events.
|
||||
POST /api/events/contributor-profile/
|
||||
Body: { "contributor_id": "EVT-XXXXXXXX" } (or email)
|
||||
"""
|
||||
authentication_classes = []
|
||||
permission_classes = [AllowAny]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
try:
|
||||
data = json.loads(request.body) if request.body else {}
|
||||
except Exception:
|
||||
data = {}
|
||||
|
||||
contributor_id = data.get("contributor_id", "").strip()
|
||||
if not contributor_id:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "contributor_id is required"},
|
||||
status=400,
|
||||
)
|
||||
|
||||
# Resolve user
|
||||
contributor = _resolve_contributor(contributor_id)
|
||||
if not contributor:
|
||||
return JsonResponse(
|
||||
{"status": "error", "message": "Contributor not found"},
|
||||
status=404,
|
||||
)
|
||||
|
||||
# Fetch this contributor's events
|
||||
user_identifiers = [v for v in [contributor['eventify_id'], contributor['email']] if v]
|
||||
events_qs = Event.objects.filter(
|
||||
contributed_by__in=user_identifiers,
|
||||
event_status__in=['published', 'live', 'completed'],
|
||||
).order_by('-start_date', '-created_date')
|
||||
|
||||
events_list = [_serialize_event_for_contributor(e) for e in events_qs]
|
||||
|
||||
return JsonResponse({
|
||||
"status": "success",
|
||||
"contributor": contributor,
|
||||
"events": events_list,
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
log("error", "ContributorProfileAPI exception", request=request, logger_data={"error": str(e)})
|
||||
return JsonResponse({"status": "error", "message": "An unexpected server error occurred."})
|
||||
|
||||
Reference in New Issue
Block a user