Ekaropolus 7e135e92ba
All checks were successful
continuous-integration/drone/push Build is passing
Bot Reply template
2025-09-17 00:20:26 -06:00

118 lines
4.2 KiB
Python

# pxy_bots/api/views.py
import json
from django.http import JsonResponse, HttpResponse
from django.views.decorators.csrf import csrf_exempt
def health(request):
return JsonResponse({"ok": True, "service": "pxy_bots", "schema_ready": ["req.v1", "render.v1"]})
@csrf_exempt
def echo_render(request):
try:
data = json.loads(request.body.decode("utf-8") or "{}")
except Exception:
data = {}
text = (((data.get("input") or {}).get("text")) or "Hola 👋")
who = (((data.get("user") or {}).get("id")) or "user")
cmd = (((data.get("command") or {}).get("name")) or "none")
spec = {
"schema_version": "render.v1",
"messages": [
{"type": "text", "text": f"echo: user={who} cmd={cmd}"},
{"type": "text", "text": f"you said: {text}"},
],
}
return JsonResponse(spec)
# pxy_bots/api/views.py
import json, string
from django.http import JsonResponse, HttpResponseBadRequest
from django.views.decorators.csrf import csrf_exempt
from pxy_bots.models import TelegramBot, BotReplyTemplate
def _ctx_from_req(req):
inp = (req.get("input") or {})
loc = inp.get("location") or {}
args_raw = (inp.get("args_raw") or "") or (inp.get("text") or "") or ""
# Strip /cmd if present for ${args}
if args_raw.startswith("/"):
parts = args_raw.split(" ", 1)
args_raw = parts[1] if len(parts) > 1 else ""
return {
"user_id": ((req.get("user") or {}).get("id")),
"chat_id": ((req.get("chat") or {}).get("id")),
"cmd": ((req.get("command") or {}).get("name")),
"trigger": ((req.get("command") or {}).get("trigger")),
"text": (inp.get("text") or ""),
"caption": (inp.get("caption") or ""),
"args": args_raw,
"lat": loc.get("lat"),
"lon": loc.get("lon"),
}
def _choose_template(bot, trigger, cmd):
qs = (BotReplyTemplate.objects
.filter(bot=bot, enabled=True, trigger=trigger)
.order_by("priority", "id"))
t = (qs.filter(command_name=(cmd or None)).first()
or qs.filter(command_name__isnull=True).first()
or qs.filter(command_name="").first())
return t
@csrf_exempt
def template_reply(request):
if request.method != "POST":
return HttpResponseBadRequest("POST only")
try:
req = json.loads(request.body.decode("utf-8") or "{}")
except Exception:
return HttpResponseBadRequest("invalid json")
bot_name = ((req.get("bot") or {}).get("username"))
if not bot_name:
return HttpResponseBadRequest("missing bot.username")
bot = TelegramBot.objects.filter(name=bot_name, is_active=True).first() \
or TelegramBot.objects.filter(username=bot_name, is_active=True).first()
if not bot:
return HttpResponseBadRequest("bot not found")
trigger = ((req.get("command") or {}).get("trigger")) or "message"
cmd = ((req.get("command") or {}).get("name") or "")
cmd = cmd.strip().lstrip("/").lower() or None
tpl = _choose_template(bot, trigger, cmd)
if not tpl:
# Soft fallback to help you see wiring issues
return JsonResponse({
"schema_version": "render.v1",
"messages": [{"type": "text",
"text": f"(no template) bot={bot_name} trigger={trigger} cmd={cmd or '(default)'}"}]
})
ctx = _ctx_from_req(req)
text = string.Template(tpl.text_template or "").safe_substitute(**{k:("" if v is None else v) for k,v in ctx.items()})
msg_list = []
if tpl.media_url:
# If media present, put text in caption; otherwise plain text message
if text.strip():
msg_list.append({"type": "photo", "media_url": tpl.media_url,
"caption": text, "parse_mode": tpl.parse_mode.upper() if tpl.parse_mode!="none" else None})
else:
msg_list.append({"type": "photo", "media_url": tpl.media_url})
if (not tpl.media_url) and text.strip():
msg = {"type": "text", "text": text}
if tpl.parse_mode != BotReplyTemplate.PARSE_NONE:
msg["parse_mode"] = tpl.parse_mode.upper()
msg_list.append(msg)
spec = {"schema_version": "render.v1", "messages": msg_list}
btns = tpl.buttons()
if btns:
spec["buttons"] = btns
return JsonResponse(spec)