Update main.py
Browse files
main.py
CHANGED
@@ -69,7 +69,8 @@ CACHE_UPDATE_INTERVAL_SECONDS = int(os.getenv('CACHE_UPDATE_INTERVAL_SECONDS', 6
|
|
69 |
# Webhook URLs
|
70 |
SCAMMER_WEBHOOK_URL = os.getenv("SCAMMER_WEBHOOK_URL")
|
71 |
VALUE_WEBHOOK_URL = os.getenv("VALUE_WEBHOOK_URL")
|
72 |
-
|
|
|
73 |
|
74 |
|
75 |
# --- Global Cache ---
|
@@ -79,7 +80,7 @@ cache = {
|
|
79 |
"user_scammers": [],
|
80 |
"server_scammers": [],
|
81 |
"dwc": [],
|
82 |
-
"trusted": [], #
|
83 |
"dupes": [], # List of duped usernames
|
84 |
"last_updated": None, # Timestamp of the last successful/partial update
|
85 |
"is_ready": False, # Is the cache populated at least once?
|
@@ -378,29 +379,33 @@ def process_dwc_data(values): # For DWC Sheet
|
|
378 |
processed_data.append(processed_item)
|
379 |
return processed_data
|
380 |
|
381 |
-
def process_trusted_data(values): #
|
382 |
if not values: return []
|
383 |
processed_data = []
|
384 |
for row in values: # Expected range like B6:E
|
385 |
-
if not row or len(row) <
|
386 |
# Indices based on B6:E (0-indexed from B)
|
387 |
-
|
388 |
-
discord_username = clean_string_optional(row[1]) if len(row) > 1 else None # Col C
|
389 |
discord_server_id = clean_string_optional(row[2]) if len(row) > 2 else None # Col D
|
390 |
roblox_username = clean_string_optional(row[3]) if len(row) > 3 else None # Col E
|
391 |
-
|
392 |
-
# Skip if all identifiers are missing
|
393 |
-
if not
|
394 |
-
|
395 |
-
if
|
|
|
|
|
|
|
396 |
continue
|
397 |
-
|
398 |
processed_item = {
|
399 |
-
'
|
400 |
-
'
|
401 |
'discord_server_id': discord_server_id,
|
402 |
'roblox_username': roblox_username,
|
403 |
-
'roblox_avatar_url': None # Will be filled later
|
|
|
404 |
}
|
405 |
processed_data.append(processed_item)
|
406 |
return processed_data
|
@@ -532,8 +537,8 @@ async def update_cache_periodically():
|
|
532 |
"user_scammers": [],
|
533 |
"server_scammers": [],
|
534 |
"dwc": [],
|
|
|
535 |
"dupes": [],
|
536 |
-
"trusted": [], # List of trusted users/servers
|
537 |
}
|
538 |
current_errors = {} # Track errors for specific fetches/sheets
|
539 |
|
@@ -543,19 +548,19 @@ async def update_cache_periodically():
|
|
543 |
f"{quote_sheet_name(USER_SCAMMER_SHEET)}!{USER_SCAMMER_RANGE}",
|
544 |
f"{quote_sheet_name(SERVER_SCAMMER_SHEET)}!{SERVER_SCAMMER_RANGE}",
|
545 |
f"{quote_sheet_name(DWC_SHEET)}!{DWC_RANGE}",
|
546 |
-
f"{quote_sheet_name(TRUSTED_SHEET)}!{TRUSTED_RANGE}",
|
547 |
]
|
548 |
scammer_dwc_processor_map = {
|
549 |
USER_SCAMMER_SHEET: process_user_scammer_data,
|
550 |
SERVER_SCAMMER_SHEET: process_server_scammer_data,
|
551 |
DWC_SHEET: process_dwc_data,
|
552 |
-
TRUSTED_SHEET: process_trusted_data,
|
553 |
}
|
554 |
scammer_dwc_target_key_map = {
|
555 |
USER_SCAMMER_SHEET: "user_scammers",
|
556 |
SERVER_SCAMMER_SHEET: "server_scammers",
|
557 |
DWC_SHEET: "dwc",
|
558 |
-
TRUSTED_SHEET: "trusted",
|
559 |
}
|
560 |
|
561 |
values_dupes_ranges = [f"{quote_sheet_name(DUPE_LIST_SHEET)}!{DUPE_LIST_RANGE}"]
|
@@ -657,10 +662,11 @@ async def update_cache_periodically():
|
|
657 |
# --- Fetch Roblox Avatars (for new data before comparison/webhook) ---
|
658 |
if not current_errors.get("scammer_dwc_batch") and \
|
659 |
not current_errors.get("process_user_scammers") and \
|
660 |
-
not current_errors.get("process_dwc")
|
|
|
661 |
logger.info("Fetching Roblox avatars for newly processed data...")
|
662 |
avatar_tasks = []
|
663 |
-
entries_needing_avatars = new_cache_data.get("user_scammers", []) + new_cache_data.get("dwc", []) + new_cache_data.get("trusted", [])
|
664 |
for entry in entries_needing_avatars:
|
665 |
if entry.get('roblox_username'):
|
666 |
avatar_tasks.append(fetch_avatar_for_entry_update(session, entry))
|
@@ -668,7 +674,7 @@ async def update_cache_periodically():
|
|
668 |
await asyncio.gather(*avatar_tasks) # Exceptions logged within helper
|
669 |
logger.info(f"Finished fetching avatars for {len(avatar_tasks)} potential new entries.")
|
670 |
else:
|
671 |
-
logger.warning("Skipping avatar fetching due to errors in fetching/processing scammer/dwc data.")
|
672 |
|
673 |
|
674 |
# --- Change Detection & Webhook Preparation (ONLY if cache is ready) ---
|
@@ -892,27 +898,17 @@ async def update_cache_periodically():
|
|
892 |
|
893 |
# Update scammer/DWC sections if their batch succeeded AND processing succeeded
|
894 |
if "scammer_dwc_batch" not in current_errors:
|
895 |
-
for key in ["user_scammers", "server_scammers", "dwc"
|
896 |
process_error_key = f"process_{key}"
|
897 |
-
logger.info(f"Partial update check for key: '{key}'")
|
898 |
if process_error_key not in current_errors:
|
899 |
-
|
900 |
-
|
901 |
-
old_data = cache.get(key)
|
902 |
-
new_data = new_cache_data.get(key) # Use .get for safety
|
903 |
-
logger.info(f"--> Comparing for '{key}': cache has {len(old_data) if old_data is not None else 'None'} items, new data has {len(new_data) if new_data is not None else 'None'} items.")
|
904 |
-
|
905 |
-
if old_data != new_data:
|
906 |
-
logger.info(f"--> Data differs for '{key}'. UPDATING CACHE.")
|
907 |
-
cache[key] = new_data
|
908 |
partial_update_details.append(key)
|
909 |
update_occurred = True
|
910 |
-
else:
|
911 |
-
logger.info(f"--> Data is identical for '{key}'. Skipping update.")
|
912 |
else:
|
913 |
-
logger.warning(f"
|
914 |
else:
|
915 |
-
logger.warning("Skipping update for 'user_scammers', 'server_scammers', 'dwc'
|
916 |
|
917 |
if update_occurred:
|
918 |
cache["last_updated"] = current_time # Mark partial update time
|
@@ -1012,8 +1008,8 @@ async def get_status():
|
|
1012 |
"user_scammers": len(cache.get("user_scammers", [])),
|
1013 |
"server_scammers": len(cache.get("server_scammers", [])),
|
1014 |
"dwc_entries": len(cache.get("dwc", [])),
|
|
|
1015 |
"duped_usernames": len(cache.get("dupes", [])),
|
1016 |
-
"trusted_entries": len(cache.get("trusted", [])),
|
1017 |
},
|
1018 |
"value_change_categories_in_last_cycle": len(cache.get("value_changes", {}))
|
1019 |
}
|
@@ -1063,13 +1059,13 @@ async def get_all_value_changes():
|
|
1063 |
|
1064 |
@app.get("/api/scammers")
|
1065 |
async def get_scammers():
|
1066 |
-
"""Get all scammer and
|
1067 |
check_cache_readiness()
|
1068 |
return {
|
1069 |
"users": cache.get("user_scammers", []),
|
1070 |
"servers": cache.get("server_scammers", []),
|
1071 |
"dwc": cache.get("dwc", []),
|
1072 |
-
"trusted": cache.get("trusted", [])
|
1073 |
}
|
1074 |
|
1075 |
@app.get("/api/dupes")
|
|
|
69 |
# Webhook URLs
|
70 |
SCAMMER_WEBHOOK_URL = os.getenv("SCAMMER_WEBHOOK_URL")
|
71 |
VALUE_WEBHOOK_URL = os.getenv("VALUE_WEBHOOK_URL")
|
72 |
+
# Optional: Separate webhook for dupe checks? Keep using the general one for now.
|
73 |
+
DUPE_CHECK_WEBHOOK_URL = os.getenv("WEBHOOK_URL")
|
74 |
|
75 |
|
76 |
# --- Global Cache ---
|
|
|
80 |
"user_scammers": [],
|
81 |
"server_scammers": [],
|
82 |
"dwc": [],
|
83 |
+
"trusted": [], # New cache key for trusted entries
|
84 |
"dupes": [], # List of duped usernames
|
85 |
"last_updated": None, # Timestamp of the last successful/partial update
|
86 |
"is_ready": False, # Is the cache populated at least once?
|
|
|
379 |
processed_data.append(processed_item)
|
380 |
return processed_data
|
381 |
|
382 |
+
def process_trusted_data(values): # New function for Trusted Sheet
|
383 |
if not values: return []
|
384 |
processed_data = []
|
385 |
for row in values: # Expected range like B6:E
|
386 |
+
if not row or len(row) < 1: continue # Need at least one identifier
|
387 |
# Indices based on B6:E (0-indexed from B)
|
388 |
+
discord_user_id = clean_string_optional(row[0]) if len(row) > 0 else None # Col B
|
389 |
+
# discord_username = clean_string_optional(row[1]) if len(row) > 1 else None # Col C - Not currently used for matching, but keep for potential future use
|
390 |
discord_server_id = clean_string_optional(row[2]) if len(row) > 2 else None # Col D
|
391 |
roblox_username = clean_string_optional(row[3]) if len(row) > 3 else None # Col E
|
392 |
+
|
393 |
+
# Skip if all relevant identifiers are missing
|
394 |
+
if not discord_user_id and not discord_server_id and not roblox_username: continue
|
395 |
+
|
396 |
+
# Skip if it looks like a header row (check common header names)
|
397 |
+
if (str(discord_user_id).lower() == 'discord user id' or
|
398 |
+
str(discord_server_id).lower() == 'discord server id' or
|
399 |
+
str(roblox_username).lower() == 'roblox username'):
|
400 |
continue
|
401 |
+
|
402 |
processed_item = {
|
403 |
+
'status': 'Trusted', # Add a status field
|
404 |
+
'discord_user_id': discord_user_id,
|
405 |
'discord_server_id': discord_server_id,
|
406 |
'roblox_username': roblox_username,
|
407 |
+
'roblox_avatar_url': None # Will be filled later if roblox_username exists
|
408 |
+
# Note: No explanation or evidence expected for trusted entries based on B6:E
|
409 |
}
|
410 |
processed_data.append(processed_item)
|
411 |
return processed_data
|
|
|
537 |
"user_scammers": [],
|
538 |
"server_scammers": [],
|
539 |
"dwc": [],
|
540 |
+
"trusted": [], # Add trusted key
|
541 |
"dupes": [],
|
|
|
542 |
}
|
543 |
current_errors = {} # Track errors for specific fetches/sheets
|
544 |
|
|
|
548 |
f"{quote_sheet_name(USER_SCAMMER_SHEET)}!{USER_SCAMMER_RANGE}",
|
549 |
f"{quote_sheet_name(SERVER_SCAMMER_SHEET)}!{SERVER_SCAMMER_RANGE}",
|
550 |
f"{quote_sheet_name(DWC_SHEET)}!{DWC_RANGE}",
|
551 |
+
f"{quote_sheet_name(TRUSTED_SHEET)}!{TRUSTED_RANGE}", # Add trusted range
|
552 |
]
|
553 |
scammer_dwc_processor_map = {
|
554 |
USER_SCAMMER_SHEET: process_user_scammer_data,
|
555 |
SERVER_SCAMMER_SHEET: process_server_scammer_data,
|
556 |
DWC_SHEET: process_dwc_data,
|
557 |
+
TRUSTED_SHEET: process_trusted_data, # Add trusted processor
|
558 |
}
|
559 |
scammer_dwc_target_key_map = {
|
560 |
USER_SCAMMER_SHEET: "user_scammers",
|
561 |
SERVER_SCAMMER_SHEET: "server_scammers",
|
562 |
DWC_SHEET: "dwc",
|
563 |
+
TRUSTED_SHEET: "trusted", # Add trusted target key
|
564 |
}
|
565 |
|
566 |
values_dupes_ranges = [f"{quote_sheet_name(DUPE_LIST_SHEET)}!{DUPE_LIST_RANGE}"]
|
|
|
662 |
# --- Fetch Roblox Avatars (for new data before comparison/webhook) ---
|
663 |
if not current_errors.get("scammer_dwc_batch") and \
|
664 |
not current_errors.get("process_user_scammers") and \
|
665 |
+
not current_errors.get("process_dwc") and \
|
666 |
+
not current_errors.get("process_trusted"): # Check trusted processing too
|
667 |
logger.info("Fetching Roblox avatars for newly processed data...")
|
668 |
avatar_tasks = []
|
669 |
+
entries_needing_avatars = new_cache_data.get("user_scammers", []) + new_cache_data.get("dwc", []) + new_cache_data.get("trusted", []) # Include trusted list
|
670 |
for entry in entries_needing_avatars:
|
671 |
if entry.get('roblox_username'):
|
672 |
avatar_tasks.append(fetch_avatar_for_entry_update(session, entry))
|
|
|
674 |
await asyncio.gather(*avatar_tasks) # Exceptions logged within helper
|
675 |
logger.info(f"Finished fetching avatars for {len(avatar_tasks)} potential new entries.")
|
676 |
else:
|
677 |
+
logger.warning("Skipping avatar fetching due to errors in fetching/processing scammer/dwc/trusted data.")
|
678 |
|
679 |
|
680 |
# --- Change Detection & Webhook Preparation (ONLY if cache is ready) ---
|
|
|
898 |
|
899 |
# Update scammer/DWC sections if their batch succeeded AND processing succeeded
|
900 |
if "scammer_dwc_batch" not in current_errors:
|
901 |
+
for key in ["user_scammers", "server_scammers", "dwc"]:
|
902 |
process_error_key = f"process_{key}"
|
|
|
903 |
if process_error_key not in current_errors:
|
904 |
+
if cache.get(key) != new_cache_data[key]:
|
905 |
+
cache[key] = new_cache_data[key]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
906 |
partial_update_details.append(key)
|
907 |
update_occurred = True
|
|
|
|
|
908 |
else:
|
909 |
+
logger.warning(f"Skipping update for '{key}' due to processing error.")
|
910 |
else:
|
911 |
+
logger.warning("Skipping update for 'user_scammers', 'server_scammers', 'dwc' due to batch fetch error.")
|
912 |
|
913 |
if update_occurred:
|
914 |
cache["last_updated"] = current_time # Mark partial update time
|
|
|
1008 |
"user_scammers": len(cache.get("user_scammers", [])),
|
1009 |
"server_scammers": len(cache.get("server_scammers", [])),
|
1010 |
"dwc_entries": len(cache.get("dwc", [])),
|
1011 |
+
"trusted_entries": len(cache.get("trusted", [])), # Add trusted count
|
1012 |
"duped_usernames": len(cache.get("dupes", [])),
|
|
|
1013 |
},
|
1014 |
"value_change_categories_in_last_cycle": len(cache.get("value_changes", {}))
|
1015 |
}
|
|
|
1059 |
|
1060 |
@app.get("/api/scammers")
|
1061 |
async def get_scammers():
|
1062 |
+
"""Get all scammer, DWC, and trusted data (users, servers, dwc, trusted) from cache"""
|
1063 |
check_cache_readiness()
|
1064 |
return {
|
1065 |
"users": cache.get("user_scammers", []),
|
1066 |
"servers": cache.get("server_scammers", []),
|
1067 |
"dwc": cache.get("dwc", []),
|
1068 |
+
"trusted": cache.get("trusted", []) # Include trusted list
|
1069 |
}
|
1070 |
|
1071 |
@app.get("/api/dupes")
|