#!/usr/bin/env python3
# Generic aldjango dynamic-form submitter.
# usage: form_submit.py GET_URL POST_URL k1=v1 k2=v2 ...
import sys, re, urllib.request, urllib.parse, http.cookiejar
from html.parser import HTMLParser

GET_URL=sys.argv[1]; POST_URL=sys.argv[2]
overrides={}
for a in sys.argv[3:]:
    k,_,v=a.partition("="); overrides[k]=v

UA="Mozilla/5.0 (X11; Linux x86_64) curl"
cj=http.cookiejar.MozillaCookieJar("/tmp/cj_A.txt"); cj.load(ignore_discard=True,ignore_expires=True)
opener=urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))

def get(url):
    req=urllib.request.Request(url,headers={"User-Agent":UA})
    with opener.open(req,timeout=30) as r: return r.status,r.read().decode("utf-8","replace")

st,html=get(GET_URL)
starts=[m.start() for m in re.finditer(r'<form[^>]*method="post"[^>]*>',html)]
main_start=None
for s in starts:
    tag=html[s:html.find(">",s)+1]
    if 'object-choice' in tag or 'form-search' in tag or 'action="/search/"' in tag: continue
    main_start=s;break
end=html.find("</form>",main_start)
form=html[main_start:end]

class F(HTMLParser):
    def __init__(s):
        super().__init__();s.fields=[];s.sel_name=None;s.cur_sel=None;s.first_opt=None;s.in_ta=False;s.ta_name=None;s.ta_val=""
    def handle_starttag(s,t,a):
        d=dict(a)
        if t=="input":
            n=d.get("name")
            if not n:return
            typ=(d.get("type") or "text").lower()
            if typ in("checkbox","radio"):
                if "checked" in d: s.fields.append((n,d.get("value","on")))
            else: s.fields.append((n,d.get("value","")))
        elif t=="select":
            s.sel_name=d.get("name");s.cur_sel=None;s.first_opt=None
        elif t=="option" and s.sel_name is not None:
            v=d.get("value","")
            if s.first_opt is None:s.first_opt=v
            if "selected" in d:s.cur_sel=v
        elif t=="textarea":
            s.in_ta=True;s.ta_name=d.get("name");s.ta_val=""
    def handle_endtag(s,t):
        if t=="select" and s.sel_name is not None:
            s.fields.append((s.sel_name, s.cur_sel if s.cur_sel is not None else (s.first_opt or "")));s.sel_name=None
        elif t=="textarea" and s.in_ta:
            s.fields.append((s.ta_name,s.ta_val));s.in_ta=False
    def handle_data(s,data):
        if s.in_ta:s.ta_val+=data
p=F();p.feed(form)
d_list=[[n,(v if v is not None else "")] for n,v in p.fields]
def setf(n,v):
    for pr in d_list:
        if pr[0]==n:pr[1]=v;return
    d_list.append([n,v])
for k,v in overrides.items(): setf(k,v)
print("=== submitting to",POST_URL,"===")
for n,v in d_list:
    print(f"  {n} = {v[:50]}")
data=urllib.parse.urlencode([(n,v) for n,v in d_list]).encode()
req=urllib.request.Request(POST_URL,data=data,headers={"User-Agent":UA,"Referer":GET_URL,"Origin":"https://admin.alwaysdata.com","Content-Type":"application/x-www-form-urlencoded"})
try:
    with opener.open(req,timeout=40) as r:
        st=r.status;body=r.read().decode("utf-8","replace");final=r.geturl()
except urllib.error.HTTPError as e:
    st=e.code;body=e.read().decode("utf-8","replace");final=POST_URL
print("POST ->",st,"final:",final)
for m in re.findall(r'(This field is required|Enter a valid|not allowed|forbidden|invalid|private|blocked|error)[^<]{0,90}',body,re.I)[:12]:
    print("  msg:",m.strip())
# save body for id extraction
open("/tmp/lastpost.html","w").write(body)
