Trunk: Merged the Devel-branch (branches/griatch) into /trunk. This constitutes a major refactoring of Evennia. Development will now continue in trunk. See the wiki and the past posts to the mailing list for info. /Griatch

This commit is contained in:
Griatch 2010-08-29 18:46:58 +00:00
parent df29defbcd
commit f83c2bddf8
222 changed files with 22304 additions and 14371 deletions

0
src/comms/__init__.py Normal file
View file

40
src/comms/admin.py Normal file
View file

@ -0,0 +1,40 @@
#
# This sets up how models are displayed
# in the web admin interface.
#
from django.contrib import admin
from src.comms.models import Channel, Msg, ChannelConnection
class MsgAdmin(admin.ModelAdmin):
list_display = ('id', 'db_date_sent', 'db_sender', 'db_receivers', 'db_channels', 'db_message')
list_display_links = ("id",)
ordering = ["db_date_sent", 'db_sender', 'db_receivers', 'db_channels']
readonly_fields = ['db_permissions', 'db_message', 'db_sender', 'db_receivers', 'db_channels']
search_fields = ['id', '^db_date_sent', '^db_message']
save_as = True
save_on_top = True
list_select_related = True
admin.site.register(Msg, MsgAdmin)
class ChannelAdmin(admin.ModelAdmin):
list_display = ('id', 'db_key', 'db_desc', 'db_aliases', 'db_keep_log', 'db_permissions')
list_display_links = ("id", 'db_key')
ordering = ["db_key"]
readonly_fields = ['db_permissions']
search_fields = ['id', 'db_key', 'db_aliases']
save_as = True
save_on_top = True
list_select_related = True
admin.site.register(Channel, ChannelAdmin)
class ChannelConnectionAdmin(admin.ModelAdmin):
list_display = ('db_channel', 'db_player')
list_display_links = ("db_player", 'db_channel')
ordering = ["db_channel"]
search_fields = ['db_channel', 'db_player']
save_as = True
save_on_top = True
list_select_related = True
admin.site.register(ChannelConnection, ChannelConnectionAdmin)

138
src/comms/channelhandler.py Normal file
View file

@ -0,0 +1,138 @@
"""
The channel handler handles the stored set of channels
and how they are represented against the cmdhandler.
If there is a channel named 'newbie', we want to be able
to just write
> newbie Hello!
For this to work, 'newbie', the name of the channel, must
be identified by the cmdhandler as a command name. The
channelhandler stores all channels as custom 'commands'
that the cmdhandler can import and look through.
Warning - channel names take precedence over command names,
so make sure to not pick clashing channel names.
Unless deleting a channel you normally don't need to bother about
the channelhandler at all - the create_channel method handles the update.
To delete a channel cleanly, delete the channel object, then call
update() on the channelhandler. Or use Channel.objects.delete() which
does this for you.
"""
from src.comms.models import Channel, Msg
from src.commands import cmdset, command
from src.permissions.permissions import has_perm
class ChannelCommand(command.Command):
"""
Channel
Usage:
<channel name or alias> <message>
This is a channel. You can send to it by entering
its name or alias, followed by the text you want to send.
"""
# this flag is what identifies this cmd as a channel cmd
# and branches off to the system send-to-channel command
# (which is customizable by admin)
key = "general"
help_category = "Channels"
permissions = "cmd:use_channels"
is_channel = True
obj = None
def parse(self):
"""
Simple parser
"""
channelname, msg = self.args.split(":", 1)
self.args = (channelname.strip(), msg.strip())
def func(self):
"""
Create a new message and send it to channel, using
the already formatted input.
"""
channelkey, msg = self.args
caller = self.caller
if not msg:
caller.msg("Say what?")
return
channel = Channel.objects.get_channel(channelkey)
if not channel:
caller.msg("Channel '%s' not found." % channelkey)
return
if not channel.has_connection(caller):
string = "You are not connected to channel '%s'."
caller.msg(string % channelkey)
return
if not has_perm(caller, channel, 'chan_send'):
string = "You are not permitted to send to channel '%s'."
caller.msg(string % channelkey)
return
msg = "[%s] %s: %s" % (channel.key, caller.name, msg)
# we can't use the utils.create function to make the Msg,
# since that creates an import recursive loop.
msgobj = Msg(db_sender=caller.player, db_message=msg)
msgobj.save()
msgobj.channels = channel
# send new message object to channel
channel.msg(msgobj)
class ChannelHandler(object):
"""
Handles the set of commands related to channels.
"""
def __init__(self):
self.cached_channel_cmds = []
def __str__(self):
return ", ".join(str(cmd) for cmd in self.cached_channel_cmds)
def reset(self):
"""
Reset the cache storage.
"""
self.cached_channel_cmds = []
def add_channel(self, channel):
"""
Add an individual channel to the handler. This should be
called whenever a new channel is created. To
remove a channel, simply delete the channel object
and run self.update on the handler.
"""
# map the channel to a searchable command
cmd = ChannelCommand()
cmd.key = channel.key.strip().lower()
cmd.obj = channel
if channel.aliases:
cmd.aliases = channel.aliases
self.cached_channel_cmds.append(cmd)
def update(self):
"Updates the handler completely."
self.cached_channel_cmds = []
for channel in Channel.objects.all():
self.add_channel(channel)
def get_cmdset(self, source_object):
"""
Retrieve cmdset for channels this source_object has
access to send to.
"""
# create a temporary cmdset holding all channels
chan_cmdset = cmdset.CmdSet()
chan_cmdset.key = '_channelset'
chan_cmdset.priority = 10
for cmd in [cmd for cmd in self.cached_channel_cmds
if has_perm(source_object, cmd, 'chan_send')]:
chan_cmdset.add(cmd)
return chan_cmdset
CHANNELHANDLER = ChannelHandler()

