From 641ea746a5b817a51b643c84e2a68681f4c20a5f Mon Sep 17 00:00:00 2001 From: Griatch Date: Sun, 18 Mar 2018 17:28:52 +0100 Subject: [PATCH] Further stabilizing of spawner storage mechanism and error checking --- evennia/commands/default/building.py | 39 +++++++++++++------ evennia/locks/lockhandler.py | 56 ++++++++++++++++++++++------ evennia/utils/spawner.py | 6 +++ 3 files changed, 79 insertions(+), 22 deletions(-) diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index c2aaa16a4c..94362ec58e 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -2229,12 +2229,15 @@ class CmdExamine(ObjManipCommand): else: things.append(content) if exits: - string += "\n|wExits|n: %s" % ", ".join(["%s(%s)" % (exit.name, exit.dbref) for exit in exits]) + string += "\n|wExits|n: %s" % ", ".join( + ["%s(%s)" % (exit.name, exit.dbref) for exit in exits]) if pobjs: - string += "\n|wCharacters|n: %s" % ", ".join(["|c%s|n(%s)" % (pobj.name, pobj.dbref) for pobj in pobjs]) + string += "\n|wCharacters|n: %s" % ", ".join( + ["|c%s|n(%s)" % (pobj.name, pobj.dbref) for pobj in pobjs]) if things: - string += "\n|wContents|n: %s" % ", ".join(["%s(%s)" % (cont.name, cont.dbref) for cont in obj.contents - if cont not in exits and cont not in pobjs]) + string += "\n|wContents|n: %s" % ", ".join( + ["%s(%s)" % (cont.name, cont.dbref) for cont in obj.contents + if cont not in exits and cont not in pobjs]) separator = "-" * _DEFAULT_WIDTH # output info return '%s\n%s\n%s' % (separator, string.strip(), separator) @@ -2961,9 +2964,6 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS): # handle lhs parts = self.lhs.split(";", 3) - key, desc, tags, lockstring = ( - "", "User-created prototype", ["user-created"], - "edit:id({}) or perm(Admin); use:all()".format(caller.id)) nparts = len(parts) if nparts == 1: key = parts[0].strip() @@ -2971,11 +2971,25 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS): key, desc = (part.strip() for part in parts) elif nparts == 3: key, desc, tags = (part.strip() for part in parts) - tags = [tag.strip().lower() for tag in tags.split(",")] + tags = [tag.strip().lower() for tag in tags.split(",") if tag] else: # lockstrings can itself contain ; key, desc, tags, lockstring = (part.strip() for part in parts) - tags = [tag.strip().lower() for tag in tags.split(",")] + tags = [tag.strip().lower() for tag in tags.split(",") if tag] + if not key: + caller.msg("The prototype must have a key.") + return + if not desc: + desc = "User-created prototype" + if not tags: + tags = ["user"] + if not lockstring: + lockstring = "edit:id({}) or perm(Admin); use:all()".format(caller.id) + + is_valid, err = caller.locks.validate(lockstring) + if not is_valid: + caller.msg("|rLock error|n: {}".format(err)) + return # handle rhs: prototype = _parse_prototype(self.rhs) @@ -3002,7 +3016,11 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS): # all seems ok. Try to save. try: - prot = save_db_prototype(caller, key, prototype, desc=desc, tags=tags, locks=lockstring) + prot = save_db_prototype( + caller, key, prototype, desc=desc, tags=tags, locks=lockstring) + if not prot: + caller.msg("|rError saving:|R {}.|n".format(key)) + return prot.locks.append("edit", "perm(Admin)") if not prot.locks.get("use"): prot.locks.add("use:all()") @@ -3043,7 +3061,6 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS): metaproto = metaprotos[0] if not caller.locks.check_lockstring(caller, metaproto.locks, access_type='use'): caller.msg("You don't have access to use this prototype.") - print("spawning2 {}:{} - {}".format(self.cmdstring, self.args, prototype)) return prototype = metaproto.prototype diff --git a/evennia/locks/lockhandler.py b/evennia/locks/lockhandler.py index 6b1a30ab03..20eb117e42 100644 --- a/evennia/locks/lockhandler.py +++ b/evennia/locks/lockhandler.py @@ -287,7 +287,7 @@ class LockHandler(object): """ self.lock_bypass = hasattr(obj, "is_superuser") and obj.is_superuser - def add(self, lockstring): + def add(self, lockstring, validate_only=False): """ Add a new lockstring to handler. @@ -296,10 +296,12 @@ class LockHandler(object): `":"`. Multiple access types should be separated by semicolon (`;`). Alternatively, a list with lockstrings. - + validate_only (bool, optional): If True, validate the lockstring but + don't actually store it. Returns: success (bool): The outcome of the addition, `False` on - error. + error. If `validate_only` is True, this will be a tuple + (bool, error), for pass/fail and a string error. """ if isinstance(lockstring, basestring): @@ -308,21 +310,41 @@ class LockHandler(object): lockdefs = [lockdef for locks in lockstring for lockdef in locks.split(";")] lockstring = ";".join(lockdefs) + err = "" # sanity checks for lockdef in lockdefs: if ':' not in lockdef: - self._log_error(_("Lock: '%s' contains no colon (:).") % lockdef) - return False + err = _("Lock: '{lockdef}' contains no colon (:).").format(lockdef=lockdef) + if validate_only: + return False, err + else: + self._log_error(err) + return False access_type, rhs = [part.strip() for part in lockdef.split(':', 1)] if not access_type: - self._log_error(_("Lock: '%s' has no access_type (left-side of colon is empty).") % lockdef) - return False + err = _("Lock: '{lockdef}' has no access_type " + "(left-side of colon is empty).").format(lockdef=lockdef) + if validate_only: + return False, err + else: + self._log_error(err) + return False if rhs.count('(') != rhs.count(')'): - self._log_error(_("Lock: '%s' has mismatched parentheses.") % lockdef) - return False + err = _("Lock: '{lockdef}' has mismatched parentheses.").format(lockdef=lockdef) + if validate_only: + return False, err + else: + self._log_error(err) + return False if not _RE_FUNCS.findall(rhs): - self._log_error(_("Lock: '%s' has no valid lock functions.") % lockdef) - return False + err = _("Lock: '{lockdef}' has no valid lock functions.").format(lockdef=lockdef) + if validate_only: + return False, err + else: + self._log_error(err) + return False + if validate_only: + return True, None # get the lock string storage_lockstring = self.obj.lock_storage if storage_lockstring: @@ -334,6 +356,18 @@ class LockHandler(object): self._save_locks() return True + def validate(self, lockstring): + """ + Validate lockstring syntactically, without saving it. + + Args: + lockstring (str): Lockstring to validate. + Returns: + valid (bool): If validation passed or not. + + """ + return self.add(lockstring, validate_only=True) + def replace(self, lockstring): """ Replaces the lockstring entirely. diff --git a/evennia/utils/spawner.py b/evennia/utils/spawner.py index ed92dfadd5..01212a38d4 100644 --- a/evennia/utils/spawner.py +++ b/evennia/utils/spawner.py @@ -197,6 +197,12 @@ def save_db_prototype(caller, key, prototype, desc="", tags=None, locks="", dele key_orig = key key = key.lower() locks = locks if locks else "use:all();edit:id({}) or perm(Admin)".format(caller.id) + + is_valid, err = caller.locks.validate(locks) + if not is_valid: + caller.msg("Lock error: {}".format(err)) + return False + tags = [(tag, "db_prototype") for tag in make_iter(tags)] if key in _MODULE_PROTOTYPES: