Skip to content

Commit 3fec089

Browse files
committed
end_utc and start_utc now dtend_utc and dtstart_utc
1 parent 242f327 commit 3fec089

File tree

12 files changed

+146
-201
lines changed

12 files changed

+146
-201
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Generated by Django 4.2.7 on 2025-11-10 05:13
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("events", "0031_remove_events_raw_json"),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name="eventdates",
15+
name="id",
16+
field=models.BigAutoField(
17+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
18+
),
19+
),
20+
migrations.AlterField(
21+
model_name="eventinterest",
22+
name="id",
23+
field=models.BigAutoField(
24+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
25+
),
26+
),
27+
migrations.AlterField(
28+
model_name="events",
29+
name="id",
30+
field=models.BigAutoField(
31+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
32+
),
33+
),
34+
migrations.AlterField(
35+
model_name="eventsubmission",
36+
name="id",
37+
field=models.BigAutoField(
38+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
39+
),
40+
),
41+
]

backend/apps/events/views.py

Lines changed: 29 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import json
22
import uuid
3-
import logging
4-
import traceback
53
from datetime import timedelta
64
import pytz
75

@@ -26,11 +24,10 @@
2624
from utils.embedding_utils import find_similar_events
2725
from utils.filters import EventFilter
2826
from utils.validation import validate_event_data
27+
from utils.date_utils import parse_utc_datetime
2928

3029
from .models import Events, EventSubmission, EventInterest, EventDates
3130

32-
logger = logging.getLogger(__name__)
33-
3431

3532
@api_view(["GET"])
3633
@permission_classes([AllowAny])
@@ -109,12 +106,7 @@ def get_events(request):
109106
cursor_dtstart_utc_str = cursor_parts[0]
110107
cursor_id = int(cursor_parts[1])
111108

112-
from dateutil import parser as dateutil_parser
113-
cursor_dtstart_utc = dateutil_parser.parse(cursor_dtstart_utc_str)
114-
if cursor_dtstart_utc.tzinfo is None:
115-
cursor_dtstart_utc = pytz.UTC.localize(cursor_dtstart_utc)
116-
else:
117-
cursor_dtstart_utc = cursor_dtstart_utc.astimezone(pytz.UTC)
109+
cursor_dtstart_utc = parse_utc_datetime(cursor_dtstart_utc_str)
118110

