From 28b2ddcdb6193f574017a1b91f0b237cb43591c5 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 a00e6071915a1d4a5896468ef7ecdb415b4619b6 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 2f158909967957d76a84eec4e38a2a88344b61f8 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 0450dae3e9a5d098a79c99ac08c85f3e3b8578ef 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 53454088b753542fd314a3405d32cccbe79fc709 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 168709d88d8dfc6efcdb3300cf10c10765e11a57 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 15b04666a5ca82e14cefa48ee584ccc468693cbb 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 cde9986be894dcfc84f7fff161d86bcd48fc91c5 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 29ab570d5509c3ec6d4b4311a8362e36a1ebb025 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 accd0f286e4a210ff23c5cfae7613cc3635876c2 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 18bce388d82096eb30694d1b708e2304e524c081 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 63e2b236f930fc2c621158a8626003e9277052f0 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 6a5ebda9fb26804350ccee17c0fa034b99324ec3 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 af4426026b9a7eb78580ebc8c22ffff9dbe2b1b9 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 84ecef616fa3617a42fe0fd08bec2e24293ec53b 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 ceb904303e2b688cb59f32870e81c3c640712b2a 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 95caa0085a8d9631ed35390f5b0879c4bf09aae1 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 f4877f8bbc862e8f1b38e7ebda23ea36174526dd 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 8fcdb4bc1ff326f3c19339e4191cfd1c6a0124f2 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 d2566d4982cdd80dc8d9a0dc9567480500385cd7 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 d5215753b8408a18aea99e7dce7354444bdf4398 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 484ab42dec5330f8a927bf2b06266050d87c08b4 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 28cbee465921696ae932e6e46175942397c9b4e2 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 cec37fc86f7c19476f8e8c3a7ffe884d9534e185 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 004fa3cc5a617756fc36053517724c9d89366cad 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 557daad7086f0375ef90eb1afcec73c7543eeb0b 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 37313fad4fb0f511c7715c47f38d9f7bf0fd94f7 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 0d27f3ac8043c724bbf04adebd746ad395ccf4c6 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 61560e53a4b44b07f44a23d7337d1ebed5443c7b 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)"