diff --git a/src/comms/managers.py b/src/comms/managers.py index 251b1c4444..9439f501da 100644 --- a/src/comms/managers.py +++ b/src/comms/managers.py @@ -231,7 +231,7 @@ class MsgManager(models.Manager): receiver_restrict = Q() # filter by full text if freetext: - fulltext_restrict = Q(db_title__icontains=freetext) | Q(db_message__icontains=freetext) + fulltext_restrict = Q(db_header__icontains=freetext) | Q(db_message__icontains=freetext) else: fulltext_restrict = Q() # execute the query diff --git a/src/comms/migrations/0006_auto.py b/src/comms/migrations/0006_auto.py index 66a0ef191c..dfd072679b 100644 --- a/src/comms/migrations/0006_auto.py +++ b/src/comms/migrations/0006_auto.py @@ -7,13 +7,13 @@ from django.db import models class Migration(SchemaMigration): def forwards(self, orm): - + # Adding index on 'Channel', fields ['db_key'] db.create_index('comms_channel', ['db_key']) def backwards(self, orm): - + # Removing index on 'Channel', fields ['db_key'] db.delete_index('comms_channel', ['db_key']) diff --git a/src/comms/migrations/0008_renamed_title_to_header.py b/src/comms/migrations/0008_renamed_title_to_header.py new file mode 100644 index 0000000000..186ffe314d --- /dev/null +++ b/src/comms/migrations/0008_renamed_title_to_header.py @@ -0,0 +1,139 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + + + + # Adding field 'Msg.db_header' + db.add_column('comms_msg', 'db_header', + self.gf('django.db.models.fields.CharField')(db_index=True, max_length=128, null=True, blank=True), + keep_default=False) + + if not db.dry_run: + for msg in orm.Msg.objects.all(): + msg.db_header = msg.db_title + msg.save() + + # Deleting field 'Msg.db_title' + db.delete_column('comms_msg', 'db_title') + + + def backwards(self, orm): + # Adding field 'Msg.db_title' + raise RuntimeError + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comms.channel': { + 'Meta': {'object_name': 'Channel'}, + 'db_aliases': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'db_desc': ('django.db.models.fields.CharField', [], {'max_length': '80', 'null': 'True', 'blank': 'True'}), + 'db_keep_log': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'db_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'comms.externalchannelconnection': { + 'Meta': {'object_name': 'ExternalChannelConnection'}, + 'db_channel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['comms.Channel']"}), + 'db_external_config': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_external_key': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'db_external_send_code': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_is_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'comms.msg': { + 'Meta': {'object_name': 'Msg'}, + 'db_date_sent': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), + 'db_header': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '128', 'null': 'True', 'blank': 'True'}), + 'db_hide_from_channles': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'hide_from_channels_set'", 'null': 'True', 'to': "orm['comms.Channel']"}), + 'db_hide_from_objects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'hide_from_objects_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_hide_from_players': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'hide_from_players_set'", 'null': 'True', 'to': "orm['players.PlayerDB']"}), + 'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}), + 'db_message': ('django.db.models.fields.TextField', [], {}), + 'db_receivers_channels': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'channel_set'", 'null': 'True', 'to': "orm['comms.Channel']"}), + 'db_receivers_objects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'receiver_object_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_receivers_players': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'receiver_player_set'", 'null': 'True', 'to': "orm['players.PlayerDB']"}), + 'db_sender_external': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'db_index': 'True'}), + 'db_sender_objects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'sender_object_set'", 'null': 'True', 'db_index': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_sender_players': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'sender_player_set'", 'null': 'True', 'db_index': 'True', 'to': "orm['players.PlayerDB']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'comms.playerchannelconnection': { + 'Meta': {'object_name': 'PlayerChannelConnection'}, + 'db_channel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['comms.Channel']"}), + 'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'objects.objectdb': { + 'Meta': {'object_name': 'ObjectDB'}, + 'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'players.playerdb': { + 'Meta': {'object_name': 'PlayerDB'}, + 'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_is_connected': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True', 'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'}) + } + } + + complete_apps = ['comms'] diff --git a/src/comms/models.py b/src/comms/models.py index 6cf032a195..d75409100c 100644 --- a/src/comms/models.py +++ b/src/comms/models.py @@ -75,11 +75,12 @@ class Msg(SharedMemoryModel): db_receivers_objects = models.ManyToManyField('objects.ObjectDB', related_name='receiver_object_set', null=True, help_text="object receivers") db_receivers_channels = models.ManyToManyField("Channel", related_name='channel_set', null=True, help_text="channel recievers") - - # The actual message and a timestamp. The message field - # should itself handle eventual headers etc. - db_title = models.CharField('title', max_length=512, null=True, blank=True, db_index=True) + # header could be used for meta-info about the message if your system needs it, or as a separate + # store for the mail subject line maybe. + db_header = models.CharField('header', max_length=128, null=True, blank=True, db_index=True) + # the message body itself db_message = models.TextField('messsage') + # send date db_date_sent = models.DateTimeField('date sent', editable=False, auto_now_add=True, db_index=True) # lock storage db_lock_storage = models.CharField('locks', max_length=512, blank=True, @@ -209,23 +210,23 @@ class Msg(SharedMemoryModel): self.save() channels = property(__channels_get, __channels_set, __channels_del) - # title property (wraps db_title) + # header property (wraps db_header) #@property - def __title_get(self): + def __header_get(self): "Getter. Allows for value = self.message" - return self.db_title + return self.db_header #@message.setter - def __title_set(self, value): + def __header_set(self, value): "Setter. Allows for self.message = value" if value: - self.db_title = value + self.db_header = value self.save() #@message.deleter - def __title_del(self): + def __header_del(self): "Deleter. Allows for del self.message" - self.db_title = "" + self.db_header = "" self.save() - title = property(__title_get, __title_set, __title_del) + header = property(__header_get, __header_set, __header_del) # message property (wraps db_message) #@property @@ -338,11 +339,12 @@ class TempMsg(object): sender to be given. """ - def __init__(self, senders=None, receivers=None, channels=None, message="", title="", lockstring="", hide_from=None): + def __init__(self, senders=None, receivers=None, channels=None, message="", header="", type="", lockstring="", hide_from=None): self.senders = senders and make_iter(senders) or [] self.receivers = receivers and make_iter(receivers) or [] self.channels = channels and make_iter(channels) or [] - self.title = title + self.type = type + self.header, header self.message = message self.lock_storage = lockstring self.locks = LockHandler(self) @@ -544,7 +546,7 @@ class Channel(SharedMemoryModel): """ return PlayerChannelConnection.objects.has_player_connection(player, self) - def msg(self, msgobj, title=None, senders=None, persistent=True): + def msg(self, msgobj, header=None, senders=None, persistent=True): """ Send the given message to all players connected to channel. Note that no permission-checking is done here; it is assumed to have been @@ -568,7 +570,7 @@ class Channel(SharedMemoryModel): msg = TempMsg() if senders: msg.senders = make_iter(senders) - msg.title = title + msg.header = header msg.message = msgobj msg.channels = [self] # add this channel else: @@ -586,11 +588,11 @@ class Channel(SharedMemoryModel): logger.log_trace("Cannot send msg to connection '%s'" % conn) return True - def tempmsg(self, message, title=None, senders=None): + def tempmsg(self, message, header=None, senders=None): """ A wrapper for sending non-persistent messages. """ - self.msg(message, senders=senders, title=title, persistent=False) + self.msg(message, senders=senders, header=header, persistent=False) def connect_to(self, player): "Connect the user to this channel" diff --git a/src/objects/migrations/0010_converting_attributes.py b/src/objects/migrations/0010_converting_attributes.py index 6612fe7136..2efda220dc 100644 --- a/src/objects/migrations/0010_converting_attributes.py +++ b/src/objects/migrations/0010_converting_attributes.py @@ -20,63 +20,63 @@ DA = object.__delattr__ class PackedDict(dict): """ Attribute helper class. - A variant of dict that stores itself to the database when - updating one of its keys. This is called and handled by - Attribute.validate_data(). + A variant of dict that stores itself to the database when + updating one of its keys. This is called and handled by + Attribute.validate_data(). """ def __init__(self, db_obj, *args, **kwargs): """ Sets up the packing dict. The db_store variable is set by Attribute.validate_data() when returned in - order to allow custom updates to the dict. + order to allow custom updates to the dict. db_obj - the Attribute object storing this dict. - + """ self.db_obj = db_obj super(PackedDict, self).__init__(*args, **kwargs) def __str__(self): return "{%s}" % ", ".join("%s:%s" % (key, str(val)) for key, val in self.items()) - def __setitem__(self, *args, **kwargs): + def __setitem__(self, *args, **kwargs): "assign item to this dict" super(PackedDict, self).__setitem__(*args, **kwargs) self.db_obj.value = self - def clear(self, *args, **kwargs): + def clear(self, *args, **kwargs): "Custom clear" super(PackedDict, self).clear(*args, **kwargs) self.db_obj.value = self - def pop(self, *args, **kwargs): + def pop(self, *args, **kwargs): "Custom pop" super(PackedDict, self).pop(*args, **kwargs) self.db_obj.value = self - def popitem(self, *args, **kwargs): + def popitem(self, *args, **kwargs): "Custom popitem" super(PackedDict, self).popitem(*args, **kwargs) self.db_obj.value = self - def update(self, *args, **kwargs): + def update(self, *args, **kwargs): "Custom update" super(PackedDict, self).update(*args, **kwargs) self.db_obj.value = self - + class PackedList(list): """ Attribute helper class. - A variant of list that stores itself to the database when - updating one of its keys. This is called and handled by - Attribute.validate_data(). + A variant of list that stores itself to the database when + updating one of its keys. This is called and handled by + Attribute.validate_data(). """ def __init__(self, db_obj, *args, **kwargs): """ - Sets up the packing list. + Sets up the packing list. db_obj - the Attribute object storing this dict. """ self.db_obj = db_obj super(PackedList, self).__init__(*args, **kwargs) def __str__(self): return "[%s]" % ", ".join(str(val) for val in self) - def __setitem__(self, *args, **kwargs): + def __setitem__(self, *args, **kwargs): "Custom setitem that stores changed list to database." - super(PackedList, self).__setitem__(*args, **kwargs) + super(PackedList, self).__setitem__(*args, **kwargs) self.db_obj.value = self def append(self, *args, **kwargs): "Custom append" @@ -123,13 +123,13 @@ def to_attr(data): (and any nested combination of them) this way, all other iterables are stored and returned as lists. - data storage format: + data storage format: (simple|dbobj|iter, ) - where + where simple - a single non-db object, like a string or number dbobj - a single dbobj iter - any iterable object - will be looped over recursively - to convert dbobj->id. + to convert dbobj->id. """ @@ -140,7 +140,7 @@ def to_attr(data): """ dtype = type(item) if dtype in (basestring, int, float): # check the most common types first, for speed - return item + return item elif hasattr(item, "id") and hasattr(item, "db_model_name") and hasattr(item, "db_key"): db_model_name = item.db_model_name if db_model_name == "typeclass": @@ -166,8 +166,8 @@ def to_attr(data): if db_model_name == "typeclass": # typeclass cannot help us, we want the actual child object model name db_model_name = GA(data.dbobj, "db_model_name") - return ("dbobj", PackedDBobject(data.id, db_model_name, data.db_key)) - elif hasattr(data, "__iter__"): + return ("dbobj", PackedDBobject(data.id, db_model_name, data.db_key)) + elif hasattr(data, "__iter__"): return ("iter", iter_db2id(data)) else: return ("simple", data) @@ -175,21 +175,21 @@ def to_attr(data): def from_attr(attr, datatuple): """ Retrieve data from a previously stored attribute. This - is always a dict with keys type and data. + is always a dict with keys type and data. - datatuple comes from the database storage and has - the following format: + datatuple comes from the database storage and has + the following format: (simple|dbobj|iter, ) where simple - a single non-db object, like a string. is returned as-is. - dbobj - a single dbobj-id. This id is retrieved back from the database. + dbobj - a single dbobj-id. This id is retrieved back from the database. iter - an iterable. This is traversed iteratively, converting all found - dbobj-ids back to objects. Also, all lists and dictionaries are - returned as their PackedList/PackedDict counterparts in order to + dbobj-ids back to objects. Also, all lists and dictionaries are + returned as their PackedList/PackedDict counterparts in order to allow in-place assignment such as obj.db.mylist[3] = val. Mylist - is then a PackedList that saves the data on the fly. + is then a PackedList that saves the data on the fly. """ - # nested functions + # nested functions def id2db(data): """ Convert db-stored dbref back to object @@ -202,39 +202,39 @@ def from_attr(attr, datatuple): try: return mclass.objects.get(id=data.id) except mclass.DoesNotExist: # could happen if object was deleted in the interim. - return None + return None def iter_id2db(item): """ Recursively looping through stored iterables, replacing ids with actual objects. We return PackedDict and PackedLists instead of normal lists; this is needed in order for the user to do dynamic saving of nested in-place, such as obj.db.attrlist[2]=3. What is - stored in the database are however always normal python primitives. + stored in the database are however always normal python primitives. """ dtype = type(item) if dtype in (basestring, int, float): # check the most common types first, for speed - return item + return item elif dtype == PackedDBobject: return id2db(item) - elif dtype == tuple: + elif dtype == tuple: return tuple([iter_id2db(val) for val in item]) elif dtype in (dict, PackedDict): return dict(zip([key for key in item.keys()], [iter_id2db(val) for val in item.values()])) elif hasattr(item, '__iter__'): return list(iter_id2db(val) for val in item) - else: - return item + else: + return item typ, data = datatuple - if typ == 'simple': + if typ == 'simple': # single non-db objects return data - elif typ == 'dbobj': - # a single stored dbobj + elif typ == 'dbobj': + # a single stored dbobj return id2db(data) - elif typ == 'iter': + elif typ == 'iter': # all types of iterables return iter_id2db(data) @@ -249,9 +249,9 @@ class Migration(DataMigration): val = pickle.loads(to_str(attr.db_value)) attr.db_value = to_unicode(pickle.dumps(to_str(to_attr(from_attr(attr, val))))) attr.save() - except TypeError, RuntimeError: - pass - + except TypeError, RuntimeError: + pass + def backwards(self, orm): "Write your backwards methods here." raise RuntimeError