38775-vm/core/views.py
2026-02-26 00:24:17 +00:00

113 lines
4.1 KiB
Python

import json
import os
import platform
from django.http import JsonResponse, HttpResponse
from django.shortcuts import render, get_object_or_404
from django.utils import timezone
from django.views.decorators.csrf import csrf_exempt
from asgiref.sync import sync_to_async
from .models import MCPToolRequest, HumanResponse, SlackSettings
from .mcp import handle_mcp_request
@csrf_exempt
async def mcp_endpoint(request):
"""
Main entry point for MCP clients via HTTP.
Accepts JSON-RPC 2.0 payloads.
"""
if request.method != "POST":
return JsonResponse({"error": "Method not allowed"}, status=405)
body = request.body.decode("utf-8")
response_data = await handle_mcp_request(body)
if response_data is None:
return HttpResponse(status=204)
return JsonResponse(response_data)
def dashboard(request):
"""
Polished landing page showing active server status and recent logs.
"""
requests_list = MCPToolRequest.objects.all().order_by('-created_at')[:20]
# Slack config check
slack_token = os.getenv("SLACK_BOT_TOKEN")
if not slack_token:
config = SlackSettings.objects.first()
if config and config.bot_token:
slack_token = config.bot_token
is_slack_configured = bool(slack_token)
context = {
"is_slack_configured": is_slack_configured,
"requests": requests_list,
"django_version": platform.python_version(),
"now": timezone.now(),
"server_status": "ONLINE" if is_slack_configured else "CONFIG_PENDING"
}
return render(request, "core/index.html", context)
@csrf_exempt
def slack_webhook(request):
"""
Slack Event API Webhook.
Captures threaded replies and saves them as HumanResponse.
"""
if request.method == "POST":
try:
data = json.loads(request.body)
# 1. Verification Challenge
if data.get("type") == "url_verification":
return JsonResponse({"challenge": data.get("challenge")})
# 2. Event Callback
if data.get("type") == "event_callback":
event = data.get("event", {})
# We only care about user messages (no bot_id) in threads (has thread_ts)
if event.get("type") == "message" and not event.get("bot_id"):
thread_ts = event.get("thread_ts")
text = event.get("text", "")
user_id = event.get("user", "Unknown User")
# Basic extraction
user_name = user_id
files = event.get("files", [])
file_url = None
if files:
file_url = files[0].get("url_private", "")
if thread_ts:
# Find the corresponding tool request
mcp_request = MCPToolRequest.objects.filter(slack_ts=thread_ts).first()
if mcp_request:
# Avoid duplicate responses if Slack retries
# We can just check if we already have this text/user in last 10 seconds, or just save it
HumanResponse.objects.create(
request=mcp_request,
text=text,
user_name=user_name,
file_url=file_url
)
return HttpResponse("Created", status=201)
except Exception as e:
print("Webhook error:", e)
return HttpResponse("Error", status=400)
return HttpResponse("OK")
def request_detail(request, pk):
"""Detailed view of a single tool call."""
tool_request = get_object_or_404(MCPToolRequest, pk=pk)
responses = tool_request.responses.all().order_by('-created_at')
return render(request, "core/request_detail.html", {
"req": tool_request,
"responses": responses
})