Files
GIA/core/views/signal.py

228 lines
7.6 KiB
Python

from urllib.parse import urlencode
import orjson
import requests
from django.conf import settings
from django.shortcuts import render
from django.urls import reverse
from django.views import View
from mixins.views import ObjectList, ObjectRead
from core.clients import transport
from core.models import Chat, PersonIdentifier
from core.views.manage.permissions import SuperUserRequiredMixin
class CustomObjectRead(ObjectRead):
def post(self, request, *args, **kwargs):
self.request = request
return super().get(request, *args, **kwargs)
class Signal(SuperUserRequiredMixin, View):
template_name = "pages/signal.html"
service = "signal"
page_title = "Signal"
accounts_url_name = "signal_accounts"
def get(self, request):
return render(
request,
self.template_name,
{
"service": self.service,
"service_label": self.page_title,
"accounts_url_name": self.accounts_url_name,
},
)
class SignalAccounts(SuperUserRequiredMixin, ObjectList):
list_template = "partials/signal-accounts.html"
service = "signal"
context_object_name_singular = "Signal Account"
context_object_name = "Signal Accounts"
list_url_name = "signal_accounts"
list_url_args = ["type"]
def _normalize_accounts(self, rows):
out = []
for item in rows or []:
if isinstance(item, dict):
value = (
item.get("number")
or item.get("id")
or item.get("jid")
or item.get("account")
)
if value:
out.append(str(value))
elif item:
out.append(str(item))
return out
def _service_context(self, service, label, add_url_name, show_contact_actions):
return {
"service": service,
"service_label": label,
"account_add_url_name": add_url_name,
"show_contact_actions": show_contact_actions,
"contacts_url_name": f"{service}_contacts",
"chats_url_name": f"{service}_chats",
"endpoint_base": str(
getattr(settings, "SIGNAL_HTTP_URL", "http://signal:8080")
).rstrip("/")
if service == "signal"
else "",
"service_warning": transport.get_service_warning(service),
}
def get_queryset(self, **kwargs):
self.extra_context = self._service_context(
service="signal",
label="Signal",
add_url_name="signal_account_add",
show_contact_actions=True,
)
return self._normalize_accounts(transport.list_accounts("signal"))
class SignalContactsList(SuperUserRequiredMixin, ObjectList):
list_template = "partials/signal-contacts-list.html"
context_object_name_singular = "Signal Contact"
context_object_name = "Signal Contacts"
list_url_name = "signal_contacts"
list_url_args = ["type", "pk"]
def get_queryset(self, *args, **kwargs):
# url = signal:8080/v1/accounts
# /v1/configuration/{number}/settings
# /v1/identities/{number}
# /v1/contacts/{number}
# response = requests.get(
# f"http://signal:8080/v1/configuration/{self.kwargs['pk']}/settings"
# )
# config = orjson.loads(response.text)
base = getattr(settings, "SIGNAL_HTTP_URL", "http://signal:8080").rstrip("/")
response = requests.get(f"{base}/v1/identities/{self.kwargs['pk']}")
identities = orjson.loads(response.text)
response = requests.get(f"{base}/v1/contacts/{self.kwargs['pk']}")
contacts = orjson.loads(response.text)
# add identities to contacts
for contact in contacts:
for identity in identities:
if contact["number"] == identity["number"]:
contact["identity"] = identity
obj = {
# "identity": identity,
"contacts": contacts,
}
self.extra_context = {"pretty": list(obj.keys())}
return obj
class SignalChatsList(SuperUserRequiredMixin, ObjectList):
list_template = "partials/signal-chats-list.html"
context_object_name_singular = "Signal Chat"
context_object_name = "Signal Chats"
list_url_name = "signal_chats"
list_url_args = ["type", "pk"]
def get_queryset(self, *args, **kwargs):
pk = self.kwargs.get("pk", "")
chats = list(Chat.objects.filter(account=pk))
rows = []
for chat in chats:
identifier_candidates = [
str(chat.source_uuid or "").strip(),
str(chat.source_number or "").strip(),
]
identifier_candidates = [value for value in identifier_candidates if value]
person_identifier = None
if identifier_candidates:
person_identifier = (
PersonIdentifier.objects.filter(
user=self.request.user,
service="signal",
identifier__in=identifier_candidates,
)
.select_related("person")
.first()
)
identifier_value = (
person_identifier.identifier if person_identifier else ""
) or (chat.source_uuid or chat.source_number or "")
service = "signal"
compose_page_url = ""
compose_widget_url = ""
if identifier_value:
query = f"service={service}&identifier={identifier_value}"
if person_identifier:
query += f"&person={person_identifier.person_id}"
compose_page_url = f"{reverse('compose_page')}?{query}"
compose_widget_url = f"{reverse('compose_widget')}?{query}"
if person_identifier:
ai_url = (
f"{reverse('ai_workspace')}?person={person_identifier.person_id}"
)
else:
ai_url = reverse("ai_workspace")
rows.append(
{
"chat": chat,
"compose_page_url": compose_page_url,
"compose_widget_url": compose_widget_url,
"ai_url": ai_url,
"person_name": (
person_identifier.person.name if person_identifier else ""
),
"manual_icon_class": "fa-solid fa-paper-plane",
"can_compose": bool(compose_page_url),
"match_url": (
f"{reverse('compose_contact_match')}?"
f"{urlencode({'service': 'signal', 'identifier': identifier_value})}"
if identifier_value
else reverse("compose_contact_match")
),
}
)
return rows
class SignalMessagesList(SuperUserRequiredMixin, ObjectList):
...
class SignalAccountAdd(SuperUserRequiredMixin, CustomObjectRead):
detail_template = "partials/signal-account-add.html"
service = "signal"
context_object_name_singular = "Add Account"
context_object_name = "Add Account"
detail_url_name = "signal_account_add"
detail_url_args = ["type", "device"]
page_title = None
def get_object(self, **kwargs):
form_args = self.request.POST.dict()
device_name = form_args["device"]
image_bytes = transport.get_link_qr(self.service, device_name)
base64_image = transport.image_bytes_to_base64(image_bytes)
return base64_image