322
src/comms/managers.py Normal file
View file

@ -0,0 +1,322 @@
"""
These managers handles the
"""
from django.db import models
from src.players.models import PlayerDB
from django.contrib.contenttypes.models import ContentType
from src.utils.utils import is_iter
class CommError(Exception):
"Raise by comm system, to allow feedback to player when caught."
pass
# helper function
def to_object(inp, objtype='player'):
"""
Locates the object related to the given
playername or channel key. If input was already
the correct object, return it.
inp - the input object/string
objtype - 'player' or 'channel'
"""
if objtype == 'player':
if type(inp) == PlayerDB:
return inp
if hasattr(inp, 'player'):
return inp.player
else:
umatch = PlayerDB.objects.filter(user__username__iexact=inp)
if umatch:
return umatch[0]
else:
# have to import this way to avoid circular imports
from src.comms.models import Channel
#= ContentType.objects.get(app_label="comms",
# model="channel").model_class()
if type(inp) == Channel:
return inp
cmatch = Channel.objects.filter(db_key__iexact=inp)
if cmatch:
return cmatch[0]
return None
#
# Msg manager
#
class MsgManager(models.Manager):
"""
Handle msg database
"""
def get_message_by_id(self, idnum):
"Retrieve message by its id."
try:
idnum = int(idnum)
return self.get(id=id)
except:
return None
def get_messages_by_sender(self, sender):
"""
Get all messages sent by one player
"""
sender = to_object(sender)
if not sender:
return None
return [msg for msg in sender.sender_set.all()
if sender not in msg.hide_from_senders.all()]
def get_messages_by_receiver(self, receiver):
"""
Get all messages sent to one player
"""
receiver = to_object(receiver)
if not receiver:
return None
return [msg for msg in receiver.receiver_set.all()
if receiver not in msg.hide_from_receivers.all()]
def get_messages_by_channel(self, channel):
"""
Get all messages sent to one channel
"""
channel = to_object(channel, objtype='channel')
if not channel:
return None
return [msg for msg in channel.channel_set.all()
if channel not in msg.hide_from_channels.all()]
#TODO add search limited by send_times
def text_search(self, searchstring, filterdict=None):
"""
Returns all messages that contain the matching
search string. To avoid too many results, and also
since this can be a very computing-
heavy operation, it's recommended to be filtered
by at least channel or sender/receiver.
searchstring - string to search for
filterdict -
{'channels':[list],
'senders':[list],
'receivers':[list]}
lists can contain either the name/keys of the
objects or the actual objects to filter by.
"""
if filterdict:
# obtain valid objects for all filters
channels = [chan for chan in
[to_object(chan, objtype='channel')
for chan in filterdict.get('channels',[])]
if chan]
senders = [sender for sender in
[to_object(sender)
for sender in filterdict.get('senders',[])]
if sender]
receivers = [receiver for receiver in
[to_object(receiver)
for receiver in filterdict.get('receivers',[])]
if receiver]
# filter the messages lazily using the filter objects
msgs = []
for sender in senders:
msgs = list(sender.message_set.filter(
db_message__icontains=searchstring))
for receiver in receivers:
rec_msgs = receiver.message_set.filter(
db_message__icontains=searchstring)
if msgs:
msgs = [msg for msg in rec_msgs if msg in msgs]
else:
msgs = rec_msgs
for channel in channels:
chan_msgs = list(channel.message_set.filter(
db_message__icontains=searchstring))
if msgs:
msgs = [msg for msg in chan_msgs if msg in msgs]
else:
msgs = chan_msgs
return list(set(msgs))
return list(self.all().filter(db_message__icontains=searchstring))
def message_search(self, sender=None, receiver=None, channel=None, freetext=None, dbref=None):
"""
Search the message database for particular messages. At least one
of the arguments must be given to do a search.
sender - get messages sent by a particular player
receiver - get messages received by a certain player or players
channel - get messages sent to a particular channel or channels
freetext - Search for a text string in a message.
NOTE: This can potentially be slow, so make sure to supply
one of the other arguments to limit the search.
dbref - (int) the exact database id of the message. This will override
all other search crieteria since it's unique and
always gives a list with only one match.
"""
if dbref:
return self.filter(id=dbref)
if freetext:
if sender:
sender = [sender]
if receiver and not is_iter(receiver):
receiver = [receiver]
if channel and not is_iter(channel):
channel = [channel]
filterdict = {"senders":sender,
"receivers":receiver,
"channels":channel}
return self.textsearch(freetext, filterdict)
msgs = []
if sender:
msgs = self.get_messages_by_sender(sender)
if receiver:
rec_msgs = self.get_messages_by_receiver(receiver)
if msgs:
msgs = [msg for msg in rec_msgs if msg in msgs]
else:
msgs = rec_msgs
if channel:
chan_msgs = self.get_messaqge_by_channel(channel)
if msgs:
msgs = [msg for msg in chan_msgs if msg in msgs]
else:
msgs = chan_msgs
return msgs
#
# Channel manager
#
class ChannelManager(models.Manager):
"""
Handle channel database
"""
def get_all_channels(self):
"""
Returns all channels in game.
"""
return self.all()
def get_channel(self, channelkey):
"""
Return the channel object if given its key.
Also searches its aliases.
"""
# first check the channel key
channels = self.filter(db_key__iexact=channelkey)
if not channels:
# also check aliases
channels = [channel for channel in self.all()
if channelkey in channel.aliases]
if channels:
return channels[0]
return None
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
def has_connection(self, player, channel):
"Check so the player is really listening to this channel."
ChannelConnection = ContentType.objects.get(app_label="comms",
model="channelconnection").model_class()
return ChannelConnection.objects.has_connection(player, channel)
def get_all_connections(self, channel):
"""
Return the connections of all players listening
to this channel
"""
# import here to avoid circular imports
from src.comms.models import ChannelConnection
#= ContentType.objects.get(app_label="comms",
# model="channelconnection").model_class()
return ChannelConnection.objects.get_all_connections(channel)
def channel_search(self, ostring):
"""
Search the channel database for a particular channel.
ostring - the key or database id of the channel.
"""
channels = []
try:
# try an id match first
dbref = int(ostring.strip('#'))
channels = self.filter(id=dbref)
except Exception:
pass
if not channels:
# no id match. Search on the key.
channels = self.filter(db_key=ostring)
return channels
#
# ChannelConnection manager
#
class ChannelConnectionManager(models.Manager):
"""
This handles all connections between a player and
a channel.
"""
def get_all_player_connections(self, player):
"Get all connections that the given player has."
player = to_object(player)
return self.filter(db_player=player)
def has_connection(self, player, channel):
"Checks so a connection exists player<->channel"
player = to_object(player)
channel = to_object(channel, objtype="channel")
if player and channel:
return self.filter(db_player=player).filter(db_channel=channel).count() > 0
return False
def get_all_connections(self, channel):
"""
Get all connections for a channel
"""
channel = to_object(channel, objtype='channel')
return self.filter(db_channel=channel)
def create_connection(self, player, channel):
"""
Connect a player to a channel. player and channel
can be actual objects or keystrings.
"""
player = to_object(player)
channel = to_object(channel, objtype='channel')
if not player or not channel:
raise CommError("NOTFOUND")
new_connection = self.model(db_player=player, db_channel=channel)
new_connection.save()
return new_connection
def break_connection(self, player, channel):
"Remove link between player and channel"
player = to_object(player)
channel = to_object(channel, objtype='channel')
if not player or not channel:
raise CommError("NOTFOUND")
conns = self.filter(db_player=player).filter(db_channel=channel)
for conn in conns:
conn.delete()

