Implemented NickHandler, AliasHandler and TagHandler in the typeclass to replace the old handlers. Some errors during login.

This commit is contained in:
Griatch 2013-07-12 14:44:49 +02:00
parent 2c17b7b675
commit 0061f884ae
7 changed files with 176 additions and 222 deletions

View file

@ -160,7 +160,7 @@ class CmdDelCom(MuxPlayerCommand):
if not channel:
self.msg("No channel with alias '%s' was found." % ostring)
else:
if caller.nicks.has(ostring, nick_type="channel"):
if caller.nicks.get(ostring, nick_type="channel", default=False):
caller.nicks.delete(ostring, nick_type="channel")
self.msg("Your alias '%s' for channel %s was cleared." % (ostring, channel.key))
else:

View file

@ -18,13 +18,11 @@ import traceback
from django.db import models
from django.conf import settings
from src.utils.idmapper.models import SharedMemoryModel
from src.typeclasses.models import Attribute, TypedObject, TypeNick, TypeNickHandler
from src.typeclasses.models import TypedObject, TagHandler, NickHandler, AliasHandler
from src.server.caches import get_field_cache, set_field_cache, del_field_cache
from src.server.caches import get_prop_cache, set_prop_cache, del_prop_cache
from src.server.caches import get_prop_cache, set_prop_cache
from src.typeclasses.typeclass import TypeClass
#from src.players.models import PlayerNick
from src.objects.manager import ObjectManager
from src.players.models import PlayerDB
from src.commands.cmdsethandler import CmdSetHandler
@ -35,7 +33,7 @@ from src.utils.utils import make_iter, to_unicode, variable_from_module, inherit
from django.utils.translation import ugettext as _
#__all__ = ("Alias", "ObjectNick", "ObjectDB")
#__all__ = ("ObjectDB", )
_ScriptDB = None
_AT_SEARCH_RESULT = variable_from_module(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
@ -48,63 +46,6 @@ _ME = _("me")
_SELF = _("self")
_HERE = _("here")
#------------------------------------------------------------
#
# Alias
#
#------------------------------------------------------------
#class Alias(SharedMemoryModel):
# """
# This model holds a range of alternate names for an object.
# These are intrinsic properties of the object. The split
# is so as to allow for effective global searches also by
# alias.
# """
# db_key = models.CharField('alias', max_length=255, db_index=True)
# db_obj = models.ForeignKey("ObjectDB", verbose_name='object')
#
# class Meta:
# "Define Django meta options"
# verbose_name = "Object alias"
# verbose_name_plural = "Object aliases"
# def __unicode__(self):
# return u"%s" % self.db_key
# def __str__(self):
# return str(self.db_key)
#
#
#
##------------------------------------------------------------
##
## Object Nicks
##
##------------------------------------------------------------
#
#class ObjectNick(TypeNick):
# """
#
# The default nick types used by Evennia are:
# inputline (default) - match against all input
# player - match against player searches
# obj - match against object searches
# channel - used to store own names for channels
# """
# db_obj = models.ForeignKey("ObjectDB", verbose_name='object')
#
# class Meta:
# "Define Django meta options"
# verbose_name = "Nickname for Objects"
# verbose_name_plural = "Nicknames for Objects"
# unique_together = ("db_nick", "db_type", "db_obj")
#
#class ObjectNickHandler(TypeNickHandler):
# """
# Handles nick access and setting. Accessed through ObjectDB.nicks
# """
# NickClass = ObjectNick
#------------------------------------------------------------
#
# ObjectDB
@ -199,7 +140,9 @@ class ObjectDB(TypedObject):
_SA(self, "cmdset", CmdSetHandler(self))
_GA(self, "cmdset").update(init_mode=True)
_SA(self, "scripts", ScriptHandler(self))
#_SA(self, "nicks", ObjectNickHandler(self))
_SA(self, "tags", TagHandler(self, "object"))
_SA(self, "aliases", AliasHandler(self, "object"))
_SA(self, "nicks", NickHandler(self, "object"))
# Wrapper properties to easily set database fields. These are
# @property decorators that allows to access these fields using
@ -209,30 +152,6 @@ class ObjectDB(TypedObject):
# value = self.attr and del self.attr respectively (where self
# is the object in question).
# aliases property (wraps (db_aliases)
#@property
def __aliases_get(self):
"Getter. Allows for value = self.aliases"
aliases = get_prop_cache(self, "_aliases")
if aliases == None:
aliases = list(Alias.objects.filter(db_obj=self).values_list("db_key", flat=True))
set_prop_cache(self, "_aliases", aliases)
return aliases
#@aliases.setter
def __aliases_set(self, aliases):
"Setter. Allows for self.aliases = value"
for alias in make_iter(aliases):
new_alias = Alias(db_key=alias, db_obj=self)
new_alias.save()
set_prop_cache(self, "_aliases", make_iter(aliases))
#@aliases.deleter
def __aliases_del(self):
"Deleter. Allows for del self.aliases"
for alias in Alias.objects.filter(db_obj=self):
alias.delete()
#del_prop_cache(self, "_aliases")
aliases = property(__aliases_get, __aliases_set, __aliases_del)
# player property (wraps db_player)
#@property
def __player_get(self):
@ -643,12 +562,12 @@ class ObjectDB(TypedObject):
return self.typeclass
if use_nicks:
nick = None
nicktype = "object"
# look up nicks
nicks = ObjectNick.objects.filter(db_obj=self, db_type=nicktype)
# get all valid nicks to search
nicks = self.nicks.get(category="object_nick_%s" % nicktype)
if self.has_player:
nicks = list(nicks) + list(PlayerNick.objects.filter(db_obj=self.db_player, db_type=nicktype))
pnicks = self.nicks.get(category="player_nick_%s" % nicktype)
nicks = nicks + pnicks
for nick in nicks:
if searchdata == nick.db_nick:
searchdata = nick.db_real
@ -723,12 +642,15 @@ class ObjectDB(TypedObject):
raw_list = raw_string.split(None)
raw_list = [" ".join(raw_list[:i+1]) for i in range(len(raw_list)) if raw_list[:i+1]]
nicks = ObjectNick.objects.filter(db_obj=self, db_type__in=("inputline", "channel"))
# fetch the nick data efficiently
nicks = self.db_lnattributes.filter(db_category__in=("object_nick_inputline", "object_nick_channel")).prefetch_related("db_key","db_data")
if self.has_player:
nicks = list(nicks) + list(PlayerNick.objects.filter(db_obj=self.db_player, db_type__in=("inputline","channel")))
pnicks = self.player.db_lnattributes.filter(
db_category__in=("player_nick_inputline", "player_nick_channel")).prefetch_related("db_key","db_data")
nicks = nicks + pnicks
for nick in nicks:
if nick.db_nick in raw_list:
raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1)
if nick.db_key in raw_list:
raw_string = raw_string.replace(nick.db_key, nick.db_data, 1)
break
return cmdhandler.cmdhandler(_GA(self, "typeclass"), raw_string, sessid=sessid)

