Implement AI workspace and mitigation workflow

This commit is contained in:
2026-02-15 04:27:28 +00:00
parent de2b9a9bbb
commit 2d3b8fdac6
64 changed files with 7669 additions and 769 deletions

View File

@@ -1,11 +1,5 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from mixins.views import (
ObjectCreate,
ObjectDelete,
ObjectList,
ObjectUpdate,
)
from mixins.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
from core.forms import AIForm
from core.models import AI
@@ -13,11 +7,12 @@ from core.util import logs
log = logs.get_logger(__name__)
class AIList(LoginRequiredMixin, ObjectList):
list_template = "partials/ai-list.html"
model = AI
page_title = "AIs"
#page_subtitle = "Add times here in order to permit trading."
# page_subtitle = "Add times here in order to permit trading."
list_url_name = "ais"
list_url_args = ["type"]

View File

@@ -1,11 +1,5 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from mixins.views import (
ObjectCreate,
ObjectDelete,
ObjectList,
ObjectUpdate,
)
from mixins.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
from core.forms import GroupForm
from core.models import Group
@@ -13,6 +7,7 @@ from core.util import logs
log = logs.get_logger(__name__)
class GroupList(LoginRequiredMixin, ObjectList):
list_template = "partials/group-list.html"
model = Group
@@ -39,4 +34,4 @@ class GroupUpdate(LoginRequiredMixin, ObjectUpdate):
class GroupDelete(LoginRequiredMixin, ObjectDelete):
model = Group
model = Group

View File

@@ -1,12 +1,14 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from mixins.views import AbortSave, ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
from django.db import IntegrityError
from mixins.views import AbortSave, ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
from core.forms import PersonIdentifierForm
from core.models import PersonIdentifier, Person
from core.models import Person, PersonIdentifier
from core.util import logs
log = logs.get_logger(__name__)
class IdentifierPermissionMixin:
def set_extra_args(self, user):
self.extra_permission_args = {
@@ -14,6 +16,7 @@ class IdentifierPermissionMixin:
"person__pk": self.kwargs["person"],
}
class PersonIdentifierList(LoginRequiredMixin, IdentifierPermissionMixin, ObjectList):
list_template = "partials/identifier-list.html"
model = PersonIdentifier
@@ -26,7 +29,9 @@ class PersonIdentifierList(LoginRequiredMixin, IdentifierPermissionMixin, Object
submit_url_args = ["type", "person"]
class PersonIdentifierCreate(LoginRequiredMixin, IdentifierPermissionMixin, ObjectCreate):
class PersonIdentifierCreate(
LoginRequiredMixin, IdentifierPermissionMixin, ObjectCreate
):
model = PersonIdentifier
form_class = PersonIdentifierForm
@@ -52,7 +57,10 @@ class PersonIdentifierCreate(LoginRequiredMixin, IdentifierPermissionMixin, Obje
log.error(f"Person {self.kwargs['person']} does not exist")
raise AbortSave("person does not exist or you don't have access")
class PersonIdentifierUpdate(LoginRequiredMixin, IdentifierPermissionMixin, ObjectUpdate):
class PersonIdentifierUpdate(
LoginRequiredMixin, IdentifierPermissionMixin, ObjectUpdate
):
model = PersonIdentifier
form_class = PersonIdentifierForm
@@ -60,5 +68,7 @@ class PersonIdentifierUpdate(LoginRequiredMixin, IdentifierPermissionMixin, Obje
submit_url_args = ["type", "pk", "person"]
class PersonIdentifierDelete(LoginRequiredMixin, IdentifierPermissionMixin, ObjectDelete):
model = PersonIdentifier
class PersonIdentifierDelete(
LoginRequiredMixin, IdentifierPermissionMixin, ObjectDelete
):
model = PersonIdentifier

View File

@@ -1,11 +1,5 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from mixins.views import (
ObjectCreate,
ObjectDelete,
ObjectList,
ObjectUpdate,
)
from mixins.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
from core.forms import ManipulationForm
from core.models import Manipulation
@@ -13,6 +7,7 @@ from core.util import logs
log = logs.get_logger(__name__)
class ManipulationList(LoginRequiredMixin, ObjectList):
list_template = "partials/manipulation-list.html"
model = Manipulation
@@ -39,4 +34,4 @@ class ManipulationUpdate(LoginRequiredMixin, ObjectUpdate):
class ManipulationDelete(LoginRequiredMixin, ObjectDelete):
model = Manipulation
model = Manipulation

View File

@@ -1,12 +1,14 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from mixins.views import AbortSave, ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
from django.db import IntegrityError
from mixins.views import AbortSave, ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
from core.forms import MessageForm
from core.models import Message
from core.util import logs
log = logs.get_logger(__name__)
class MessagePermissionMixin:
def set_extra_args(self, user):
self.extra_permission_args = {
@@ -14,6 +16,7 @@ class MessagePermissionMixin:
"session__pk": self.kwargs["session"],
}
class MessageList(LoginRequiredMixin, MessagePermissionMixin, ObjectList):
list_template = "partials/message-list.html"
model = Message
@@ -52,6 +55,7 @@ class MessageCreate(LoginRequiredMixin, MessagePermissionMixin, ObjectCreate):
log.error(f"Session {self.kwargs['session']} does not exist")
raise AbortSave("session does not exist or you don't have access")
class MessageUpdate(LoginRequiredMixin, MessagePermissionMixin, ObjectUpdate):
model = Message
form_class = MessageForm
@@ -62,5 +66,3 @@ class MessageUpdate(LoginRequiredMixin, MessagePermissionMixin, ObjectUpdate):
class MessageDelete(LoginRequiredMixin, MessagePermissionMixin, ObjectDelete):
model = Message

View File

@@ -1,11 +1,5 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from mixins.views import (
ObjectCreate,
ObjectDelete,
ObjectList,
ObjectUpdate,
)
from mixins.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
from core.forms import PersonForm
from core.models import Person
@@ -13,11 +7,12 @@ from core.util import logs
log = logs.get_logger(__name__)
class PersonList(LoginRequiredMixin, ObjectList):
list_template = "partials/person-list.html"
model = Person
page_title = "People"
#page_subtitle = "Add times here in order to permit trading."
# page_subtitle = "Add times here in order to permit trading."
list_url_name = "people"
list_url_args = ["type"]

View File

@@ -1,11 +1,5 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from mixins.views import (
ObjectCreate,
ObjectDelete,
ObjectList,
ObjectUpdate,
)
from mixins.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
from core.forms import PersonaForm
from core.models import Persona
@@ -13,6 +7,7 @@ from core.util import logs
log = logs.get_logger(__name__)
class PersonaList(LoginRequiredMixin, ObjectList):
list_template = "partials/persona-list.html"
model = Persona
@@ -39,4 +34,4 @@ class PersonaUpdate(LoginRequiredMixin, ObjectUpdate):
class PersonaDelete(LoginRequiredMixin, ObjectDelete):
model = Persona
model = Persona

View File

@@ -1,56 +1,63 @@
from rest_framework.views import APIView
from asgiref.sync import async_to_sync
from django.contrib.auth.mixins import LoginRequiredMixin
from rest_framework import status
from django.db import transaction
from django.http import HttpResponse
from core.models import QueuedMessage, Message
from mixins.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
from rest_framework import status
from rest_framework.views import APIView
from core.clients import signalapi
from core.forms import QueueForm
from core.models import Message, QueuedMessage
from core.util import logs
import requests
import orjson
from django.conf import settings
import redis
import msgpack
from mixins.views import (
ObjectCreate,
ObjectDelete,
ObjectList,
ObjectUpdate,
)
# def start_typing(uuid):
# url = f"http://signal:8080/v1/typing_indicator/{settings.SIGNAL_NUMBER}"
# data = {
# "recipient": uuid,
# }
# response = requests.put(url, json=data)
# def stop_typing(uuid):
# url = f"http://signal:8080/v1/typing_indicator/{settings.SIGNAL_NUMBER}"
# data = {
# "recipient": uuid,
# }
# response = requests.delete(url, json=data)
r = redis.from_url("unix://var/run/gia-redis.sock", db=10)
log = logs.get_logger("queue")
class AcceptMessageAPI(LoginRequiredMixin, APIView):
def get(self, request, message_id):
to_submit = {
"type": "def",
"method": "accept_message",
"user_id": request.user.id,
"message_id": message_id,
}
packed = msgpack.packb(to_submit, use_bin_type=True)
r.publish("processing", packed)
try:
queued = QueuedMessage.objects.select_related(
"session",
"session__identifier",
"session__user",
).get(
user=request.user,
id=message_id,
)
except QueuedMessage.DoesNotExist:
return HttpResponse(status=status.HTTP_404_NOT_FOUND)
if queued.session.identifier.service != "signal":
log.warning(
"Queue accept failed: unsupported service '%s' for queued message %s",
queued.session.identifier.service,
queued.id,
)
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)
ts = async_to_sync(signalapi.send_message_raw)(
queued.session.identifier.identifier,
queued.text or "",
[],
)
if not ts:
log.error("Queue accept send failed for queued message %s", queued.id)
return HttpResponse(status=status.HTTP_502_BAD_GATEWAY)
with transaction.atomic():
Message.objects.create(
user=queued.session.user,
session=queued.session,
custom_author=queued.custom_author or "BOT",
text=queued.text,
ts=ts,
)
queued.delete()
return HttpResponse(status=status.HTTP_200_OK)
class RejectMessageAPI(LoginRequiredMixin, APIView):
def get(self, request, message_id):
try:
@@ -64,11 +71,12 @@ class RejectMessageAPI(LoginRequiredMixin, APIView):
message.delete()
return HttpResponse(status=status.HTTP_200_OK)
class QueueList(LoginRequiredMixin, ObjectList):
list_template = "partials/queue-list.html"
model = QueuedMessage
page_title = "Queues"
page_title = "Queue"
list_url_name = "queues"
list_url_args = ["type"]

View File

@@ -1,11 +1,5 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from mixins.views import (
ObjectCreate,
ObjectDelete,
ObjectList,
ObjectUpdate,
)
from mixins.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
from core.forms import SessionForm
from core.models import ChatSession
@@ -13,11 +7,12 @@ from core.util import logs
log = logs.get_logger(__name__)
class SessionList(LoginRequiredMixin, ObjectList):
list_template = "partials/session-list.html"
model = ChatSession
page_title = "Chat Sessions"
#page_subtitle = "Add times here in order to permit trading."
# page_subtitle = "Add times here in order to permit trading."
list_url_name = "sessions"
list_url_args = ["type"]
@@ -41,4 +36,3 @@ class SessionUpdate(LoginRequiredMixin, ObjectUpdate):
class SessionDelete(LoginRequiredMixin, ObjectDelete):
model = ChatSession

View File

@@ -1,24 +1,28 @@
from core.views.manage.permissions import SuperUserRequiredMixin
from django.views import View
from django.shortcuts import render
import base64
from core.models import Chat
from mixins.views import ObjectRead, ObjectList
import requests
import orjson
import requests
from django.shortcuts import render
from django.views import View
from mixins.views import ObjectList, ObjectRead
from core.models import Chat
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"
def get(self, request):
return render(request, self.template_name)
class SignalAccounts(SuperUserRequiredMixin, ObjectList):
list_template = "partials/signal-accounts.html"
@@ -36,6 +40,7 @@ class SignalAccounts(SuperUserRequiredMixin, ObjectList):
return accounts
class SignalContactsList(SuperUserRequiredMixin, ObjectList):
list_template = "partials/signal-contacts-list.html"
@@ -45,7 +50,6 @@ class SignalContactsList(SuperUserRequiredMixin, ObjectList):
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
@@ -67,13 +71,14 @@ class SignalContactsList(SuperUserRequiredMixin, ObjectList):
contact["identity"] = identity
obj = {
#"identity": identity,
# "identity": identity,
"contacts": contacts,
}
self.extra_context = {"pretty": list(obj.keys())}
return obj
class SignalChatsList(SuperUserRequiredMixin, ObjectList):
list_template = "partials/signal-chats-list.html"
@@ -82,15 +87,17 @@ class SignalChatsList(SuperUserRequiredMixin, ObjectList):
list_url_name = "signal_chats"
list_url_args = ["type", "pk"]
def get_queryset(self, *args, **kwargs):
pk = self.kwargs.get("pk", "")
object_list = Chat.objects.filter(account=pk)
return object_list
class SignalMessagesList(SuperUserRequiredMixin, ObjectList):
...
class SignalAccountAdd(SuperUserRequiredMixin, CustomObjectRead):
detail_template = "partials/signal-account-add.html"
@@ -107,7 +114,7 @@ class SignalAccountAdd(SuperUserRequiredMixin, CustomObjectRead):
device_name = form_args["device"]
url = f"http://signal:8080/v1/qrcodelink?device_name={device_name}"
response = requests.get(url)
image_bytes = response.content
image_bytes = response.content
base64_image = base64.b64encode(image_bytes).decode("utf-8")
return base64_image
return base64_image

2864
core/views/workspace.py Normal file

File diff suppressed because it is too large Load Diff