From d29c6340fc7ee4d653ec3951ac07e6c117b13e55 Mon Sep 17 00:00:00 2001 From: Greg Taylor Date: Thu, 4 Jun 2009 03:42:19 +0000 Subject: [PATCH] Finally transition away from those horrid channel attributes for tracking channel memberships. We'll see about doing away with them altogether if it's possible efficiently. NOTE: MAKE SURE YOU SYNCDB. A new model was added to track channel memberships. --- src/channels/models.py | 15 +++++++++- src/commands/comsys.py | 63 +++++++++++++++++++++++------------------- src/comsys.py | 51 +++++++++++++++++++--------------- src/session_mgr.py | 9 ++++++ 4 files changed, 86 insertions(+), 52 deletions(-) diff --git a/src/channels/models.py b/src/channels/models.py index 9a0a81e836..eb74bf605e 100644 --- a/src/channels/models.py +++ b/src/channels/models.py @@ -12,7 +12,7 @@ class CommChannel(models.Model): """ name = models.CharField(max_length=255) ansi_name = models.CharField(max_length=255) - owner = models.ForeignKey(Object, related_name="chan_owner") + owner = models.ForeignKey(Object, related_name="channel_owner_set") description = models.CharField(max_length=80, blank=True, null=True) is_joined_by_default = models.BooleanField(default=False) req_grp = models.ManyToManyField(Group, blank=True, null=True) @@ -91,6 +91,19 @@ class CommChannel(models.Model): Returns a default channel alias for the channel if none is provided. """ return self.name[:3].lower() + +class CommChannelMembership(models.Model): + """ + Used to track which channels an Object is listening to. + """ + channel = models.ForeignKey(CommChannel, related_name="membership_set") + listener = models.ForeignKey(Object, related_name="channel_membership_set") + user_alias = models.CharField(max_length=10) + comtitle = models.CharField(max_length=25, blank=True) + is_listening = models.BooleanField(default=True) + + def __str__(self): + return "%s: %s" % (self.channel.name, self.listener.name) class CommChannelMessage(models.Model): """ diff --git a/src/commands/comsys.py b/src/commands/comsys.py index ee23da996a..508419195e 100644 --- a/src/commands/comsys.py +++ b/src/commands/comsys.py @@ -3,7 +3,8 @@ Comsys command module. """ import time from django.conf import settings -import src.comsys +from src import comsys +from src.channels.models import CommChannelMembership, CommChannel from src import defines_global from src import ansi from src.util import functions_general @@ -36,24 +37,26 @@ def cmd_addcom(command): chan_name = command_argument.strip() chan_alias = chan_name - if chan_alias in command.session.channels_subscribed: + if source_object.channel_membership_set.filter(channel__name__iexact=chan_name): source_object.emit_to("You are already on that channel.") return - name_matches = src.comsys.cname_search(chan_name, exact=True) - - if name_matches: - chan_name_parsed = name_matches[0].get_name() + try: + chan = CommChannel.objects.get(name__iexact=chan_name) + # This adds a CommChannelMembership object and a matching dict entry + # on the session's cdict. + comsys.plr_add_channel(source_object, chan_alias, chan) + + # Let the player know everything went well. source_object.emit_to("You join %s, with an alias of %s." % \ - (chan_name_parsed, chan_alias)) - src.comsys.plr_set_channel(command.session, chan_alias, - chan_name_parsed, True) + (chan.get_name(), chan_alias)) # Announce the user's joining. join_msg = "%s has joined the channel." % \ (source_object.get_name(show_dbref=False),) - src.comsys.send_cmessage(chan_name_parsed, join_msg) - else: + comsys.send_cmessage(chan, join_msg) + except CommChannel.DoesNotExist: + # Failed to match iexact on channel's 'name' attribute. source_object.emit_to("Could not find channel %s." % chan_name) GLOBAL_CMD_TABLE.add_command("addcom", cmd_addcom), @@ -73,18 +76,20 @@ def cmd_delcom(command): source_object.emit_to("You must specify a channel alias.") return - if command.command_argument not in command.session.channels_subscribed: + try: + membership = source_object.channel_membership_set.get(user_alias__iexact=command.command_argument) + except CommChannelMembership.DoesNotExist: source_object.emit_to("You are not on that channel.") return - chan_name = command.session.channels_subscribed[command.command_argument][0] + chan_name = membership.channel.get_name() source_object.emit_to("You have left %s." % chan_name) - src.comsys.plr_del_channel(command.session, command.command_argument) + comsys.plr_del_channel(source_object, command.command_argument) # Announce the user's leaving. leave_msg = "%s has left the channel." % \ (source_object.get_name(show_dbref=False),) - src.comsys.send_cmessage(chan_name, leave_msg) + comsys.send_cmessage(chan_name, leave_msg) GLOBAL_CMD_TABLE.add_command("delcom", cmd_delcom), def cmd_comlist(command): @@ -95,14 +100,16 @@ def cmd_comlist(command): session = command.session source_object.emit_to("Alias Channel Status") - for chan in session.channels_subscribed: - if session.channels_subscribed[chan][1]: + for membership in source_object.channel_membership_set.all(): + chan = membership.channel + if membership.is_listening: chan_on = "On" else: chan_on = "Off" - source_object.emit_to("%-9.9s %-19.19s %s" % - (chan, session.channels_subscribed[chan][0], chan_on)) + source_object.emit_to("%-9.9s %-19.19s %s" % (membership.user_alias, + chan.get_name(), + chan_on)) source_object.emit_to("-- End of comlist --") GLOBAL_CMD_TABLE.add_command("comlist", cmd_comlist), @@ -136,7 +143,7 @@ def cmd_clist(command): source_object = command.source_object source_object.emit_to("** Channel Owner Description") - for chan in src.comsys.get_all_channels(): + for chan in comsys.get_all_channels(): source_object.emit_to("%s%s %-15.14s%-22.15s%s" % ('-', '-', @@ -159,7 +166,7 @@ def cmd_cdestroy(command): source_object.emit_to("You must supply a name!") return - name_matches = src.comsys.cname_search(cname, exact=True) + name_matches = comsys.cname_search(cname, exact=True) if not name_matches: source_object.emit_to("Could not find channel %s." % (cname,)) @@ -234,7 +241,7 @@ def cmd_cemit(command): source_object.emit_to("You must provide a message to emit.") return - name_matches = src.comsys.cname_search(cname, exact=True) + name_matches = comsys.cname_search(cname, exact=True) if name_matches: cname_parsed = name_matches[0].get_name() else: @@ -252,7 +259,7 @@ def cmd_cemit(command): show_channel_header = False else: if "sendername" in command.command_switches: - if not src.comsys.plr_has_channel(command.session, cname_parsed, + if not comsys.plr_has_channel(command.session, cname_parsed, return_muted=False): source_object.emit_to("You must be on %s to do that." % (cname_parsed,)) return @@ -266,7 +273,7 @@ def cmd_cemit(command): if not "quiet" in command.command_switches: source_object.emit_to("Sent - %s" % (name_matches[0],)) - src.comsys.send_cmessage(cname_parsed, final_cmessage, + comsys.send_cmessage(cname_parsed, final_cmessage, show_header=show_channel_header) if settings.IMC2_ENABLED: @@ -311,7 +318,7 @@ def cmd_cwho(command): source_object.emit_to("You must specify a channel name.") return - name_matches = src.comsys.cname_search(channel_name, exact=True) + name_matches = comsys.cname_search(channel_name, exact=True) if name_matches: # Check to make sure the user has permission to use @cwho. @@ -319,7 +326,7 @@ def cmd_cwho(command): is_controlled_by_plr = name_matches[0].controlled_by(source_object) if is_controlled_by_plr or is_channel_admin: - src.comsys.msg_cwho(source_object, channel_name) + comsys.msg_cwho(source_object, channel_name) else: source_object.emit_to("Permission denied.") return @@ -346,13 +353,13 @@ def cmd_ccreate(command): source_object.emit_to("Permission denied.") return - name_matches = src.comsys.cname_search(cname, exact=True) + name_matches = comsys.cname_search(cname, exact=True) if name_matches: source_object.emit_to("A channel with that name already exists.") else: # Create and set the object up. - new_chan = src.comsys.create_channel(cname, source_object) + new_chan = comsys.create_channel(cname, source_object) source_object.emit_to("Channel %s created." % (new_chan.get_name(),)) GLOBAL_CMD_TABLE.add_command("@ccreate", cmd_ccreate, priv_tuple=("objects.add_commchannel")), diff --git a/src/comsys.py b/src/comsys.py index a6803b0abd..2c5dc9a741 100644 --- a/src/comsys.py +++ b/src/comsys.py @@ -4,7 +4,7 @@ Comsys functions. import time import datetime from django.utils import simplejson -from src.channels.models import CommChannel, CommChannelMessage +from src.channels.models import CommChannel, CommChannelMessage, CommChannelMembership from src import session_mgr from src import ansi from src import logger @@ -119,44 +119,48 @@ def plr_has_channel(session, cname, alias_search=False, return_muted=False): def plr_set_channel_listening(session, alias, listening): """ - Add a channel to a session's channel list. + Enables or disables listening on a particular channel. session: (SessionProtocol) A reference to the player session. alias: (str) The channel alias. listening: (bool) A True or False value to determine listening status. """ + membership = session.pobject.channel_membership_set.get(user_alias=alias) + membership.is_listening = listening + membership.save() plr_get_cdict(session).get(alias)[1] = listening - plr_jsondump_channels(session) -def plr_set_channel(session, alias, cname, listening): +def plr_add_channel(source_object, alias, channel): """ - Set a channels alias, name, and listening status in one go, or add the - channel if it doesn't already exist on a user's list. + Adds a player to a channel via a CommChannelMembership and sets the cached + cdict value. - session: (SessionProtocol) A reference to the player session. + source_object: (Object) Reference to the object that will be listening. alias: (str) The channel alias (also the key in the user's cdict) - cname: (str) Desired channel name to set. + channel: (CommChannel) The channel object to add. listening: (bool) A True or False value to determine listening status. """ - plr_get_cdict(session)[alias] = [cname, listening] - plr_jsondump_channels(session) - -def plr_jsondump_channels(session): - """ - Save the player's channel list to the CHANLIST attribute. + membership = CommChannelMembership(channel=channel, listener=source_object, + user_alias=alias) + membership.save() - session: (SessionProtocol) A reference to the player session. - """ - session.get_pobject().set_attribute("__CHANLIST", simplejson.dumps(plr_get_cdict(session))) + sessions = session_mgr.sessions_from_object(source_object) + for session in sessions: + plr_get_cdict(session)[alias] = [channel.get_name(), True] -def plr_del_channel(session, alias): +def plr_del_channel(source_object, alias): """ Remove a channel from a session's channel list. - session: (SessionProtocol) A reference to the player session. + source_object: (Object) Reference to the object that will be listening. alias: (str) The channel alias (also the key in the user's cdict) """ - del plr_get_cdict(session)[alias] + membership = source_object.channel_membership_set.get(user_alias=alias) + membership.delete() + + sessions = session_mgr.sessions_from_object(source_object) + for session in sessions: + del plr_get_cdict(session)[alias] def msg_chan_hist(target_obj, channel_name): """ @@ -214,11 +218,12 @@ def load_object_channels(pobject): """ Parse JSON dict of a user's channel list from their CHANLIST attribute. """ - chan_list = pobject.get_attribute_value("__CHANLIST") - if chan_list: + membership_list = pobject.channel_membership_set.all() + for membership in membership_list: sessions = session_mgr.sessions_from_object(pobject) for session in sessions: - session.channels_subscribed = simplejson.loads(chan_list) + session.channels_subscribed[membership.user_alias] = [membership.channel.name, + membership.is_listening] def send_cmessage(channel, message, show_header=True): """ diff --git a/src/session_mgr.py b/src/session_mgr.py index 2af3501ec8..b6a027b115 100644 --- a/src/session_mgr.py +++ b/src/session_mgr.py @@ -36,6 +36,15 @@ def get_session_list(return_unlogged=False): return session_list else: return [sess for sess in session_list if sess.is_loggedin()] + +def get_session_id_list(return_unlogged=False): + """ + Lists the connected session object ids. + """ + if return_unlogged: + return session_list + else: + return [sess.uid for sess in session_list if sess.is_loggedin()] def disconnect_all_sessions(): """