Update routes/stylist.py
Browse files- routes/stylist.py +91 -6
routes/stylist.py
CHANGED
@@ -381,12 +381,82 @@ def get_monthly_likes(user_id: str) -> Dict[str, Any]:
|
|
381 |
start_date = (now_ny - relativedelta(months=6)).strftime('%Y-%m-%d')
|
382 |
|
383 |
def parse_datetime_safely(date_str: str) -> datetime:
|
384 |
-
"""Parse datetime string safely, handling microseconds overflow"""
|
385 |
try:
|
|
|
|
|
386 |
# Remove 'Z' e substitui por '+00:00' se necessário
|
387 |
if date_str.endswith('Z'):
|
388 |
date_str = date_str.replace('Z', '+00:00')
|
389 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
390 |
# Verificar se há microssegundos com mais de 6 dígitos
|
391 |
if '.' in date_str:
|
392 |
# Separar a parte dos microssegundos
|
@@ -397,7 +467,7 @@ def get_monthly_likes(user_id: str) -> Dict[str, Any]:
|
|
397 |
|
398 |
# Encontrar onde começa o timezone (+ ou - após os dígitos)
|
399 |
tz_start_idx = -1
|
400 |
-
for i in range(
|
401 |
if microsec_and_tz[i] in ['+', '-']:
|
402 |
tz_start_idx = i
|
403 |
break
|
@@ -418,11 +488,26 @@ def get_monthly_likes(user_id: str) -> Dict[str, Any]:
|
|
418 |
microsec_and_tz = microsec_and_tz[:6]
|
419 |
date_str = f"{base_part}.{microsec_and_tz}"
|
420 |
|
421 |
-
|
|
|
|
|
|
|
422 |
except ValueError as e:
|
423 |
-
logger.warning(f"⚠️ Error parsing date '{
|
424 |
-
#
|
425 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
426 |
|
427 |
try:
|
428 |
# Primeiro, obter todos os feed_items do usuário
|
|
|
381 |
start_date = (now_ny - relativedelta(months=6)).strftime('%Y-%m-%d')
|
382 |
|
383 |
def parse_datetime_safely(date_str: str) -> datetime:
|
384 |
+
"""Parse datetime string safely, handling microseconds overflow and timezone formats"""
|
385 |
try:
|
386 |
+
original_date_str = date_str
|
387 |
+
|
388 |
# Remove 'Z' e substitui por '+00:00' se necessário
|
389 |
if date_str.endswith('Z'):
|
390 |
date_str = date_str.replace('Z', '+00:00')
|
391 |
|
392 |
+
# Normalizar timezone de -04 para -04:00
|
393 |
+
import re
|
394 |
+
tz_pattern = r'([+-])(\d{2})
|
395 |
+
|
396 |
+
try:
|
397 |
+
# Primeiro, obter todos os feed_items do usuário
|
398 |
+
feeds_url = f"{SUPABASE_URL}/rest/v1/Feeds?user_id=eq.{user_id}"
|
399 |
+
feeds_response = requests.get(feeds_url, headers=SUPABASE_HEADERS)
|
400 |
+
|
401 |
+
if feeds_response.status_code == 200:
|
402 |
+
feeds = feeds_response.json()
|
403 |
+
feed_ids = [feed.get("id") for feed in feeds]
|
404 |
+
|
405 |
+
if feed_ids:
|
406 |
+
# Construir a condição para os feed_ids
|
407 |
+
# (não podemos usar in.() diretamente por limitações da API, então vamos fazer uma string)
|
408 |
+
feed_ids_str = ','.join([str(id) for id in feed_ids])
|
409 |
+
|
410 |
+
# Obter likes para esses feeds no intervalo de tempo
|
411 |
+
likes_url = f"{SUPABASE_URL}/rest/v1/likes?feed_item_id=in.({feed_ids_str})&created_at=gte.{start_date}"
|
412 |
+
likes_response = requests.get(likes_url, headers=SUPABASE_HEADERS)
|
413 |
+
|
414 |
+
if likes_response.status_code == 200:
|
415 |
+
likes = likes_response.json()
|
416 |
+
logger.info(f"📊 Found {len(likes)} likes for user {user_id}")
|
417 |
+
|
418 |
+
# Contar likes por mês
|
419 |
+
for like in likes:
|
420 |
+
# Converter a data para o fuso horário de NY usando o parse seguro
|
421 |
+
like_date_str = like.get("created_at")
|
422 |
+
if like_date_str:
|
423 |
+
like_date = parse_datetime_safely(like_date_str).astimezone(ny_timezone)
|
424 |
+
|
425 |
+
month_key = f"{like_date.year}-{like_date.month}"
|
426 |
+
logger.debug(f"📅 Like date: {like_date_str} -> {like_date} -> month_key: {month_key}")
|
427 |
+
|
428 |
+
if month_key in monthly_data:
|
429 |
+
monthly_data[month_key]["likes_count"] += 1
|
430 |
+
total_likes_last_6_months += 1
|
431 |
+
logger.debug(f"✅ Added like to {month_key}, total now: {monthly_data[month_key]['likes_count']}")
|
432 |
+
else:
|
433 |
+
logger.debug(f"⚠️ Month key {month_key} not in range, skipping like from {like_date}")
|
434 |
+
else:
|
435 |
+
logger.warning(f"⚠️ Failed to fetch likes: {likes_response.status_code}")
|
436 |
+
else:
|
437 |
+
logger.info(f"📭 No feed items found for user {user_id}")
|
438 |
+
else:
|
439 |
+
logger.warning(f"⚠️ Failed to fetch feeds: {feeds_response.status_code}")
|
440 |
+
|
441 |
+
# Convertendo para lista e ordenando por mês (do mais recente para o mais antigo)
|
442 |
+
result = list(monthly_data.values())
|
443 |
+
result.sort(key=lambda x: (now_ny.year * 12 + now_ny.month - (x["month"])) % 12)
|
444 |
+
|
445 |
+
return {
|
446 |
+
"monthly_likes": result,
|
447 |
+
"total_likes_last_6_months": total_likes_last_6_months
|
448 |
+
}
|
449 |
+
except Exception as e:
|
450 |
+
logger.error(f"❌ Error getting monthly likes: {str(e)}")
|
451 |
+
return {
|
452 |
+
"monthly_likes": list(monthly_data.values()),
|
453 |
+
"total_likes_last_6_months": 0
|
454 |
+
}
|
455 |
+
match = re.search(tz_pattern, date_str)
|
456 |
+
if match:
|
457 |
+
sign, hours = match.groups()
|
458 |
+
date_str = re.sub(tz_pattern, f'{sign}{hours}:00', date_str)
|
459 |
+
|
460 |
# Verificar se há microssegundos com mais de 6 dígitos
|
461 |
if '.' in date_str:
|
462 |
# Separar a parte dos microssegundos
|
|
|
467 |
|
468 |
# Encontrar onde começa o timezone (+ ou - após os dígitos)
|
469 |
tz_start_idx = -1
|
470 |
+
for i in range(len(microsec_and_tz)):
|
471 |
if microsec_and_tz[i] in ['+', '-']:
|
472 |
tz_start_idx = i
|
473 |
break
|
|
|
488 |
microsec_and_tz = microsec_and_tz[:6]
|
489 |
date_str = f"{base_part}.{microsec_and_tz}"
|
490 |
|
491 |
+
parsed_date = datetime.fromisoformat(date_str)
|
492 |
+
logger.debug(f"✅ Successfully parsed date '{original_date_str}' -> '{date_str}' -> {parsed_date}")
|
493 |
+
return parsed_date
|
494 |
+
|
495 |
except ValueError as e:
|
496 |
+
logger.warning(f"⚠️ Error parsing date '{original_date_str}': {str(e)}")
|
497 |
+
# Tentar um parsing mais simples como fallback
|
498 |
+
try:
|
499 |
+
# Remover microssegundos completamente e tentar novamente
|
500 |
+
simple_date = original_date_str.split('.')[0]
|
501 |
+
# Adicionar timezone padrão se não tiver
|
502 |
+
if not any(tz in simple_date for tz in ['+', '-', 'Z']):
|
503 |
+
simple_date += '-04:00'
|
504 |
+
elif simple_date.endswith('-04'):
|
505 |
+
simple_date += ':00'
|
506 |
+
return datetime.fromisoformat(simple_date)
|
507 |
+
except:
|
508 |
+
logger.error(f"❌ Failed to parse date '{original_date_str}' with fallback method")
|
509 |
+
# Último recurso: retornar data atual
|
510 |
+
return datetime.now(pytz.UTC)
|
511 |
|
512 |
try:
|
513 |
# Primeiro, obter todos os feed_items do usuário
|