View file

@ -25,25 +25,21 @@ account info and OOC account configuration variables etc.
from django.conf import settings
from django.db import models
from django.contrib.auth.models import AbstractUser, User
from django.contrib.auth.models import AbstractUser
from django.utils.encoding import smart_str
from django.db.models.signals import post_init, pre_delete
from src.server.caches import get_field_cache, set_field_cache, del_field_cache
from src.server.caches import get_prop_cache, set_prop_cache, del_prop_cache
from src.server.caches import get_field_cache, set_field_cache
from src.players import manager
from src.scripts.models import ScriptDB
from src.typeclasses.models import Attribute, TypedObject, TypeNick, TypeNickHandler
from src.typeclasses.typeclass import TypeClass
from src.typeclasses.models import TypedObject, TagHandler, NickHandler, AliasHandler
from src.commands.cmdsethandler import CmdSetHandler
from src.commands import cmdhandler
from src.utils import logger, utils
from src.utils.utils import inherits_from, make_iter
from src.utils import utils
from django.utils.translation import ugettext as _
__all__ = ("PlayerNick", "PlayerDB")
__all__ = ("PlayerDB",)
_ME = _("me")
_SELF = _("self")
@ -59,35 +55,6 @@ _DA = object.__delattr__
_TYPECLASS = None
##------------------------------------------------------------
##
## Player Nicks
##
##------------------------------------------------------------
#
#class PlayerNick(TypeNick):
# """
#
# The default nick types used by Evennia are:
# inputline (default) - match against all input
# player - match against player searches
# obj - match against object searches
# channel - used to store own names for channels
# """
# db_obj = models.ForeignKey("PlayerDB", verbose_name="player")
#
# class Meta:
# "Define Django meta options"
# verbose_name = "Nickname for Players"
# verbose_name_plural = "Nicknames Players"
# unique_together = ("db_nick", "db_type", "db_obj")
#
#class PlayerNickHandler(TypeNickHandler):
# """
# Handles nick access and setting. Accessed through ObjectDB.nicks
# """
# NickClass = PlayerNick
#------------------------------------------------------------
#
@ -153,7 +120,9 @@ class PlayerDB(TypedObject, AbstractUser):
# handlers
_SA(self, "cmdset", CmdSetHandler(self))
_GA(self, "cmdset").update(init_mode=True)
#_SA(self, "nicks", PlayerNickHandler(self))
_SA(self, "tags", TagHandler(self, "player"))
_SA(self, "aliases", AliasHandler(self, "player"))
_SA(self, "nicks", NickHandler(self, "player"))
# Wrapper properties to easily set database fields. These are
# @property decorators that allows to access these fields using
@ -520,9 +489,12 @@ class PlayerDB(TypedObject, AbstractUser):
raw_list = raw_string.split(None)
raw_list = [" ".join(raw_list[:i+1]) for i in range(len(raw_list)) if raw_list[:i+1]]
for nick in PlayerNick.objects.filter(db_obj=self, db_type__in=("inputline","channel")):
if nick.db_nick in raw_list:
raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1)
# get the nick replacement data directly from the database to be able to use db_category__in
nicks = self.db_liteattributes.filter(
db_category__in=("object_nick_inputline", "object_nick_channel")).prefetch_related("db_key","db_data")
for nick in nicks:
if nick.db_key in raw_list:
raw_string = raw_string.replace(nick.db_key, nick.db_data, 1)
break
if not sessid and _MULTISESSION_MODE in (0, 1):
# in this case, we should either have only one sessid, or the sessid