119111
# Filter events after cursor position
120112
filtered_queryset = filtered_queryset.filter(
@@ -218,7 +210,7 @@ def get_event(request, event_id):
218210
event_data["is_submitter"] = submission and request.user_id and str(submission.submitted_by) == str(request.user_id)
219211

220212
# Get all event dates
221-
event_data["dates"] = list(
213+
event_data["occurrences"] = list(
222214
EventDates.objects.filter(event_id=event_id)
223215
.order_by('dtstart_utc').values("dtstart_utc", "dtend_utc")
224216
)
@@ -600,7 +592,6 @@ def submit_event(request):
600592
# Event data is passed flat at top level
601593
cleaned = validate_event_data(data)
602594

603-
from dateutil import parser as dateutil_parser
604595
with transaction.atomic():
605596
event = Events.objects.create(
606597
title=cleaned["title"],
@@ -618,19 +609,8 @@ def submit_event(request):
618609

619610
# Create EventDates for each occurrence
620611
for occ in cleaned["occurrences"]:
621-
dtstart_utc = dateutil_parser.parse(occ["start_utc"])
622-
if dtstart_utc.tzinfo is None:
623-
dtstart_utc = pytz.UTC.localize(dtstart_utc)
624-
else:
625-
dtstart_utc = dtstart_utc.astimezone(pytz.UTC)
626-
627-
dtend_utc = None
628-
if occ.get("end_utc"):
629-
dtend_utc = dateutil_parser.parse(occ["end_utc"])
630-
if dtend_utc.tzinfo is None:
631-
dtend_utc = pytz.UTC.localize(dtend_utc)
632-
else:
633-
dtend_utc = dtend_utc.astimezone(pytz.UTC)
612+
dtstart_utc = parse_utc_datetime(occ["dtstart_utc"])
613+
dtend_utc = parse_utc_datetime(occ.get("dtend_utc")) if occ.get("dtend_utc") else None
634614

635615
EventDates.objects.create(
636616
event=event,
@@ -654,7 +634,7 @@ def submit_event(request):
654634

655635
@api_view(["GET"])
656636
@ratelimit(key="ip", rate="100/hr", block=True)
657-
@jwt_required
637+
@admin_required
658638
def get_submissions(request):
659639
try:
660640
submissions = EventSubmission.objects.select_related("created_event").all().order_by("-submitted_at")
@@ -675,121 +655,38 @@ def get_submissions(request):
675655

676656

677657
@api_view(["POST"])
678-
@jwt_required
658+
@admin_required
679659
@ratelimit(key="ip", rate="100/hr", block=True)
680660
def review_submission(request, event_id):
681661
"""Approve or reject submission"""
682662
try:
683-
logger.info(f"[review_submission] Starting review for event_id={event_id}, user_id={request.user_id}")
684-
685-
# Parse request body
686-
try:
687-
data = json.loads(request.body)
688-
logger.debug(f"[review_submission] Parsed request data: {data}")
689-
except json.JSONDecodeError as e:
690-
logger.error(f"[review_submission] JSON decode error: {e}, body: {request.body}")
691-
return Response(
692-
{"message": "Invalid JSON in request body", "error": str(e)},
693-
status=status.HTTP_400_BAD_REQUEST
694-
)
695-
696-
# Get event
697-
try:
698-
event = get_object_or_404(Events, id=event_id)
699-
logger.debug(f"[review_submission] Found event: id={event.id}, title={event.title}, status={event.status}")
700-
except Exception as e:
701-
logger.error(f"[review_submission] Error getting event {event_id}: {e}")
702-
logger.error(f"[review_submission] Traceback: {traceback.format_exc()}")
703-
return Response(
704-
{"message": f"Event not found: {event_id}", "error": str(e)},
705-
status=status.HTTP_404_NOT_FOUND
706-
)
707-
708-
# Get submission (safer query method)
709-
try:
710-
submission = EventSubmission.objects.filter(created_event=event).first()
711-
if not submission:
712-
logger.warning(f"[review_submission] No submission found for event_id={event_id}")
713-
return Response(
714-
{"message": "No submission found for this event"},
715-
status=status.HTTP_404_NOT_FOUND
716-
)
717-
logger.debug(f"[review_submission] Found submission: id={submission.id}, submitted_by={submission.submitted_by}")
718-
except Exception as e:
719-
logger.error(f"[review_submission] Error getting submission for event {event_id}: {e}")
720-
logger.error(f"[review_submission] Traceback: {traceback.format_exc()}")
721-
return Response(
722-
{"message": "Error retrieving submission", "error": str(e)},
723-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
724-
)
725-
726-
# Get action
663+
data = json.loads(request.body)
664+
event = get_object_or_404(Events, id=event_id)
665+
submission = EventSubmission.objects.filter(created_event=event).first()
666+
if not submission:
667+
return Response({"message": "No submission found for this event"}, status=status.HTTP_404_NOT_FOUND)
727668
action = data.get("action")
728-
if not action:
729-
logger.warning(f"[review_submission] No action provided in request data")
730-
return Response(
731-
{"message": "Action is required. Use 'approve' or 'reject'"},
732-
status=status.HTTP_400_BAD_REQUEST
733-
)
734-
735-
logger.info(f"[review_submission] Processing action={action} for event_id={event_id}")
736669

737670
if action == "approve":
738-
try:
739-
event.status = "CONFIRMED"
740-
event.save()
741-
logger.debug(f"[review_submission] Updated event status to CONFIRMED")
742-
743-
submission.reviewed_at = timezone.now()
744-
submission.reviewed_by = request.user_id
745-
submission.save()
746-
logger.info(f"[review_submission] Successfully approved event_id={event_id}")
747-
748-
return Response({"message": "Event approved", "event_id": event.id})
749-
except Exception as e:
750-
logger.error(f"[review_submission] Error approving event {event_id}: {e}")
751-
logger.error(f"[review_submission] Traceback: {traceback.format_exc()}")
752-
return Response(
753-
{"message": "Error approving event", "error": str(e)},
754-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
755-
)
671+
event.status = "CONFIRMED"
672+
event.save()
673+
submission.reviewed_at = timezone.now()
674+
submission.reviewed_by = request.user_id
675+
submission.save()
676+
return Response({"message": "Event approved", "event_id": event.id})
756677

757678
elif action == "reject":
758-
try:
759-
submission.reviewed_at = timezone.now()
760-
submission.reviewed_by = request.user_id
761-
submission.save()
762-
logger.debug(f"[review_submission] Updated submission review info")
763-
764-
if event:
765-
event.status = "CANCELLED"
766-
event.save()
767-
logger.debug(f"[review_submission] Updated event status to CANCELLED")
768-
769-
logger.info(f"[review_submission] Successfully rejected event_id={event_id}")
770-
return Response({"message": "Event rejected"})
771-
except Exception as e:
772-
logger.error(f"[review_submission] Error rejecting event {event_id}: {e}")
773-
logger.error(f"[review_submission] Traceback: {traceback.format_exc()}")
774-
return Response(
775-
{"message": "Error rejecting event", "error": str(e)},
776-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
777-
)
679+
submission.reviewed_at = timezone.now()
680+
submission.reviewed_by = request.user_id
681+
submission.save()
682+
if event:
683+
event.status = "CANCELLED"
684+
event.save()
685+
return Response({"message": "Event rejected"})
778686

779-
logger.warning(f"[review_submission] Invalid action: {action}")
780-
return Response(
781-
{"message": "Invalid action. Use 'approve' or 'reject'"},
782-
status=status.HTTP_400_BAD_REQUEST
783-
)
784-
687+
return Response({"message": "Invalid action. Use 'approve' or 'reject'"}, status=status.HTTP_400_BAD_REQUEST)
785688
except Exception as e:
786-
logger.error(f"[review_submission] Unexpected error in review_submission: {e}")
787-
logger.error(f"[review_submission] Traceback: {traceback.format_exc()}")
788-
logger.error(f"[review_submission] Request data: event_id={event_id}, user_id={getattr(request, 'user_id', 'unknown')}")
789-
return Response(
790-
{"message": "Internal server error", "error": str(e)},
791-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
792-
)
689+
return Response({"message": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
793690

794691

795692
@api_view(["GET"])
@@ -976,21 +873,9 @@ def update_event(request, event_id):
976873
# Update occurrences if provided
977874
if cleaned.get("occurrences"):
978875
EventDates.objects.filter(event=event).delete()
979-
from dateutil import parser as dateutil_parser
980876
for occ in cleaned["occurrences"]:
981-
dtstart_utc = dateutil_parser.parse(occ["start_utc"])
982-
if dtstart_utc.tzinfo is None:
983-
dtstart_utc = pytz.UTC.localize(dtstart_utc)
984-
else:
985-
dtstart_utc = dtstart_utc.astimezone(pytz.UTC)
986-
987-
dtend_utc = None
988-
if occ.get("end_utc"):
989-
dtend_utc = dateutil_parser.parse(occ["end_utc"])
990-
if dtend_utc.tzinfo is None:
991-
dtend_utc = pytz.UTC.localize(dtend_utc)
992-
else:
993-
dtend_utc = dtend_utc.astimezone(pytz.UTC)
877+
dtstart_utc = parse_utc_datetime(occ["dtstart_utc"])
878+
dtend_utc = parse_utc_datetime(occ.get("dtend_utc")) if occ.get("dtend_utc") else None
994879

995880
EventDates.objects.create(
996881
event=event,

backend/scraping/instagram_feed.py

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
from django.utils import timezone
2222
from dotenv import load_dotenv
2323
from instaloader import Instaloader
24-
from dateutil import parser
2524

2625
from apps.clubs.models import Clubs
2726
from apps.events.models import Events, IgnoredPost, EventDates
@@ -38,6 +37,7 @@
3837
sequence_similarity,
3938
get_post_image_url,
4039
)
40+
from utils.date_utils import parse_utc_datetime
4141

4242

4343
MAX_POSTS = int(os.getenv("MAX_POSTS", "25"))
@@ -58,14 +58,6 @@
5858
SUPABASE_DB_URL = os.getenv("SUPABASE_DB_URL")
5959

6060

61-
def parse_datetime(dt_str):
62-
"""Parse a datetime string to a timezone-aware datetime object."""
63-
dt = parser.parse(dt_str)
64-
if timezone.is_naive(dt):
65-
dt = timezone.make_aware(dt)
66-
return dt
67-
68-
6961
def is_duplicate_event(event_data):
7062
"""Check for duplicate events using title, occurrences, location, and description."""
7163

@@ -77,8 +69,8 @@ def is_duplicate_event(event_data):
7769
if not occurrences:
7870
return False
7971

80-
target_start_str = occurrences[0].get("start_utc")
81-
target_start = parse_datetime(target_start_str)
72+
target_start_str = occurrences[0].get("dtstart_utc")
73+
target_start = parse_utc_datetime(target_start_str)
8274
if not target_start:
8375
return False
8476

@@ -151,8 +143,8 @@ def append_event_to_csv(
151143
occurrences = event_data.get("occurrences", []) or []
152144
primary_occurrence = occurrences[0] if occurrences else {}
153145

154-
dtstart_utc = primary_occurrence.get("start_utc")
155-
dtend_utc = primary_occurrence.get("end_utc")
146+
dtstart_utc = primary_occurrence.get("dtstart_utc")
147+
dtend_utc = primary_occurrence.get("dtend_utc")
156148
duration = primary_occurrence.get("duration")
157149
tz = primary_occurrence.get("tz")
158150
location = event_data.get("location", "")
@@ -279,8 +271,8 @@ def insert_event_to_db(event_data, ig_handle, source_url):
279271
event_dates = []
280272

281273
for occ in occurrences:
282-
dtstart_utc = parse_datetime(occ.get("start_utc"))
283-
dtend_utc_raw = occ.get("end_utc")
274+
dtstart_utc = parse_datetime(occ.get("dtstart_utc"))
275+
dtend_utc_raw = occ.get("dtend_utc")
284276
dtend_utc = parse_datetime(dtend_utc_raw) if dtend_utc_raw and dtend_utc_raw.strip() else None
285277

286278
event_dates.append(
@@ -448,12 +440,10 @@ def check_post_limit():
448440
continue
449441

450442
first_occurrence = event_data.get("occurrences")[0]
451-
dtstart_utc = first_occurrence.get("start_utc")
443+
dtstart_utc = first_occurrence.get("dtstart_utc")
452444
now = timezone.now()
453445
if isinstance(dtstart_utc, str):
454-
dtstart_utc = parser.parse(dtstart_utc)
455-
if timezone.is_naive(dtstart_utc):
456-
dtstart_utc = timezone.make_aware(dtstart_utc)
446+
dtstart_utc = parse_utc_datetime(dtstart_utc)
457447
if dtstart_utc and dtstart_utc < now:
458448
logger.info(
459449
f"[{post.shortcode}] [{post.owner_username}] Skipping event '{event_data.get('title')}' with past date {dtstart_utc}"

0 commit comments

Comments
 (0)