Reformat and remove stale debugging
This commit is contained in:
@@ -621,6 +621,7 @@ class SignalClient(ClientBase):
|
|||||||
async def _drain_runtime_commands(self):
|
async def _drain_runtime_commands(self):
|
||||||
"""Process queued runtime commands (e.g., web UI sends via composite router)."""
|
"""Process queued runtime commands (e.g., web UI sends via composite router)."""
|
||||||
from core.clients import transport
|
from core.clients import transport
|
||||||
|
|
||||||
# Process a small burst each loop to keep sends responsive.
|
# Process a small burst each loop to keep sends responsive.
|
||||||
for _ in range(5):
|
for _ in range(5):
|
||||||
command = transport.pop_runtime_command(self.service)
|
command = transport.pop_runtime_command(self.service)
|
||||||
@@ -631,6 +632,7 @@ class SignalClient(ClientBase):
|
|||||||
async def _execute_runtime_command(self, command):
|
async def _execute_runtime_command(self, command):
|
||||||
"""Execute a single runtime command like send_message_raw."""
|
"""Execute a single runtime command like send_message_raw."""
|
||||||
from core.clients import transport
|
from core.clients import transport
|
||||||
|
|
||||||
command_id = str((command or {}).get("id") or "").strip()
|
command_id = str((command or {}).get("id") or "").strip()
|
||||||
action = str((command or {}).get("action") or "").strip()
|
action = str((command or {}).get("action") or "").strip()
|
||||||
payload = dict((command or {}).get("payload") or {})
|
payload = dict((command or {}).get("payload") or {})
|
||||||
@@ -672,7 +674,9 @@ class SignalClient(ClientBase):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if action == "notify_xmpp_sent":
|
if action == "notify_xmpp_sent":
|
||||||
person_identifier_id = str(payload.get("person_identifier_id") or "").strip()
|
person_identifier_id = str(
|
||||||
|
payload.get("person_identifier_id") or ""
|
||||||
|
).strip()
|
||||||
text = str(payload.get("text") or "")
|
text = str(payload.get("text") or "")
|
||||||
if not person_identifier_id:
|
if not person_identifier_id:
|
||||||
transport.set_runtime_command_result(
|
transport.set_runtime_command_result(
|
||||||
@@ -683,7 +687,9 @@ class SignalClient(ClientBase):
|
|||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
identifier = await sync_to_async(
|
identifier = await sync_to_async(
|
||||||
lambda: PersonIdentifier.objects.filter(id=person_identifier_id).select_related("user", "person").first()
|
lambda: PersonIdentifier.objects.filter(id=person_identifier_id)
|
||||||
|
.select_related("user", "person")
|
||||||
|
.first()
|
||||||
)()
|
)()
|
||||||
if identifier is None:
|
if identifier is None:
|
||||||
transport.set_runtime_command_result(
|
transport.set_runtime_command_result(
|
||||||
|
|||||||
@@ -685,7 +685,7 @@ class WhatsAppClient(ClientBase):
|
|||||||
payload = dict((command or {}).get("payload") or {})
|
payload = dict((command or {}).get("payload") or {})
|
||||||
if not command_id:
|
if not command_id:
|
||||||
return
|
return
|
||||||
self.log.info(
|
self.log.debug(
|
||||||
"whatsapp runtime command start: id=%s action=%s",
|
"whatsapp runtime command start: id=%s action=%s",
|
||||||
command_id,
|
command_id,
|
||||||
action,
|
action,
|
||||||
@@ -718,7 +718,7 @@ class WhatsAppClient(ClientBase):
|
|||||||
else int(time.time() * 1000),
|
else int(time.time() * 1000),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
self.log.info(
|
self.log.debug(
|
||||||
"whatsapp runtime command ok: id=%s action=%s",
|
"whatsapp runtime command ok: id=%s action=%s",
|
||||||
command_id,
|
command_id,
|
||||||
action,
|
action,
|
||||||
@@ -800,7 +800,9 @@ class WhatsAppClient(ClientBase):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if action == "notify_xmpp_sent":
|
if action == "notify_xmpp_sent":
|
||||||
person_identifier_id = str(payload.get("person_identifier_id") or "").strip()
|
person_identifier_id = str(
|
||||||
|
payload.get("person_identifier_id") or ""
|
||||||
|
).strip()
|
||||||
text = str(payload.get("text") or "")
|
text = str(payload.get("text") or "")
|
||||||
if not person_identifier_id:
|
if not person_identifier_id:
|
||||||
transport.set_runtime_command_result(
|
transport.set_runtime_command_result(
|
||||||
@@ -811,7 +813,9 @@ class WhatsAppClient(ClientBase):
|
|||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
identifier = await sync_to_async(
|
identifier = await sync_to_async(
|
||||||
lambda: PersonIdentifier.objects.filter(id=person_identifier_id).select_related("user", "person").first()
|
lambda: PersonIdentifier.objects.filter(id=person_identifier_id)
|
||||||
|
.select_related("user", "person")
|
||||||
|
.first()
|
||||||
)()
|
)()
|
||||||
if identifier is None:
|
if identifier is None:
|
||||||
transport.set_runtime_command_result(
|
transport.set_runtime_command_result(
|
||||||
@@ -1424,13 +1428,13 @@ class WhatsAppClient(ClientBase):
|
|||||||
# Read contact-like rows directly from the session sqlite DB instead.
|
# Read contact-like rows directly from the session sqlite DB instead.
|
||||||
contacts, source, lid_map = await self._sync_contacts_from_sqlite()
|
contacts, source, lid_map = await self._sync_contacts_from_sqlite()
|
||||||
if not contacts:
|
if not contacts:
|
||||||
self.log.info("whatsapp contacts sync empty (%s)", source or "unknown")
|
self.log.debug("whatsapp contacts sync empty (%s)", source or "unknown")
|
||||||
self._publish_state(
|
self._publish_state(
|
||||||
last_event="contacts_sync_empty",
|
last_event="contacts_sync_empty",
|
||||||
contacts_source=source or "unknown",
|
contacts_source=source or "unknown",
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
self.log.info(
|
self.log.debug(
|
||||||
"whatsapp contacts synced: count=%s source=%s",
|
"whatsapp contacts synced: count=%s source=%s",
|
||||||
len(contacts),
|
len(contacts),
|
||||||
source or "unknown",
|
source or "unknown",
|
||||||
@@ -2600,7 +2604,11 @@ class WhatsAppClient(ClientBase):
|
|||||||
)
|
)
|
||||||
if is_transient and attempt < 1:
|
if is_transient and attempt < 1:
|
||||||
# If runtime rejected string target, try to build protobuf JID for retry.
|
# If runtime rejected string target, try to build protobuf JID for retry.
|
||||||
if jid_obj is None and self._build_jid is not None and "@" in jid_str:
|
if (
|
||||||
|
jid_obj is None
|
||||||
|
and self._build_jid is not None
|
||||||
|
and "@" in jid_str
|
||||||
|
):
|
||||||
local_part, server_part = jid_str.split("@", 1)
|
local_part, server_part = jid_str.split("@", 1)
|
||||||
try:
|
try:
|
||||||
maybe_retry_jid = self._build_jid(local_part, server_part)
|
maybe_retry_jid = self._build_jid(local_part, server_part)
|
||||||
@@ -2740,10 +2748,12 @@ class WhatsAppClient(ClientBase):
|
|||||||
async def send_message_to_contact(self, contact_jid: str, text: str) -> bool:
|
async def send_message_to_contact(self, contact_jid: str, text: str) -> bool:
|
||||||
"""Send a text message to a WhatsApp contact."""
|
"""Send a text message to a WhatsApp contact."""
|
||||||
try:
|
try:
|
||||||
jid = build_jid(contact_jid.split("@")[0], contact_jid.split("@")[1])
|
jid = self._to_jid(contact_jid)
|
||||||
|
if not jid or self._client is None:
|
||||||
|
return False
|
||||||
# neonize.send_message() accepts either a Message protobuf or a plain string
|
# neonize.send_message() accepts either a Message protobuf or a plain string
|
||||||
# If passing a string, it auto-converts to Message(conversation=text)
|
# If passing a string, it auto-converts to Message(conversation=text)
|
||||||
response = self.client.send_message(jid, text)
|
response = self._client.send_message(jid, text)
|
||||||
return response is not None
|
return response is not None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log.error(f"Failed to send WhatsApp message: {e}")
|
self.log.error(f"Failed to send WhatsApp message: {e}")
|
||||||
@@ -2753,8 +2763,10 @@ class WhatsAppClient(ClientBase):
|
|||||||
async def send_structured_message(self, contact_jid: str, message: Message) -> bool:
|
async def send_structured_message(self, contact_jid: str, message: Message) -> bool:
|
||||||
"""Send a structured Message protobuf to a WhatsApp contact."""
|
"""Send a structured Message protobuf to a WhatsApp contact."""
|
||||||
try:
|
try:
|
||||||
jid = build_jid(contact_jid.split("@")[0], contact_jid.split("@")[1])
|
jid = self._to_jid(contact_jid)
|
||||||
response = self.client.send_message(jid, message)
|
if not jid or self._client is None:
|
||||||
|
return False
|
||||||
|
response = self._client.send_message(jid, message)
|
||||||
return response is not None
|
return response is not None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log.error(f"Failed to send structured WhatsApp message: {e}")
|
self.log.error(f"Failed to send structured WhatsApp message: {e}")
|
||||||
|
|||||||
@@ -155,15 +155,15 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Lookup user in Django
|
# Lookup user in Django
|
||||||
self.log.info(f"User {sender_username}")
|
self.log.debug("Resolving XMPP sender user=%s", sender_username)
|
||||||
user = User.objects.get(username=sender_username)
|
user = User.objects.get(username=sender_username)
|
||||||
|
|
||||||
# Find Person object with name=person_name.lower()
|
# Find Person object with name=person_name.lower()
|
||||||
self.log.info(f"Name {person_name.title()}")
|
self.log.debug("Resolving XMPP recipient person=%s", person_name.title())
|
||||||
person = Person.objects.get(user=user, name=person_name.title())
|
person = Person.objects.get(user=user, name=person_name.title())
|
||||||
|
|
||||||
# Ensure a PersonIdentifier exists for this user, person, and service
|
# Ensure a PersonIdentifier exists for this user, person, and service
|
||||||
self.log.info(f"Identifier {service}")
|
self.log.debug("Resolving XMPP identifier service=%s", service)
|
||||||
identifier = PersonIdentifier.objects.get(
|
identifier = PersonIdentifier.objects.get(
|
||||||
user=user, person=person, service=service
|
user=user, person=person, service=service
|
||||||
)
|
)
|
||||||
@@ -580,13 +580,13 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
iq["roster"]["items"] = {jid: {"name": name or jid}}
|
iq["roster"]["items"] = {jid: {"name": name or jid}}
|
||||||
|
|
||||||
iq.send()
|
iq.send()
|
||||||
self.log.info(f"Updated roster: Added {jid} ({name})")
|
self.log.debug("Updated roster: added %s (%s)", jid, name)
|
||||||
|
|
||||||
def on_chatstate_active(self, msg):
|
def on_chatstate_active(self, msg):
|
||||||
"""
|
"""
|
||||||
Handle when a user is actively engaged in the chat.
|
Handle when a user is actively engaged in the chat.
|
||||||
"""
|
"""
|
||||||
self.log.info(f"Chat state: Active from {msg['from']}.")
|
self.log.debug("Chat state active from %s", msg["from"])
|
||||||
|
|
||||||
self.get_identifier(msg)
|
self.get_identifier(msg)
|
||||||
|
|
||||||
@@ -594,7 +594,7 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
"""
|
"""
|
||||||
Handle when a user is typing a message.
|
Handle when a user is typing a message.
|
||||||
"""
|
"""
|
||||||
self.log.info(f"Chat state: Composing from {msg['from']}.")
|
self.log.debug("Chat state composing from %s", msg["from"])
|
||||||
|
|
||||||
identifier = self.get_identifier(msg)
|
identifier = self.get_identifier(msg)
|
||||||
if identifier:
|
if identifier:
|
||||||
@@ -609,7 +609,7 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
"""
|
"""
|
||||||
Handle when a user has paused typing.
|
Handle when a user has paused typing.
|
||||||
"""
|
"""
|
||||||
self.log.info(f"Chat state: Paused from {msg['from']}.")
|
self.log.debug("Chat state paused from %s", msg["from"])
|
||||||
|
|
||||||
identifier = self.get_identifier(msg)
|
identifier = self.get_identifier(msg)
|
||||||
if identifier:
|
if identifier:
|
||||||
@@ -624,7 +624,7 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
"""
|
"""
|
||||||
Handle when a user is inactive in the chat.
|
Handle when a user is inactive in the chat.
|
||||||
"""
|
"""
|
||||||
self.log.info(f"Chat state: Inactive from {msg['from']}.")
|
self.log.debug("Chat state inactive from %s", msg["from"])
|
||||||
|
|
||||||
self.get_identifier(msg)
|
self.get_identifier(msg)
|
||||||
|
|
||||||
@@ -632,7 +632,7 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
"""
|
"""
|
||||||
Handle when a user has left the chat.
|
Handle when a user has left the chat.
|
||||||
"""
|
"""
|
||||||
self.log.info(f"Chat state: Gone from {msg['from']}.")
|
self.log.debug("Chat state gone from %s", msg["from"])
|
||||||
|
|
||||||
self.get_identifier(msg)
|
self.get_identifier(msg)
|
||||||
|
|
||||||
@@ -640,37 +640,37 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
"""
|
"""
|
||||||
Handle when a user becomes available.
|
Handle when a user becomes available.
|
||||||
"""
|
"""
|
||||||
self.log.info(f"Presence available from {pres['from']}")
|
self.log.debug("Presence available from %s", pres["from"])
|
||||||
|
|
||||||
def on_presence_dnd(self, pres):
|
def on_presence_dnd(self, pres):
|
||||||
"""
|
"""
|
||||||
Handle when a user sets 'Do Not Disturb' status.
|
Handle when a user sets 'Do Not Disturb' status.
|
||||||
"""
|
"""
|
||||||
self.log.info(f"User {pres['from']} is now in 'Do Not Disturb' mode.")
|
self.log.debug("Presence dnd from %s", pres["from"])
|
||||||
|
|
||||||
def on_presence_xa(self, pres):
|
def on_presence_xa(self, pres):
|
||||||
"""
|
"""
|
||||||
Handle when a user sets 'Extended Away' status.
|
Handle when a user sets 'Extended Away' status.
|
||||||
"""
|
"""
|
||||||
self.log.info(f"User {pres['from']} is now 'Extended Away'.")
|
self.log.debug("Presence extended-away from %s", pres["from"])
|
||||||
|
|
||||||
def on_presence_chat(self, pres):
|
def on_presence_chat(self, pres):
|
||||||
"""
|
"""
|
||||||
Handle when a user is actively available for chat.
|
Handle when a user is actively available for chat.
|
||||||
"""
|
"""
|
||||||
self.log.info(f"User {pres['from']} is now available for chat.")
|
self.log.debug("Presence chat-available from %s", pres["from"])
|
||||||
|
|
||||||
def on_presence_away(self, pres):
|
def on_presence_away(self, pres):
|
||||||
"""
|
"""
|
||||||
Handle when a user sets 'Away' status.
|
Handle when a user sets 'Away' status.
|
||||||
"""
|
"""
|
||||||
self.log.info(f"User {pres['from']} is now 'Away'.")
|
self.log.debug("Presence away from %s", pres["from"])
|
||||||
|
|
||||||
def on_presence_unavailable(self, pres):
|
def on_presence_unavailable(self, pres):
|
||||||
"""
|
"""
|
||||||
Handle when a user goes offline or unavailable.
|
Handle when a user goes offline or unavailable.
|
||||||
"""
|
"""
|
||||||
self.log.info(f"User {pres['from']} is now unavailable.")
|
self.log.debug("Presence unavailable from %s", pres["from"])
|
||||||
|
|
||||||
def on_presence_subscribe(self, pres):
|
def on_presence_subscribe(self, pres):
|
||||||
"""
|
"""
|
||||||
@@ -681,7 +681,7 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
sender_jid = str(pres["from"]).split("/")[0] # Bare JID (user@domain)
|
sender_jid = str(pres["from"]).split("/")[0] # Bare JID (user@domain)
|
||||||
recipient_jid = str(pres["to"]).split("/")[0]
|
recipient_jid = str(pres["to"]).split("/")[0]
|
||||||
|
|
||||||
self.log.info(
|
self.log.debug(
|
||||||
f"Received subscription request from {sender_jid} to {recipient_jid}"
|
f"Received subscription request from {sender_jid} to {recipient_jid}"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -699,36 +699,36 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
service = None
|
service = None
|
||||||
|
|
||||||
# Lookup user in Django
|
# Lookup user in Django
|
||||||
self.log.info(f"User {user_username}")
|
self.log.debug("Resolving subscription user=%s", user_username)
|
||||||
user = User.objects.get(username=user_username)
|
user = User.objects.get(username=user_username)
|
||||||
|
|
||||||
# Find Person object with name=person_name.lower()
|
# Find Person object with name=person_name.lower()
|
||||||
self.log.info(f"Name {person_name.title()}")
|
self.log.debug("Resolving subscription person=%s", person_name.title())
|
||||||
person = Person.objects.get(user=user, name=person_name.title())
|
person = Person.objects.get(user=user, name=person_name.title())
|
||||||
|
|
||||||
# Ensure a PersonIdentifier exists for this user, person, and service
|
# Ensure a PersonIdentifier exists for this user, person, and service
|
||||||
self.log.info(f"Identifier {service}")
|
self.log.debug("Resolving subscription identifier service=%s", service)
|
||||||
PersonIdentifier.objects.get(user=user, person=person, service=service)
|
PersonIdentifier.objects.get(user=user, person=person, service=service)
|
||||||
|
|
||||||
component_jid = f"{person_name.lower()}|{service}@{self.boundjid.bare}"
|
component_jid = f"{person_name.lower()}|{service}@{self.boundjid.bare}"
|
||||||
|
|
||||||
# Accept the subscription
|
# Accept the subscription
|
||||||
self.send_presence(ptype="subscribed", pto=sender_jid, pfrom=component_jid)
|
self.send_presence(ptype="subscribed", pto=sender_jid, pfrom=component_jid)
|
||||||
self.log.info(
|
self.log.debug(
|
||||||
f"Accepted subscription from {sender_jid}, sent from {component_jid}"
|
f"Accepted subscription from {sender_jid}, sent from {component_jid}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Send a presence request **from the recipient to the sender** (ASKS THEM TO ACCEPT BACK)
|
# Send a presence request **from the recipient to the sender** (ASKS THEM TO ACCEPT BACK)
|
||||||
# self.send_presence(ptype="subscribe", pto=sender_jid, pfrom=component_jid)
|
# self.send_presence(ptype="subscribe", pto=sender_jid, pfrom=component_jid)
|
||||||
# self.log.info(f"Sent presence subscription request from {component_jid} to {sender_jid}")
|
|
||||||
|
|
||||||
# Add sender to roster
|
# Add sender to roster
|
||||||
# self.update_roster(sender_jid, name=sender_jid.split("@")[0])
|
# self.update_roster(sender_jid, name=sender_jid.split("@")[0])
|
||||||
# self.log.info(f"Added {sender_jid} to roster.")
|
|
||||||
|
|
||||||
# Send presence update to sender **from the correct JID**
|
# Send presence update to sender **from the correct JID**
|
||||||
self.send_presence(ptype="available", pto=sender_jid, pfrom=component_jid)
|
self.send_presence(ptype="available", pto=sender_jid, pfrom=component_jid)
|
||||||
self.log.info(f"Sent presence update from {component_jid} to {sender_jid}")
|
self.log.debug(
|
||||||
|
"Sent presence update from %s to %s", component_jid, sender_jid
|
||||||
|
)
|
||||||
|
|
||||||
except (User.DoesNotExist, Person.DoesNotExist, PersonIdentifier.DoesNotExist):
|
except (User.DoesNotExist, Person.DoesNotExist, PersonIdentifier.DoesNotExist):
|
||||||
# If any lookup fails, reject the subscription
|
# If any lookup fails, reject the subscription
|
||||||
@@ -744,25 +744,25 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
"""
|
"""
|
||||||
Handle successful subscription confirmations.
|
Handle successful subscription confirmations.
|
||||||
"""
|
"""
|
||||||
self.log.info(f"Subscription to {pres['from']} was accepted.")
|
self.log.debug("Subscription to %s accepted", pres["from"])
|
||||||
|
|
||||||
def on_presence_unsubscribe(self, pres):
|
def on_presence_unsubscribe(self, pres):
|
||||||
"""
|
"""
|
||||||
Handle when a user unsubscribes from presence updates.
|
Handle when a user unsubscribes from presence updates.
|
||||||
"""
|
"""
|
||||||
self.log.info(f"User {pres['from']} has unsubscribed from presence updates.")
|
self.log.debug("Presence unsubscribe from %s", pres["from"])
|
||||||
|
|
||||||
def on_presence_unsubscribed(self, pres):
|
def on_presence_unsubscribed(self, pres):
|
||||||
"""
|
"""
|
||||||
Handle when a user's unsubscription request is confirmed.
|
Handle when a user's unsubscription request is confirmed.
|
||||||
"""
|
"""
|
||||||
self.log.info(f"Unsubscription from {pres['from']} confirmed.")
|
self.log.debug("Presence unsubscribed confirmation from %s", pres["from"])
|
||||||
|
|
||||||
def on_roster_subscription_request(self, pres):
|
def on_roster_subscription_request(self, pres):
|
||||||
"""
|
"""
|
||||||
Handle roster subscription requests.
|
Handle roster subscription requests.
|
||||||
"""
|
"""
|
||||||
self.log.info(f"New roster subscription request from {pres['from']}.")
|
self.log.debug("Roster subscription request from %s", pres["from"])
|
||||||
|
|
||||||
async def session_start(self, *args):
|
async def session_start(self, *args):
|
||||||
self.log.info("XMPP session started")
|
self.log.info("XMPP session started")
|
||||||
@@ -793,8 +793,6 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
# self.log.error("No XEP-0363 upload service found.")
|
# self.log.error("No XEP-0363 upload service found.")
|
||||||
# return None
|
# return None
|
||||||
|
|
||||||
# self.log.info(f"Upload service: {upload_service}")
|
|
||||||
|
|
||||||
upload_service_jid = str(
|
upload_service_jid = str(
|
||||||
getattr(settings, "XMPP_UPLOAD_SERVICE", "")
|
getattr(settings, "XMPP_UPLOAD_SERVICE", "")
|
||||||
or getattr(settings, "XMPP_UPLOAD_JID", "")
|
or getattr(settings, "XMPP_UPLOAD_JID", "")
|
||||||
@@ -851,8 +849,6 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
def sym(value):
|
def sym(value):
|
||||||
msg.reply(f"[>] {value}").send()
|
msg.reply(f"[>] {value}").send()
|
||||||
|
|
||||||
# self.log.info(f"Received message: {msg}")
|
|
||||||
|
|
||||||
# Extract sender JID (full format: user@domain/resource)
|
# Extract sender JID (full format: user@domain/resource)
|
||||||
sender_jid = str(msg["from"])
|
sender_jid = str(msg["from"])
|
||||||
|
|
||||||
@@ -878,7 +874,9 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
body = msg["body"] if msg["body"] else ""
|
body = msg["body"] if msg["body"] else ""
|
||||||
|
|
||||||
attachments = []
|
attachments = []
|
||||||
self.log.info(f"Full XMPP Message: {ET.tostring(msg.xml, encoding='unicode')}")
|
self.log.debug(
|
||||||
|
"Received XMPP stanza: %s", ET.tostring(msg.xml, encoding="unicode")
|
||||||
|
)
|
||||||
|
|
||||||
# Extract attachments from standard XMPP payloads.
|
# Extract attachments from standard XMPP payloads.
|
||||||
for att in msg.xml.findall(".//{urn:xmpp:attachments}attachment"):
|
for att in msg.xml.findall(".//{urn:xmpp:attachments}attachment"):
|
||||||
@@ -933,7 +931,7 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
if attachment_urls:
|
if attachment_urls:
|
||||||
body = "\n".join(attachment_urls)
|
body = "\n".join(attachment_urls)
|
||||||
|
|
||||||
self.log.info(f"Extracted {len(attachments)} attachments from XMPP message.")
|
self.log.debug("Extracted %s attachments from XMPP message", len(attachments))
|
||||||
# Log extracted information with variable name annotations
|
# Log extracted information with variable name annotations
|
||||||
log_message = (
|
log_message = (
|
||||||
f"Sender JID: {sender_jid}, Sender Username: {sender_username}, Sender Domain: {sender_domain}, "
|
f"Sender JID: {sender_jid}, Sender Username: {sender_username}, Sender Domain: {sender_domain}, "
|
||||||
@@ -941,7 +939,7 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
f"Recipient JID: {recipient_jid}, Recipient Username: {recipient_username}, Recipient Domain: {recipient_domain}, "
|
f"Recipient JID: {recipient_jid}, Recipient Username: {recipient_username}, Recipient Domain: {recipient_domain}, "
|
||||||
f"Body: {body or '[No Body]'}"
|
f"Body: {body or '[No Body]'}"
|
||||||
)
|
)
|
||||||
self.log.info(log_message)
|
self.log.debug(log_message)
|
||||||
|
|
||||||
# Ensure recipient domain matches our configured component
|
# Ensure recipient domain matches our configured component
|
||||||
expected_domain = settings.XMPP_JID # 'jews.zm.is' in your config
|
expected_domain = settings.XMPP_JID # 'jews.zm.is' in your config
|
||||||
@@ -959,14 +957,14 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if recipient_jid == settings.XMPP_JID:
|
if recipient_jid == settings.XMPP_JID:
|
||||||
self.log.info("Message to JID")
|
self.log.debug("Handling command message sent to gateway JID")
|
||||||
if body.startswith("."):
|
if body.startswith("."):
|
||||||
# Messaging the gateway directly
|
# Messaging the gateway directly
|
||||||
if body == ".contacts":
|
if body == ".contacts":
|
||||||
# Lookup Person objects linked to sender
|
# Lookup Person objects linked to sender
|
||||||
persons = Person.objects.filter(user=sender_user)
|
persons = Person.objects.filter(user=sender_user)
|
||||||
if not persons.exists():
|
if not persons.exists():
|
||||||
self.log.info(f"No contacts found for {sender_username}")
|
self.log.debug("No contacts found for %s", sender_username)
|
||||||
sym("No contacts found.")
|
sym("No contacts found.")
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -989,7 +987,7 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
else:
|
else:
|
||||||
sym("No such command")
|
sym("No such command")
|
||||||
else:
|
else:
|
||||||
self.log.info("Other message")
|
self.log.debug("Handling routed message to contact")
|
||||||
if "|" in recipient_username:
|
if "|" in recipient_username:
|
||||||
recipient_name, recipient_service = recipient_username.split("|")
|
recipient_name, recipient_service = recipient_username.split("|")
|
||||||
|
|
||||||
@@ -1029,7 +1027,7 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
identifier=identifier,
|
identifier=identifier,
|
||||||
user=identifier.user,
|
user=identifier.user,
|
||||||
)
|
)
|
||||||
self.log.info(f"Component history store message {body}")
|
self.log.debug("Storing outbound XMPP message in history")
|
||||||
await history.store_message(
|
await history.store_message(
|
||||||
session=session,
|
session=session,
|
||||||
sender="XMPP",
|
sender="XMPP",
|
||||||
@@ -1037,7 +1035,7 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
ts=int(now().timestamp() * 1000),
|
ts=int(now().timestamp() * 1000),
|
||||||
outgoing=True,
|
outgoing=True,
|
||||||
)
|
)
|
||||||
self.log.info("Stored a message sent from XMPP in the history.")
|
self.log.debug("Stored outbound XMPP message in history")
|
||||||
|
|
||||||
manipulations = Manipulation.objects.filter(
|
manipulations = Manipulation.objects.filter(
|
||||||
group__people=identifier.person,
|
group__people=identifier.person,
|
||||||
@@ -1045,7 +1043,7 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
mode="mutate",
|
mode="mutate",
|
||||||
enabled=True,
|
enabled=True,
|
||||||
)
|
)
|
||||||
self.log.info(f"MANIP11 {manipulations}")
|
self.log.debug("Found %s active manipulations", manipulations.count())
|
||||||
if not manipulations:
|
if not manipulations:
|
||||||
await self.ur.stopped_typing(
|
await self.ur.stopped_typing(
|
||||||
"xmpp",
|
"xmpp",
|
||||||
@@ -1056,7 +1054,7 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
body,
|
body,
|
||||||
attachments,
|
attachments,
|
||||||
)
|
)
|
||||||
self.log.info("Message sent unaltered")
|
self.log.debug("Message sent unaltered")
|
||||||
return
|
return
|
||||||
|
|
||||||
manip = manipulations.first()
|
manip = manipulations.first()
|
||||||
@@ -1068,9 +1066,9 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
manip,
|
manip,
|
||||||
chat_history,
|
chat_history,
|
||||||
)
|
)
|
||||||
self.log.info("Running XMPP context prompt")
|
self.log.debug("Running XMPP context prompt")
|
||||||
result = await ai.run_prompt(prompt, manip.ai)
|
result = await ai.run_prompt(prompt, manip.ai)
|
||||||
self.log.info(f"RESULT {result}")
|
self.log.debug("Generated mutated response for XMPP message")
|
||||||
await history.store_own_message(
|
await history.store_own_message(
|
||||||
session=session,
|
session=session,
|
||||||
text=result,
|
text=result,
|
||||||
@@ -1085,7 +1083,7 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
result,
|
result,
|
||||||
attachments,
|
attachments,
|
||||||
)
|
)
|
||||||
self.log.info("Message sent with modifications")
|
self.log.debug("Message sent with modifications")
|
||||||
|
|
||||||
async def request_upload_slots(self, recipient_jid, attachments):
|
async def request_upload_slots(self, recipient_jid, attachments):
|
||||||
"""Requests upload slots for multiple attachments concurrently."""
|
"""Requests upload slots for multiple attachments concurrently."""
|
||||||
@@ -1120,8 +1118,8 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
f"Upload failed: {response.status} {await response.text()}"
|
f"Upload failed: {response.status} {await response.text()}"
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
self.log.info(
|
self.log.debug(
|
||||||
f"Successfully uploaded {att['filename']} to {upload_url}"
|
"Successfully uploaded %s to %s", att["filename"], upload_url
|
||||||
)
|
)
|
||||||
|
|
||||||
# Send XMPP message immediately after successful upload
|
# Send XMPP message immediately after successful upload
|
||||||
@@ -1148,7 +1146,7 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
url_element.text = attachment_url
|
url_element.text = attachment_url
|
||||||
msg.xml.append(oob_element)
|
msg.xml.append(oob_element)
|
||||||
|
|
||||||
self.log.info(f"Sending XMPP message: {msg.xml}")
|
self.log.debug("Sending XMPP message: %s", msg.xml)
|
||||||
msg.send()
|
msg.send()
|
||||||
|
|
||||||
async def send_chat_state(self, recipient_jid, sender_jid, started):
|
async def send_chat_state(self, recipient_jid, sender_jid, started):
|
||||||
@@ -1158,7 +1156,7 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
msg.xml.append(
|
msg.xml.append(
|
||||||
ET.Element(f"{{http://jabber.org/protocol/chatstates}}{state_tag}")
|
ET.Element(f"{{http://jabber.org/protocol/chatstates}}{state_tag}")
|
||||||
)
|
)
|
||||||
self.log.info(
|
self.log.debug(
|
||||||
"Sending XMPP chat-state %s: %s -> %s",
|
"Sending XMPP chat-state %s: %s -> %s",
|
||||||
state_tag,
|
state_tag,
|
||||||
sender_jid,
|
sender_jid,
|
||||||
@@ -1193,7 +1191,7 @@ class XMPPComponent(ComponentXMPP):
|
|||||||
|
|
||||||
# Step 2: Request upload slots concurrently
|
# Step 2: Request upload slots concurrently
|
||||||
valid_uploads = await self.request_upload_slots(recipient_jid, attachments)
|
valid_uploads = await self.request_upload_slots(recipient_jid, attachments)
|
||||||
self.log.info("Got upload slots")
|
self.log.debug("Got upload slots")
|
||||||
if not valid_uploads:
|
if not valid_uploads:
|
||||||
self.log.warning("No valid upload slots obtained.")
|
self.log.warning("No valid upload slots obtained.")
|
||||||
return []
|
return []
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ async def get_chat_session(user, identifier):
|
|||||||
|
|
||||||
|
|
||||||
async def store_message(session, sender, text, ts, outgoing=False):
|
async def store_message(session, sender, text, ts, outgoing=False):
|
||||||
log.info(f"STORE MESSAGE {text}")
|
log.debug("Storing message for session=%s outgoing=%s", session.id, outgoing)
|
||||||
msg = await sync_to_async(Message.objects.create)(
|
msg = await sync_to_async(Message.objects.create)(
|
||||||
user=session.user,
|
user=session.user,
|
||||||
session=session,
|
session=session,
|
||||||
@@ -160,7 +160,7 @@ async def store_message(session, sender, text, ts, outgoing=False):
|
|||||||
|
|
||||||
|
|
||||||
async def store_own_message(session, text, ts, manip=None, queue=False):
|
async def store_own_message(session, text, ts, manip=None, queue=False):
|
||||||
log.info(f"STORE OWN MESSAGE {text}")
|
log.debug("Storing own message for session=%s queue=%s", session.id, queue)
|
||||||
cast = {
|
cast = {
|
||||||
"user": session.user,
|
"user": session.user,
|
||||||
"session": session,
|
"session": session,
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ class UnifiedRouter(object):
|
|||||||
self._typing_stop_tasks[key] = self.loop.create_task(_timer())
|
self._typing_stop_tasks[key] = self.loop.create_task(_timer())
|
||||||
|
|
||||||
def _start(self):
|
def _start(self):
|
||||||
print("UR _start")
|
self.log.info("Starting unified router clients")
|
||||||
self.xmpp.start()
|
self.xmpp.start()
|
||||||
self.signal.start()
|
self.signal.start()
|
||||||
self.whatsapp.start()
|
self.whatsapp.start()
|
||||||
@@ -81,7 +81,7 @@ class UnifiedRouter(object):
|
|||||||
try:
|
try:
|
||||||
# self.xmpp.client.client.process()
|
# self.xmpp.client.client.process()
|
||||||
# self.xmpp.start()
|
# self.xmpp.start()
|
||||||
print("IN RUN BEFORE START")
|
self.log.debug("Router run loop initializing")
|
||||||
self._start()
|
self._start()
|
||||||
self.loop.run_forever()
|
self.loop.run_forever()
|
||||||
except (KeyboardInterrupt, SystemExit):
|
except (KeyboardInterrupt, SystemExit):
|
||||||
|
|||||||
@@ -71,9 +71,7 @@ def _load_since(user_id, service, identifier, person_id, after_ts, limit):
|
|||||||
qs = base_queryset.order_by("ts")
|
qs = base_queryset.order_by("ts")
|
||||||
seed_previous = None
|
seed_previous = None
|
||||||
if after_ts > 0:
|
if after_ts > 0:
|
||||||
seed_previous = (
|
seed_previous = base_queryset.filter(ts__lte=after_ts).order_by("-ts").first()
|
||||||
base_queryset.filter(ts__lte=after_ts).order_by("-ts").first()
|
|
||||||
)
|
|
||||||
# Use a small rolling window to capture late/out-of-order timestamps.
|
# Use a small rolling window to capture late/out-of-order timestamps.
|
||||||
# Frontend dedupes by message id, so repeated rows are ignored.
|
# Frontend dedupes by message id, so repeated rows are ignored.
|
||||||
window_start = max(0, int(after_ts) - 5 * 60 * 1000)
|
window_start = max(0, int(after_ts) - 5 * 60 * 1000)
|
||||||
@@ -84,8 +82,7 @@ def _load_since(user_id, service, identifier, person_id, after_ts, limit):
|
|||||||
"session",
|
"session",
|
||||||
"session__identifier",
|
"session__identifier",
|
||||||
"session__identifier__person",
|
"session__identifier__person",
|
||||||
)
|
).order_by("-ts")[: max(10, min(limit, 200))]
|
||||||
.order_by("-ts")[: max(10, min(limit, 200))]
|
|
||||||
)
|
)
|
||||||
rows_desc.reverse()
|
rows_desc.reverse()
|
||||||
rows = rows_desc
|
rows = rows_desc
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
# Other library imports
|
# Other library imports
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
log = logging.getLogger("util")
|
log = logging.getLogger("util")
|
||||||
|
|
||||||
debug = True
|
debug = str(os.getenv("GIA_DEBUG_LOGS", "0")).strip().lower() in {
|
||||||
|
"1",
|
||||||
|
"true",
|
||||||
|
"yes",
|
||||||
|
"on",
|
||||||
|
}
|
||||||
|
|
||||||
# Color definitions
|
# Color definitions
|
||||||
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
|
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
|
||||||
@@ -49,20 +55,26 @@ def get_logger(name):
|
|||||||
color_formatter = ColoredFormatter(COLOR_FORMAT)
|
color_formatter = ColoredFormatter(COLOR_FORMAT)
|
||||||
# formatter = logging.Formatter(
|
# formatter = logging.Formatter(
|
||||||
|
|
||||||
# Why is this so complicated?
|
|
||||||
ch = logging.StreamHandler()
|
|
||||||
ch.setLevel(logging.INFO)
|
|
||||||
# ch.setFormatter(formatter)
|
|
||||||
ch.setFormatter(color_formatter)
|
|
||||||
|
|
||||||
# Define the logger on the base class
|
# Define the logger on the base class
|
||||||
log = logging.getLogger(name)
|
log = logging.getLogger(name)
|
||||||
log.setLevel(logging.INFO)
|
log.setLevel(logging.INFO)
|
||||||
if debug:
|
if debug:
|
||||||
log.setLevel(logging.DEBUG)
|
log.setLevel(logging.DEBUG)
|
||||||
ch.setLevel(logging.DEBUG)
|
|
||||||
|
|
||||||
# Add the handler and stop it being silly and printing everything twice
|
# Add exactly one stream handler per logger to avoid duplicate lines.
|
||||||
log.addHandler(ch)
|
existing_handler = None
|
||||||
|
for handler in log.handlers:
|
||||||
|
if getattr(handler, "_gia_logger_handler", False):
|
||||||
|
existing_handler = handler
|
||||||
|
break
|
||||||
|
|
||||||
|
if existing_handler is None:
|
||||||
|
ch = logging.StreamHandler()
|
||||||
|
ch._gia_logger_handler = True
|
||||||
|
ch.setFormatter(color_formatter)
|
||||||
|
log.addHandler(ch)
|
||||||
|
existing_handler = ch
|
||||||
|
|
||||||
|
existing_handler.setLevel(logging.DEBUG if debug else logging.INFO)
|
||||||
log.propagate = False
|
log.propagate = False
|
||||||
return log
|
return log
|
||||||
|
|||||||
@@ -2758,7 +2758,9 @@ class ComposeCommandResult(LoginRequiredMixin, View):
|
|||||||
request,
|
request,
|
||||||
"partials/compose-send-status.html",
|
"partials/compose-send-status.html",
|
||||||
{
|
{
|
||||||
"notice_message": str(timeout_result.get("error") or "Send failed."),
|
"notice_message": str(
|
||||||
|
timeout_result.get("error") or "Send failed."
|
||||||
|
),
|
||||||
"notice_level": "danger",
|
"notice_level": "danger",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -3323,12 +3325,12 @@ class ComposeSend(LoginRequiredMixin, View):
|
|||||||
log_prefix = (
|
log_prefix = (
|
||||||
f"[ComposeSend] service={base['service']} identifier={base['identifier']}"
|
f"[ComposeSend] service={base['service']} identifier={base['identifier']}"
|
||||||
)
|
)
|
||||||
logger.info(f"{log_prefix} text_len={len(text)} attempting send")
|
logger.debug(f"{log_prefix} text_len={len(text)} attempting send")
|
||||||
|
|
||||||
# If runtime is out-of-process, enqueue command and return immediately (non-blocking).
|
# If runtime is out-of-process, enqueue command and return immediately (non-blocking).
|
||||||
# Expose command id for cancellation so the client can cancel or poll later.
|
# Expose command id for cancellation so the client can cancel or poll later.
|
||||||
runtime_client = transport.get_runtime_client(base["service"]) or None
|
runtime_client = transport.get_runtime_client(base["service"]) or None
|
||||||
logger.info(
|
logger.debug(
|
||||||
f"{log_prefix} runtime_client={type(runtime_client).__name__ if runtime_client else 'None (queued)'}"
|
f"{log_prefix} runtime_client={type(runtime_client).__name__ if runtime_client else 'None (queued)'}"
|
||||||
)
|
)
|
||||||
ts = None
|
ts = None
|
||||||
@@ -3338,7 +3340,9 @@ class ComposeSend(LoginRequiredMixin, View):
|
|||||||
runtime_state = transport.get_runtime_state("whatsapp")
|
runtime_state = transport.get_runtime_state("whatsapp")
|
||||||
last_seen = int(runtime_state.get("runtime_seen_at") or 0)
|
last_seen = int(runtime_state.get("runtime_seen_at") or 0)
|
||||||
is_connected = bool(runtime_state.get("connected"))
|
is_connected = bool(runtime_state.get("connected"))
|
||||||
pair_status = str(runtime_state.get("pair_status") or "").strip().lower()
|
pair_status = (
|
||||||
|
str(runtime_state.get("pair_status") or "").strip().lower()
|
||||||
|
)
|
||||||
now_s = int(time.time())
|
now_s = int(time.time())
|
||||||
# Runtime may process sends even when `connected` lags false briefly;
|
# Runtime may process sends even when `connected` lags false briefly;
|
||||||
# heartbeat freshness is the reliable signal for queue availability.
|
# heartbeat freshness is the reliable signal for queue availability.
|
||||||
@@ -3358,15 +3362,12 @@ class ComposeSend(LoginRequiredMixin, View):
|
|||||||
level="warning",
|
level="warning",
|
||||||
panel_id=panel_id,
|
panel_id=panel_id,
|
||||||
)
|
)
|
||||||
logger.info(f"{log_prefix} enqueuing runtime command (out-of-process)")
|
|
||||||
command_id = transport.enqueue_runtime_command(
|
command_id = transport.enqueue_runtime_command(
|
||||||
base["service"],
|
base["service"],
|
||||||
"send_message_raw",
|
"send_message_raw",
|
||||||
{"recipient": base["identifier"], "text": text, "attachments": []},
|
{"recipient": base["identifier"], "text": text, "attachments": []},
|
||||||
)
|
)
|
||||||
logger.info(
|
logger.debug(f"{log_prefix} command_id={command_id} enqueued")
|
||||||
f"{log_prefix} command_id={command_id} enqueued, returning immediately"
|
|
||||||
)
|
|
||||||
# attach command id to request so _response can include it in HX-Trigger
|
# attach command id to request so _response can include it in HX-Trigger
|
||||||
request._compose_command_id = command_id
|
request._compose_command_id = command_id
|
||||||
# Do NOT wait here — return immediately so the UI doesn't block.
|
# Do NOT wait here — return immediately so the UI doesn't block.
|
||||||
@@ -3374,14 +3375,12 @@ class ComposeSend(LoginRequiredMixin, View):
|
|||||||
ts = int(time.time() * 1000)
|
ts = int(time.time() * 1000)
|
||||||
else:
|
else:
|
||||||
# In-process runtime can perform the send synchronously and return a timestamp.
|
# In-process runtime can perform the send synchronously and return a timestamp.
|
||||||
logger.info(f"{log_prefix} calling in-process send_message_raw (blocking)")
|
|
||||||
ts = async_to_sync(transport.send_message_raw)(
|
ts = async_to_sync(transport.send_message_raw)(
|
||||||
base["service"],
|
base["service"],
|
||||||
base["identifier"],
|
base["identifier"],
|
||||||
text=text,
|
text=text,
|
||||||
attachments=[],
|
attachments=[],
|
||||||
)
|
)
|
||||||
logger.info(f"{log_prefix} in-process send returned ts={ts}")
|
|
||||||
# For queued sends we set `ts` to a local timestamp; for in-process sends ts may be False.
|
# For queued sends we set `ts` to a local timestamp; for in-process sends ts may be False.
|
||||||
if not ts:
|
if not ts:
|
||||||
return self._response(
|
return self._response(
|
||||||
@@ -3397,13 +3396,12 @@ class ComposeSend(LoginRequiredMixin, View):
|
|||||||
user=request.user,
|
user=request.user,
|
||||||
identifier=base["person_identifier"],
|
identifier=base["person_identifier"],
|
||||||
)
|
)
|
||||||
logger.info(f"{log_prefix} session_id={session.id}")
|
|
||||||
# For in-process sends (Signal, etc), ts is a timestamp or True.
|
# For in-process sends (Signal, etc), ts is a timestamp or True.
|
||||||
# For queued sends (WhatsApp/UR), ts is a local timestamp.
|
# For queued sends (WhatsApp/UR), ts is a local timestamp.
|
||||||
# Set delivered_ts only if we got a real timestamp OR if it's an in-process sync send.
|
# Set delivered_ts only if we got a real timestamp OR if it's an in-process sync send.
|
||||||
msg_ts = int(ts) if str(ts).isdigit() else int(time.time() * 1000)
|
msg_ts = int(ts) if str(ts).isdigit() else int(time.time() * 1000)
|
||||||
delivered_ts = msg_ts if runtime_client is not None else None
|
delivered_ts = msg_ts if runtime_client is not None else None
|
||||||
msg = Message.objects.create(
|
Message.objects.create(
|
||||||
user=request.user,
|
user=request.user,
|
||||||
session=session,
|
session=session,
|
||||||
sender_uuid="",
|
sender_uuid="",
|
||||||
@@ -3412,9 +3410,6 @@ class ComposeSend(LoginRequiredMixin, View):
|
|||||||
delivered_ts=delivered_ts,
|
delivered_ts=delivered_ts,
|
||||||
custom_author="USER",
|
custom_author="USER",
|
||||||
)
|
)
|
||||||
logger.info(
|
|
||||||
f"{log_prefix} created message id={msg.id} ts={msg_ts} delivered_ts={delivered_ts} custom_author=USER"
|
|
||||||
)
|
|
||||||
# Notify XMPP clients from runtime so cross-platform sends appear there too.
|
# Notify XMPP clients from runtime so cross-platform sends appear there too.
|
||||||
if base["service"] in {"signal", "whatsapp"}:
|
if base["service"] in {"signal", "whatsapp"}:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -695,21 +695,21 @@ class OSINTSearch(LoginRequiredMixin, View):
|
|||||||
|
|
||||||
def _field_options(self, model_cls: type[models.Model]) -> list[dict[str, str]]:
|
def _field_options(self, model_cls: type[models.Model]) -> list[dict[str, str]]:
|
||||||
options = []
|
options = []
|
||||||
for field in model_cls._meta.get_fields():
|
for model_field in model_cls._meta.get_fields():
|
||||||
# Skip reverse/accessor relations (e.g. ManyToManyRel) that are not
|
# Skip reverse/accessor relations (e.g. ManyToManyRel) that are not
|
||||||
# directly searchable as user-facing fields in this selector.
|
# directly searchable as user-facing fields in this selector.
|
||||||
if field.auto_created and not field.concrete:
|
if model_field.auto_created and not model_field.concrete:
|
||||||
continue
|
continue
|
||||||
if field.name == "user":
|
if model_field.name == "user":
|
||||||
continue
|
continue
|
||||||
label = getattr(
|
label = getattr(
|
||||||
field,
|
model_field,
|
||||||
"verbose_name",
|
"verbose_name",
|
||||||
str(field.name).replace("_", " "),
|
str(model_field.name).replace("_", " "),
|
||||||
)
|
)
|
||||||
options.append(
|
options.append(
|
||||||
{
|
{
|
||||||
"value": field.name,
|
"value": model_field.name,
|
||||||
"label": str(label).title(),
|
"label": str(label).title(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -892,7 +892,6 @@ class OSINTSearch(LoginRequiredMixin, View):
|
|||||||
object_list: list[Any],
|
object_list: list[Any],
|
||||||
request_type: str,
|
request_type: str,
|
||||||
) -> list[dict[str, Any]]:
|
) -> list[dict[str, Any]]:
|
||||||
context_type = _context_type(request_type)
|
|
||||||
rows = []
|
rows = []
|
||||||
for item in object_list:
|
for item in object_list:
|
||||||
row = {"id": str(item.pk), "cells": [], "actions": []}
|
row = {"id": str(item.pk), "cells": [], "actions": []}
|
||||||
|
|||||||
@@ -25,9 +25,7 @@ The watcher ignores `__pycache__`, `.pyc` files and `.git` paths.
|
|||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from watchdog.events import FileSystemEventHandler
|
from watchdog.events import FileSystemEventHandler
|
||||||
from watchdog.observers import Observer
|
from watchdog.observers import Observer
|
||||||
|
|||||||
Reference in New Issue
Block a user