@@ -32,6 +32,7 @@ def __init__(
32
32
incoming_msg_type : str | None = None ,
33
33
incoming_msg_body : dict | None = None ,
34
34
message_id : str | None = None ,
35
+ message_unix_time : int | None = None ,
35
36
):
36
37
if agent :
37
38
self .settings = agent .settings
@@ -48,6 +49,7 @@ def __init__(
48
49
self .incoming_msg_type = incoming_msg_type
49
50
self .incoming_msg_body = incoming_msg_body
50
51
self .message_id = message_id
52
+ self .message_unix_time = message_unix_time
51
53
self .typing_indicator_task = None
52
54
self .first_indicator_time = None
53
55
@@ -59,6 +61,7 @@ def create_user_specific_presenter(
59
61
incoming_msg_type : str ,
60
62
incoming_msg_body : dict ,
61
63
message_id : str ,
64
+ message_unix_time : int | None = None ,
62
65
):
63
66
"""Creates a user-specific presenter instance from a general presenter."""
64
67
return cls (
@@ -69,20 +72,22 @@ def create_user_specific_presenter(
69
72
incoming_msg_type = incoming_msg_type ,
70
73
incoming_msg_body = incoming_msg_body ,
71
74
message_id = message_id ,
75
+ message_unix_time = message_unix_time ,
72
76
)
73
77
74
78
async def extract_relevant_whatsapp_message_details (
75
79
self ,
76
80
body : dict [str , Any ],
77
- ) -> tuple [bool , str | None , str | None , dict | None , str | None ]:
81
+ ) -> tuple [bool , str | None , str | None , dict | None , str | None , int | None ]:
78
82
"""Extracts relevant whatsapp message details from the incoming webhook payload.
79
83
80
84
Args:
81
85
body (Dict[str, Any]): The JSON body of the incoming request.
82
86
83
87
Returns:
84
- tuple[bool, Optional[str], Optional[str], Optional[dict], Optional[str]]:
85
- A tuple of (is_status, user_whatsapp_number, incoming_msg_type, incoming_msg_body, message_id)
88
+ tuple[bool, Optional[str], Optional[str], Optional[dict], Optional[str], Optional[int]]:
89
+ A tuple of:
90
+ (is_status, user_whatsapp_number, incoming_msg_type, incoming_msg_body, message_id, message_unix_time)
86
91
87
92
Raises:
88
93
Exception: If the payload structure is invalid or unsupported.
@@ -109,7 +114,7 @@ async def extract_relevant_whatsapp_message_details(
109
114
# logger.debug(
110
115
# f"WhatsApp status update received:\n({status} at {timestamp}.)",
111
116
# )
112
- return True , None , None , None , None
117
+ return True , None , None , None , None , None
113
118
else :
114
119
is_status = False
115
120
@@ -127,6 +132,9 @@ async def extract_relevant_whatsapp_message_details(
127
132
message_id = incoming_msg .get ("id" )
128
133
# Extract the phone number of the WhatsApp sender
129
134
user_whatsapp_number = incoming_msg ["from" ]
135
+ # Extract timestamp from message (in Unix time format) and convert to int if present
136
+ message_unix_time_str = incoming_msg .get ("timestamp" )
137
+ message_unix_time = int (message_unix_time_str ) if message_unix_time_str is not None else None
130
138
# Meta API note: Meta sends "errors" key when receiving unsupported message types
131
139
# (e.g., video notes, gifs sent from giphy, or polls)
132
140
incoming_msg_type = incoming_msg ["type" ] if incoming_msg ["type" ] in incoming_msg .keys () else "errors"
@@ -135,7 +143,7 @@ async def extract_relevant_whatsapp_message_details(
135
143
136
144
logger .info (f"Received a supported whatsapp message from { user_whatsapp_number } : { incoming_msg_body } " )
137
145
138
- return (is_status , user_whatsapp_number , incoming_msg_type , incoming_msg_body , message_id )
146
+ return (is_status , user_whatsapp_number , incoming_msg_type , incoming_msg_body , message_id , message_unix_time )
139
147
140
148
async def check_and_register_user (self ) -> bool :
141
149
"""
@@ -795,5 +803,50 @@ async def handle_unsupported_message(
795
803
f"Sorry, I can't process { msg_type } yet. Please send me a text message." ,
796
804
)
797
805
806
+ def is_message_too_old (self ) -> bool :
807
+ """
808
+ Checks if the incoming message is older than the allowed threshold (24 hours).
809
+
810
+ Uses the message_unix_time attribute (timestamp in Unix time format - seconds since epoch)
811
+ extracted during message processing to determine if the message is too old.
812
+
813
+ Returns:
814
+ bool: True if the message is older than 24 hours, False otherwise
815
+ """
816
+ # Define the too old threshold (24 hours in seconds)
817
+ TOO_OLD_THRESHOLD = 24 * 60 * 60 # 24 hours in seconds
818
+
819
+ # If there's no timestamp, message can't be verified as too old
820
+ if not self .message_unix_time :
821
+ logger .debug ("No timestamp available, cannot determine message age" )
822
+ return False
823
+
824
+ # Convert the Unix timestamp to a datetime object
825
+ try :
826
+ msg_time = datetime .fromtimestamp (self .message_unix_time , tz = timezone .utc )
827
+ # Get the current time in UTC
828
+ current_time = datetime .now (timezone .utc )
829
+ # Calculate time difference in seconds
830
+ time_diff = (current_time - msg_time ).total_seconds ()
831
+
832
+ # Log the message age for debugging
833
+ if time_diff < 60 :
834
+ age_logging = f"{ time_diff :.1f} seconds"
835
+ elif time_diff < 3600 :
836
+ age_logging = f"{ time_diff / 60 :.1f} minutes"
837
+ elif time_diff < 86400 :
838
+ age_logging = f"{ time_diff / 3600 :.1f} hours"
839
+ else :
840
+ age_logging = f"{ time_diff / 86400 :.1f} days"
841
+
842
+ logger .debug (f"Message age: { age_logging } " )
843
+
844
+ # Return True if the message is older than the threshold
845
+ return time_diff > TOO_OLD_THRESHOLD
846
+
847
+ except (ValueError , TypeError ) as e :
848
+ logger .error (f"Error parsing message timestamp: { e } " )
849
+ return False
850
+
798
851
def present (self ):
799
852
pass
0 commit comments