diff --git a/contrib/email-login.py b/contrib/email-login.py index 45a105604d..63ce2f4423 100644 --- a/contrib/email-login.py +++ b/contrib/email-login.py @@ -237,7 +237,7 @@ its and @/./+/-/_ only.") # this echoes the restrictions made by django's auth m pchanneldef = settings.CHANNEL_PUBLIC if pchanneldef: pchannel = ChannelDB.objects.get_channel(pchanneldef[0]) - if not pchannel.connect_to(new_player): + if not pchannel.connect(new_player): string = "New player '%s' could not connect to public channel!" % new_player.key logger.log_errmsg(string) diff --git a/contrib/menu_login.py b/contrib/menu_login.py index 54e843700e..bc5d22fd6f 100644 --- a/contrib/menu_login.py +++ b/contrib/menu_login.py @@ -233,7 +233,7 @@ class CmdPasswordCreate(Command): pchanneldef = settings.CHANNEL_PUBLIC if pchanneldef: pchannel = managers.channels.get_channel(pchanneldef[0]) - if not pchannel.connect_to(new_player): + if not pchannel.connect(new_player): string = "New player '%s' could not connect to public channel!" % new_player.key logger.log_errmsg(string) diff --git a/ev.py b/ev.py index a40e6f6f02..0b05405671 100644 --- a/ev.py +++ b/ev.py @@ -143,7 +143,7 @@ from src.locks import lockfuncs from src.scripts.scripts import Script # comms -from src.comms.models import Msg, ChannelDB, PlayerChannelConnection, ExternalChannelConnection +from src.comms.models import Msg, ChannelDB, ExternalChannelConnection from src.comms.comms import Channel # objects @@ -201,7 +201,6 @@ class DBmanagers(_EvContainer): scripts - ScriptDB.objects msgs - Msg.objects channels - Channel.objects - connections - PlayerChannelConnection.objects externalconnections - ExternalChannelConnection.objects objects - ObjectDB.objects @@ -209,7 +208,7 @@ class DBmanagers(_EvContainer): from src.help.models import HelpEntry from src.players.models import PlayerDB from src.scripts.models import ScriptDB - from src.comms.models import Msg, ChannelDB, PlayerChannelConnection, ExternalChannelConnection + from src.comms.models import Msg, ChannelDB, ExternalChannelConnection from src.objects.models import ObjectDB from src.server.models import ServerConfig from src.typeclasses.models import Tag, Attribute @@ -220,14 +219,13 @@ class DBmanagers(_EvContainer): scripts = ScriptDB.objects msgs = Msg.objects channels = ChannelDB.objects - connections = PlayerChannelConnection.objects externalconnections = ExternalChannelConnection.objects objects = ObjectDB.objects serverconfigs = ServerConfig.objects attributes = Attribute.objects tags = Tag.objects # remove these so they are not visible as properties - del HelpEntry, PlayerDB, ScriptDB, Msg, ChannelDB, PlayerChannelConnection, + del HelpEntry, PlayerDB, ScriptDB, Msg, ChannelDB del ExternalChannelConnection, ObjectDB, ServerConfig, Tag, Attribute managers = DBmanagers() diff --git a/src/commands/default/comms.py b/src/commands/default/comms.py index b182b0ad19..f85539993a 100644 --- a/src/commands/default/comms.py +++ b/src/commands/default/comms.py @@ -8,7 +8,7 @@ for easy handling. """ from django.conf import settings -from src.comms.models import ChannelDB, Msg, PlayerChannelConnection, ExternalChannelConnection +from src.comms.models import ChannelDB, Msg, ExternalChannelConnection from src.comms import irc, imc2, rss from src.comms.channelhandler import CHANNELHANDLER from src.utils import create, utils, prettytable @@ -96,7 +96,7 @@ class CmdAddCom(MuxPlayerCommand): string = "" if not channel.has_connection(player): # we want to connect as well. - if not channel.connect_to(player): + if not channel.connect(player): # if this would have returned True, the player is connected self.msg("%s: You are not allowed to join this channel." % channel.key) return @@ -154,7 +154,7 @@ class CmdDelCom(MuxPlayerCommand): for nick in [nick for nick in caller.nicks.get(category="channel") if nick.strvalue.lower() == chkey]: nick.delete() - disconnect = channel.disconnect_from(player) + disconnect = channel.disconnect(player) if disconnect: self.msg("You stop listening to channel '%s'. Eventual aliases were removed." % channel.key) return @@ -209,7 +209,7 @@ class CmdAllCom(MuxPlayerCommand): caller.execute_cmd("addcom %s" % channel.key) elif args == "off": #get names all subscribed channels and disconnect from them all - channels = [conn.channel for conn in PlayerChannelConnection.objects.get_all_player_connections(caller)] + channels = ChannelDB.objects.get_subscriptions(caller) for channel in channels: caller.execute_cmd("delcom %s" % channel.key) elif args == "destroy": @@ -227,9 +227,9 @@ class CmdAllCom(MuxPlayerCommand): string += "No channels." for channel in channels: string += "\n{w%s:{n\n" % channel.key - conns = PlayerChannelConnection.objects.get_all_connections(channel) - if conns: - string += " " + ", ".join([conn.player.key for conn in conns]) + subs = channel.subscriptions.all() + if subs: + string += " " + ", ".join([player.key for player in subs]) else: string += " " self.msg(string.strip()) @@ -269,7 +269,7 @@ class CmdChannels(MuxPlayerCommand): self.msg("No channels available.") return # all channel we are already subscribed to - subs = [conn.channel for conn in PlayerChannelConnection.objects.get_all_player_connections(caller)] + subs = ChannelDB.objects.get_subscriptions(caller) #print subs if self.cmdstring == "comlist": @@ -388,7 +388,7 @@ class CmdCBoot(MuxPlayerCommand): string = "You don't control this channel." self.msg(string) return - if not PlayerChannelConnection.objects.has_player_connection(player, channel): + if not player.dbobj in channel.db_subscriptions.all(): string = "Player %s is not connected to channel %s." % (player.key, channel.key) self.msg(string) return @@ -401,7 +401,7 @@ class CmdCBoot(MuxPlayerCommand): if nick.db_real.lower() == channel.key]: nick.delete() # disconnect player - channel.disconnect_from(player) + channel.disconnect(player) CHANNELHANDLER.update() @@ -483,9 +483,9 @@ class CmdCWho(MuxPlayerCommand): return string = "\n{CChannel subscriptions{n" string += "\n{w%s:{n\n" % channel.key - conns = PlayerChannelConnection.objects.get_all_connections(channel) - if conns: - string += " " + ", ".join([conn.player.key for conn in conns]) + subs = channel.db_subscriptions.all() + if subs: + string += " " + ", ".join([player.key for player in subs]) else: string += " " self.msg(string.strip()) @@ -537,7 +537,7 @@ class CmdChannelCreate(MuxPlayerCommand): aliases, description, locks=lockstring) - new_chan.connect_to(caller) + new_chan.connect(caller) self.msg("Created channel %s and connected to it." % new_chan.key) diff --git a/src/commands/default/unloggedin.py b/src/commands/default/unloggedin.py index 5c1ec96869..98d1643e63 100644 --- a/src/commands/default/unloggedin.py +++ b/src/commands/default/unloggedin.py @@ -181,7 +181,7 @@ class CmdUnconnectedCreate(MuxCommand): pchanneldef = settings.CHANNEL_PUBLIC if pchanneldef: pchannel = ChannelDB.objects.get_channel(pchanneldef[0]) - if not pchannel.connect_to(new_player): + if not pchannel.connect(new_player): string = "New player '%s' could not connect to public channel!" % new_player.key logger.log_errmsg(string) diff --git a/src/comms/comms.py b/src/comms/comms.py index 7d28274e40..0928cdd663 100644 --- a/src/comms/comms.py +++ b/src/comms/comms.py @@ -162,15 +162,16 @@ class Channel(TypeClass): this channel, and sending them a message. """ # get all players connected to this channel and send to them - for conn in ChannelDB.objects.get_all_connections(self, online=online): + for player in self.dbobj.db_subscriptions.all(): + player = player.typeclass try: - conn.player.msg(msg.message, from_obj=msg.senders) + player.msg(msg.message, from_obj=msg.senders) except AttributeError: try: - conn.to_external(msg.message, + player.to_external(msg.message, senders=msg.senders, from_channel=self) except Exception: - logger.log_trace("Cannot send msg to connection '%s'" % conn) + logger.log_trace("Cannot send msg to connection '%s'" % player) def msg(self, msgobj, header=None, senders=None, sender_strings=None, persistent=False, online=False, emit=False, external=False): diff --git a/src/comms/managers.py b/src/comms/managers.py index 5b4c5f55fb..3581a612c0 100644 --- a/src/comms/managers.py +++ b/src/comms/managers.py @@ -2,10 +2,8 @@ These managers handles the """ -import itertools from django.db import models from django.db.models import Q -from django.contrib.contenttypes.models import ContentType from src.typeclasses.managers import returns_typeclass_list, returns_typeclass _GA = object.__getattribute__ @@ -14,7 +12,6 @@ _ObjectDB = None _ChannelDB = None _SESSIONS = None _ExternalConnection = None -_User = None # error class @@ -49,7 +46,7 @@ def dbref(dbref, reqhash=True): def identify_object(inp): "identify if an object is a player or an object; return its database model" # load global stores - global _PlayerDB, _ObjectDB, _ChannelDB, _ExternalConnection, _User + global _PlayerDB, _ObjectDB, _ChannelDB, _ExternalConnection if not _PlayerDB: from src.players.models import PlayerDB as _PlayerDB if not _ObjectDB: @@ -58,8 +55,6 @@ def identify_object(inp): from src.comms.models import ChannelDB as _ChannelDB if not _ExternalConnection: from src.comms.models import ExternalChannelConnection as _ExternalConnection - if not _User: - from django.contrib.auth.models import User as _User if not inp: return inp, None # try to identify the type @@ -284,9 +279,8 @@ class ChannelManager(models.Manager): Evennia-specific: get_all_channels - get_channel - del_channel - get_all_connections + get_channel(channel) + get_subscriptions(player) channel_search (equivalent to ev.search_channel) """ @@ -313,56 +307,65 @@ class ChannelManager(models.Manager): return channels[0] return None - def del_channel(self, channelkey): + @returns_typeclass_list + def get_subscriptions(self, player): """ - Delete channel matching channelkey. - Also cleans up channelhandler. + Return all channels a given player is subscribed to """ - channels = self.filter(db_key__iexact=channelkey) - if not channels: - # no aliases allowed for deletion. - return False - for channel in channels: - channel.delete() - from src.comms.channelhandler import CHANNELHANDLER - CHANNELHANDLER.update() - return None + return player.dbobj.subscription_set.all() - def get_all_connections(self, channel, online=False): - """ - Return the connections of all players listening - to this channel. If Online is true, it only returns - connected players. - """ - global _SESSIONS - if not _SESSIONS: - from src.server.sessionhandler import SESSIONS as _SESSIONS - PlayerChannelConnection = ContentType.objects.get(app_label="comms", - model="playerchannelconnection").model_class() - ExternalChannelConnection = ContentType.objects.get(app_label="comms", - model="externalchannelconnection").model_class() - players = [] - if online: - session_list = _SESSIONS.get_sessions() - unique_online_users = set(sess.uid for sess in session_list if sess.logged_in) - online_players = (sess.get_player() for sess in session_list if sess.uid in unique_online_users) - for player in online_players: - players.extend(PlayerChannelConnection.objects.filter( - db_player=player.dbobj, db_channel=channel.dbobj)) - else: - players.extend(PlayerChannelConnection.objects.get_all_connections(channel)) +# def del_channel(self, channelkey): +# """ +# Delete channel matching channelkey. +# Also cleans up channelhandler. +# """ +# channels = self.filter(db_key__iexact=channelkey) +# if not channels: +# # no aliases allowed for deletion. +# return False +# for channel in channels: +# channel.delete() +# from src.comms.channelhandler import CHANNELHANDLER +# CHANNELHANDLER.update() +# return None - external_connections = ExternalChannelConnection.objects.get_all_connections(channel) - - return itertools.chain(players, external_connections) +# def get_all_connections(self, channel, online=False): +# """ +# Return the connections of all players listening +# to this channel. If Online is true, it only returns +# connected players. +# """ +# global _SESSIONS +# if not _SESSIONS: +# from src.server.sessionhandler import SESSIONS as _SESSIONS +# +# PlayerChannelConnection = ContentType.objects.get(app_label="comms", +# model="playerchannelconnection").model_class() +# ExternalChannelConnection = ContentType.objects.get(app_label="comms", +# model="externalchannelconnection").model_class() +# players = [] +# if online: +# session_list = _SESSIONS.get_sessions() +# unique_online_users = set(sess.uid for sess in session_list if sess.logged_in) +# online_players = (sess.get_player() for sess in session_list if sess.uid in unique_online_users) +# for player in online_players: +# players.extend(PlayerChannelConnection.objects.filter( +# db_player=player.dbobj, db_channel=channel.dbobj)) +# else: +# players.extend(PlayerChannelConnection.objects.get_all_connections(channel)) +# +# external_connections = ExternalChannelConnection.objects.get_all_connections(channel) +# +# return itertools.chain(players, external_connections) @returns_typeclass_list - def channel_search(self, ostring): + def channel_search(self, ostring, exact=True): """ Search the channel database for a particular channel. ostring - the key or database id of the channel. + exact - require an exact key match (still not case sensitive) """ channels = [] if not ostring: return channels @@ -374,7 +377,10 @@ class ChannelManager(models.Manager): pass if not channels: # no id match. Search on the key. - channels = self.filter(db_key__iexact=ostring) + if exact: + channels = self.filter(db_key__iexact=ostring) + else: + channels = self.filter(db_key__icontains=ostring) if not channels: # still no match. Search by alias. channels = [channel for channel in self.all() diff --git a/src/comms/migrations/0018_add_subscribers_m2mfield.py b/src/comms/migrations/0018_add_subscribers_m2mfield.py new file mode 100644 index 0000000000..da58e843fd --- /dev/null +++ b/src/comms/migrations/0018_add_subscribers_m2mfield.py @@ -0,0 +1,153 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding M2M table for field db_subscriptions on 'ChannelDB' + m2m_table_name = db.shorten_name(u'comms_channeldb_db_subscriptions') + db.create_table(m2m_table_name, ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('channeldb', models.ForeignKey(orm[u'comms.channeldb'], null=False)), + ('playerdb', models.ForeignKey(orm[u'players.playerdb'], null=False)) + )) + db.create_unique(m2m_table_name, ['channeldb_id', 'playerdb_id']) + + + def backwards(self, orm): + # Removing M2M table for field db_subscriptions on 'ChannelDB' + db.delete_table(db.shorten_name(u'comms_channeldb_db_subscriptions')) + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'comms.channeldb': { + 'Meta': {'object_name': 'ChannelDB'}, + 'db_attributes': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['typeclasses.Attribute']", 'null': 'True', 'symmetrical': 'False'}), + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'subscriber_player_set'", 'null': 'True', 'db_index': 'True', 'to': u"orm['players.PlayerDB']"}), + 'db_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['typeclasses.Tag']", 'null': 'True', 'symmetrical': 'False'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'comms.externalchannelconnection': { + 'Meta': {'object_name': 'ExternalChannelConnection'}, + 'db_channel': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['comms.ChannelDB']"}), + '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'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'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.TextField', [], {'null': 'True', 'blank': 'True'}), + 'db_hide_from_channels': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'hide_from_channels_set'", 'null': 'True', 'to': u"orm['comms.ChannelDB']"}), + 'db_hide_from_objects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'hide_from_objects_set'", 'null': 'True', 'to': u"orm['objects.ObjectDB']"}), + 'db_hide_from_players': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'hide_from_players_set'", 'null': 'True', 'to': u"orm['players.PlayerDB']"}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'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': u"orm['comms.ChannelDB']"}), + 'db_receivers_objects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'receiver_object_set'", 'null': 'True', 'to': u"orm['objects.ObjectDB']"}), + 'db_receivers_players': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'receiver_player_set'", 'null': 'True', 'to': u"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': u"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': u"orm['players.PlayerDB']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'comms.playerchannelconnection': { + 'Meta': {'object_name': 'PlayerChannelConnection'}, + 'db_channel': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['comms.ChannelDB']"}), + 'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['players.PlayerDB']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'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'}), + u'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'}) + }, + u'objects.objectdb': { + 'Meta': {'object_name': 'ObjectDB'}, + 'db_attributes': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['typeclasses.Attribute']", 'null': 'True', 'symmetrical': 'False'}), + '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': u"orm['objects.ObjectDB']"}), + 'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': u"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': u"orm['objects.ObjectDB']"}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}), + 'db_sessid': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'db_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['typeclasses.Tag']", 'null': 'True', 'symmetrical': 'False'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'players.playerdb': { + 'Meta': {'object_name': 'PlayerDB'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'db_attributes': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['typeclasses.Attribute']", 'null': 'True', 'symmetrical': 'False'}), + '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.TextField', [], {'blank': 'True'}), + 'db_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['typeclasses.Tag']", 'null': 'True', 'symmetrical': 'False'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + '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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'typeclasses.attribute': { + 'Meta': {'object_name': 'Attribute'}, + 'db_attrtype': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '16', 'null': 'True', 'blank': 'True'}), + 'db_category': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '128', 'null': 'True', 'blank': 'True'}), + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_model': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'db_strvalue': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'db_value': ('src.utils.picklefield.PickledObjectField', [], {'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'typeclasses.tag': { + 'Meta': {'unique_together': "(('db_key', 'db_category'),)", 'object_name': 'Tag', 'index_together': "(('db_key', 'db_category'),)"}, + 'db_category': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'db_index': 'True'}), + 'db_data': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'db_index': 'True'}), + 'db_model': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'db_index': 'True'}), + 'db_tagtype': ('django.db.models.fields.CharField', [], {'max_length': '16', 'null': 'True', 'db_index': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + } + } + + complete_apps = ['comms'] diff --git a/src/comms/migrations/0019_converting_playerconnection_to_m2m.py b/src/comms/migrations/0019_converting_playerconnection_to_m2m.py new file mode 100644 index 0000000000..21d02b9db3 --- /dev/null +++ b/src/comms/migrations/0019_converting_playerconnection_to_m2m.py @@ -0,0 +1,151 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + + def forwards(self, orm): + "Write your forwards methods here." + # Note: Don't use "from appname.models import ModelName". + # Use orm.ModelName to refer to models in this application, + # and orm['appname.ModelName'] for models in other applications. + + for connection in orm['comms.PlayerChannelConnection'].objects.all(): + channel, player = connection.db_channel, connection.db_player + channel.db_subscriptions.add(player) + + def backwards(self, orm): + "Write your backwards methods here." + raise RuntimeError("Cannot revert this migration.") + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'comms.channeldb': { + 'Meta': {'object_name': 'ChannelDB'}, + 'db_attributes': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['typeclasses.Attribute']", 'null': 'True', 'symmetrical': 'False'}), + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'subscriber_player_set'", 'null': 'True', 'db_index': 'True', 'to': u"orm['players.PlayerDB']"}), + 'db_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['typeclasses.Tag']", 'null': 'True', 'symmetrical': 'False'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'comms.externalchannelconnection': { + 'Meta': {'object_name': 'ExternalChannelConnection'}, + 'db_channel': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['comms.ChannelDB']"}), + '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'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'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.TextField', [], {'null': 'True', 'blank': 'True'}), + 'db_hide_from_channels': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'hide_from_channels_set'", 'null': 'True', 'to': u"orm['comms.ChannelDB']"}), + 'db_hide_from_objects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'hide_from_objects_set'", 'null': 'True', 'to': u"orm['objects.ObjectDB']"}), + 'db_hide_from_players': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'hide_from_players_set'", 'null': 'True', 'to': u"orm['players.PlayerDB']"}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'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': u"orm['comms.ChannelDB']"}), + 'db_receivers_objects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'receiver_object_set'", 'null': 'True', 'to': u"orm['objects.ObjectDB']"}), + 'db_receivers_players': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'receiver_player_set'", 'null': 'True', 'to': u"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': u"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': u"orm['players.PlayerDB']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'comms.playerchannelconnection': { + 'Meta': {'object_name': 'PlayerChannelConnection'}, + 'db_channel': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['comms.ChannelDB']"}), + 'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['players.PlayerDB']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'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'}), + u'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'}) + }, + u'objects.objectdb': { + 'Meta': {'object_name': 'ObjectDB'}, + 'db_attributes': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['typeclasses.Attribute']", 'null': 'True', 'symmetrical': 'False'}), + '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': u"orm['objects.ObjectDB']"}), + 'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': u"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': u"orm['objects.ObjectDB']"}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}), + 'db_sessid': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'db_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['typeclasses.Tag']", 'null': 'True', 'symmetrical': 'False'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'players.playerdb': { + 'Meta': {'object_name': 'PlayerDB'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'db_attributes': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['typeclasses.Attribute']", 'null': 'True', 'symmetrical': 'False'}), + '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.TextField', [], {'blank': 'True'}), + 'db_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['typeclasses.Tag']", 'null': 'True', 'symmetrical': 'False'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + '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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'typeclasses.attribute': { + 'Meta': {'object_name': 'Attribute'}, + 'db_attrtype': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '16', 'null': 'True', 'blank': 'True'}), + 'db_category': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '128', 'null': 'True', 'blank': 'True'}), + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_model': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'db_strvalue': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'db_value': ('src.utils.picklefield.PickledObjectField', [], {'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'typeclasses.tag': { + 'Meta': {'unique_together': "(('db_key', 'db_category'),)", 'object_name': 'Tag', 'index_together': "(('db_key', 'db_category'),)"}, + 'db_category': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'db_index': 'True'}), + 'db_data': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'db_index': 'True'}), + 'db_model': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'db_index': 'True'}), + 'db_tagtype': ('django.db.models.fields.CharField', [], {'max_length': '16', 'null': 'True', 'db_index': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + } + } + + complete_apps = ['comms'] + symmetrical = True diff --git a/src/comms/models.py b/src/comms/models.py index 9bea7775e9..5b469a5500 100644 --- a/src/comms/models.py +++ b/src/comms/models.py @@ -31,7 +31,7 @@ from src.utils import logger from src.utils.utils import to_str, crop, make_iter __all__ = ("Msg", "TempMsg", "ChannelDB", - "PlayerChannelConnection", "ExternalChannelConnection") + "ExternalChannelConnection") _GA = object.__getattribute__ _SA = object.__setattr__ @@ -356,8 +356,8 @@ class ChannelDB(TypedObject): permissions - perm strings """ - db_subscribers = models.ManyToManyField("players.PlayerDB", - related_name="subscriber_player_set", null=True, verbose_name='subscribers', db_index=True) + db_subscriptions = models.ManyToManyField("players.PlayerDB", + related_name="subscription_set", null=True, verbose_name='subscriptions', db_index=True) # Database manager objects = managers.ChannelManager() @@ -388,47 +388,44 @@ class ChannelDB(TypedObject): Checks so this player is actually listening to this channel. """ - # also handle object.player calls - player, typ = identify_object(player) - if typ == 'object': + if hasattr(player, "player"): player = player.player - player, typ = identify_object(player) - if player and not typ == "player": - logger.log_errmsg("Channel.has_connection received object of type '%s'. It only accepts players/characters." % typ) - return - # do the check - return PlayerChannelConnection.objects.has_player_connection(player, self) + player = player.dbobj + return player in self.db_subscriptions.all() - def connect_to(self, player): - "Connect the user to this channel" - self.typeclass.pre_join_channel(player) + def connect(self, player): + "Connect the user to this channel. This checks access." + if hasattr(player, "player"): + player = player.player + player = player.typeclass + # check access if not self.access(player, 'listen'): return False + # pre-join hook connect = self.typeclass.pre_join_channel(player) if not connect: return False - player = player.dbobj - conn = PlayerChannelConnection.objects.create_connection(player, self) - if conn: - self.typeclass.post_join_channel(player) - return True - return False + # subscribe + self.db_subscriptions.add(player.dbobj) + # post-join hook + self.typeclass.post_join_channel(player) + return True - def disconnect_from(self, player): + def disconnect(self, player): "Disconnect user from this channel." + if hasattr(player, "player"): + player = player.player + player = player.typeclass + # pre-disconnect hook disconnect = self.typeclass.pre_leave_channel(player) if not disconnect: return False - PlayerChannelConnection.objects.break_connection(player, self) - self.typeclass.post_leave_channel(player) + # disconnect + self.db_subscriptions.remove(player) + # post-disconnect hook + self.typeclass.post_leave_channel(player.dbobj) return True - def delete(self): - "Clean out all connections to this channel and delete it." - for connection in ChannelDB.objects.get_all_connections(self): - connection.delete() - super(ChannelDB, self).delete() - def access(self, accessing_obj, access_type='listen', default=False): """ Determines if another object has permission to access. @@ -438,65 +435,13 @@ class ChannelDB(TypedObject): """ return self.locks.check(accessing_obj, access_type=access_type, default=default) - -class PlayerChannelConnection(SharedMemoryModel): - """ - This connects a player object to a particular comm channel. - The advantage of making it like this is that one can easily - break the connection just by deleting this object. - """ - - # Player connected to a channel - db_player = models.ForeignKey("players.PlayerDB", verbose_name='player') - # Channel the player is connected to - db_channel = models.ForeignKey(ChannelDB, verbose_name='channel') - - # Database manager - objects = managers.PlayerChannelConnectionManager() - - # player property (wraps db_player) - #@property - def player_get(self): - "Getter. Allows for value = self.player" - return self.db_player - - #@player.setter - def player_set(self, value): - "Setter. Allows for self.player = value" - self.db_player = value - self.save() - - #@player.deleter - def player_del(self): - "Deleter. Allows for del self.player. Deletes connection." - self.delete() - player = property(player_get, player_set, player_del) - - # channel property (wraps db_channel) - #@property - def channel_get(self): - "Getter. Allows for value = self.channel" - return self.db_channel.typeclass - - #@channel.setter - def channel_set(self, value): - "Setter. Allows for self.channel = value" - self.db_channel = value.dbobj - self.save() - - #@channel.deleter - def channel_del(self): - "Deleter. Allows for del self.channel. Deletes connection." - self.delete() - channel = property(channel_get, channel_set, channel_del) - - def __str__(self): - return "Connection Player '%s' <-> %s" % (self.player, self.channel) - - class Meta: - "Define Django meta options" - verbose_name = "Channel<->Player link" - verbose_name_plural = "Channel<->Player links" + def delete(self): + """ + Deletes channel while also cleaning up channelhandler + """ + super(ChannelDB, self).delete() + from src.comms.channelhandler import CHANNELHANDLER + CHANNELHANDLER.update() class ExternalChannelConnection(SharedMemoryModel): diff --git a/src/server/initial_setup.py b/src/server/initial_setup.py index 19f2440589..da71b0e016 100644 --- a/src/server/initial_setup.py +++ b/src/server/initial_setup.py @@ -141,10 +141,9 @@ def create_channels(): # connect the god user to all these channels by default. goduser = get_god_player() - from src.comms.models import PlayerChannelConnection - PlayerChannelConnection.objects.create_connection(goduser, pchan) - PlayerChannelConnection.objects.create_connection(goduser, ichan) - PlayerChannelConnection.objects.create_connection(goduser, cchan) + pchan.connect(goduser) + ichan.connect(goduser) + cchan.connect(goduser) def create_system_scripts():