From a0907ec94df45bd0dec5ee5becad3f50047c9abf Mon Sep 17 00:00:00 2001 From: Andrew Bastien Date: Sat, 25 Nov 2023 18:09:30 -0500 Subject: [PATCH] Improved lock-setting logic to handle empty locks, and allow customizing locks via .create()'s new generate_default_locks --- evennia/accounts/accounts.py | 13 ++-- evennia/locks/lockhandler.py | 11 +++- evennia/objects/objects.py | 124 ++++++++++++++++++++++++++++------- 3 files changed, 118 insertions(+), 30 deletions(-) diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index 1acf45a2f3..8098724347 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -277,6 +277,12 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase): # Used by account.create_character() to choose default typeclass for characters. default_character_typeclass = settings.BASE_CHARACTER_TYPECLASS + lockstring = ( + "examine:perm(Admin);edit:perm(Admin);" + "delete:perm(Admin);boot:perm(Admin);msg:all();" + "noidletimeout:perm(Builder) or perm(noidletimeout)" + ) + # properties @lazy_property def cmdset(self): @@ -1399,12 +1405,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase): """ # A basic security setup - lockstring = ( - "examine:perm(Admin);edit:perm(Admin);" - "delete:perm(Admin);boot:perm(Admin);msg:all();" - "noidletimeout:perm(Builder) or perm(noidletimeout)" - ) - self.locks.add(lockstring) + self.locks.add(self.lockstring) # The ooc account cmdset self.cmdset.add_default(_CMDSET_ACCOUNT, persistent=True) diff --git a/evennia/locks/lockhandler.py b/evennia/locks/lockhandler.py index 29cce23cde..eba0e64509 100644 --- a/evennia/locks/lockhandler.py +++ b/evennia/locks/lockhandler.py @@ -338,9 +338,16 @@ class LockHandler: """ if isinstance(lockstring, str): - lockdefs = lockstring.split(";") + lockdefs = [ + stripped for lockdef in lockstring.split(";") if (stripped := lockdef.strip()) + ] else: - lockdefs = [lockdef for locks in lockstring for lockdef in locks.split(";")] + lockdefs = [ + stripped + for locks in lockstring + for lockdef in locks.split(";") + if (stripped := lockdef.strip()) + ] lockstring = ";".join(lockdefs) err = "" diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 67ee70b9c8..baec752198 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -1010,6 +1010,26 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase): obj.msg(_(string)) obj.move_to(home, move_type="teleport") + @classmethod + def generate_default_locks( + cls, account: "DefaultAccount" = None, caller: "DefaultObject" = None, **kwargs + ): + """ + Classmethod called during .create() to determine default locks for the object. + + Args: + account (Account): Account to attribute this object to. + caller (DefaultObject): The object which is creating this one. + **kwargs: Arbitrary input. + + Returns: + lockstring (str): A lockstring to use for this object. + """ + if cls.lockstring: + account_id = account.id if account else -1 + return cls.lockstring.format(account_id=account_id) + return "" + @classmethod def create( cls, @@ -1058,8 +1078,8 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase): # Create a sane lockstring if one wasn't supplied lockstring = kwargs.get("locks") - if account and not lockstring: - lockstring = cls.lockstring.format(account_id=account.id) + if (account or caller) and not lockstring: + lockstring = cls.generate_default_locks(account=account, caller=caller, **kwargs) kwargs["locks"] = lockstring # Create object @@ -1078,7 +1098,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase): obj.db.desc = desc except Exception as e: - errors.append("An error occurred while creating this '%s' object." % key) + errors.append(f"An error occurred while creating this '{key}' object: {e}") logger.log_err(e) return obj, errors @@ -2503,6 +2523,28 @@ class DefaultCharacter(DefaultObject): "edit:pid({account_id}) or perm(Admin)" ) + @classmethod + def generate_default_locks( + cls, account: "DefaultAccount" = None, caller: "DefaultObject" = None, **kwargs + ): + """ + Classmethod called during .create() to determine default locks for the object. + + Args: + account (Account): Account to attribute this object to. + caller (DefaultObject): The object which is creating this one. + **kwargs: Arbitrary input. + + Returns: + lockstring (str): A lockstring to use for this object. + """ + if cls.lockstring: + account_id = account.id if account else -1 + character = kwargs.get("character", None) + character_id = character.id if character else -1 + return cls.lockstring.format(character_id=character.id, account_id=account_id) + return "" + @classmethod def create(cls, key, account=None, **kwargs): """ @@ -2573,21 +2615,20 @@ class DefaultCharacter(DefaultObject): account.characters.add(obj) # Add locks - if not locks and account: + if not locks: # Allow only the character itself and the creator account to puppet this character # (and Developers). - locks = cls.lockstring.format(character_id=obj.id, account_id=account.id) - elif not locks and not account: - locks = cls.lockstring.format(character_id=obj.id, account_id=-1) + locks = cls.generate_default_locks(account=account, character=obj) - obj.locks.add(locks) + if locks: + obj.locks.add(locks) # If no description is set, set a default description if description or not obj.db.desc: obj.db.desc = description if description else _("This is a character.") except Exception as e: - errors.append(f"An error occurred while creating object '{key} object.") + errors.append(f"An error occurred while creating object '{key} object: {e}") logger.log_err(e) return obj, errors @@ -2793,6 +2834,27 @@ class DefaultRoom(DefaultObject): "edit:id({id}) or perm(Admin)" ) + @classmethod + def generate_default_locks( + cls, account: "DefaultAccount" = None, caller: "DefaultObject" = None, **kwargs + ): + """ + Classmethod called during .create() to determine default locks for the object. + + Args: + account (Account): Account to attribute this object to. + caller (DefaultObject): The object which is creating this one. + **kwargs: Arbitrary input. + + Returns: + lockstring (str): A lockstring to use for this object. + """ + if cls.lockstring: + room = kwargs.get("room") + id = account.id if account else caller.id if caller else room.id + return cls.lockstring.format(id=id) + return "" + @classmethod def create( cls, @@ -2851,12 +2913,10 @@ class DefaultRoom(DefaultObject): obj = create.create_object(**kwargs) # Add locks - if not locks and account: - locks = cls.lockstring.format(id=account.id) - elif not locks and not account: - locks = cls.lockstring.format(id=obj.id) - - obj.locks.add(locks) + if not locks: + locks = cls.generate_default_locks(account=account, caller=caller, room=obj) + if locks: + obj.locks.add(locks) # Record creator id and creation IP if ip: @@ -2869,7 +2929,7 @@ class DefaultRoom(DefaultObject): obj.db.desc = description if description else _("This is a room.") except Exception as e: - errors.append("An error occurred while creating this '%s' object." % key) + errors.append(f"An error occurred while creating this '{key}' object: {e}") logger.log_err(e) return obj, errors @@ -3008,6 +3068,27 @@ class DefaultExit(DefaultObject): # Command hooks + @classmethod + def generate_default_locks( + cls, account: "DefaultAccount" = None, caller: "DefaultObject" = None, **kwargs + ): + """ + Classmethod called during .create() to determine default locks for the object. + + Args: + account (Account): Account to attribute this object to. + caller (DefaultObject): The object which is creating this one. + **kwargs: Arbitrary input. + + Returns: + lockstring (str): A lockstring to use for this object. + """ + if cls.lockstring: + room = kwargs.get("room", None) + id = account.id if account else caller.id if caller else room.id if room else -1 + return cls.lockstring.format(id=id) + return "" + @classmethod def create( cls, @@ -3070,11 +3151,10 @@ class DefaultExit(DefaultObject): obj = create.create_object(**kwargs) # Set appropriate locks - if not locks and account: - locks = cls.lockstring.format(id=account.id) - elif not locks and not account: - locks = cls.lockstring.format(id=obj.id) - obj.locks.add(locks) + if not locks: + locks = cls.generate_default_locks(account=account, caller=caller, exit=obj) + if locks: + obj.locks.add(locks) # Record creator id and creation IP if ip: @@ -3087,7 +3167,7 @@ class DefaultExit(DefaultObject): obj.db.desc = description if description else _("This is an exit.") except Exception as e: - errors.append("An error occurred while creating this '%s' object." % key) + errors.append(f"An error occurred while creating this '{key}' object: {e}") logger.log_err(e) return obj, errors