diff --git a/analytics.py b/analytics.py index c67ddfc..c569e28 100644 --- a/analytics.py +++ b/analytics.py @@ -56,6 +56,40 @@ def get_device_type(user_agent): else: return 'Other' +def parse_timestamp(ts_str): + try: + # Try the normal ISO parsing. + return datetime.fromisoformat(ts_str) + except ValueError as e: + if 'unconverted data remains' in str(e): + # Find where the timezone starts. Look for a '+' or '-' after the time. + for sign in ['+', '-']: + pos = ts_str.find(sign) + if pos != -1: + # Assume the base part is up to pos and then the tz part + base = ts_str[:pos] + tz_part = ts_str[pos:] + # Remove any colon from the tz part to help with parsing. + tz_clean = tz_part.replace(':', '') + # Try parsing the base part. It might or might not have fractional seconds. + try: + dt = datetime.fromisoformat(base) + except ValueError: + dt = datetime.strptime(base, '%Y-%m-%dT%H:%M:%S') + # Extract hours and minutes from the tz portion. + try: + offset_hours = int(tz_clean[1:3]) + offset_minutes = int(tz_clean[3:5]) + except Exception: + raise ValueError(f"Unable to parse timezone from {ts_str}") + offset = timedelta(hours=offset_hours, minutes=offset_minutes) + if tz_clean[0] == '-': + offset = -offset + # Return a timezone-aware datetime. + return dt.replace(tzinfo=timezone(offset)) + # If it's some other ValueError, re-raise it. + raise + def log_file_access(rel_path, filesize, mime, ip_address, user_agent, device_id, cached): """Insert a file access record into the database and prune entries older than 10 minutes.""" global file_access_temp @@ -70,11 +104,11 @@ def log_file_access(rel_path, filesize, mime, ip_address, user_agent, device_id, VALUES (?, ?, ?, ?, ?, ?, ?, ?) ''', (iso_ts, rel_path, filesize, mime, ip_address, user_agent, device_id, cached)) - # Remove entries older than 10 minutes + # Remove entries older than 10 minutes using our robust parser. cutoff_time = datetime.now(timezone.utc).astimezone() - timedelta(minutes=10) file_access_temp[:] = [ entry for entry in file_access_temp - if datetime.fromisoformat(entry[0]) >= cutoff_time + if parse_timestamp(entry[0]) >= cutoff_time ] # Add the new entry at the beginning of the list diff --git a/app.py b/app.py index 4fbd3e8..cee0bb8 100755 --- a/app.py +++ b/app.py @@ -364,13 +364,13 @@ def query_recent_connections(): rows = a.return_file_access() connections = [ { - 'timestamp': datetime.strptime(row[0], '%Y-%m-%dT%H:%M:%S.%f').strftime('%d.%m.%Y %H:%M:%S'), + 'timestamp': datetime.fromisoformat(row[0]).strftime('%d.%m.%Y %H:%M:%S'), 'full_path': row[1], - 'filesize' : row[2], - 'mime_typ' : row[3], + 'filesize': row[2], + 'mime_typ': row[3], 'ip_address': row[4], 'user_agent': row[5], - 'cached': row[7] + 'cached': row[7] } for row in rows ] @@ -384,6 +384,7 @@ def query_recent_connections(): background_thread_running = False print("No clients connected; stopping query thread.") + @socketio.on('connect') def handle_connect(auth=None): global clients_connected, background_thread_running @@ -405,7 +406,7 @@ def handle_request_initial_data(): rows = a.return_file_access() connections = [ { - 'timestamp': datetime.strptime(row[0], '%Y-%m-%dT%H:%M:%S.%f').strftime('%d.%m.%Y %H:%M:%S'), + 'timestamp': datetime.fromisoformat(row[0]).strftime('%d.%m.%Y %H:%M:%S'), 'full_path': row[1], 'filesize' : row[2], 'mime_typ' : row[3],