View file

@ -28,7 +28,7 @@ from django.conf import settings
from django.db import models
from django.db.models.signals import post_init, pre_delete
from src.typeclasses.models import Attribute, TypedObject
from src.typeclasses.models import Attribute, TypedObject, TagHandler, AliasHandler, NickHandler
from django.contrib.contenttypes.models import ContentType
from src.scripts.manager import ScriptManager
@ -104,6 +104,12 @@ class ScriptDB(TypedObject):
"Define Django meta options"
verbose_name = "Script"
def __init__(self, *args, **kwargs):
super(ScriptDB, self).__init__(self, *args, **kwargs)
_SA(self, "tags", TagHandler(self, "script"))
_SA(self, "aliases", AliasHandler(self, "script"))
# 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()

View file

@ -101,9 +101,9 @@ class LiteAttributeManager(models.Manager):
if search_key or category:
key_cands = Q(db_key__iexact=search_key.lower().strip()) if search_key!=None else Q()
cat_cands = Q(db_category__iexact=category.lower.strip()) if search_key!=None else Q()
return _GA(obj, "db_tags").filter(cat_cands & key_cands)
return _GA(obj, "db_liteattributes").filter(cat_cands & key_cands)
else:
return list(_GA(obj, "db_tags").all())
return list(_GA(obj, "db_liteattributes").all())
def get_lattr(self, search_key=None, category=None):
"""
@ -167,10 +167,17 @@ class TagManager(models.Manager):
the search criteria.
search_key (string) - the tag identifier
category (string) - the tag category
Returns a single Tag (or None) if both key and category is given, otherwise
it will return a list.
"""
key_cands = Q(db_key__iexact=search_key.lower().strip()) if search_key!=None else Q()
cat_cands = Q(db_category__iexact=category.lower.strip()) if search_key!=None else Q()
return list(self.filter(key_cands & cat_cands))
tags = self.filter(key_cands & cat_cands)
if search_key and category:
return tags[0] if tags else None
else:
return list(tags)
def get_objs_with_tag(self, objclass, search_key=None, category=None):
"""

View file

@ -15,18 +15,18 @@ class Migration(DataMigration):
# and orm['appname.ModelName'] for models in other applications.
for alias in orm['objects.Alias'].objects.all():
# convert all Aliases to tags
tag = orm.Tag(db_key=alias.db_key, db_category="aliases", db_data=None)
tag = orm.Tag(db_key=alias.db_key, db_category="object_alias", db_data=None)
tag.save()
obj = alias.db_obj
obj.db_tags.add(tag)
# convert all nicks to LiteAttrs
for nick in orm['objects.ObjectNick'].objects.all():
lattr = orm.LiteAttribute(db_key=nick.db_nick, db_category="nick_%s" % nick.db_type, db_data=nick.db_real)
lattr = orm.LiteAttribute(db_key=nick.db_nick, db_category="object_nick_%s" % nick.db_type, db_data=nick.db_real)
lattr.save()
obj = nick.db_obj
obj.db_liteattributes.add(lattr)
for nick in orm['players.PlayerNick'].objects.all():
lattr = orm.LiteAttribute(db_key=nick.db_nick, db_category="nick_%s" % nick.db_type, db_data=nick.db_real)
lattr = orm.LiteAttribute(db_key=nick.db_nick, db_category="player_nick_%s" % nick.db_type, db_data=nick.db_real)
lattr.save()
obj = nick.db_obj
obj.db_liteattributes.add(lattr)

View file

@ -346,52 +346,104 @@ class Tag(models.Model):
def __str__(self):
return str(self.db_key)
#------------------------------------------------------------
#
# Nicks
# Helper handlers
#
#------------------------------------------------------------
class TypeNick(SharedMemoryModel):
class TagHandler(object):
"""
This model holds whichever alternate names this object
has for OTHER objects, but also for arbitrary strings,
channels, players etc. Setting a nick does not affect
the nicknamed object at all (as opposed to Aliases above),
and only this object will be able to refer to the nicknamed
object by the given nick.
The default nick types used by Evennia are:
inputline (default) - match against all input
player - match against player searches
obj - match against object searches
channel - used to store own names for channels
Generic tag-handler. Accessed via TypedObject.tags.
"""
db_nick = models.CharField('nickname',max_length=255, db_index=True, help_text='the alias')
db_real = models.TextField('realname', help_text='the original string to match and replace.')
db_type = models.CharField('nick type',default="inputline", max_length=16, null=True, blank=True,
help_text="the nick type describes when the engine tries to do nick-replacement. Common options are 'inputline','player','obj' and 'channel'. Inputline checks everything being inserted, whereas the other cases tries to replace in various searches or when posting to channels.")
db_obj = None #models.ForeignKey("ObjectDB")
class Meta:
"Define Django meta options"
abstract = True
verbose_name = "Nickname"
unique_together = ("db_nick", "db_type", "db_obj")
class TypeNickHandler(object):
"""
Handles nick access and setting. Accessed through ObjectDB.nicks
"""
NickClass = TypeNick
def __init__(self, obj):
def __init__(self, obj, category_prefix=""):
"""
This handler allows for accessing and setting nicks -
on-the-fly replacements for various text input passing through
this object (most often a Character)
Tags are stored internally in the TypedObject.db_tags m2m field
using the category <category_prefix><tag_category>
"""
self.obj = obj
self.prefix = category_prefix.strip().lower() if category_prefix else ""
def add(self, tag, category=None, data=None):
"Add a new tag to the handler"
tag = tag.strip().lower() if tag!=None else None
category = "%s%s" % (self.prefix, category.strip.lower()) if category!=None else None
data = str(data) if data!=None else None
# this will only create tag if no matches existed beforehand (it will overload
# data on an existing tag since that is not considered part of making the tag unique)
tagobj = Tag.objects.create_tag(key=tag, category=category, data=data)
self.obj.db_tags.add(tagobj)
def remove(self, tag, category=None):
"Remove a tag from the handler"
tag = tag.strip().lower() if tag!=None else None
category = "%s%s" % (self.prefix, category.strip.lower()) if category!=None else None
#TODO This does not delete the tag object itself. Maybe it should do that when no
# objects reference the tag anymore?
tagobj = self.obj.db_tags.filter(db_key=tag, db_category=category)
if tagobj:
self.obj.remove(tagobj[0])
def all(self):
"Get all tags in this handler"
return self.obj.db_tags.all().get_values("db_key")
def __str__(self):
return ",".join(self.all())
def __unicode(self):
return u",".join(self.all())
class AliasHandler(object):
"""
Handles alias access and setting. Accessed through TypedObject.aliases.
"""
def __init__(self, obj, category_prefix="object_"):
"""
Aliases are alternate names for an entity.
Implements the alias handler, using Tags for storage and
the <categoryprefix>_alias tag category. It is available
as TypedObjects.aliases.
"""
self.obj = obj
self.category = "%salias" % category_prefix
def add(self, alias):
"Add a new nick to the handler"
if not alias or not alias.strip():
return
alias = alias.strip()
# create a unique tag only if it didn't already exist
aliasobj = Tag.objects.create_tag(key=alias, category=self.category)
self.obj.db_tags.add(aliasobj)
def remove(self, alias):
"Remove alias from handler."
aliasobj = Tag.objects.filter(db_key__iexact=alias.strip(), category=self.category).count()
#TODO note that this doesn't delete the tag itself. We might want to do this when no object
# uses it anymore ...
self.obj.db_tags.remove(aliasobj)
def all(self):
"Get all aliases in this handler"
return self.obj.db_tags.filter(db_category=self.category).get_values("db_key")
def __str__(self):
return ",".join(self.all())
def __unicode(self):
return u",".join(self.all())
class NickHandler(object):
"""
Handles nick access and setting. Accessed through TypedObject.nicks.
"""
def __init__(self, obj, category_prefix="object_"):
"""
Nicks are alternate names an entity as of ANOTHER entity. The
engine will auto-replace nicks under circumstances dictated
by the nick category. It uses LiteAttributes for storage.
The default nick types used by Evennia are:
@ -400,13 +452,11 @@ class TypeNickHandler(object):
obj - match against object searches
channel - used to store own names for channels
You can define other nicktypes by using the add() method of
this handler and set nick_type to whatever you want. It's then
up to you to somehow make use of this nick_type in your game
(such as for a "recog" system).
These are all stored interally using categories
<category_prefix>nick_inputline etc.
"""
self.obj = obj
self.prefix = "%snick_" % category_prefix.strip().lower() if category_prefix else ""
def add(self, nick, realname, nick_type="inputline"):
"""
@ -417,50 +467,47 @@ class TypeNickHandler(object):
if not nick or not nick.strip():
return
nick = nick.strip()
real = realname.strip()
query = self.NickClass.objects.filter(db_obj=self.obj, db_nick__iexact=nick, db_type__iexact=nick_type)
real = realname
nick_type = "%s%s" % (self.prefix, nick_type.strip().lower())
query = self.obj.db_liteattributes.filter(db_key__iexact=nick, db_category__iexact=nick_type)
if query.count():
old_nick = query[0]
old_nick.db_real = real
old_nick.db_data = real
old_nick.save()
else:
new_nick = self.NickClass(db_nick=nick, db_real=real, db_type=nick_type, db_obj=self.obj)
new_nick = LiteAttribute(db_key=nick, db_category=nick_type, db_data=real)
new_nick.save()
def delete(self, nick, nick_type="inputline"):
self.obj.db_liteattributes.add(new_nick)
def remove(self, nick, nick_type="inputline"):
"Removes a previously stored nick"
nick = nick.strip()
query = self.NickClass.objects.filter(db_obj=self.obj, db_nick__iexact=nick, db_type__iexact=nick_type)
nick_type = "%s%s" % (self.prefix, nick_type.strip().lower())
query = self.obj.liteattributes.filter(db_key__iexact=nick, db_category__iexact=nick_type)
if query.count():
# remove the found nick(s)
query.delete()
def get(self, nick=None, nick_type="inputline", obj=None):
"""
Retrieves a given nick (with a specified nick_type) on an object. If no nick is given, returns a list
of all nicks on the object, or the empty list.
Defaults to searching the current object.
"""
if not obj:
# defaults to the current object
obj = self.obj
if nick:
query = self.NickClass.objects.filter(db_obj=obj, db_nick__iexact=nick, db_type__iexact=nick_type)
query = query.values_list("db_real", flat=True)
if query.count():
return query[0]
else:
return nick
else:
return self.NickClass.objects.filter(db_obj=obj)
def has(self, nick, nick_type="inputline", obj=None):
"""
Returns true/false if this nick and nick_type is defined on the given
object or not. If no obj is given, default to the current object the
handler is defined on.
def delete(self, *args, **kwargs):
"alias wrapper"
self.remove(self, *args, **kwargs)
def get(self, nick=None, nick_type="inputline", default=None):
"""
if not obj:
obj = self.obj
return self.NickClass.objects.filter(db_obj=obj, db_nick__iexact=nick, db_type__iexact=nick_type).count()
Retrieves a given nick replacement based on the input nick. If
given but no matching conversion was found, returns
original input or default if given
If no nick is given, returns a list of all matching nick
objects (LiteAttributes) on the object, or the empty list.
"""
nick = nick.strip().lower() if nick!=None else None
nick_type = "%s%s" % (self.prefix, nick_type.strip().lower())
if nick:
nicks = _GA(self.obj, "db_liteattributes").objects.filter(db_key=nick, db_category=nick_type).prefetch_related("db_data")
default = default if default!=None else nick
return nicks[0].db_data if nicks else default
else:
return list(self.obj.db_liteattributes.all())
#------------------------------------------------------------