From c5e0c2321b3e54ccd3661787a35d09fab772eb4c Mon Sep 17 00:00:00 2001 From: arumford Date: Wed, 7 Feb 2018 14:22:38 -0600 Subject: [PATCH 01/29] typo in docstring. --- evennia/comms/channelhandler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evennia/comms/channelhandler.py b/evennia/comms/channelhandler.py index 02c9e19291..058b7d9ba4 100644 --- a/evennia/comms/channelhandler.py +++ b/evennia/comms/channelhandler.py @@ -159,7 +159,7 @@ class ChannelHandler(object): """ The ChannelHandler manages all active in-game channels and dynamically creates channel commands for users so that they can - just give the channek's key or alias to write to it. Whenever a + just give the channel's key or alias to write to it. Whenever a new channel is created in the database, the update() method on this handler must be called to sync it with the database (this is done automatically if creating the channel with From 11c9d60111076d7b44ae44d4baf2121136dc66c4 Mon Sep 17 00:00:00 2001 From: Nicholas Matlaga Date: Tue, 13 Feb 2018 12:49:55 -0500 Subject: [PATCH 02/29] Change if statement to better handle objects; move options dict before at_msg_receive call to allow channels to be known in hook --- evennia/comms/models.py | 4 +--- evennia/objects/objects.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/evennia/comms/models.py b/evennia/comms/models.py index b1a5a37ed9..c358cf352b 100644 --- a/evennia/comms/models.py +++ b/evennia/comms/models.py @@ -584,9 +584,7 @@ class SubscriptionHandler(object): for obj in self.all(): from django.core.exceptions import ObjectDoesNotExist try: - if hasattr(obj, 'account'): - if not obj.account: - continue + if hasattr(obj, 'account') and obj.account: obj = obj.account if not obj.is_connected: continue diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 5531b7f856..b55cd0962f 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -519,6 +519,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): obj.at_msg_send(text=text, to_obj=self, **kwargs) except Exception: logger.log_trace() + kwargs["options"] = options try: if not self.at_msg_receive(text=text, **kwargs): # if at_msg_receive returns false, we abort message to this object @@ -526,7 +527,6 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): except Exception: logger.log_trace() - kwargs["options"] = options if text and not (isinstance(text, basestring) or isinstance(text, tuple)): # sanitize text before sending across the wire From fad008d66024267e683e14d16e1c8358d3287622 Mon Sep 17 00:00:00 2001 From: Nicholas Matlaga Date: Tue, 13 Feb 2018 12:54:03 -0500 Subject: [PATCH 03/29] add in is_connected property to base objects --- evennia/objects/objects.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index b55cd0962f..d4ce390977 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -206,6 +206,14 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): def sessions(self): return ObjectSessionHandler(self) + @property + def is_connected(self): + # we get an error for objects subscribed to channels without this + if self.account: # seems sane to pass on the account + return self.account.is_connected + else: + return False + @property def has_account(self): """ From 9d3d627e220ad054e728884b36038bd3d5014b2d Mon Sep 17 00:00:00 2001 From: Griatch Date: Wed, 21 Feb 2018 20:18:33 +0100 Subject: [PATCH 04/29] Catch the case of a prematurely deleted guest account. Resolves #1500. --- evennia/typeclasses/attributes.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/evennia/typeclasses/attributes.py b/evennia/typeclasses/attributes.py index 84a21c0c27..3f8b4cd742 100644 --- a/evennia/typeclasses/attributes.py +++ b/evennia/typeclasses/attributes.py @@ -282,6 +282,8 @@ class AttributeHandler(object): "attribute__db_attrtype": self._attrtype, "attribute__db_key__iexact": key.lower(), "attribute__db_category__iexact": category.lower() if category else None} + if not self.obj.pk: + return [] conn = getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) if conn: attr = conn[0].attribute From 6101ee0a1cc83db86be155ddfbfe4a92fb07a41b Mon Sep 17 00:00:00 2001 From: Griatch Date: Wed, 21 Feb 2018 20:34:29 +0100 Subject: [PATCH 05/29] Add warning if Favico.js library is not reachable --- evennia/web/webclient/templates/webclient/base.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/evennia/web/webclient/templates/webclient/base.html b/evennia/web/webclient/templates/webclient/base.html index 373ff0f357..f5f47b230f 100644 --- a/evennia/web/webclient/templates/webclient/base.html +++ b/evennia/web/webclient/templates/webclient/base.html @@ -25,7 +25,7 @@ JQuery available. @@ -57,6 +57,12 @@ JQuery available. {% endblock %} + + From 5b96b09bcafd682542def7b14824dc5f63578251 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 1 Mar 2018 20:13:36 +0100 Subject: [PATCH 06/29] Fix bug in accessing attribute through manager --- evennia/typeclasses/managers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/evennia/typeclasses/managers.py b/evennia/typeclasses/managers.py index 11a84f275a..ed61154e7f 100644 --- a/evennia/typeclasses/managers.py +++ b/evennia/typeclasses/managers.py @@ -8,6 +8,8 @@ import shlex from django.db.models import Q from evennia.utils import idmapper from evennia.utils.utils import make_iter, variable_from_module, to_unicode +from evennia.typeclasses.attributes import Attribute +from evennia.typeclasses.tags import Tag __all__ = ("TypedObjectManager", ) _GA = object.__getattribute__ @@ -56,7 +58,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager): dbmodel = self.model.__dbclass__.__name__.lower() query = [("attribute__db_attrtype", attrtype), ("attribute__db_model", dbmodel)] if obj: - query.append(("%s__id" % self.model.__name__.lower(), obj.id)) + query.append(("%s__id" % self.model.__dbclass__.__name__.lower(), obj.id)) if key: query.append(("attribute__db_key", key)) if category: From aa9663024c7880f7354ecaf81b41448224128cb3 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 1 Mar 2018 20:23:18 +0100 Subject: [PATCH 07/29] Make desc/set abide by edit/control locks --- evennia/commands/default/building.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index ebd8f66871..c87ffaaedc 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -568,6 +568,9 @@ class CmdDesc(COMMAND_DEFAULT_CLASS): if not obj: return + if not (obj.access(self.caller, 'control') or obj.access(self.caller, 'edit')): + self.caller.msg("You don't have permission to edit the description of %s." % obj.key) + self.caller.db.evmenu_target = obj # launch the editor EvEditor(self.caller, loadfunc=_desc_load, savefunc=_desc_save, @@ -597,7 +600,7 @@ class CmdDesc(COMMAND_DEFAULT_CLASS): if not obj: return desc = self.args - if obj.access(caller, "edit"): + if (obj.access(self.caller, 'control') or obj.access(self.caller, 'edit')): obj.db.desc = desc caller.msg("The description was set on %s." % obj.get_display_name(caller)) else: @@ -1581,6 +1584,10 @@ class CmdSetAttribute(ObjManipCommand): result = [] if "edit" in self.switches: # edit in the line editor + if not (obj.access(self.caller, 'control') or obj.access(self.caller, 'edit')): + caller.msg("You don't have permission to edit %s." % obj.key) + return + if len(attrs) > 1: caller.msg("The Line editor can only be applied " "to one attribute at a time.") @@ -1601,12 +1608,18 @@ class CmdSetAttribute(ObjManipCommand): return else: # deleting the attribute(s) + if not (obj.access(self.caller, 'control') or obj.access(self.caller, 'edit')): + caller.msg("You don't have permission to edit %s." % obj.key) + return for attr in attrs: if not self.check_attr(obj, attr): continue result.append(self.rm_attr(obj, attr)) else: # setting attribute(s). Make sure to convert to real Python type before saving. + if not (obj.access(self.caller, 'control') or obj.access(self.caller, 'edit')): + caller.msg("You don't have permission to edit %s." % obj.key) + return for attr in attrs: if not self.check_attr(obj, attr): continue From 1f1b3552634b9cd1cc8a3b517a0b1b142e853f70 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 1 Mar 2018 20:53:20 +0100 Subject: [PATCH 08/29] Don't allow those with 'edit' access to obj to change the 'control' lock. --- evennia/commands/default/building.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index c87ffaaedc..7085ce2f98 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -1853,9 +1853,16 @@ class CmdLock(ObjManipCommand): obj = caller.search(objname) if not obj: return - if not (obj.access(caller, 'control') or obj.access(caller, "edit")): + has_control_access = obj.access(caller, 'control') + if access_type == 'control' and not has_control_access: + # only allow to change 'control' access if you have 'control' access already + caller.msg("You need 'control' access to change this type of lock.") + return + + if not has_control_access or obj.access(caller, "edit"): caller.msg("You are not allowed to do that.") return + lockdef = obj.locks.get(access_type) if lockdef: From 047e9f619a303b7b8db8a2248a74731044150f07 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 1 Mar 2018 21:56:40 +0100 Subject: [PATCH 09/29] Make get_attribute/tag manager methods return querysets --- evennia/typeclasses/managers.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/evennia/typeclasses/managers.py b/evennia/typeclasses/managers.py index ed61154e7f..358066e3f1 100644 --- a/evennia/typeclasses/managers.py +++ b/evennia/typeclasses/managers.py @@ -68,7 +68,9 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager): elif value: # strvalue and value are mutually exclusive query.append(("attribute__db_value", value)) - return [th.attribute for th in self.model.db_attributes.through.objects.filter(**dict(query))] + return Attribute.objects.filter( + pk__in=self.model.db_attributes.through.objects.filter( + **dict(query)).values_list("attribute_id", flat=True)) def get_nick(self, key=None, category=None, value=None, strvalue=None, obj=None): """ @@ -190,7 +192,9 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager): query.append(("tag__db_key", key)) if category: query.append(("tag__db_category", category)) - return [th.tag for th in self.model.db_tags.through.objects.filter(**dict(query))] + return Tag.objects.filter( + pk__in=self.model.db_tags.through.objects.filter( + **dict(query)).values_list("tag_id", flat=True)) def get_permission(self, key=None, category=None, obj=None): """ From 71b6e6cdeaa610fb58ebc6e4101f5c60e11aa899 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 1 Mar 2018 22:21:22 +0100 Subject: [PATCH 10/29] Remove mutual exclusivity between value/strvalue when searching for Attributes with manager --- evennia/typeclasses/managers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evennia/typeclasses/managers.py b/evennia/typeclasses/managers.py index 358066e3f1..e6ef778eb8 100644 --- a/evennia/typeclasses/managers.py +++ b/evennia/typeclasses/managers.py @@ -65,8 +65,8 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager): query.append(("attribute__db_category", category)) if strvalue: query.append(("attribute__db_strvalue", strvalue)) - elif value: - # strvalue and value are mutually exclusive + if value: + # no reason to make strvalue/value mutually exclusive at this level query.append(("attribute__db_value", value)) return Attribute.objects.filter( pk__in=self.model.db_attributes.through.objects.filter( From 223648782fd55d6f9bcf3564514e8046fabf1aa0 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 3 Mar 2018 10:12:34 +0100 Subject: [PATCH 11/29] Allow nick command to list individual nicks --- evennia/commands/default/general.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/evennia/commands/default/general.py b/evennia/commands/default/general.py index ff377119fa..2f4c51a227 100644 --- a/evennia/commands/default/general.py +++ b/evennia/commands/default/general.py @@ -145,8 +145,9 @@ class CmdNick(COMMAND_DEFAULT_CLASS): caller = self.caller account = self.caller.account or caller switches = self.switches - nicktypes = [switch for switch in switches if switch in ( - "object", "account", "inputline")] or ["inputline"] + nicktypes = [switch for switch in switches if switch in ("object", "account", "inputline")] + specified_nicktype = bool(nicktypes) + nicktypes = nicktypes if specified_nicktype else ["inputline"] nicklist = (utils.make_iter(caller.nicks.get(category="inputline", return_obj=True) or []) + utils.make_iter(caller.nicks.get(category="object", return_obj=True) or []) + @@ -197,6 +198,28 @@ class CmdNick(COMMAND_DEFAULT_CLASS): nicktypestr, old_nickstring, old_replstring)) return + if not self.rhs and self.lhs: + # check what a nick is set to + strings = [] + if not specified_nicktype: + nicktypes = ("object", "account", "inputline") + for nicktype in nicktypes: + if nicktype == "account": + obj = account + else: + obj = caller + nicks = utils.make_iter(obj.nicks.get(category=nicktype, return_obj=True)) + for nick in nicks: + _, _, nick, repl = nick.value + if nick.startswith(self.lhs): + strings.append("{}-nick: '{}' -> '{}'".format( + nicktype.capitalize(), nick, repl)) + if strings: + caller.msg("\n".join(strings)) + else: + caller.msg("No nicks found matching '{}'".format(self.lhs)) + return + if not self.args or not self.lhs: caller.msg("Usage: nick[/switches] nickname = [realname]") return From 96ebe8d0f3081a77fa94e7cd54d487d012ee8d67 Mon Sep 17 00:00:00 2001 From: arumford Date: Wed, 7 Feb 2018 14:22:38 -0600 Subject: [PATCH 12/29] typo in docstring. --- evennia/comms/channelhandler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evennia/comms/channelhandler.py b/evennia/comms/channelhandler.py index 02c9e19291..058b7d9ba4 100644 --- a/evennia/comms/channelhandler.py +++ b/evennia/comms/channelhandler.py @@ -159,7 +159,7 @@ class ChannelHandler(object): """ The ChannelHandler manages all active in-game channels and dynamically creates channel commands for users so that they can - just give the channek's key or alias to write to it. Whenever a + just give the channel's key or alias to write to it. Whenever a new channel is created in the database, the update() method on this handler must be called to sync it with the database (this is done automatically if creating the channel with From 861c722d3004e4796aa9cc01c58e322f543c7a1e Mon Sep 17 00:00:00 2001 From: Nicholas Matlaga Date: Tue, 13 Feb 2018 12:49:55 -0500 Subject: [PATCH 13/29] Change if statement to better handle objects; move options dict before at_msg_receive call to allow channels to be known in hook --- evennia/comms/models.py | 4 +--- evennia/objects/objects.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/evennia/comms/models.py b/evennia/comms/models.py index c456a6e72c..1123e4e5b6 100644 --- a/evennia/comms/models.py +++ b/evennia/comms/models.py @@ -585,9 +585,7 @@ class SubscriptionHandler(object): for obj in self.all(): from django.core.exceptions import ObjectDoesNotExist try: - if hasattr(obj, 'account'): - if not obj.account: - continue + if hasattr(obj, 'account') and obj.account: obj = obj.account if not obj.is_connected: continue diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 9e4d8d588a..5572ef26e2 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -553,6 +553,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): obj.at_msg_send(text=text, to_obj=self, **kwargs) except Exception: logger.log_trace() + kwargs["options"] = options try: if not self.at_msg_receive(text=text, **kwargs): # if at_msg_receive returns false, we abort message to this object @@ -560,7 +561,6 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): except Exception: logger.log_trace() - kwargs["options"] = options if text and not (isinstance(text, basestring) or isinstance(text, tuple)): # sanitize text before sending across the wire From 5817c1b7907d8d5e16cbaa637ecfe56e8fb121ef Mon Sep 17 00:00:00 2001 From: Nicholas Matlaga Date: Tue, 13 Feb 2018 12:54:03 -0500 Subject: [PATCH 14/29] add in is_connected property to base objects --- evennia/objects/objects.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 5572ef26e2..037f3ff019 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -210,6 +210,14 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): def sessions(self): return ObjectSessionHandler(self) + @property + def is_connected(self): + # we get an error for objects subscribed to channels without this + if self.account: # seems sane to pass on the account + return self.account.is_connected + else: + return False + @property def has_account(self): """ From cbcb91f48730cb7fc3a28aca7fd0bf1512ce1763 Mon Sep 17 00:00:00 2001 From: Griatch Date: Wed, 21 Feb 2018 20:18:33 +0100 Subject: [PATCH 15/29] Catch the case of a prematurely deleted guest account. Resolves #1500. --- evennia/typeclasses/attributes.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/evennia/typeclasses/attributes.py b/evennia/typeclasses/attributes.py index 84a21c0c27..3f8b4cd742 100644 --- a/evennia/typeclasses/attributes.py +++ b/evennia/typeclasses/attributes.py @@ -282,6 +282,8 @@ class AttributeHandler(object): "attribute__db_attrtype": self._attrtype, "attribute__db_key__iexact": key.lower(), "attribute__db_category__iexact": category.lower() if category else None} + if not self.obj.pk: + return [] conn = getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) if conn: attr = conn[0].attribute From fcc103ecea243e22733c56eefadc104d68578f09 Mon Sep 17 00:00:00 2001 From: Griatch Date: Wed, 21 Feb 2018 20:34:29 +0100 Subject: [PATCH 16/29] Add warning if Favico.js library is not reachable --- evennia/web/webclient/templates/webclient/base.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/evennia/web/webclient/templates/webclient/base.html b/evennia/web/webclient/templates/webclient/base.html index 30a68c498f..863a90ba11 100644 --- a/evennia/web/webclient/templates/webclient/base.html +++ b/evennia/web/webclient/templates/webclient/base.html @@ -25,7 +25,7 @@ JQuery available. @@ -57,6 +57,12 @@ JQuery available. {% endblock %} + + From 9f7dcebc5b4080d5211582f4dbf3811cfaf151e1 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 1 Mar 2018 20:13:36 +0100 Subject: [PATCH 17/29] Fix bug in accessing attribute through manager --- evennia/typeclasses/managers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/evennia/typeclasses/managers.py b/evennia/typeclasses/managers.py index 67eb9e065b..dcb147cb70 100644 --- a/evennia/typeclasses/managers.py +++ b/evennia/typeclasses/managers.py @@ -8,6 +8,8 @@ import shlex from django.db.models import Q from evennia.utils import idmapper from evennia.utils.utils import make_iter, variable_from_module, to_unicode +from evennia.typeclasses.attributes import Attribute +from evennia.typeclasses.tags import Tag __all__ = ("TypedObjectManager", ) _GA = object.__getattribute__ @@ -56,7 +58,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager): dbmodel = self.model.__dbclass__.__name__.lower() query = [("attribute__db_attrtype", attrtype), ("attribute__db_model", dbmodel)] if obj: - query.append(("%s__id" % self.model.__name__.lower(), obj.id)) + query.append(("%s__id" % self.model.__dbclass__.__name__.lower(), obj.id)) if key: query.append(("attribute__db_key", key)) if category: From 07f55c8cb6f1b0ea527dc8b3c0bf3352ad5c84c7 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 1 Mar 2018 20:23:18 +0100 Subject: [PATCH 18/29] Make desc/set abide by edit/control locks --- evennia/commands/default/building.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index 4bc107dcfb..b43e6f93c3 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -588,6 +588,9 @@ class CmdDesc(COMMAND_DEFAULT_CLASS): if not obj: return + if not (obj.access(self.caller, 'control') or obj.access(self.caller, 'edit')): + self.caller.msg("You don't have permission to edit the description of %s." % obj.key) + self.caller.db.evmenu_target = obj # launch the editor EvEditor(self.caller, loadfunc=_desc_load, savefunc=_desc_save, @@ -617,7 +620,7 @@ class CmdDesc(COMMAND_DEFAULT_CLASS): if not obj: return desc = self.args - if obj.access(caller, "edit"): + if (obj.access(self.caller, 'control') or obj.access(self.caller, 'edit')): obj.db.desc = desc caller.msg("The description was set on %s." % obj.get_display_name(caller)) else: @@ -1637,6 +1640,10 @@ class CmdSetAttribute(ObjManipCommand): result = [] if "edit" in self.switches: # edit in the line editor + if not (obj.access(self.caller, 'control') or obj.access(self.caller, 'edit')): + caller.msg("You don't have permission to edit %s." % obj.key) + return + if len(attrs) > 1: caller.msg("The Line editor can only be applied " "to one attribute at a time.") @@ -1657,12 +1664,18 @@ class CmdSetAttribute(ObjManipCommand): return else: # deleting the attribute(s) + if not (obj.access(self.caller, 'control') or obj.access(self.caller, 'edit')): + caller.msg("You don't have permission to edit %s." % obj.key) + return for attr in attrs: if not self.check_attr(obj, attr): continue result.append(self.rm_attr(obj, attr)) else: # setting attribute(s). Make sure to convert to real Python type before saving. + if not (obj.access(self.caller, 'control') or obj.access(self.caller, 'edit')): + caller.msg("You don't have permission to edit %s." % obj.key) + return for attr in attrs: if not self.check_attr(obj, attr): continue From d5c1e5306020322f71dc6d4226eb511a12417230 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 1 Mar 2018 20:53:20 +0100 Subject: [PATCH 19/29] Don't allow those with 'edit' access to obj to change the 'control' lock. --- evennia/commands/default/building.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index b43e6f93c3..a964e880eb 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -1909,9 +1909,16 @@ class CmdLock(ObjManipCommand): obj = caller.search(objname) if not obj: return - if not (obj.access(caller, 'control') or obj.access(caller, "edit")): + has_control_access = obj.access(caller, 'control') + if access_type == 'control' and not has_control_access: + # only allow to change 'control' access if you have 'control' access already + caller.msg("You need 'control' access to change this type of lock.") + return + + if not has_control_access or obj.access(caller, "edit"): caller.msg("You are not allowed to do that.") return + lockdef = obj.locks.get(access_type) if lockdef: From 6479e445a5ac170c4ef0d703fd0e447cbb2a6fec Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 1 Mar 2018 21:56:40 +0100 Subject: [PATCH 20/29] Make get_attribute/tag manager methods return querysets --- evennia/typeclasses/managers.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/evennia/typeclasses/managers.py b/evennia/typeclasses/managers.py index dcb147cb70..0bede3b192 100644 --- a/evennia/typeclasses/managers.py +++ b/evennia/typeclasses/managers.py @@ -68,7 +68,9 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager): elif value: # strvalue and value are mutually exclusive query.append(("attribute__db_value", value)) - return [th.attribute for th in self.model.db_attributes.through.objects.filter(**dict(query))] + return Attribute.objects.filter( + pk__in=self.model.db_attributes.through.objects.filter( + **dict(query)).values_list("attribute_id", flat=True)) def get_nick(self, key=None, category=None, value=None, strvalue=None, obj=None): """ @@ -191,7 +193,9 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager): query.append(("tag__db_key", key)) if category: query.append(("tag__db_category", category)) - return [th.tag for th in self.model.db_tags.through.objects.filter(**dict(query))] + return Tag.objects.filter( + pk__in=self.model.db_tags.through.objects.filter( + **dict(query)).values_list("tag_id", flat=True)) def get_permission(self, key=None, category=None, obj=None): """ From 48e35bfbe40756da9c6a71890b6b48f99d85e856 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 1 Mar 2018 22:21:22 +0100 Subject: [PATCH 21/29] Remove mutual exclusivity between value/strvalue when searching for Attributes with manager --- evennia/typeclasses/managers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evennia/typeclasses/managers.py b/evennia/typeclasses/managers.py index 0bede3b192..25488f4987 100644 --- a/evennia/typeclasses/managers.py +++ b/evennia/typeclasses/managers.py @@ -65,8 +65,8 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager): query.append(("attribute__db_category", category)) if strvalue: query.append(("attribute__db_strvalue", strvalue)) - elif value: - # strvalue and value are mutually exclusive + if value: + # no reason to make strvalue/value mutually exclusive at this level query.append(("attribute__db_value", value)) return Attribute.objects.filter( pk__in=self.model.db_attributes.through.objects.filter( From dbb5373523a160034de0ee1c5865621585d97598 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 3 Mar 2018 10:12:34 +0100 Subject: [PATCH 22/29] Allow nick command to list individual nicks --- evennia/commands/default/general.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/evennia/commands/default/general.py b/evennia/commands/default/general.py index 7bf861c91f..dd0ef11773 100644 --- a/evennia/commands/default/general.py +++ b/evennia/commands/default/general.py @@ -145,8 +145,9 @@ class CmdNick(COMMAND_DEFAULT_CLASS): caller = self.caller account = self.caller.account or caller switches = self.switches - nicktypes = [switch for switch in switches if switch in ( - "object", "account", "inputline")] or ["inputline"] + nicktypes = [switch for switch in switches if switch in ("object", "account", "inputline")] + specified_nicktype = bool(nicktypes) + nicktypes = nicktypes if specified_nicktype else ["inputline"] nicklist = (utils.make_iter(caller.nicks.get(category="inputline", return_obj=True) or []) + utils.make_iter(caller.nicks.get(category="object", return_obj=True) or []) + @@ -197,6 +198,28 @@ class CmdNick(COMMAND_DEFAULT_CLASS): nicktypestr, old_nickstring, old_replstring)) return + if not self.rhs and self.lhs: + # check what a nick is set to + strings = [] + if not specified_nicktype: + nicktypes = ("object", "account", "inputline") + for nicktype in nicktypes: + if nicktype == "account": + obj = account + else: + obj = caller + nicks = utils.make_iter(obj.nicks.get(category=nicktype, return_obj=True)) + for nick in nicks: + _, _, nick, repl = nick.value + if nick.startswith(self.lhs): + strings.append("{}-nick: '{}' -> '{}'".format( + nicktype.capitalize(), nick, repl)) + if strings: + caller.msg("\n".join(strings)) + else: + caller.msg("No nicks found matching '{}'".format(self.lhs)) + return + if not self.args or not self.lhs: caller.msg("Usage: nick[/switches] nickname = [realname]") return From 11965a1c34083e1100819bb0cbe72af0eb5767b7 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 3 Mar 2018 10:27:49 +0100 Subject: [PATCH 23/29] Store all nicks on caller (don't store 'account-nicks' on caller.account) --- evennia/commands/default/general.py | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/evennia/commands/default/general.py b/evennia/commands/default/general.py index dd0ef11773..a5cc179ac7 100644 --- a/evennia/commands/default/general.py +++ b/evennia/commands/default/general.py @@ -143,7 +143,6 @@ class CmdNick(COMMAND_DEFAULT_CLASS): return re.sub(r"(\$[0-9]+|\*|\?|\[.+?\])", r"|Y\1|n", string) caller = self.caller - account = self.caller.account or caller switches = self.switches nicktypes = [switch for switch in switches if switch in ("object", "account", "inputline")] specified_nicktype = bool(nicktypes) @@ -151,7 +150,7 @@ class CmdNick(COMMAND_DEFAULT_CLASS): nicklist = (utils.make_iter(caller.nicks.get(category="inputline", return_obj=True) or []) + utils.make_iter(caller.nicks.get(category="object", return_obj=True) or []) + - utils.make_iter(account.nicks.get(category="account", return_obj=True) or [])) + utils.make_iter(caller.nicks.get(category="account", return_obj=True) or [])) if 'list' in switches or self.cmdstring in ("nicks", "@nicks"): @@ -190,10 +189,7 @@ class CmdNick(COMMAND_DEFAULT_CLASS): nicktype = oldnick.category nicktypestr = "%s-nick" % nicktype.capitalize() - if nicktype == "account": - account.nicks.remove(old_nickstring, category=nicktype) - else: - caller.nicks.remove(old_nickstring, category=nicktype) + caller.nicks.remove(old_nickstring, category=nicktype) caller.msg("%s removed: '|w%s|n' -> |w%s|n." % ( nicktypestr, old_nickstring, old_replstring)) return @@ -204,11 +200,7 @@ class CmdNick(COMMAND_DEFAULT_CLASS): if not specified_nicktype: nicktypes = ("object", "account", "inputline") for nicktype in nicktypes: - if nicktype == "account": - obj = account - else: - obj = caller - nicks = utils.make_iter(obj.nicks.get(category=nicktype, return_obj=True)) + nicks = utils.make_iter(caller.nicks.get(category=nicktype, return_obj=True)) for nick in nicks: _, _, nick, repl = nick.value if nick.startswith(self.lhs): @@ -237,16 +229,11 @@ class CmdNick(COMMAND_DEFAULT_CLASS): errstring = "" string = "" for nicktype in nicktypes: - if nicktype == "account": - obj = account - else: - obj = caller - nicktypestr = "%s-nick" % nicktype.capitalize() old_nickstring = None old_replstring = None - oldnick = obj.nicks.get(key=nickstring, category=nicktype, return_obj=True) + oldnick = caller.nicks.get(key=nickstring, category=nicktype, return_obj=True) if oldnick: _, _, old_nickstring, old_replstring = oldnick.value if replstring: @@ -261,7 +248,7 @@ class CmdNick(COMMAND_DEFAULT_CLASS): else: string += "\n%s '|w%s|n' mapped to '|w%s|n'." % (nicktypestr, nickstring, replstring) try: - obj.nicks.add(nickstring, replstring, category=nicktype) + caller.nicks.add(nickstring, replstring, category=nicktype) except NickTemplateInvalid: caller.msg("You must use the same $-markers both in the nick and in the replacement.") return From 11ddd26c7e0573facdf4567f01eccc87ea638906 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 3 Mar 2018 10:30:14 +0100 Subject: [PATCH 24/29] Add nick-command to account cmdset --- evennia/commands/default/cmdset_account.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/evennia/commands/default/cmdset_account.py b/evennia/commands/default/cmdset_account.py index 4e357a2ce0..d7b887c017 100644 --- a/evennia/commands/default/cmdset_account.py +++ b/evennia/commands/default/cmdset_account.py @@ -11,7 +11,7 @@ command method rather than caller.msg(). from evennia.commands.cmdset import CmdSet from evennia.commands.default import help, comms, admin, system -from evennia.commands.default import building, account +from evennia.commands.default import building, account, general class AccountCmdSet(CmdSet): @@ -39,6 +39,9 @@ class AccountCmdSet(CmdSet): self.add(account.CmdColorTest()) self.add(account.CmdQuell()) + # nicks + self.add(general.CmdNick()) + # testing self.add(building.CmdExamine()) From 3e5f2ef68a5c4b5b6036e64d8651a928fda83f72 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 3 Mar 2018 11:01:06 +0100 Subject: [PATCH 25/29] Clarify nick-deletion mechanism --- evennia/commands/default/general.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/evennia/commands/default/general.py b/evennia/commands/default/general.py index a5cc179ac7..f6f624032d 100644 --- a/evennia/commands/default/general.py +++ b/evennia/commands/default/general.py @@ -173,26 +173,37 @@ class CmdNick(COMMAND_DEFAULT_CLASS): if 'delete' in switches or 'del' in switches: if not self.args or not self.lhs: - caller.msg("usage nick/delete #num ('nicks' for list)") + caller.msg("usage nick/delete or <#num> ('nicks' for list)") return # see if a number was given arg = self.args.lstrip("#") + oldnicks = [] if arg.isdigit(): # we are given a index in nicklist delindex = int(arg) if 0 < delindex <= len(nicklist): - oldnick = nicklist[delindex - 1] - _, _, old_nickstring, old_replstring = oldnick.value + oldnicks.append(nicklist[delindex - 1]) else: caller.msg("Not a valid nick index. See 'nicks' for a list.") return - nicktype = oldnick.category - nicktypestr = "%s-nick" % nicktype.capitalize() + else: + if not specified_nicktype: + nicktypes = ("object", "account", "inputline") + for nicktype in nicktypes: + oldnicks.append(caller.nicks.get(arg, category=nicktype, return_obj=True)) - caller.nicks.remove(old_nickstring, category=nicktype) - caller.msg("%s removed: '|w%s|n' -> |w%s|n." % ( - nicktypestr, old_nickstring, old_replstring)) - return + oldnicks = [oldnick for oldnick in oldnicks if oldnick] + if oldnicks: + for oldnick in oldnicks: + nicktype = oldnick.category + nicktypestr = "%s-nick" % nicktype.capitalize() + _, _, old_nickstring, old_replstring = oldnick.value + caller.nicks.remove(old_nickstring, category=nicktype) + caller.msg("%s removed: '|w%s|n' -> |w%s|n." % ( + nicktypestr, old_nickstring, old_replstring)) + else: + caller.msg("No matching nicks to remove.") + return if not self.rhs and self.lhs: # check what a nick is set to From 4eb38e2b69753ba2817a218903c7412174f52fb3 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 3 Mar 2018 11:24:20 +0100 Subject: [PATCH 26/29] Fix unittests --- evennia/commands/default/tests.py | 4 ++-- evennia/comms/models.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/evennia/commands/default/tests.py b/evennia/commands/default/tests.py index 38829f0cf5..dba1d329cc 100644 --- a/evennia/commands/default/tests.py +++ b/evennia/commands/default/tests.py @@ -130,8 +130,8 @@ class TestGeneral(CommandTest): self.call(general.CmdNick(), "/account testalias = testaliasedstring2", "Accountnick 'testalias' mapped to 'testaliasedstring2'.") self.call(general.CmdNick(), "/object testalias = testaliasedstring3", "Objectnick 'testalias' mapped to 'testaliasedstring3'.") self.assertEqual(u"testaliasedstring1", self.char1.nicks.get("testalias")) - self.assertEqual(None, self.char1.nicks.get("testalias", category="account")) - self.assertEqual(u"testaliasedstring2", self.char1.account.nicks.get("testalias", category="account")) + self.assertEqual(u"testaliasedstring2", self.char1.nicks.get("testalias", category="account")) + self.assertEqual(None, self.char1.account.nicks.get("testalias", category="account")) self.assertEqual(u"testaliasedstring3", self.char1.nicks.get("testalias", category="object")) def test_get_and_drop(self): diff --git a/evennia/comms/models.py b/evennia/comms/models.py index 1123e4e5b6..c358cf352b 100644 --- a/evennia/comms/models.py +++ b/evennia/comms/models.py @@ -527,7 +527,6 @@ class SubscriptionHandler(object): for subscriber in make_iter(entity): if subscriber: clsname = subscriber.__dbclass__.__name__ - print("subscriber:", subscriber, clsname) # chooses the right type if clsname == "ObjectDB": self.obj.db_object_subscriptions.add(subscriber) From bbe4a6925abe850c82295c9b4bfbc579806c40d9 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 3 Mar 2018 18:30:48 +0100 Subject: [PATCH 27/29] Fix a teleport example missing = --- evennia/commands/default/building.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index 7085ce2f98..0afeea8fe5 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -2331,7 +2331,7 @@ class CmdTeleport(COMMAND_DEFAULT_CLASS): Examples: @tel Limbo - @tel/quiet box Limbo + @tel/quiet box = Limbo @tel/tonone box Switches: @@ -2347,7 +2347,8 @@ class CmdTeleport(COMMAND_DEFAULT_CLASS): loc - teleport object to the target's location instead of its contents Teleports an object somewhere. If no object is given, you yourself - is teleported to the target location. """ + is teleported to the target location. + """ key = "@tel" aliases = "@teleport" locks = "cmd:perm(teleport) or perm(Builder)" From b704363cf75c487f4c35788d6acbe508e7823f29 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 3 Mar 2018 10:12:34 +0100 Subject: [PATCH 28/29] Allow nick command to list individual nicks --- evennia/commands/default/general.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/evennia/commands/default/general.py b/evennia/commands/default/general.py index f6f624032d..7a50f41eda 100644 --- a/evennia/commands/default/general.py +++ b/evennia/commands/default/general.py @@ -223,6 +223,28 @@ class CmdNick(COMMAND_DEFAULT_CLASS): caller.msg("No nicks found matching '{}'".format(self.lhs)) return + if not self.rhs and self.lhs: + # check what a nick is set to + strings = [] + if not specified_nicktype: + nicktypes = ("object", "account", "inputline") + for nicktype in nicktypes: + if nicktype == "account": + obj = account + else: + obj = caller + nicks = utils.make_iter(obj.nicks.get(category=nicktype, return_obj=True)) + for nick in nicks: + _, _, nick, repl = nick.value + if nick.startswith(self.lhs): + strings.append("{}-nick: '{}' -> '{}'".format( + nicktype.capitalize(), nick, repl)) + if strings: + caller.msg("\n".join(strings)) + else: + caller.msg("No nicks found matching '{}'".format(self.lhs)) + return + if not self.args or not self.lhs: caller.msg("Usage: nick[/switches] nickname = [realname]") return From 2bc87c0b0d8f92d4030c411a3e802d80520dc3c5 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 3 Mar 2018 18:30:48 +0100 Subject: [PATCH 29/29] Fix a teleport example missing = --- evennia/commands/default/building.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index a964e880eb..853ca6b88f 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -2396,7 +2396,7 @@ class CmdTeleport(COMMAND_DEFAULT_CLASS): Examples: @tel Limbo - @tel/quiet box Limbo + @tel/quiet box = Limbo @tel/tonone box Switches: @@ -2412,7 +2412,8 @@ class CmdTeleport(COMMAND_DEFAULT_CLASS): loc - teleport object to the target's location instead of its contents Teleports an object somewhere. If no object is given, you yourself - is teleported to the target location. """ + is teleported to the target location. + """ key = "@tel" aliases = "@teleport" locks = "cmd:perm(teleport) or perm(Builder)"