#!/usr/bin/python3.9
import requests
from datetime import datetime
import time
import cgi
import cgitb
import requests
from bs4 import BeautifulSoup
cgitb.enable()
# Variables to be received from the form via CGI are:
# region: the name of the region,
# chk = d : check endorsements of delegate
# = n : a specific nation
# nname : the nation in case of n above
# point : whether to only include nations endorsing a particular nation
# (useful when checking for crossing)
# pname : the name of the above "point"
def err(msg: str):
print("
Error
")
print(msg)
print('
New query')
exit()
def get_form() -> tuple :
# returns (region, chk, nname, point, pname).
# If any field is not required, it is set to None.
form = cgi.FieldStorage()
if "region" not in form:
err("Please enter a region and select the required options.")
region = form.getvalue("region")
chk = form.getvalue("chk", "d")
t = (region, chk)
if chk == "n":
if "nname" in form:
nname = form.getvalue("nname")
t += (nname,)
else:
err("Your selected options require you to enter a nation name.")
else: t += (None,)
if "point" in form:
if "pname" in form:
pname = form.getvalue("pname")
t += (True, pname)
else:
err("Your selected options require you to enter a nation name.")
else: t += (False, None)
return t
def get_region(region: str, delegate: bool) -> tuple : # returns (set(nations), [delegate])
namef = region.casefold().replace(' ', '_')
url = f"https://www.nationstates.net/cgi-bin/api.cgi?region={namef}&q=nations+delegate"
req = requests.get(url, headers=headers)
if req.status_code == 404:
err(f"No such region {namef}.")
elif req.status_code == 429:
err("API rate limit hit. Please try after a few minutes.")
req.raise_for_status()
soup = BeautifulSoup(req.text, "xml")
nlist = soup.find("NATIONS").string
if not nlist:
err(f"Empty region {namef}.")
nset = set(nlist.split(":"))
if delegate:
wadel = soup.find("DELEGATE").string
if not wadel or wadel == "0":
err(f"No WA delegate in {namef}.")
else: wadel = None
return (nset, wadel)
def get_endos(nation: str) -> set :
namef = nation.casefold().replace(' ', '_')
url = f"https://www.nationstates.net/cgi-bin/api.cgi?nation={namef}&q=endorsements"
req = requests.get(url, headers=headers)
if req.status_code == 404:
err(f"No such nation {namef}.")
elif req.status_code == 429:
err("API rate limit hit. Please try after a few minutes.")
req.raise_for_status()
soup = BeautifulSoup(req.text, "xml")
elist = soup.find("ENDORSEMENTS").string
if not elist:
err(f"{namef} has no endorsements.")
eset = set(elist.split(','))
return eset
def get_all_was() -> set :
url = "https://www.nationstates.net/cgi-bin/api.cgi?wa=1&q=members"
req = requests.get(url, headers=headers)
if req.status_code == 429:
err("API rate limit hit. Please try after a few minutes.")
req.raise_for_status()
soup = BeautifulSoup(req.text, "xml")
mlist = soup.find("MEMBERS").string
if not mlist:
err("Invalid response from NS API.")
mset = set(mlist.split(','))
return mset
# Get the HTTP headers out
print("Content-Type: text/html")
print()
nt = datetime.utcnow().strftime('%Y-%m-%d at %H:%M:%S UTC')
out1 = f'Merni\'s endorsement checker: outputEndorsement checker: Output
Report generated (start) on {nt}
New query
'
out2 = '
If you get any errors, check your input and try again after a minute or so. If the error persists, contact me (see below).
Script by NationStates user Merni. (Github)
View source with your browser. The script\'s source can be seen here.
Send questions, suggestions, error reports etc. to me through NS telegram (preferred) or at merni dot ns at protonmail dot ch.
Web site hosted for free by HelioHost
Sorry for the 90s appearance, but I have just enough time to get this working without worrying about CSS...
'
headers = {"User-Agent": "Merni's endo checking script: merni.heliohost.org"}
x = get_form()
try:
region, chk, nname, point, pname = x
except:
err(f"All fields not received. Please contact me to report this, with this data: {x}")
print(out1)
time.sleep(1) # very dumb ratelimit safety
if not point:
if chk == "d":
regnations, checknation = get_region(region, True)
elif chk == "n":
regnations = get_region(region, False)[0]
checknation = nname.casefold().replace(' ', '_')
wamembers = get_all_was()
nations = regnations.intersection(wamembers)
else:
nations = get_endos(pname)
if chk == "d":
checknation = get_region(region, True)[1]
elif chk == "n":
checknation = nname.casefold().replace(' ', '_')
endorsers = get_endos(checknation)
nend = nations.difference(endorsers).difference({checknation})
perc = 100 * len(endorsers) / (len(nations) - 1)
print(f"Region: {region}
")
if point:
print(f"Checked: Nations endorsing {pname}
")
else:
print(f"Checked: All WA members in region
")
print(f"Nations checked: {len(nations)}
")
print(f"Nation to endorse: {checknation}
")
print(f"Endorsements: {len(endorsers)}
")
print(f"Missing endorsements: {len(nend)}
")
print(f"% endorsing: {perc:2f}
")
print("List of nations not endorsing:
")
for i in nend:
print(f"- {i}
")
print("
")
print("Telegrammable list
")
n = 0
for i in nend:
print(f"{i},")
n += 1
if n % 8 == 0: print("
")
print(" ")
print(out2)