#import copy import os #import sys #import base64 #import hashlib import traceback #import re import pprint import docing import filing import lxml.etree as etree from lxml.builder import ElementMaker from anpro import Anpro from nitpo import Nitpo #from sheets import Sheets from profile import Profile from emailer import Emailer from kafik import Kafik from kapro import Kapro from vakis import Vakis from chapro import Chapro from xpaths import Xpaths from surks import Surks from urllib.parse import urlparse, parse_qs class Web(Nitpo): def __init__(self, do_verbose=False): """web class""" super().__init__() self.N = "{%s}" % self.const['ns'] self.E = ElementMaker(nsmap={None: self.const['ns']}) self.env = None #self.sheets = Sheets() self.len_start = 0 if self.has_conf('web', 'pathstart'): self.len_start = len(self.conf['web']['pathstart']) self.diags = [] self.anpro = Anpro(do_verbose=do_verbose) self.surks = Surks(do_verbose=do_verbose) self.a = Kapro() self.p = Profile() self.e = Emailer() self.kafik = Kafik() self.c = Chapro() self.x = Xpaths() # # web element to be transformed self.web_ele = None # # action code from request self.acod = None # # subscription key self.kisu = None # # current file self.fiken = None # # surkof_state self.surkof_multiple = None # # repcodes to work on self.repcodes = [] self.vakis = Vakis() self.do_verbose = do_verbose def logbug(self, string): if not self.is_dev(): return print(string, flush=True) def output(self, env, preps): self.env = env self.preps = preps web_ele = self.E(self.N + 'web') self.web_ele = web_ele # web_doc = etree.ElementTree(web_ele) # sheet_fufi = self.sheets.get_sheet_fufi('web') # changes self.logbug('b4 check') try: self.check_request(env) except Exception: self.web_ele.attrib['error'] = 'system' error_ele = etree.SubElement(self.web_ele, self.N + 'error') lines = traceback.format_exc().split("\n") for line in lines: if line.isspace(): continue line = line.replace(' ', ' ') line_ele = etree.SubElement(error_ele, self.N + 'line') line_ele.text = line self.logbug(docing.show(web_ele)) self.logbug('after check') #if out['status'] == '301': # return out # out = docing.show(web_ele) web_doc = etree.ElementTree(web_ele) if self.is_dev: etree.cleanup_namespaces(web_doc) etree.register_namespace("n", self.const['ns']) out = etree.tostring(web_doc, pretty_print=True).decode() filing.srite('/tmp/web.xml', out, do_verbose=self.do_verbose) out = str(preps['sheets']['web'](web_doc)) return out def check_request(self, env): self.fiken = None raw_uri = env['RAW_URI'] full_uri = env['RAW_URI'] if raw_uri.startswith('//'): # # add the pathstart if self.has_conf('web', 'pathstart'): full_uri = self.conf['web']['pathstart'] + '/' \ + raw_uri[2:] self.web_ele.attrib['raw_uri'] = raw_uri # if not self.preps['res']['url_u'].match(raw_uri): if not self.preps['res']['url'].match(raw_uri): self.web_ele.attrib['status'] = '400' self.web_ele.attrib['error'] = 'wrong_url' self.web_ele.attrib['arger'] = raw_uri self.logbug('bad url ' + raw_uri) self.logbug(self.preps['res']['url']) return key = raw_uri[4:26] self.acod = raw_uri[2:3] if self.acod == 'u': self.deal_u(env, key) if self.acod == 'w': self.deal_w(env, key) def deal_w(self, env, chaid): """work on rewinds""" asar = self.c.get_asar() self.web_ele.attrib['chaid'] = chaid if chaid not in asar: self.web_ele.attrib['status'] = '200' self.web_ele.attrib['error'] = 'unknown_chaid' self.web_ele.attrib['arger'] = chaid return fufi = asar[chaid] ## if it has dealt with, the target is gzipped if not os.path.isfile(fufi) and os.path.isfile(fufi + '.gz'): self.web_ele.attrib['status'] = '200' self.web_ele.attrib['error'] = 'processed_chaid' if chaid in self.preps['events']: self.web_ele.attrib['event'] = self.preps['events'][chaid] self.web_ele.attrib['arger'] = chaid return web_doc = filing.parse_lax(fufi) if web_doc is None: self.web_ele.attrib['status'] = '200' self.web_ele.attrib['error'] = 'broken_chaid' self.web_ele.attrib['arger'] = chaid return xp = '/n:web/n:profile[1]' profile_ele = self.x.none_or_one(web_doc, xp) ## to report the time of the date of last profile change self.web_ele.attrib['dalacha'] = self.surks.get_dalacha(profile_ele) profile_doc = etree.ElementTree(profile_ele) fufi = self.p.fufi_from_doc(profile_doc) self.p.write(profile_doc) timeset = self.c.read_timeset(web_doc) os.utime(fufi, timeset) self.c.clear(chaid) ## send the user a profile announcement self.anpro.from_doc(profile_doc, source='terew') return fufi def deal_u(self, env, kisu): self.web_ele.attrib['kisu'] = kisu if kisu not in self.preps['vakis']: # # load by adding kisus to the memory stock # # problem, if we are bombarded by request for an invalid # # kisu, loading will take time and could lead to problems # # thus, it is prudent to introduce a maximum if kisu not in self.preps['count_reload_vakis']: self.preps['count_reload_vakis'][kisu] = 0 self.preps['count_reload_vakis'][kisu] += 1 # # should be configurable but it's hard to describe if self.preps['count_reload_vakis'][kisu] < 100: self.logbug('reload vakis to find ' + kisu + ' ' + str(self.preps['count_reload_vakis'][kisu])) filing.add(self.conf['files']['vakis'], self.preps['vakis']) else: self.logbug('no reload for ' + kisu) if kisu not in self.preps['vakis']: self.web_ele.attrib['status'] = '200' self.web_ele.attrib['error'] = 'unknown_kisu' self.web_ele.attrib['arger'] = kisu self.logbug('bad kisu ' + kisu) return self.kisu = kisu self.logbug('work on ' + kisu) subda = self.preps['vakis'][kisu] self.logbug(str(subda)) emad = subda['emad'] self.web_ele.attrib['emad'] = emad repcode = subda['repcode'] self.web_ele.attrib['repcode'] = repcode query_string = env['QUERY_STRING'] if len(query_string) > 0 and self.acod == 'u': self.parse_query_u(env) fufi = self.p.fufi_from_emad(emad) self.web_ele.attrib['fufi'] = fufi # # suggested fiken to put into the form sugfik = filing.md5(fufi) self.web_ele.attrib['prop_fiken'] = sugfik self.logbug(sugfik) if not os.path.isfile(fufi): print(f"web does not see {fufi}") #if not os.path.isfile(fufi): # # well reads the file twice sub_doc = filing.parse_lax(fufi) ## if there no live subscription of the prime repcode, ## create a failure ele if not self.p.s.has_it_live(sub_doc, repcode): failure_ele = etree.SubElement(self.web_ele, self.N + 'failure') failure_ele.attrib['type'] = 'already_gone' repcode_ele = etree.SubElement(failure_ele, self.N + 'repcode') repcode_ele.text = repcode emad_ele = etree.SubElement(failure_ele, self.N + 'emad') emad_ele.text = emad froom = self.p.s.birth_datim(sub_doc, repcode) from_ele = etree.SubElement(failure_ele, self.N + 'from') from_ele.text = froom return self.web_ele.append(sub_doc.getroot()) if self.fiken is not None: self.web_ele.attrib['fiken'] = self.fiken self.logbug(docing.show(self.web_ele)) self.deal_with_fiken(env) return ## as long as one repcode is alive, just reports all that have ## something unsubed def deal_with_fiken(self, env): """deals with the request, really""" subda = self.preps['vakis'][self.kisu] emad = subda['emad'] untils = {} frooms = {} repcodes = self.repcodes if not self.kafik.is_correct(self.fiken, emad): # # this should show the surkof form again return # # should not load here, but ok doc = self.p.load(emad) ### etree.SubElement(self.web_ele, doc) self.web_ele.append(doc.getroot()) for repcode in repcodes: self.logbug(f"I look at {repcode}") if not self.p.s.has_it_live(doc, repcode): ## a cumbersome way to produce verbiage like ## at time yyyy-mm-ddTHH:MM:SS, I deleted recodes a, b and c ## delete_report checks this, we do it here for information ## we need to set the doc, as death_datim uses it until = self.p.s.death_datim(doc, repcode) if until is None: self.logbug(f"Bummer! No until= for {repcode}.") continue if until not in untils: untils[until] = [] untils[until].append(repcode) else: ## about to be deleted froom = self.p.s.birth_datim(doc, repcode) ## a cumbersome way to produce verbiage like ## since yyyy-mm-ddTHH:MM:SS you have been a member of recodes a, b and c if froom is None: self.logbug(f"Bummer! No from= for {repcode}.") continue if froom not in frooms: frooms[froom] = [] frooms[froom].append(repcode) doc = self.p.delete_report(emad, repcode, doc=doc, dont_write=True) ## better to remove it straight from the kapro self.a.delete(repcode, emad) # etree.SubElement(self.web_ele, doc) # looser: reports that are deleted now losers = sorted(frooms.keys()) losers_ele = etree.SubElement(self.web_ele, self.N + 'losers') for froom in losers: loser_ele = etree.SubElement(losers_ele, self.N + 'loser') loser_ele.attrib['from'] = froom for repcode in frooms[froom]: report_ele = etree.SubElement(loser_ele, self.N + 'repcode') report_ele.text = repcode ## goners: reports that were deleted before goners = sorted(untils.keys()) goners_ele = etree.SubElement(self.web_ele, self.N + 'goners') for until in goners: goner_ele = etree.SubElement(goners_ele, self.N + 'goner') goner_ele.attrib['until'] = until for repcode in untils[until]: report_ele = etree.SubElement(goner_ele, self.N + 'repcode') report_ele.text = repcode for goner in goners: goner_ele = etree.SubElement(goners_ele, self.N + 'goner') goner_ele.attrib['until'] = until for repcode in untils[until]: report_ele = etree.SubElement(goner_ele, self.N + 'repcode') report_ele.text = repcode if len(losers) > 0: chapro_fufi = self.c.dump(self.web_ele, emad=emad) token = self.c.token(chapro_fufi) self.preps['events']['token'] = self.now() chapro_doc = etree.ElementTree(self.web_ele) ## send the temptation to rewind 'terew' self.e.web(chapro_fufi, chapro_doc, 'terew', self.preps) self.logbug(f"I write {chapro_fufi}") ## write the changed profile self.p.write(doc) return self.web_ele def write_web(self): doc = self.web_ele if 'fiken' not in self.web_ele.attrib: return fiken = self.web_ele.arr def parse_query_u(self, env): self.repcodes = [] query_string = env['QUERY_STRING'] self.web_ele.attrib['query_string'] = query_string query = parse_qs(query_string) query_ele = etree.SubElement(self.web_ele, self.N + 'query') for name in query: for value in query[name]: name_ele = etree.SubElement(query_ele, self.N + name) name_ele.text = value if name == 'fiken': # # this triggers treatment as as response self.web_ele.attrib['fiken'] = value self.fiken = value continue if name.startswith('check_') and value == 'on': repcode = name[6:] self.repcodes.append(repcode) action_ele = etree.SubElement(self.web_ele, self.N + 'action') action_ele.text = repcode continue if name.startswith('sign_multi'): ## the multiple signoff case sign_multi_ele = etree.SubElement(self.web_ele, self.N + 'sign_multi') sign_multi_ele.text = value continue if name.startswith('not_really'): ## the single signoff case continue if name.startswith('sign_multi'): continue print(f"I don't know about {name}", flush=True)