mirror of
https://github.com/evennia/evennia.git
synced 2026-04-04 06:57:16 +02:00
OBS: run migrations! This changes the Msg model to work with ManyToManyFields rather than with custom string representations for storing multiple receivers or channels. It also expands the Msg object with a "title" field and various filter options. This should make it easier to implement mail-like operations using the comms system.
This commit is contained in:
parent
7995c91eee
commit
dcc7f29a91
8 changed files with 656 additions and 381 deletions
|
|
@ -1,7 +1,12 @@
|
|||
"""
|
||||
Models for the comsystem.
|
||||
Models for the comsystem. The Commsystem is intended to be
|
||||
used by Players (thematic IC communication is probably
|
||||
best handled by custom commands instead).
|
||||
|
||||
The comsystem's main component is the Message, which
|
||||
The comm system could take the form of channels, but can also
|
||||
be adopted for storing tells or in-game mail.
|
||||
|
||||
The comsystem's main component is the Message (Msg), which
|
||||
carries the actual information between two parties.
|
||||
Msgs are stored in the database and usually not
|
||||
deleted.
|
||||
|
|
@ -17,46 +22,12 @@ be able to delete connections on the fly).
|
|||
from django.db import models
|
||||
from src.utils.idmapper.models import SharedMemoryModel
|
||||
from src.comms import managers
|
||||
from src.comms.managers import identify_object
|
||||
from src.locks.lockhandler import LockHandler
|
||||
from src.utils import logger
|
||||
from src.utils.utils import is_iter, to_str
|
||||
from src.utils.utils import dbref as is_dbref
|
||||
from src.utils.utils import is_iter, to_str, crop
|
||||
__all__ = ("Msg", "TempMsg", "Channel", "PlayerChannelConnection", "ExternalChannelConnection")
|
||||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
# 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.players.models 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
|
||||
|
|
@ -87,37 +58,50 @@ class Msg(SharedMemoryModel):
|
|||
# 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("players.PlayerDB", related_name='sender_set', null=True, verbose_name='sender')
|
||||
# in the case of external senders, no Player object might be available
|
||||
db_sender_external = models.CharField('external sender', max_length=255, null=True, blank=True,
|
||||
# Sender is either a player, an object or an external sender, like an IRC channel
|
||||
# normally there is only one, but if co-modification of a message is allowed, there
|
||||
# may be more than one "author"
|
||||
db_sender_players = models.ManyToManyField("players.PlayerDB", related_name='sender_player_set', null=True, verbose_name='sender(player)', db_index=True)
|
||||
db_sender_objects = models.ManyToManyField("objects.ObjectDB", related_name='sender_object_set', null=True, verbose_name='sender(object)', db_index=True)
|
||||
db_sender_external = models.CharField('external sender', max_length=255, null=True, db_index=True,
|
||||
help_text="identifier for external sender, for example a sender over an IRC connection (i.e. someone who doesn't have an exixtence in-game).")
|
||||
# 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('receivers', max_length=255, null=True, blank=True,
|
||||
help_text='comma-separated list of object dbrefs this message is aimed at.')
|
||||
# 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('channels', max_length=255, null=True, blank=True,
|
||||
help_text='comma-separated list of channel dbrefs this message is aimed at.')
|
||||
db_receivers_players = models.ManyToManyField('players.PlayerDB', related_name='receiver_player_set', null=True, help_text="player receivers")
|
||||
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)
|
||||
db_message = models.TextField('messsage')
|
||||
db_date_sent = models.DateTimeField('date sent', editable=False, auto_now_add=True)
|
||||
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,
|
||||
help_text='access locks on this message.')
|
||||
# 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)
|
||||
# Storage of lock strings
|
||||
#db_lock_storage = models.TextField(null=True)
|
||||
|
||||
# these can be used to filter/hide a given message from supplied objects/players/channels
|
||||
db_hide_from_players = models.ManyToManyField("players.PlayerDB", related_name='hide_from_players_set', null=True)
|
||||
db_hide_from_objects = models.ManyToManyField("objects.ObjectDB", related_name='hide_from_objects_set', null=True)
|
||||
db_hide_from_channles = models.ManyToManyField("Channel", related_name='hide_from_channels_set', null=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)
|
||||
## Storage of lock strings
|
||||
##db_receivers = models.CharField('receivers', max_length=255, null=True, blank=True,
|
||||
## help_text='comma-separated list of object dbrefs this message is aimed at.')
|
||||
### 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('channels', max_length=255, null=True, blank=True,
|
||||
## help_text='comma-separated list of channel dbrefs this message is aimed at.')
|
||||
|
||||
# Database manager
|
||||
objects = managers.MsgManager()
|
||||
|
|
@ -138,80 +122,120 @@ class Msg(SharedMemoryModel):
|
|||
# value = self.attr and del self.attr respectively (where self
|
||||
# is the object in question).
|
||||
|
||||
# sender property (wraps db_sender)
|
||||
# sender property (wraps db_sender_*)
|
||||
#@property
|
||||
def __sender_get(self):
|
||||
def __senders_get(self):
|
||||
"Getter. Allows for value = self.sender"
|
||||
return self.db_sender
|
||||
return list(self.db_sender_players.all()) + list(self.db_sender_objects.all())
|
||||
#@sender.setter
|
||||
def __sender_set(self, value):
|
||||
def __senders_set(self, value):
|
||||
"Setter. Allows for self.sender = value"
|
||||
self.db_sender = value
|
||||
obj, typ = identify_object(value)
|
||||
if typ == 'player':
|
||||
self.db_sender_players.add(obj)
|
||||
elif typ == 'object':
|
||||
self.db_sender_objects.add(obj)
|
||||
elif isinstance(typ, basestring):
|
||||
self.db_sender_external = obj
|
||||
elif not obj:
|
||||
return
|
||||
else:
|
||||
raise ValueError
|
||||
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)
|
||||
|
||||
# sender_external property (wraps db_sender_external)
|
||||
#@property
|
||||
def __sender_external_get(self):
|
||||
"Getter. Allows for value = self.sender_external"
|
||||
return self.db_sender_external
|
||||
#@sender_external.setter
|
||||
def __sender_external_set(self, value):
|
||||
"Setter. Allows for self.sender_external = value"
|
||||
self.db_sender_external = value
|
||||
def __senders_del(self):
|
||||
"Deleter. Clears all senders"
|
||||
self.db_sender_players.clear()
|
||||
self.db_sender_objects.clear()
|
||||
self.db_sender_external = ""
|
||||
self.save()
|
||||
senders = property(__senders_get, __senders_set, __senders_del)
|
||||
|
||||
def remove_sender(self, obj):
|
||||
"Remove a single sender"
|
||||
obj, typ = identify_object(obj)
|
||||
if typ == 'player':
|
||||
self.db_sender_players.remove(obj)
|
||||
elif typ == 'object':
|
||||
self.db_sender_objects.remove(obj)
|
||||
elif isinstance(obj, basestring) and self.db_sender_external == obj:
|
||||
self.db_sender_external = ""
|
||||
else:
|
||||
raise ValueError
|
||||
self.save()
|
||||
#@sender_external.deleter
|
||||
def __sender_external_del(self):
|
||||
"Deleter. Allows for del self.sender_external"
|
||||
raise Exception("You cannot delete the sender_external of a message!")
|
||||
sender_external = property(__sender_external_get, __sender_external_set, __sender_external_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 []
|
||||
"Getter. Allows for value = self.receivers. Returns three lists of receivers: players, objects and channels."
|
||||
return list(self.db_receivers_players.all()) + list(self.db_receivers_objects.all())
|
||||
#@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)
|
||||
"Setter. Allows for self.receivers = value. This appends a new receiver to the message."
|
||||
obj, typ = identify_object(value)
|
||||
if typ == 'player':
|
||||
self.db_receivers_players.add(obj)
|
||||
elif typ == 'object':
|
||||
self.db_receivers_objects.add(obj)
|
||||
elif not obj:
|
||||
return
|
||||
else:
|
||||
raise ValueError
|
||||
self.save()
|
||||
#@receivers.deleter
|
||||
def __receivers_del(self):
|
||||
"Deleter. Allows for del self.receivers"
|
||||
self.db_receivers = ""
|
||||
"Deleter. Clears all receivers"
|
||||
self.db_receivers_players.clear()
|
||||
self.db_receivers_objects.clear()
|
||||
self.save()
|
||||
receivers = property(__receivers_get, __receivers_set, __receivers_del)
|
||||
|
||||
def remove_receiver(self, obj):
|
||||
"Remove a single recevier"
|
||||
obj, typ = identify_object(obj)
|
||||
if typ == 'player':
|
||||
self.db_receivers_players.remove(obj)
|
||||
elif typ == 'object':
|
||||
self.db_receivers_objects.remove(obj)
|
||||
else:
|
||||
raise ValueError
|
||||
self.save()
|
||||
|
||||
# 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 []
|
||||
return self.db_receivers_channels.all()
|
||||
#@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()
|
||||
"Setter. Allows for self.channels = value. Requires a channel to be added."
|
||||
if value:
|
||||
self.db_receivers_channels.add(value)
|
||||
#@channels.deleter
|
||||
def __channels_del(self):
|
||||
"Deleter. Allows for del self.channels"
|
||||
self.db_channels = ""
|
||||
self.db_receivers_channels.clear()
|
||||
self.save()
|
||||
channels = property(__channels_get, __channels_set, __channels_del)
|
||||
|
||||
# title property (wraps db_title)
|
||||
#@property
|
||||
def __title_get(self):
|
||||
"Getter. Allows for value = self.message"
|
||||
return self.db_title
|
||||
#@message.setter
|
||||
def __title_set(self, value):
|
||||
"Setter. Allows for self.message = value"
|
||||
if value:
|
||||
self.db_title = value
|
||||
self.save()
|
||||
#@message.deleter
|
||||
def __title_del(self):
|
||||
"Deleter. Allows for del self.message"
|
||||
self.db_title = ""
|
||||
self.save()
|
||||
title = property(__title_get, __title_set, __title_del)
|
||||
|
||||
# message property (wraps db_message)
|
||||
#@property
|
||||
def __message_get(self):
|
||||
|
|
@ -244,64 +268,32 @@ class Msg(SharedMemoryModel):
|
|||
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
|
||||
# hide_from property
|
||||
#@property
|
||||
def __hide_from_sender_get(self):
|
||||
"Getter. Allows for value = self.hide_from_sender."
|
||||
return self.db_hide_from_sender
|
||||
def __hide_from_get(self):
|
||||
"Getter. Allows for value = self.hide_from. Returns 3 lists of players, objects and channels"
|
||||
return self.db_hide_from_players.all(), self.db_hide_from_objects.all(), self.db_hide_from_channels.all()
|
||||
#@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
|
||||
def __hide_from_set(self, value):
|
||||
"Setter. Allows for self.hide_from = value. Will append to hiders"
|
||||
obj, typ = identify_object(value)
|
||||
if typ == "player":
|
||||
self.db_hide_from_players.add(obj)
|
||||
elif typ == "object":
|
||||
self.db_hide_from_objects.add(obj)
|
||||
elif typ == "channel":
|
||||
self.db_hide_from_channels.add(obj)
|
||||
else:
|
||||
raise ValueError
|
||||
self.save()
|
||||
#@hide_from_sender.deleter
|
||||
def __hide_from_sender_del(self):
|
||||
def __hide_from_del(self):
|
||||
"Deleter. Allows for del self.hide_from_senders"
|
||||
self.db_hide_from_sender = False
|
||||
self.db_hide_from_players.clear()
|
||||
self.db_hide_from_objects.clear()
|
||||
self.db_hide_from_channels.clear()
|
||||
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)
|
||||
hide_from = property(__hide_from_get, __hide_from_set, __hide_from_del)
|
||||
|
||||
# lock_storage property (wraps db_lock_storage)
|
||||
#@property
|
||||
|
|
@ -326,15 +318,11 @@ class Msg(SharedMemoryModel):
|
|||
#
|
||||
|
||||
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)
|
||||
"This handles what is shown when e.g. printing the message"
|
||||
senders = ",".join(obj.key for obj in self.senders)
|
||||
receivers = ",".join(["[%s]" % obj.key for obj in self.channels] + [obj.key for obj in self.receivers])
|
||||
return "%s->%s::%s" % (senders, receivers, crop(self.message, width=40))
|
||||
|
||||
def access(self, accessing_obj, access_type='read', default=False):
|
||||
"""
|
||||
Determines if another object has permission to access.
|
||||
|
|
@ -360,13 +348,11 @@ class TempMsg(object):
|
|||
|
||||
"""
|
||||
def __init__(self, sender=None, receivers=[], channels=[], message="", permissions=[]):
|
||||
self.sender = sender
|
||||
self.senders = sender
|
||||
self.receivers = receivers
|
||||
self.message = message
|
||||
self.permissions = permissions
|
||||
self.hide_from_sender = False
|
||||
self.hide_from_sender = receivers = False
|
||||
self.hide_from_channels = False
|
||||
self.hide_from = None
|
||||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
|
|
@ -408,6 +394,7 @@ class Channel(SharedMemoryModel):
|
|||
# Storage of lock definitions
|
||||
db_lock_storage = models.CharField('locks', max_length=512, blank=True)
|
||||
|
||||
|
||||
# Database manager
|
||||
objects = managers.ChannelManager()
|
||||
|
||||
|
|
@ -533,7 +520,7 @@ class Channel(SharedMemoryModel):
|
|||
Checks so this player is actually listening
|
||||
to this channel.
|
||||
"""
|
||||
return PlayerChannelConnection.objects.has_connection(player, self)
|
||||
return PlayerChannelConnection.objects.has_player_connection(player, self)
|
||||
|
||||
def msg(self, msgobj, from_obj=None):
|
||||
"""
|
||||
|
|
@ -582,7 +569,7 @@ class Channel(SharedMemoryModel):
|
|||
|
||||
message - a Msg object or a text string.
|
||||
"""
|
||||
if type(msgobj) == Msg:
|
||||
if type(message) == Msg:
|
||||
# extract only the string
|
||||
message = message.message
|
||||
return self.msg(message)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue