#!/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: output

Endorsement 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"
  1. {i}
  2. ") print("
") print("
Telegrammable list") n = 0 for i in nend: print(f"{i},") n += 1 if n % 8 == 0: print("
") print("
") print(out2)