diff --git a/src/commands/default/tests.py b/src/commands/default/tests.py index 4b31cc8cd1..05ef9b60c7 100644 --- a/src/commands/default/tests.py +++ b/src/commands/default/tests.py @@ -21,9 +21,9 @@ from src.players.player import Player from src.utils import create, ansi from src.server.sessionhandler import SESSIONS -from django.db.models.signals import pre_save -from src.server.caches import field_pre_save -pre_save.connect(field_pre_save, dispatch_uid="fieldcache") +from django.db.models.signals import post_save +from src.server.caches import field_post_save +post_save.connect(field_post_save, dispatch_uid="fieldcache") # set up signal here since we are not starting the server @@ -78,12 +78,12 @@ class CommandTest(TestCase): CID = 0 # we must set a different CID in every test to avoid unique-name collisions creating the objects def setUp(self): "sets up testing environment" - settings.DEFAULT_HOME = "#2" #print "creating player %i: %s" % (self.CID, self.__class__.__name__) self.player = create.create_player("TestPlayer%i" % self.CID, "test@test.com", "testpassword", typeclass=TestPlayerClass) self.player2 = create.create_player("TestPlayer%ib" % self.CID, "test@test.com", "testpassword", typeclass=TestPlayerClass) self.room1 = create.create_object("src.objects.objects.Room", key="Room%i"%self.CID, nohome=True) self.room1.db.desc = "room_desc" + settings.DEFAULT_HOME = "#%i" % self.room1.id # we must have a default home self.room2 = create.create_object("src.objects.objects.Room", key="Room%ib" % self.CID) self.obj1 = create.create_object(TestObjectClass, key="Obj%i" % self.CID, location=self.room1, home=self.room1) self.obj2 = create.create_object(TestObjectClass, key="Obj%ib" % self.CID, location=self.room1, home=self.room1) @@ -272,7 +272,7 @@ class TestComms(CommandTest): self.call(comms.CmdCdesc(), "testchan = Test Channel", "Description of channel 'testchan' set to 'Test Channel'.") self.call(comms.CmdCemit(), "testchan = Test Message", "[testchan] Test Message|Sent to channel testchan: Test Message") self.call(comms.CmdCWho(), "testchan", "Channel subscriptions\ntestchan:\n TestPlayer7") - self.call(comms.CmdPage(), "TestPlayer7b = Test", "You paged TestPlayer7b with: 'Test'.") + self.call(comms.CmdPage(), "TestPlayer7b = Test", "TestPlayer7b is offline. They will see your message if they list their pages later.|You paged TestPlayer7b with: 'Test'.") self.call(comms.CmdCBoot(), "", "Usage: @cboot[/quiet] = [:reason]") # noone else connected to boot self.call(comms.CmdCdestroy(), "testchan" ,"[testchan] TestPlayer7: testchan is being destroyed. Make sure to change your aliases.|Channel 'testchan' was destroyed.") diff --git a/src/typeclasses/models.py b/src/typeclasses/models.py index e2b30917b2..f31634ab6c 100644 --- a/src/typeclasses/models.py +++ b/src/typeclasses/models.py @@ -321,11 +321,6 @@ class AttributeHandler(object): return ret if len(key) > 1 else default return ret[0] if len(ret)==1 else ret - def batch_add(self, keys, values, categories=None, lockstrings=None, - stratts=None, accessing_obj=None, default_access=True): - """ - Batch version supporting the addition of more than one - """ def add(self, key, value, category=None, lockstring="", strattr=False, accessing_obj=None, default_access=True): @@ -338,11 +333,50 @@ class AttributeHandler(object): If accessing_obj is given, self.obj's 'attrcreate' lock access will be checked against it. If no accessing_obj is given, no check will be done. + """ + if accessing_obj and not self.obj.access(accessing_obj, + self._attrcreate, default=default_access): + # check create access + return + if self._cache is None: + self._recache() + if not key: + return - The method also accepts multiple attributes (this is a faster way - to add attributes since it allows for some optimizations). - If so, key and value (or strvalue) must be iterables of the same length. - All batch-added Attributes will use the same category and lockstring. + category = category.strip().lower() if category is not None else None + keystr = key.strip().lower() + cachekey = "%s-%s" % (keystr, category) + attr_obj = self._cache.get(cachekey) + + if attr_obj: + # update an existing attribute object + if strattr: + # store as a simple string (will not notify OOB handlers) + attr_obj.db_strvalue = value + attr_obj.save(update_fields=["db_strvalue"]) + else: + # store normally (this will also notify OOB handlers) + attr_obj.value = value + else: + # create a new Attribute (no OOB handlers can be notified) + kwargs = {"db_key" : keystr, "db_category" : category, + "db_model" : self._model, "db_attrtype" : self._attrtype, + "db_value" : None if strattr else to_pickle(value), + "db_strvalue" : value if strattr else None} + new_attr = Attribute(**kwargs) + new_attr.save() + getattr(self.obj, self._m2m_fieldname).add(new_attr) + self._cache[cachekey] = new_attr + + + def batch_add(self, key, value, category=None, lockstring="", + strattr=False, accessing_obj=None, default_access=True): + """ + Batch-version of add(). This is more efficient than + repeat-calling add. + + key and value must be sequences of the same length, each + representing a key-value pair. """ if accessing_obj and not self.obj.access(accessing_obj, @@ -389,6 +423,7 @@ class AttributeHandler(object): getattr(self.obj, self._m2m_fieldname).add(*new_attrobjs) self._recache() + def remove(self, key, raise_exception=False, category=None, accessing_obj=None, default_access=True): """Remove attribute or a list of attributes from object. @@ -441,6 +476,7 @@ class AttributeHandler(object): else: return self._cache.values() + class NickHandler(AttributeHandler): """ Handles the addition and removal of Nicks