def check_user(site: str, user: str, sig: str = "") -> UserCheck: validate_username(user) errors: Set[Result] = set() failure = None html_sig = "" if site not in datasources.get_sitematrix(): flask.abort(404) sitedata = datasources.get_site_data(site) dbname = sitedata.dbname user = (user[0].upper() + user[1:]).replace("_", " ") if not sig: # signature not supplied, get data from database user_props = datasources.get_user_properties(user, dbname) logger.debug(user_props) if not user_props.nickname: # user does not exist or uses default sig if not datasources.check_user_exists(user, sitedata): # user does not exist errors.add(WebAppMessage.USER_DOES_NOT_EXIST) failure = True else: # user exists but uses default signature errors.add(WebAppMessage.DEFAULT_SIG) sig = get_default_sig(site, user, user) failure = False elif not user_props.fancysig: # user exists but uses non-fancy sig with nickname errors.add(WebAppMessage.SIG_NOT_FANCY) sig = get_default_sig(site, user, user_props.nickname) failure = False else: # user exists and has custom fancy sig, check it sig = user_props.nickname if failure is None: # OK so far, actually check the signature errors = cast(Set[Result], sigprobs.check_sig(user, sig, sitedata, site)) html_sig = get_rendered_sig(site, sigprobs.evaluate_subst(sig, sitedata)) logger.debug(errors) if not errors: # check returned no errors errors.add(WebAppMessage.NO_ERRORS) failure = False data = UserCheck( site=site, username=user, errors=list(errors), signature=sig, failure=failure, html_sig=html_sig, ) return data
def sitedata(site): data = datasources.get_site_data(site["domain"]) return data
def main( hostname: str, lastedit: Optional[str] = None, days: int = 30, checks: datatypes.Checks = datatypes.Checks.DEFAULT, data: Optional[Union[Dict[str, str], List[str]]] = None, ) -> Optional[Dict]: """Site-level report mode: Iterate over signatures and check for errors""" logger.info(f"Processing signatures for {hostname}") total = 0 sitedata = datasources.get_site_data(hostname) dbname = sitedata.dbname if data is None: sigsource = datasources.iter_active_user_sigs(dbname, lastedit, days) elif isinstance(data, list): sigsource = datasources.iter_listed_user_sigs(data, dbname) elif isinstance(data, dict): sigsource = data.items() # type: ignore else: raise TypeError( "Data is of type %s when None, list, or dict expected" % (type(data)) ) resultdata: Dict[str, Dict[str, Union[str, List[SigError]]]] = {} accumulate = {} for user, sig in sigsource: total += 1 if not sig: continue try: errors = check_sig( user, sig, sitedata, hostname, checks=checks ^ Checks.LINT ) if SigError.PLAIN_FANCY_SIG not in errors: accumulate[user] = sig except Exception: logger.error(f"Processing User:{user}: {sig}") raise if errors: resultdata[user] = {"signature": sig, "errors": list(errors)} # Batch requests to lint, since network requests are slow # There is probably a better way to do this with async, but # that's more work. if len(accumulate) >= 5: accumulate, resultdata = batch_check_lint( accumulate, resultdata, hostname, checks ) # Catch any sigs that didn't get linted if accumulate: accumulate, resultdata = batch_check_lint( accumulate, resultdata, hostname, checks ) # Collect stats, and generate json file stats = {} stats["total"] = len(resultdata) for user, line in resultdata.items(): line["errors"] = [error.value for error in cast(List[SigError], line["errors"])] for error in line.get("errors", []): stats[error] = stats.setdefault(error, 0) + 1 meta = {"last_update": datetime.datetime.utcnow().isoformat(), "site": hostname} if lastedit: meta["active_since"] = datetime.datetime.strptime( lastedit, "%Y%m%d%H%M%S" ).isoformat() else: meta["active_since"] = ( datetime.datetime.utcnow() - datetime.timedelta(days=days) ).isoformat() outdata = { "errors": stats, "meta": meta, "sigs": {key: resultdata[key] for key in sorted(resultdata)}, } return outdata