590
src/comms/models.py Normal file
View file

@ -0,0 +1,590 @@
"""
Models for the comsystem.
The comsystem's main component is the Message, which
carries the actual information between two parties.
Msgs are stored in the database and usually not
deleted.
A Msg always have one sender (a user), but can have
any number targets, both users and channels.
Channels are central objects that act as targets for
Msgs. Players can connect to channels by use of a
ChannelConnect object (this object is necessary to easily
be able to delete connections on the fly).
"""
from django.db import models
from src.utils.idmapper.models import SharedMemoryModel
from src.players.models import PlayerDB
from src.comms import managers
from src.server import sessionhandler
from src.permissions.permissions import has_perm
from src.utils.utils import is_iter
from src.utils.utils import dbref as is_dbref
#------------------------------------------------------------
#
# Utils
#
#------------------------------------------------------------
def obj_to_id(inp):
"""
Converts input object to an id string.
"""
dbref = is_dbref(inp)
if dbref:
return str(dbref)
if hasattr(inp, 'id'):
return str(inp.id)
if hasattr(inp, 'dbobj') and hasattr(inp.dbobj, 'id'):
return str(inp.dbobj.id)
return str(inp)
def id_to_obj(dbref, db_model='PlayerDB'):
"""
loads from dbref to object. Uses the db_model to search
for the id.
"""
if db_model == 'PlayerDB':
from src.player.objects import PlayerDB as db_model
else:
db_model = Channel
try:
dbref = int(dbref.strip())
return db_model.objects.get(id=dbref)
except Exception:
return None
#------------------------------------------------------------
#
# Msg
#
#------------------------------------------------------------
class Msg(SharedMemoryModel):
"""
A single message. This model describes all ooc messages
sent in-game, both to channels and between players.
The Msg class defines the following properties:
sender - sender of message
receivers - list of target objects for message
channels - list of channels message was sent to
message - the text being sent
date_sent - time message was sent
hide_from_sender - bool if message should be hidden from sender
hide_from_receivers - list of receiver objects to hide message from
hide_from_channels - list of channels objects to hide message from
permissions - perm strings
"""
#
# Msg database model setup
#
#
# These databse fields are all set using their corresponding properties,
# named same as the field, but withtout the db_* prefix.
# There must always be one sender of the message.
db_sender = models.ForeignKey(PlayerDB, related_name='sender_set')
# The destination objects of this message. Stored as a
# comma-separated string of object dbrefs. Can be defined along
# with channels below.
db_receivers = models.CharField(max_length=255, null=True, blank=True)
# The channels this message was sent to. Stored as a
# comma-separated string of channel dbrefs. A message can both
# have channel targets and destination objects.
db_channels = models.CharField(max_length=255, null=True, blank=True)
# The actual message and a timestamp. The message field
# should itself handle eventual headers etc.
db_message = models.TextField()
db_date_sent = models.DateTimeField(editable=False, auto_now_add=True)
# These are settable by senders/receivers/channels respectively.
# Stored as a comma-separated string of dbrefs. Can be used by the
# game to mask out messages from being visible in the archive (no
# messages are actually deleted)
#db_hide_from_sender = models.BooleanField(default=False)
#db_hide_from_receivers = models.CharField(max_length=255, null=True, blank=True)
#db_hide_from_channels = models.CharField(max_length=255, null=True, blank=True)
# permission strings, separated by commas
db_permissions = models.CharField(max_length=255, blank=True)
# Database manager
objects = managers.MsgManager()
class Meta:
"Define Django meta options"
verbose_name = "Message"
verbose_name_plural = "Messages"
# Wrapper properties to easily set database fields. These are
# @property decorators that allows to access these fields using
# normal python operations (without having to remember to save()
# etc). So e.g. a property 'attr' has a get/set/del decorator
# defined that allows the user to do self.attr = value,
# value = self.attr and del self.attr respectively (where self
# is the object in question).
# sender property (wraps db_sender)
#@property
def sender_get(self):
"Getter. Allows for value = self.sender"
return self.db_sender
#@sender.setter
def sender_set(self, value):
"Setter. Allows for self.sender = value"
self.db_sender = value
self.save()
#@sender.deleter
def sender_del(self):
"Deleter. Allows for del self.sender"
raise Exception("You cannot delete the sender of a message!")
sender = property(sender_get, sender_set, sender_del)
# receivers property
#@property
def receivers_get(self):
"Getter. Allows for value = self.receivers. Returns a list of receivers."
if self.db_receivers:
return [id_to_obj(dbref) for dbref in self.db_receivers.split(',')]
return []
#@receivers.setter
def receivers_set(self, value):
"Setter. Allows for self.receivers = value. Stores as a comma-separated string."
if is_iter(value):
value = ",".join([obj_to_id(val) for val in value])
self.db_receivers = obj_to_id(value)
self.save()
#@receivers.deleter
def receivers_del(self):
"Deleter. Allows for del self.receivers"
self.db_receivers = ""
self.save()
receivers = property(receivers_get, receivers_set, receivers_del)
# channels property
#@property
def channels_get(self):
"Getter. Allows for value = self.channels. Returns a list of channels."
if self.db_channels:
return [id_to_obj(dbref, 'Channel') for dbref in self.db_channels.split(',')]
return []
#@channels.setter
def channels_set(self, value):
"Setter. Allows for self.channels = value. Stores as a comma-separated string."
if is_iter(value):
value = ",".join([obj_to_id(val) for val in value])
self.db_channels = obj_to_id(value)
self.save()
#@channels.deleter
def channels_del(self):
"Deleter. Allows for del self.channels"
self.db_channels = ""
self.save()
channels = property(channels_get, channels_set, channels_del)
# message property (wraps db_message)
#@property
def message_get(self):
"Getter. Allows for value = self.message"
return self.db_message
#@message.setter
def message_set(self, value):
"Setter. Allows for self.message = value"
self.db_message = value
self.save()
#@message.deleter
def message_del(self):
"Deleter. Allows for del self.message"
self.db_message = ""
self.save()
message = property(message_get, message_set, message_del)
# date_sent property (wraps db_date_sent)
#@property
def date_sent_get(self):
"Getter. Allows for value = self.date_sent"
return self.db_date_sent
#@date_sent.setter
def date_sent_set(self, value):
"Setter. Allows for self.date_sent = value"
self.db_date_sent = value
self.save()
#@date_sent.deleter
def date_sent_del(self):
"Deleter. Allows for del self.date_sent"
raise Exception("You cannot delete the date_sent property!")
date_sent = property(date_sent_get, date_sent_set, date_sent_del)
# hide_from_sender property
#@property
def hide_from_sender_get(self):
"Getter. Allows for value = self.hide_from_sender."
return self.db_hide_from_sender
#@hide_from_sender.setter
def hide_from_sender_set(self, value):
"Setter. Allows for self.hide_from_senders = value."
self.db_hide_from_sender = value
self.save()
#@hide_from_sender.deleter
def hide_from_sender_del(self):
"Deleter. Allows for del self.hide_from_senders"
self.db_hide_from_sender = False
self.save()
hide_from_sender = property(hide_from_sender_get, hide_from_sender_set, hide_from_sender_del)
# hide_from_receivers property
#@property
def hide_from_receivers_get(self):
"Getter. Allows for value = self.hide_from_receivers. Returns a list of hide_from_receivers."
if self.db_hide_from_receivers:
return [id_to_obj(dbref) for dbref in self.db_hide_from_receivers.split(',')]
return []
#@hide_from_receivers.setter
def hide_from_receivers_set(self, value):
"Setter. Allows for self.hide_from_receivers = value. Stores as a comma-separated string."
if is_iter(value):
value = ",".join([obj_to_id(val) for val in value])
self.db_hide_from_receivers = obj_to_id(value)
self.save()
#@hide_from_receivers.deleter
def hide_from_receivers_del(self):
"Deleter. Allows for del self.hide_from_receivers"
self.db_hide_from_receivers = ""
self.save()
hide_from_receivers = property(hide_from_receivers_get, hide_from_receivers_set, hide_from_receivers_del)
# hide_from_channels property
#@property
def hide_from_channels_get(self):
"Getter. Allows for value = self.hide_from_channels. Returns a list of hide_from_channels."
if self.db_hide_from_channels:
return [id_to_obj(dbref) for dbref in self.db_hide_from_channels.split(',')]
return []
#@hide_from_channels.setter
def hide_from_channels_set(self, value):
"Setter. Allows for self.hide_from_channels = value. Stores as a comma-separated string."
if is_iter(value):
value = ",".join([obj_to_id(val) for val in value])
self.db_hide_from_channels = obj_to_id(value)
self.save()
#@hide_from_channels.deleter
def hide_from_channels_del(self):
"Deleter. Allows for del self.hide_from_channels"
self.db_hide_from_channels = ""
self.save()
hide_from_channels = property(hide_from_channels_get, hide_from_channels_set, hide_from_channels_del)
# permissions property
#@property
def permissions_get(self):
"Getter. Allows for value = self.permissions. Returns a list of permissions."
if self.db_permissions:
return [perm.strip() for perm in self.db_permissions.split(',')]
return []
#@permissions.setter
def permissions_set(self, value):
"Setter. Allows for self.permissions = value. Stores as a comma-separated string."
if is_iter(value):
value = ",".join([str(val).strip().lower() for val in value])
self.db_permissions = value
self.save()
#@permissions.deleter
def permissions_del(self):
"Deleter. Allows for del self.permissions"
self.db_permissions = ""
self.save()
permissions = property(permissions_get, permissions_set, permissions_del)
#
# Msg class method
#
def __str__(self):
"Print text"
if self.channels:
return "%s -> %s: %s" % (self.sender.key,
", ".join([chan.key for chan in self.channels]),
self.message)
else:
return "%s -> %s: %s" % (self.sender.key,
", ".join([rec.key for rec in self.receivers]),
self.message)
#------------------------------------------------------------
#
# Channel
#
#------------------------------------------------------------
class Channel(SharedMemoryModel):
"""
This is the basis of a comm channel, only implementing
the very basics of distributing messages.
The Channel class defines the following properties:
key - main name for channel
desc - optional description of channel
aliases - alternative names for the channel
keep_log - bool if the channel should remember messages
permissions - perm strings
"""
#
# Channel database model setup
#
#
# These databse fields are all set using their corresponding properties,
# named same as the field, but withtout the db_* prefix.
# unique identifier for this channel
db_key = models.CharField(max_length=255, unique=True)
# optional description of channel
db_desc = models.CharField(max_length=80, blank=True, null=True)
# aliases for the channel. These are searched by cmdhandler
# as well to determine if a command is the name of a channel.
# Several aliases are separated by commas.
db_aliases = models.CharField(max_length=255)
# Whether this channel should remember its past messages
db_keep_log = models.BooleanField(default=True)
# Permission strings, separated by commas
db_permissions = models.CharField(max_length=255, blank=True)
# Database manager
objects = managers.ChannelManager()
# Wrapper properties to easily set database fields. These are
# @property decorators that allows to access these fields using
# normal python operations (without having to remember to save()
# etc). So e.g. a property 'attr' has a get/set/del decorator
# defined that allows the user to do self.attr = value,
# value = self.attr and del self.attr respectively (where self
# is the object in question).
# key property (wraps db_key)
#@property
def key_get(self):
"Getter. Allows for value = self.key"
return self.db_key
#@key.setter
def key_set(self, value):
"Setter. Allows for self.key = value"
self.db_key = value
self.save()
#@key.deleter
def key_del(self):
"Deleter. Allows for del self.key"
raise Exception("You cannot delete the channel key!")
key = property(key_get, key_set, key_del)
# desc property (wraps db_desc)
#@property
def desc_get(self):
"Getter. Allows for value = self.desc"
return self.db_desc
#@desc.setter
def desc_set(self, value):
"Setter. Allows for self.desc = value"
self.db_desc = value
self.save()
#@desc.deleter
def desc_del(self):
"Deleter. Allows for del self.desc"
self.db_desc = ""
self.save()
desc = property(desc_get, desc_set, desc_del)
# aliases property
#@property
def aliases_get(self):
"Getter. Allows for value = self.aliases. Returns a list of aliases."
if self.db_aliases:
return [perm.strip() for perm in self.db_aliases.split(',')]
return []
#@aliases.setter
def aliases_set(self, value):
"Setter. Allows for self.aliases = value. Stores as a comma-separated string."
if is_iter(value):
value = ",".join([str(val).strip().lower() for val in value])
self.db_aliases = value
self.save()
#@aliases_del.deleter
def aliases_del(self):
"Deleter. Allows for del self.aliases"
self.db_aliases = ""
self.save()
aliases = property(aliases_get, aliases_set, aliases_del)
# keep_log property (wraps db_keep_log)
#@property
def keep_log_get(self):
"Getter. Allows for value = self.keep_log"
return self.db_keep_log
#@keep_log.setter
def keep_log_set(self, value):
"Setter. Allows for self.keep_log = value"
self.db_keep_log = value
self.save()
#@keep_log.deleter
def keep_log_del(self):
"Deleter. Allows for del self.keep_log"
self.db_keep_log = False
self.save()
keep_log = property(keep_log_get, keep_log_set, keep_log_del)
# permissions property
#@property
def permissions_get(self):
"Getter. Allows for value = self.permissions. Returns a list of permissions."
if self.db_permissions:
return [perm.strip() for perm in self.db_permissions.split(',')]
return []
#@permissions.setter
def permissions_set(self, value):
"Setter. Allows for self.permissions = value. Stores as a comma-separated string."
if is_iter(value):
value = ",".join([str(val).strip().lower() for val in value])
self.db_permissions = value
self.save()
#@permissions.deleter
def permissions_del(self):
"Deleter. Allows for del self.permissions"
self.db_permissions = ""
self.save()
permissions = property(permissions_get, permissions_set, permissions_del)
class Meta:
"Define Django meta options"
verbose_name = "Channel"
verbose_name_plural = "Channels"
#
# Channel class methods
#
def __str__(self):
return "Channel '%s' (%s)" % (self.key, self.desc)
def has_connection(self, player):
"""
Checks so this player is actually listening
to this channel.
"""
return Channel.objects.has_connection(player, self)
def msg(self, msgobj, from_obj=None):
"""
Send the given message to all players connected to channel. Note that
no permission-checking is done here; it is assumed to have been
done before calling this method.
msgobj - a Msg instance. May be a message string.
from_obj - if msgobj is not an Msg-instance, this is used to create
a message on the fly. The advantage of this is that such
messages are logged.
"""
if not type(msgobj) == Msg:
# the given msgobj is not an Msg instance. If it is a string and from_obj
# was given, we create the message on the fly instead.
if from_obj and isinstance(msgobj, basestring):
msgobj = Msg(db_sender=from_obj, db_message=msgobj)
msgobj.save()
msgobj.channels = [self]
msg = msgobj.message
else:
# this just sends a message, without any sender
# (and without storing it in a persistent Msg object)
msg = str(msgobj)
else:
msg = msgobj.message
# get all players connected to this channel
conns = Channel.objects.get_all_connections(self)
# send message to all connected players
for conn in conns:
for session in \
sessionhandler.find_sessions_from_username(conn.player.name):
session.msg(msg)
return True
def connect_to(self, player):
"Connect the user to this channel"
if not has_perm(player, self, 'chan_listen'):
return False
conn = ChannelConnection.objects.create_connection(player, self)
if conn:
return True
return False
def disconnect_from(self, player):
"Disconnect user from this channel."
ChannelConnection.objects.break_connection(player, self)
def delete(self):
"Clean out all connections to this channel and delete it."
for connection in Channel.objects.get_all_connections(self):
connection.delete()
super(Channel, self).delete()
class ChannelConnection(SharedMemoryModel):
"""
This connects a user 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(PlayerDB)
# Channel the player is connected to
db_channel = models.ForeignKey(Channel)
# Database manager
objects = managers.ChannelConnectionManager()
# 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
#@channel.setter
def channel_set(self, value):
"Setter. Allows for self.channel = value"
self.db_channel = value
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"