Move create methods into managers, leave utils.create as wrappers.
Resolve #2118.
This commit is contained in:
parent
cc22a776ee
commit
e70337b6d2
8 changed files with 692 additions and 522 deletions
|
|
@ -134,6 +134,8 @@ Up requirements to Django 3.2+, Twisted 21+
|
||||||
subfolders. All imports will need to be updated.
|
subfolders. All imports will need to be updated.
|
||||||
- Made `MonitorHandler.add/remove` support `category` for monitoring Attributes
|
- Made `MonitorHandler.add/remove` support `category` for monitoring Attributes
|
||||||
with a category (before only key was used, ignoring category entirely).
|
with a category (before only key was used, ignoring category entirely).
|
||||||
|
- Move `create_*` functions into db managers, leaving `utils.create` only being
|
||||||
|
wrapper functions (consistent with `utils.search`). No change of api otherwise.
|
||||||
|
|
||||||
### Evennia 0.9.5 (2019-2020)
|
### Evennia 0.9.5 (2019-2020)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,12 @@ The managers for the custom Account object and permissions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
from django.conf import settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.contrib.auth.models import UserManager
|
from django.contrib.auth.models import UserManager
|
||||||
from evennia.typeclasses.managers import TypedObjectManager, TypeclassManager
|
from evennia.typeclasses.managers import TypedObjectManager, TypeclassManager
|
||||||
|
from evennia.server import signals
|
||||||
|
from evennia.utils.utils import make_iter, class_from_module, dbid_to_obj
|
||||||
|
|
||||||
__all__ = ("AccountManager", "AccountDBManager")
|
__all__ = ("AccountManager", "AccountDBManager")
|
||||||
|
|
||||||
|
|
@ -181,6 +184,108 @@ class AccountDBManager(TypedObjectManager, UserManager):
|
||||||
)
|
)
|
||||||
return matches
|
return matches
|
||||||
|
|
||||||
|
def create_account(
|
||||||
|
self,
|
||||||
|
key,
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
typeclass=None,
|
||||||
|
is_superuser=False,
|
||||||
|
locks=None,
|
||||||
|
permissions=None,
|
||||||
|
tags=None,
|
||||||
|
attributes=None,
|
||||||
|
report_to=None,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
This creates a new account.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key (str): The account's name. This should be unique.
|
||||||
|
email (str or None): Email on valid addr@addr.domain form. If
|
||||||
|
the empty string, will be set to None.
|
||||||
|
password (str): Password in cleartext.
|
||||||
|
|
||||||
|
Keyword Args:
|
||||||
|
typeclass (str): The typeclass to use for the account.
|
||||||
|
is_superuser (bool): Wether or not this account is to be a superuser
|
||||||
|
locks (str): Lockstring.
|
||||||
|
permission (list): List of permission strings.
|
||||||
|
tags (list): List of Tags on form `(key, category[, data])`
|
||||||
|
attributes (list): List of Attributes on form
|
||||||
|
`(key, value [, category, [,lockstring [, default_pass]]])`
|
||||||
|
report_to (Object): An object with a msg() method to report
|
||||||
|
errors to. If not given, errors will be logged.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Account: The newly created Account.
|
||||||
|
Raises:
|
||||||
|
ValueError: If `key` already exists in database.
|
||||||
|
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
Usually only the server admin should need to be superuser, all
|
||||||
|
other access levels can be handled with more fine-grained
|
||||||
|
permissions or groups. A superuser bypasses all lock checking
|
||||||
|
operations and is thus not suitable for play-testing the game.
|
||||||
|
|
||||||
|
"""
|
||||||
|
typeclass = typeclass if typeclass else settings.BASE_ACCOUNT_TYPECLASS
|
||||||
|
locks = make_iter(locks) if locks is not None else None
|
||||||
|
permissions = make_iter(permissions) if permissions is not None else None
|
||||||
|
tags = make_iter(tags) if tags is not None else None
|
||||||
|
attributes = make_iter(attributes) if attributes is not None else None
|
||||||
|
|
||||||
|
if isinstance(typeclass, str):
|
||||||
|
# a path is given. Load the actual typeclass.
|
||||||
|
typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)
|
||||||
|
|
||||||
|
# setup input for the create command. We use AccountDB as baseclass
|
||||||
|
# here to give us maximum freedom (the typeclasses will load
|
||||||
|
# correctly when each object is recovered).
|
||||||
|
|
||||||
|
if not email:
|
||||||
|
email = None
|
||||||
|
if self.model.objects.filter(username__iexact=key):
|
||||||
|
raise ValueError("An Account with the name '%s' already exists." % key)
|
||||||
|
|
||||||
|
# this handles a given dbref-relocate to an account.
|
||||||
|
report_to = dbid_to_obj(report_to, self.model)
|
||||||
|
|
||||||
|
# create the correct account entity, using the setup from
|
||||||
|
# base django auth.
|
||||||
|
now = timezone.now()
|
||||||
|
email = typeclass.objects.normalize_email(email)
|
||||||
|
new_account = typeclass(
|
||||||
|
username=key,
|
||||||
|
email=email,
|
||||||
|
is_staff=is_superuser,
|
||||||
|
is_superuser=is_superuser,
|
||||||
|
last_login=now,
|
||||||
|
date_joined=now,
|
||||||
|
)
|
||||||
|
if password is not None:
|
||||||
|
# the password may be None for 'fake' accounts, like bots
|
||||||
|
valid, error = new_account.validate_password(password, new_account)
|
||||||
|
if not valid:
|
||||||
|
raise error
|
||||||
|
|
||||||
|
new_account.set_password(password)
|
||||||
|
|
||||||
|
new_account._createdict = dict(
|
||||||
|
locks=locks, permissions=permissions,
|
||||||
|
report_to=report_to, tags=tags, attributes=attributes
|
||||||
|
)
|
||||||
|
# saving will trigger the signal that calls the
|
||||||
|
# at_first_save hook on the typeclass, where the _createdict
|
||||||
|
# can be used.
|
||||||
|
new_account.save()
|
||||||
|
|
||||||
|
# note that we don't send a signal here, that is sent from the Account.create helper method
|
||||||
|
# instead.
|
||||||
|
|
||||||
|
return new_account
|
||||||
|
|
||||||
# back-compatibility alias
|
# back-compatibility alias
|
||||||
account_search = search_account
|
account_search = search_account
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,12 @@ Comm system components.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from evennia.typeclasses.managers import TypedObjectManager, TypeclassManager
|
from evennia.typeclasses.managers import TypedObjectManager, TypeclassManager
|
||||||
|
from evennia.server import signals
|
||||||
from evennia.utils import logger
|
from evennia.utils import logger
|
||||||
from evennia.utils.utils import dbref
|
from evennia.utils.utils import dbref, make_iter, class_from_module
|
||||||
|
|
||||||
_GA = object.__getattribute__
|
_GA = object.__getattribute__
|
||||||
_AccountDB = None
|
_AccountDB = None
|
||||||
|
|
@ -287,6 +289,55 @@ class MsgManager(TypedObjectManager):
|
||||||
# back-compatibility alias
|
# back-compatibility alias
|
||||||
message_search = search_message
|
message_search = search_message
|
||||||
|
|
||||||
|
def create_message(self, senderobj, message, receivers=None, locks=None, tags=None,
|
||||||
|
header=None, **kwargs):
|
||||||
|
"""
|
||||||
|
Create a new communication Msg. Msgs represent a unit of
|
||||||
|
database-persistent communication between entites.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
senderobj (Object, Account, Script, str or list): The entity (or
|
||||||
|
entities) sending the Msg. If a `str`, this is the id-string
|
||||||
|
for an external sender type.
|
||||||
|
message (str): Text with the message. Eventual headers, titles
|
||||||
|
etc should all be included in this text string. Formatting
|
||||||
|
will be retained.
|
||||||
|
receivers (Object, Account, Script, str or list): An Account/Object to send
|
||||||
|
to, or a list of them. If a string, it's an identifier for an external
|
||||||
|
receiver.
|
||||||
|
locks (str): Lock definition string.
|
||||||
|
tags (list): A list of tags or tuples `(tag, category)`.
|
||||||
|
header (str): Mime-type or other optional information for the message
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
The Comm system is created to be very open-ended, so it's fully
|
||||||
|
possible to let a message both go several receivers at the same time,
|
||||||
|
it's up to the command definitions to limit this as desired.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if 'channels' in kwargs:
|
||||||
|
raise DeprecationWarning(
|
||||||
|
"create_message() does not accept 'channel' kwarg anymore "
|
||||||
|
"- channels no longer accept Msg objects."
|
||||||
|
)
|
||||||
|
|
||||||
|
if not message:
|
||||||
|
# we don't allow empty messages.
|
||||||
|
return None
|
||||||
|
new_message = self.model(db_message=message)
|
||||||
|
new_message.save()
|
||||||
|
for sender in make_iter(senderobj):
|
||||||
|
new_message.senders = sender
|
||||||
|
new_message.header = header
|
||||||
|
for receiver in make_iter(receivers):
|
||||||
|
new_message.receivers = receiver
|
||||||
|
if locks:
|
||||||
|
new_message.locks.add(locks)
|
||||||
|
if tags:
|
||||||
|
new_message.tags.batch_add(*tags)
|
||||||
|
|
||||||
|
new_message.save()
|
||||||
|
return new_message
|
||||||
|
|
||||||
#
|
#
|
||||||
# Channel manager
|
# Channel manager
|
||||||
|
|
@ -388,6 +439,56 @@ class ChannelDBManager(TypedObjectManager):
|
||||||
).distinct()
|
).distinct()
|
||||||
return channels
|
return channels
|
||||||
|
|
||||||
|
def create_channel(
|
||||||
|
self, key, aliases=None, desc=None, locks=None, keep_log=True, typeclass=None, tags=None
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Create A communication Channel. A Channel serves as a central hub
|
||||||
|
for distributing Msgs to groups of people without specifying the
|
||||||
|
receivers explicitly. Instead accounts may 'connect' to the channel
|
||||||
|
and follow the flow of messages. By default the channel allows
|
||||||
|
access to all old messages, but this can be turned off with the
|
||||||
|
keep_log switch.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key (str): This must be unique.
|
||||||
|
|
||||||
|
Keyword Args:
|
||||||
|
aliases (list of str): List of alternative (likely shorter) keynames.
|
||||||
|
desc (str): A description of the channel, for use in listings.
|
||||||
|
locks (str): Lockstring.
|
||||||
|
keep_log (bool): Log channel throughput.
|
||||||
|
typeclass (str or class): The typeclass of the Channel (not
|
||||||
|
often used).
|
||||||
|
tags (list): A list of tags or tuples `(tag, category)`.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
channel (Channel): A newly created channel.
|
||||||
|
|
||||||
|
"""
|
||||||
|
typeclass = typeclass if typeclass else settings.BASE_CHANNEL_TYPECLASS
|
||||||
|
|
||||||
|
if isinstance(typeclass, str):
|
||||||
|
# a path is given. Load the actual typeclass
|
||||||
|
typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)
|
||||||
|
|
||||||
|
# create new instance
|
||||||
|
new_channel = typeclass(db_key=key)
|
||||||
|
|
||||||
|
# store call signature for the signal
|
||||||
|
new_channel._createdict = dict(
|
||||||
|
key=key, aliases=aliases, desc=desc, locks=locks, keep_log=keep_log, tags=tags
|
||||||
|
)
|
||||||
|
|
||||||
|
# this will trigger the save signal which in turn calls the
|
||||||
|
# at_first_save hook on the typeclass, where the _createdict can be
|
||||||
|
# used.
|
||||||
|
new_channel.save()
|
||||||
|
|
||||||
|
signals.SIGNAL_CHANNEL_POST_CREATE.send(sender=new_channel)
|
||||||
|
|
||||||
|
return new_channel
|
||||||
|
|
||||||
# back-compatibility alias
|
# back-compatibility alias
|
||||||
channel_search = search_channel
|
channel_search = search_channel
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
"""
|
"""
|
||||||
Custom manager for HelpEntry objects.
|
Custom manager for HelpEntry objects.
|
||||||
"""
|
"""
|
||||||
|
from django.db import IntegrityError
|
||||||
from evennia.utils import logger, utils
|
from evennia.utils import logger, utils
|
||||||
from evennia.typeclasses.managers import TypedObjectManager
|
from evennia.typeclasses.managers import TypedObjectManager
|
||||||
|
from evennia.utils.utils import make_iter
|
||||||
|
from evennia.server import signals
|
||||||
|
|
||||||
__all__ = ("HelpEntryManager",)
|
__all__ = ("HelpEntryManager",)
|
||||||
|
|
||||||
|
|
@ -149,3 +152,46 @@ class HelpEntryManager(TypedObjectManager):
|
||||||
return self.filter(db_key__iexact=ostring, db_help_category__iexact=help_category)
|
return self.filter(db_key__iexact=ostring, db_help_category__iexact=help_category)
|
||||||
else:
|
else:
|
||||||
return self.filter(db_key__iexact=ostring)
|
return self.filter(db_key__iexact=ostring)
|
||||||
|
|
||||||
|
def create_help(self, key, entrytext, category="General", locks=None, aliases=None, tags=None):
|
||||||
|
"""
|
||||||
|
Create a static help entry in the help database. Note that Command
|
||||||
|
help entries are dynamic and directly taken from the __doc__
|
||||||
|
entries of the command. The database-stored help entries are
|
||||||
|
intended for more general help on the game, more extensive info,
|
||||||
|
in-game setting information and so on.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key (str): The name of the help entry.
|
||||||
|
entrytext (str): The body of te help entry
|
||||||
|
category (str, optional): The help category of the entry.
|
||||||
|
locks (str, optional): A lockstring to restrict access.
|
||||||
|
aliases (list of str, optional): List of alternative (likely shorter) keynames.
|
||||||
|
tags (lst, optional): List of tags or tuples `(tag, category)`.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
help (HelpEntry): A newly created help entry.
|
||||||
|
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
new_help = self.model()
|
||||||
|
new_help.key = key
|
||||||
|
new_help.entrytext = entrytext
|
||||||
|
new_help.help_category = category
|
||||||
|
if locks:
|
||||||
|
new_help.locks.add(locks)
|
||||||
|
if aliases:
|
||||||
|
new_help.aliases.add(make_iter(aliases))
|
||||||
|
if tags:
|
||||||
|
new_help.tags.batch_add(*tags)
|
||||||
|
new_help.save()
|
||||||
|
return new_help
|
||||||
|
except IntegrityError:
|
||||||
|
string = "Could not add help entry: key '%s' already exists." % key
|
||||||
|
logger.log_err(string)
|
||||||
|
return None
|
||||||
|
except Exception:
|
||||||
|
logger.log_trace()
|
||||||
|
return None
|
||||||
|
|
||||||
|
signals.SIGNAL_HELPENTRY_POST_CREATE.send(sender=new_help)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@ from django.conf import settings
|
||||||
from django.db.models.fields import exceptions
|
from django.db.models.fields import exceptions
|
||||||
from evennia.typeclasses.managers import TypedObjectManager, TypeclassManager
|
from evennia.typeclasses.managers import TypedObjectManager, TypeclassManager
|
||||||
from evennia.utils.utils import is_iter, make_iter, string_partial_matching
|
from evennia.utils.utils import is_iter, make_iter, string_partial_matching
|
||||||
|
from evennia.utils.utils import class_from_module, dbid_to_obj
|
||||||
|
from evennia.server import signals
|
||||||
|
|
||||||
|
|
||||||
__all__ = ("ObjectManager", "ObjectDBManager")
|
__all__ = ("ObjectManager", "ObjectDBManager")
|
||||||
_GA = object.__getattribute__
|
_GA = object.__getattribute__
|
||||||
|
|
@ -595,6 +598,117 @@ class ObjectDBManager(TypedObjectManager):
|
||||||
"""
|
"""
|
||||||
self.filter(db_sessid__isnull=False).update(db_sessid=None)
|
self.filter(db_sessid__isnull=False).update(db_sessid=None)
|
||||||
|
|
||||||
|
def create_object(
|
||||||
|
self,
|
||||||
|
typeclass=None,
|
||||||
|
key=None,
|
||||||
|
location=None,
|
||||||
|
home=None,
|
||||||
|
permissions=None,
|
||||||
|
locks=None,
|
||||||
|
aliases=None,
|
||||||
|
tags=None,
|
||||||
|
destination=None,
|
||||||
|
report_to=None,
|
||||||
|
nohome=False,
|
||||||
|
attributes=None,
|
||||||
|
nattributes=None,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
|
||||||
|
Create a new in-game object.
|
||||||
|
|
||||||
|
Keyword Args:
|
||||||
|
typeclass (class or str): Class or python path to a typeclass.
|
||||||
|
key (str): Name of the new object. If not set, a name of
|
||||||
|
`#dbref` will be set.
|
||||||
|
location (Object or str): Obj or #dbref to use as the location of the new object.
|
||||||
|
home (Object or str): Obj or #dbref to use as the object's home location.
|
||||||
|
permissions (list): A list of permission strings or tuples (permstring, category).
|
||||||
|
locks (str): one or more lockstrings, separated by semicolons.
|
||||||
|
aliases (list): A list of alternative keys or tuples (aliasstring, category).
|
||||||
|
tags (list): List of tag keys or tuples (tagkey, category) or (tagkey, category, data).
|
||||||
|
destination (Object or str): Obj or #dbref to use as an Exit's target.
|
||||||
|
report_to (Object): The object to return error messages to.
|
||||||
|
nohome (bool): This allows the creation of objects without a
|
||||||
|
default home location; only used when creating the default
|
||||||
|
location itself or during unittests.
|
||||||
|
attributes (list): Tuples on the form (key, value) or (key, value, category),
|
||||||
|
(key, value, lockstring) or (key, value, lockstring, default_access).
|
||||||
|
to set as Attributes on the new object.
|
||||||
|
nattributes (list): Non-persistent tuples on the form (key, value). Note that
|
||||||
|
adding this rarely makes sense since this data will not survive a reload.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
object (Object): A newly created object of the given typeclass.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ObjectDB.DoesNotExist: If trying to create an Object with
|
||||||
|
`location` or `home` that can't be found.
|
||||||
|
|
||||||
|
"""
|
||||||
|
typeclass = typeclass if typeclass else settings.BASE_OBJECT_TYPECLASS
|
||||||
|
|
||||||
|
# convenience converters to avoid common usage mistake
|
||||||
|
permissions = make_iter(permissions) if permissions is not None else None
|
||||||
|
locks = make_iter(locks) if locks is not None else None
|
||||||
|
aliases = make_iter(aliases) if aliases is not None else None
|
||||||
|
tags = make_iter(tags) if tags is not None else None
|
||||||
|
attributes = make_iter(attributes) if attributes is not None else None
|
||||||
|
|
||||||
|
if isinstance(typeclass, str):
|
||||||
|
# a path is given. Load the actual typeclass
|
||||||
|
typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)
|
||||||
|
|
||||||
|
# Setup input for the create command. We use ObjectDB as baseclass here
|
||||||
|
# to give us maximum freedom (the typeclasses will load
|
||||||
|
# correctly when each object is recovered).
|
||||||
|
|
||||||
|
location = dbid_to_obj(location, self.model)
|
||||||
|
destination = dbid_to_obj(destination, self.model)
|
||||||
|
home = dbid_to_obj(home, self.model)
|
||||||
|
if not home:
|
||||||
|
try:
|
||||||
|
home = dbid_to_obj(settings.DEFAULT_HOME, self.model) if not nohome else None
|
||||||
|
except self.model_ObjectDB.DoesNotExist:
|
||||||
|
raise self.model.DoesNotExist(
|
||||||
|
"settings.DEFAULT_HOME (= '%s') does not exist, or the setting is malformed."
|
||||||
|
% settings.DEFAULT_HOME
|
||||||
|
)
|
||||||
|
|
||||||
|
# create new instance
|
||||||
|
new_object = typeclass(
|
||||||
|
db_key=key,
|
||||||
|
db_location=location,
|
||||||
|
db_destination=destination,
|
||||||
|
db_home=home,
|
||||||
|
db_typeclass_path=typeclass.path,
|
||||||
|
)
|
||||||
|
# store the call signature for the signal
|
||||||
|
new_object._createdict = dict(
|
||||||
|
key=key,
|
||||||
|
location=location,
|
||||||
|
destination=destination,
|
||||||
|
home=home,
|
||||||
|
typeclass=typeclass.path,
|
||||||
|
permissions=permissions,
|
||||||
|
locks=locks,
|
||||||
|
aliases=aliases,
|
||||||
|
tags=tags,
|
||||||
|
report_to=report_to,
|
||||||
|
nohome=nohome,
|
||||||
|
attributes=attributes,
|
||||||
|
nattributes=nattributes,
|
||||||
|
)
|
||||||
|
# this will trigger the save signal which in turn calls the
|
||||||
|
# at_first_save hook on the typeclass, where the _createdict can be
|
||||||
|
# used.
|
||||||
|
new_object.save()
|
||||||
|
|
||||||
|
signals.SIGNAL_OBJECT_POST_CREATE.send(sender=new_object)
|
||||||
|
|
||||||
|
return new_object
|
||||||
|
|
||||||
|
|
||||||
class ObjectManager(ObjectDBManager, TypeclassManager):
|
class ObjectManager(ObjectDBManager, TypeclassManager):
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,19 @@
|
||||||
The custom manager for Scripts.
|
The custom manager for Scripts.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from evennia.typeclasses.managers import TypedObjectManager, TypeclassManager
|
from evennia.typeclasses.managers import TypedObjectManager, TypeclassManager
|
||||||
from evennia.utils.utils import make_iter
|
from evennia.utils.utils import make_iter, class_from_module, dbid_to_obj
|
||||||
|
from evennia.server import signals
|
||||||
|
|
||||||
__all__ = ("ScriptManager", "ScriptDBManager")
|
__all__ = ("ScriptManager", "ScriptDBManager")
|
||||||
_GA = object.__getattribute__
|
_GA = object.__getattribute__
|
||||||
|
|
||||||
|
_ObjectDB = None
|
||||||
|
_AccountDB = None
|
||||||
|
|
||||||
|
|
||||||
VALIDATE_ITERATION = 0
|
VALIDATE_ITERATION = 0
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -81,7 +87,6 @@ class ScriptDBManager(TypedObjectManager):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if key:
|
if key:
|
||||||
script = []
|
|
||||||
dbref = self.dbref(key)
|
dbref = self.dbref(key)
|
||||||
if dbref:
|
if dbref:
|
||||||
return self.filter(id=dbref)
|
return self.filter(id=dbref)
|
||||||
|
|
@ -191,6 +196,129 @@ class ScriptDBManager(TypedObjectManager):
|
||||||
)
|
)
|
||||||
return new_script
|
return new_script
|
||||||
|
|
||||||
|
def create_script(
|
||||||
|
self,
|
||||||
|
typeclass=None,
|
||||||
|
key=None,
|
||||||
|
obj=None,
|
||||||
|
account=None,
|
||||||
|
locks=None,
|
||||||
|
interval=None,
|
||||||
|
start_delay=None,
|
||||||
|
repeats=None,
|
||||||
|
persistent=None,
|
||||||
|
autostart=True,
|
||||||
|
report_to=None,
|
||||||
|
desc=None,
|
||||||
|
tags=None,
|
||||||
|
attributes=None,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Create a new script. All scripts are a combination of a database
|
||||||
|
object that communicates with the database, and an typeclass that
|
||||||
|
'decorates' the database object into being different types of
|
||||||
|
scripts. It's behaviour is similar to the game objects except
|
||||||
|
scripts has a time component and are more limited in scope.
|
||||||
|
|
||||||
|
Keyword Args:
|
||||||
|
typeclass (class or str): Class or python path to a typeclass.
|
||||||
|
key (str): Name of the new object. If not set, a name of
|
||||||
|
#dbref will be set.
|
||||||
|
obj (Object): The entity on which this Script sits. If this
|
||||||
|
is `None`, we are creating a "global" script.
|
||||||
|
account (Account): The account on which this Script sits. It is
|
||||||
|
exclusiv to `obj`.
|
||||||
|
locks (str): one or more lockstrings, separated by semicolons.
|
||||||
|
interval (int): The triggering interval for this Script, in
|
||||||
|
seconds. If unset, the Script will not have a timing
|
||||||
|
component.
|
||||||
|
start_delay (bool): If `True`, will wait `interval` seconds
|
||||||
|
before triggering the first time.
|
||||||
|
repeats (int): The number of times to trigger before stopping.
|
||||||
|
If unset, will repeat indefinitely.
|
||||||
|
persistent (bool): If this Script survives a server shutdown
|
||||||
|
or not (all Scripts will survive a reload).
|
||||||
|
autostart (bool): If this Script will start immediately when
|
||||||
|
created or if the `start` method must be called explicitly.
|
||||||
|
report_to (Object): The object to return error messages to.
|
||||||
|
desc (str): Optional description of script
|
||||||
|
tags (list): List of tags or tuples (tag, category).
|
||||||
|
attributes (list): List if tuples (key, value) or (key, value, category)
|
||||||
|
(key, value, lockstring) or (key, value, lockstring, default_access).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
script (obj): An instance of the script created
|
||||||
|
|
||||||
|
See evennia.scripts.manager for methods to manipulate existing
|
||||||
|
scripts in the database.
|
||||||
|
|
||||||
|
"""
|
||||||
|
global _ObjectDB, _AccountDB
|
||||||
|
if not _ObjectDB:
|
||||||
|
from evennia.objects.models import ObjectDB as _ObjectDB
|
||||||
|
from evennia.accounts.models import AccountDB as _AccountDB
|
||||||
|
|
||||||
|
typeclass = typeclass if typeclass else settings.BASE_SCRIPT_TYPECLASS
|
||||||
|
|
||||||
|
if isinstance(typeclass, str):
|
||||||
|
# a path is given. Load the actual typeclass
|
||||||
|
typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)
|
||||||
|
|
||||||
|
# validate input
|
||||||
|
kwarg = {}
|
||||||
|
if key:
|
||||||
|
kwarg["db_key"] = key
|
||||||
|
if account:
|
||||||
|
kwarg["db_account"] = dbid_to_obj(account, _AccountDB)
|
||||||
|
if obj:
|
||||||
|
kwarg["db_obj"] = dbid_to_obj(obj, _ObjectDB)
|
||||||
|
if interval:
|
||||||
|
kwarg["db_interval"] = max(0, interval)
|
||||||
|
if start_delay:
|
||||||
|
kwarg["db_start_delay"] = start_delay
|
||||||
|
if repeats:
|
||||||
|
kwarg["db_repeats"] = max(0, repeats)
|
||||||
|
if persistent:
|
||||||
|
kwarg["db_persistent"] = persistent
|
||||||
|
if desc:
|
||||||
|
kwarg["db_desc"] = desc
|
||||||
|
tags = make_iter(tags) if tags is not None else None
|
||||||
|
attributes = make_iter(attributes) if attributes is not None else None
|
||||||
|
|
||||||
|
# create new instance
|
||||||
|
new_script = typeclass(**kwarg)
|
||||||
|
|
||||||
|
# store the call signature for the signal
|
||||||
|
new_script._createdict = dict(
|
||||||
|
key=key,
|
||||||
|
obj=obj,
|
||||||
|
account=account,
|
||||||
|
locks=locks,
|
||||||
|
interval=interval,
|
||||||
|
start_delay=start_delay,
|
||||||
|
repeats=repeats,
|
||||||
|
persistent=persistent,
|
||||||
|
autostart=autostart,
|
||||||
|
report_to=report_to,
|
||||||
|
desc=desc,
|
||||||
|
tags=tags,
|
||||||
|
attributes=attributes,
|
||||||
|
)
|
||||||
|
# this will trigger the save signal which in turn calls the
|
||||||
|
# at_first_save hook on the typeclass, where the _createdict
|
||||||
|
# can be used.
|
||||||
|
new_script.save()
|
||||||
|
|
||||||
|
if not new_script.id:
|
||||||
|
# this happens in the case of having a repeating script with `repeats=1` and
|
||||||
|
# `start_delay=False` - the script will run once and immediately stop before
|
||||||
|
# save is over.
|
||||||
|
return None
|
||||||
|
|
||||||
|
signals.SIGNAL_SCRIPT_POST_CREATE.send(sender=new_script)
|
||||||
|
|
||||||
|
return new_script
|
||||||
|
|
||||||
|
|
||||||
class ScriptManager(ScriptDBManager, TypeclassManager):
|
class ScriptManager(ScriptDBManager, TypeclassManager):
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -13,26 +13,9 @@ The respective object managers hold more methods for manipulating and searching
|
||||||
objects already existing in the database.
|
objects already existing in the database.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.conf import settings
|
|
||||||
from django.db import IntegrityError
|
|
||||||
from django.utils import timezone
|
|
||||||
from evennia.utils import logger
|
|
||||||
from evennia.server import signals
|
|
||||||
from evennia.utils.utils import make_iter, class_from_module, dbid_to_obj
|
|
||||||
|
|
||||||
# delayed imports
|
|
||||||
_User = None
|
|
||||||
_ObjectDB = None
|
|
||||||
_Object = None
|
|
||||||
_Script = None
|
|
||||||
_ScriptDB = None
|
|
||||||
_HelpEntry = None
|
|
||||||
_Msg = None
|
|
||||||
_Account = None
|
|
||||||
_AccountDB = None
|
|
||||||
_to_object = None
|
|
||||||
_ChannelDB = None
|
|
||||||
|
|
||||||
|
from django.db.utils import OperationalError
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
||||||
# limit symbol import from API
|
# limit symbol import from API
|
||||||
__all__ = (
|
__all__ = (
|
||||||
|
|
@ -46,125 +29,60 @@ __all__ = (
|
||||||
|
|
||||||
_GA = object.__getattribute__
|
_GA = object.__getattribute__
|
||||||
|
|
||||||
|
# import objects this way to avoid circular import problems
|
||||||
|
try:
|
||||||
|
ObjectDB = ContentType.objects.get(app_label="objects", model="objectdb").model_class()
|
||||||
|
ScriptDB = ContentType.objects.get(app_label="scripts", model="scriptdb").model_class()
|
||||||
|
AccountDB = ContentType.objects.get(app_label="accounts", model="accountdb").model_class()
|
||||||
|
Msg = ContentType.objects.get(app_label="comms", model="msg").model_class()
|
||||||
|
ChannelDB = ContentType.objects.get(app_label="comms", model="channeldb").model_class()
|
||||||
|
HelpEntry = ContentType.objects.get(app_label="help", model="helpentry").model_class()
|
||||||
|
Tag = ContentType.objects.get(app_label="typeclasses", model="tag").model_class()
|
||||||
|
except OperationalError:
|
||||||
|
# this is a fallback used during tests/doc building
|
||||||
|
print("Couldn't initialize create managers - db not set up.")
|
||||||
|
from evennia.objects.models import ObjectDB
|
||||||
|
from evennia.accounts.models import AccountDB
|
||||||
|
from evennia.scripts.models import ScriptDB
|
||||||
|
from evennia.comms.models import Msg, ChannelDB
|
||||||
|
from evennia.help.models import HelpEntry
|
||||||
|
from evennia.typeclasses.tags import Tag # noqa
|
||||||
|
|
||||||
#
|
#
|
||||||
# Game Object creation
|
# Game Object creation
|
||||||
|
#
|
||||||
|
# Create a new in-game object.
|
||||||
|
#
|
||||||
|
# Keyword Args:
|
||||||
|
# typeclass (class or str): Class or python path to a typeclass.
|
||||||
|
# key (str): Name of the new object. If not set, a name of
|
||||||
|
# `#dbref` will be set.
|
||||||
|
# location (Object or str): Obj or #dbref to use as the location of the new object.
|
||||||
|
# home (Object or str): Obj or #dbref to use as the object's home location.
|
||||||
|
# permissions (list): A list of permission strings or tuples (permstring, category).
|
||||||
|
# locks (str): one or more lockstrings, separated by semicolons.
|
||||||
|
# aliases (list): A list of alternative keys or tuples (aliasstring, category).
|
||||||
|
# tags (list): List of tag keys or tuples (tagkey, category) or (tagkey, category, data).
|
||||||
|
# destination (Object or str): Obj or #dbref to use as an Exit's target.
|
||||||
|
# report_to (Object): The object to return error messages to.
|
||||||
|
# nohome (bool): This allows the creation of objects without a
|
||||||
|
# default home location; only used when creating the default
|
||||||
|
# location itself or during unittests.
|
||||||
|
# attributes (list): Tuples on the form (key, value) or (key, value, category),
|
||||||
|
# (key, value, lockstring) or (key, value, lockstring, default_access).
|
||||||
|
# to set as Attributes on the new object.
|
||||||
|
# nattributes (list): Non-persistent tuples on the form (key, value). Note that
|
||||||
|
# adding this rarely makes sense since this data will not survive a reload.
|
||||||
|
#
|
||||||
|
# Returns:
|
||||||
|
# object (Object): A newly created object of the given typeclass.
|
||||||
|
#
|
||||||
|
# Raises:
|
||||||
|
# ObjectDB.DoesNotExist: If trying to create an Object with
|
||||||
|
# `location` or `home` that can't be found.
|
||||||
|
#
|
||||||
|
|
||||||
|
create_object = ObjectDB.objects.create_object
|
||||||
def create_object(
|
|
||||||
typeclass=None,
|
|
||||||
key=None,
|
|
||||||
location=None,
|
|
||||||
home=None,
|
|
||||||
permissions=None,
|
|
||||||
locks=None,
|
|
||||||
aliases=None,
|
|
||||||
tags=None,
|
|
||||||
destination=None,
|
|
||||||
report_to=None,
|
|
||||||
nohome=False,
|
|
||||||
attributes=None,
|
|
||||||
nattributes=None,
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
|
|
||||||
Create a new in-game object.
|
|
||||||
|
|
||||||
Keyword Args:
|
|
||||||
typeclass (class or str): Class or python path to a typeclass.
|
|
||||||
key (str): Name of the new object. If not set, a name of
|
|
||||||
`#dbref` will be set.
|
|
||||||
location (Object or str): Obj or #dbref to use as the location of the new object.
|
|
||||||
home (Object or str): Obj or #dbref to use as the object's home location.
|
|
||||||
permissions (list): A list of permission strings or tuples (permstring, category).
|
|
||||||
locks (str): one or more lockstrings, separated by semicolons.
|
|
||||||
aliases (list): A list of alternative keys or tuples (aliasstring, category).
|
|
||||||
tags (list): List of tag keys or tuples (tagkey, category) or (tagkey, category, data).
|
|
||||||
destination (Object or str): Obj or #dbref to use as an Exit's target.
|
|
||||||
report_to (Object): The object to return error messages to.
|
|
||||||
nohome (bool): This allows the creation of objects without a
|
|
||||||
default home location; only used when creating the default
|
|
||||||
location itself or during unittests.
|
|
||||||
attributes (list): Tuples on the form (key, value) or (key, value, category),
|
|
||||||
(key, value, lockstring) or (key, value, lockstring, default_access).
|
|
||||||
to set as Attributes on the new object.
|
|
||||||
nattributes (list): Non-persistent tuples on the form (key, value). Note that
|
|
||||||
adding this rarely makes sense since this data will not survive a reload.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
object (Object): A newly created object of the given typeclass.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ObjectDB.DoesNotExist: If trying to create an Object with
|
|
||||||
`location` or `home` that can't be found.
|
|
||||||
|
|
||||||
"""
|
|
||||||
global _ObjectDB
|
|
||||||
if not _ObjectDB:
|
|
||||||
from evennia.objects.models import ObjectDB as _ObjectDB
|
|
||||||
|
|
||||||
typeclass = typeclass if typeclass else settings.BASE_OBJECT_TYPECLASS
|
|
||||||
|
|
||||||
# convenience converters to avoid common usage mistake
|
|
||||||
permissions = make_iter(permissions) if permissions is not None else None
|
|
||||||
locks = make_iter(locks) if locks is not None else None
|
|
||||||
aliases = make_iter(aliases) if aliases is not None else None
|
|
||||||
tags = make_iter(tags) if tags is not None else None
|
|
||||||
attributes = make_iter(attributes) if attributes is not None else None
|
|
||||||
|
|
||||||
if isinstance(typeclass, str):
|
|
||||||
# a path is given. Load the actual typeclass
|
|
||||||
typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)
|
|
||||||
|
|
||||||
# Setup input for the create command. We use ObjectDB as baseclass here
|
|
||||||
# to give us maximum freedom (the typeclasses will load
|
|
||||||
# correctly when each object is recovered).
|
|
||||||
|
|
||||||
location = dbid_to_obj(location, _ObjectDB)
|
|
||||||
destination = dbid_to_obj(destination, _ObjectDB)
|
|
||||||
home = dbid_to_obj(home, _ObjectDB)
|
|
||||||
if not home:
|
|
||||||
try:
|
|
||||||
home = dbid_to_obj(settings.DEFAULT_HOME, _ObjectDB) if not nohome else None
|
|
||||||
except _ObjectDB.DoesNotExist:
|
|
||||||
raise _ObjectDB.DoesNotExist(
|
|
||||||
"settings.DEFAULT_HOME (= '%s') does not exist, or the setting is malformed."
|
|
||||||
% settings.DEFAULT_HOME
|
|
||||||
)
|
|
||||||
|
|
||||||
# create new instance
|
|
||||||
new_object = typeclass(
|
|
||||||
db_key=key,
|
|
||||||
db_location=location,
|
|
||||||
db_destination=destination,
|
|
||||||
db_home=home,
|
|
||||||
db_typeclass_path=typeclass.path,
|
|
||||||
)
|
|
||||||
# store the call signature for the signal
|
|
||||||
new_object._createdict = dict(
|
|
||||||
key=key,
|
|
||||||
location=location,
|
|
||||||
destination=destination,
|
|
||||||
home=home,
|
|
||||||
typeclass=typeclass.path,
|
|
||||||
permissions=permissions,
|
|
||||||
locks=locks,
|
|
||||||
aliases=aliases,
|
|
||||||
tags=tags,
|
|
||||||
report_to=report_to,
|
|
||||||
nohome=nohome,
|
|
||||||
attributes=attributes,
|
|
||||||
nattributes=nattributes,
|
|
||||||
)
|
|
||||||
# this will trigger the save signal which in turn calls the
|
|
||||||
# at_first_save hook on the typeclass, where the _createdict can be
|
|
||||||
# used.
|
|
||||||
new_object.save()
|
|
||||||
|
|
||||||
signals.SIGNAL_OBJECT_POST_CREATE.send(sender=new_object)
|
|
||||||
|
|
||||||
return new_object
|
|
||||||
|
|
||||||
|
|
||||||
# alias for create_object
|
# alias for create_object
|
||||||
object = create_object
|
object = create_object
|
||||||
|
|
||||||
|
|
@ -172,128 +90,45 @@ object = create_object
|
||||||
#
|
#
|
||||||
# Script creation
|
# Script creation
|
||||||
|
|
||||||
|
# Create a new script. All scripts are a combination of a database
|
||||||
|
# object that communicates with the database, and an typeclass that
|
||||||
|
# 'decorates' the database object into being different types of
|
||||||
|
# scripts. It's behaviour is similar to the game objects except
|
||||||
|
# scripts has a time component and are more limited in scope.
|
||||||
|
#
|
||||||
|
# Keyword Args:
|
||||||
|
# typeclass (class or str): Class or python path to a typeclass.
|
||||||
|
# key (str): Name of the new object. If not set, a name of
|
||||||
|
# #dbref will be set.
|
||||||
|
# obj (Object): The entity on which this Script sits. If this
|
||||||
|
# is `None`, we are creating a "global" script.
|
||||||
|
# account (Account): The account on which this Script sits. It is
|
||||||
|
# exclusiv to `obj`.
|
||||||
|
# locks (str): one or more lockstrings, separated by semicolons.
|
||||||
|
# interval (int): The triggering interval for this Script, in
|
||||||
|
# seconds. If unset, the Script will not have a timing
|
||||||
|
# component.
|
||||||
|
# start_delay (bool): If `True`, will wait `interval` seconds
|
||||||
|
# before triggering the first time.
|
||||||
|
# repeats (int): The number of times to trigger before stopping.
|
||||||
|
# If unset, will repeat indefinitely.
|
||||||
|
# persistent (bool): If this Script survives a server shutdown
|
||||||
|
# or not (all Scripts will survive a reload).
|
||||||
|
# autostart (bool): If this Script will start immediately when
|
||||||
|
# created or if the `start` method must be called explicitly.
|
||||||
|
# report_to (Object): The object to return error messages to.
|
||||||
|
# desc (str): Optional description of script
|
||||||
|
# tags (list): List of tags or tuples (tag, category).
|
||||||
|
# attributes (list): List if tuples (key, value) or (key, value, category)
|
||||||
|
# (key, value, lockstring) or (key, value, lockstring, default_access).
|
||||||
|
#
|
||||||
|
# Returns:
|
||||||
|
# script (obj): An instance of the script created
|
||||||
|
#
|
||||||
|
# See evennia.scripts.manager for methods to manipulate existing
|
||||||
|
# scripts in the database.
|
||||||
|
|
||||||
def create_script(
|
create_script = ScriptDB.objects.create_script
|
||||||
typeclass=None,
|
|
||||||
key=None,
|
|
||||||
obj=None,
|
|
||||||
account=None,
|
|
||||||
locks=None,
|
|
||||||
interval=None,
|
|
||||||
start_delay=None,
|
|
||||||
repeats=None,
|
|
||||||
persistent=None,
|
|
||||||
autostart=True,
|
|
||||||
report_to=None,
|
|
||||||
desc=None,
|
|
||||||
tags=None,
|
|
||||||
attributes=None,
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Create a new script. All scripts are a combination of a database
|
|
||||||
object that communicates with the database, and an typeclass that
|
|
||||||
'decorates' the database object into being different types of
|
|
||||||
scripts. It's behaviour is similar to the game objects except
|
|
||||||
scripts has a time component and are more limited in scope.
|
|
||||||
|
|
||||||
Keyword Args:
|
|
||||||
typeclass (class or str): Class or python path to a typeclass.
|
|
||||||
key (str): Name of the new object. If not set, a name of
|
|
||||||
#dbref will be set.
|
|
||||||
obj (Object): The entity on which this Script sits. If this
|
|
||||||
is `None`, we are creating a "global" script.
|
|
||||||
account (Account): The account on which this Script sits. It is
|
|
||||||
exclusiv to `obj`.
|
|
||||||
locks (str): one or more lockstrings, separated by semicolons.
|
|
||||||
interval (int): The triggering interval for this Script, in
|
|
||||||
seconds. If unset, the Script will not have a timing
|
|
||||||
component.
|
|
||||||
start_delay (bool): If `True`, will wait `interval` seconds
|
|
||||||
before triggering the first time.
|
|
||||||
repeats (int): The number of times to trigger before stopping.
|
|
||||||
If unset, will repeat indefinitely.
|
|
||||||
persistent (bool): If this Script survives a server shutdown
|
|
||||||
or not (all Scripts will survive a reload).
|
|
||||||
autostart (bool): If this Script will start immediately when
|
|
||||||
created or if the `start` method must be called explicitly.
|
|
||||||
report_to (Object): The object to return error messages to.
|
|
||||||
desc (str): Optional description of script
|
|
||||||
tags (list): List of tags or tuples (tag, category).
|
|
||||||
attributes (list): List if tuples (key, value) or (key, value, category)
|
|
||||||
(key, value, lockstring) or (key, value, lockstring, default_access).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
script (obj): An instance of the script created
|
|
||||||
|
|
||||||
See evennia.scripts.manager for methods to manipulate existing
|
|
||||||
scripts in the database.
|
|
||||||
|
|
||||||
"""
|
|
||||||
global _ScriptDB
|
|
||||||
if not _ScriptDB:
|
|
||||||
from evennia.scripts.models import ScriptDB as _ScriptDB
|
|
||||||
|
|
||||||
typeclass = typeclass if typeclass else settings.BASE_SCRIPT_TYPECLASS
|
|
||||||
|
|
||||||
if isinstance(typeclass, str):
|
|
||||||
# a path is given. Load the actual typeclass
|
|
||||||
typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)
|
|
||||||
|
|
||||||
# validate input
|
|
||||||
kwarg = {}
|
|
||||||
if key:
|
|
||||||
kwarg["db_key"] = key
|
|
||||||
if account:
|
|
||||||
kwarg["db_account"] = dbid_to_obj(account, _AccountDB)
|
|
||||||
if obj:
|
|
||||||
kwarg["db_obj"] = dbid_to_obj(obj, _ObjectDB)
|
|
||||||
if interval:
|
|
||||||
kwarg["db_interval"] = max(0, interval)
|
|
||||||
if start_delay:
|
|
||||||
kwarg["db_start_delay"] = start_delay
|
|
||||||
if repeats:
|
|
||||||
kwarg["db_repeats"] = max(0, repeats)
|
|
||||||
if persistent:
|
|
||||||
kwarg["db_persistent"] = persistent
|
|
||||||
if desc:
|
|
||||||
kwarg["db_desc"] = desc
|
|
||||||
tags = make_iter(tags) if tags is not None else None
|
|
||||||
attributes = make_iter(attributes) if attributes is not None else None
|
|
||||||
|
|
||||||
# create new instance
|
|
||||||
new_script = typeclass(**kwarg)
|
|
||||||
|
|
||||||
# store the call signature for the signal
|
|
||||||
new_script._createdict = dict(
|
|
||||||
key=key,
|
|
||||||
obj=obj,
|
|
||||||
account=account,
|
|
||||||
locks=locks,
|
|
||||||
interval=interval,
|
|
||||||
start_delay=start_delay,
|
|
||||||
repeats=repeats,
|
|
||||||
persistent=persistent,
|
|
||||||
autostart=autostart,
|
|
||||||
report_to=report_to,
|
|
||||||
desc=desc,
|
|
||||||
tags=tags,
|
|
||||||
attributes=attributes,
|
|
||||||
)
|
|
||||||
# this will trigger the save signal which in turn calls the
|
|
||||||
# at_first_save hook on the typeclass, where the _createdict
|
|
||||||
# can be used.
|
|
||||||
new_script.save()
|
|
||||||
|
|
||||||
if not new_script.id:
|
|
||||||
# this happens in the case of having a repeating script with `repeats=1` and
|
|
||||||
# `start_delay=False` - the script will run once and immediately stop before save is over.
|
|
||||||
return None
|
|
||||||
|
|
||||||
signals.SIGNAL_SCRIPT_POST_CREATE.send(sender=new_script)
|
|
||||||
|
|
||||||
return new_script
|
|
||||||
|
|
||||||
|
|
||||||
# alias
|
# alias
|
||||||
script = create_script
|
script = create_script
|
||||||
|
|
||||||
|
|
@ -302,55 +137,26 @@ script = create_script
|
||||||
# Help entry creation
|
# Help entry creation
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# """
|
||||||
|
# Create a static help entry in the help database. Note that Command
|
||||||
|
# help entries are dynamic and directly taken from the __doc__
|
||||||
|
# entries of the command. The database-stored help entries are
|
||||||
|
# intended for more general help on the game, more extensive info,
|
||||||
|
# in-game setting information and so on.
|
||||||
|
#
|
||||||
|
# Args:
|
||||||
|
# key (str): The name of the help entry.
|
||||||
|
# entrytext (str): The body of te help entry
|
||||||
|
# category (str, optional): The help category of the entry.
|
||||||
|
# locks (str, optional): A lockstring to restrict access.
|
||||||
|
# aliases (list of str, optional): List of alternative (likely shorter) keynames.
|
||||||
|
# tags (lst, optional): List of tags or tuples `(tag, category)`.
|
||||||
|
#
|
||||||
|
# Returns:
|
||||||
|
# help (HelpEntry): A newly created help entry.
|
||||||
|
#
|
||||||
|
|
||||||
def create_help_entry(key, entrytext, category="General", locks=None, aliases=None, tags=None):
|
create_help_entry = HelpEntry.objects.create_help
|
||||||
"""
|
|
||||||
Create a static help entry in the help database. Note that Command
|
|
||||||
help entries are dynamic and directly taken from the __doc__
|
|
||||||
entries of the command. The database-stored help entries are
|
|
||||||
intended for more general help on the game, more extensive info,
|
|
||||||
in-game setting information and so on.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
key (str): The name of the help entry.
|
|
||||||
entrytext (str): The body of te help entry
|
|
||||||
category (str, optional): The help category of the entry.
|
|
||||||
locks (str, optional): A lockstring to restrict access.
|
|
||||||
aliases (list of str, optional): List of alternative (likely shorter) keynames.
|
|
||||||
tags (lst, optional): List of tags or tuples `(tag, category)`.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
help (HelpEntry): A newly created help entry.
|
|
||||||
|
|
||||||
"""
|
|
||||||
global _HelpEntry
|
|
||||||
if not _HelpEntry:
|
|
||||||
from evennia.help.models import HelpEntry as _HelpEntry
|
|
||||||
|
|
||||||
try:
|
|
||||||
new_help = _HelpEntry()
|
|
||||||
new_help.key = key
|
|
||||||
new_help.entrytext = entrytext
|
|
||||||
new_help.help_category = category
|
|
||||||
if locks:
|
|
||||||
new_help.locks.add(locks)
|
|
||||||
if aliases:
|
|
||||||
new_help.aliases.add(make_iter(aliases))
|
|
||||||
if tags:
|
|
||||||
new_help.tags.batch_add(*tags)
|
|
||||||
new_help.save()
|
|
||||||
return new_help
|
|
||||||
except IntegrityError:
|
|
||||||
string = "Could not add help entry: key '%s' already exists." % key
|
|
||||||
logger.log_err(string)
|
|
||||||
return None
|
|
||||||
except Exception:
|
|
||||||
logger.log_trace()
|
|
||||||
return None
|
|
||||||
|
|
||||||
signals.SIGNAL_HELPENTRY_POST_CREATE.send(sender=new_help)
|
|
||||||
|
|
||||||
|
|
||||||
# alias
|
# alias
|
||||||
help_entry = create_help_entry
|
help_entry = create_help_entry
|
||||||
|
|
||||||
|
|
@ -358,117 +164,59 @@ help_entry = create_help_entry
|
||||||
#
|
#
|
||||||
# Comm system methods
|
# Comm system methods
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create a new communication Msg. Msgs represent a unit of
|
||||||
|
# database-persistent communication between entites.
|
||||||
|
#
|
||||||
|
# Args:
|
||||||
|
# senderobj (Object, Account, Script, str or list): The entity (or
|
||||||
|
# entities) sending the Msg. If a `str`, this is the id-string
|
||||||
|
# for an external sender type.
|
||||||
|
# message (str): Text with the message. Eventual headers, titles
|
||||||
|
# etc should all be included in this text string. Formatting
|
||||||
|
# will be retained.
|
||||||
|
# receivers (Object, Account, Script, str or list): An Account/Object to send
|
||||||
|
# to, or a list of them. If a string, it's an identifier for an external
|
||||||
|
# receiver.
|
||||||
|
# locks (str): Lock definition string.
|
||||||
|
# tags (list): A list of tags or tuples `(tag, category)`.
|
||||||
|
# header (str): Mime-type or other optional information for the message
|
||||||
|
#
|
||||||
|
# Notes:
|
||||||
|
# The Comm system is created to be very open-ended, so it's fully
|
||||||
|
# possible to let a message both go several receivers at the same time,
|
||||||
|
# it's up to the command definitions to limit this as desired.
|
||||||
|
#
|
||||||
|
|
||||||
def create_message(
|
create_message = Msg.objects.create_message
|
||||||
senderobj, message, receivers=None, locks=None, tags=None,
|
|
||||||
header=None, **kwargs):
|
|
||||||
"""
|
|
||||||
Create a new communication Msg. Msgs represent a unit of
|
|
||||||
database-persistent communication between entites.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
senderobj (Object, Account, Script, str or list): The entity (or
|
|
||||||
entities) sending the Msg. If a `str`, this is the id-string
|
|
||||||
for an external sender type.
|
|
||||||
message (str): Text with the message. Eventual headers, titles
|
|
||||||
etc should all be included in this text string. Formatting
|
|
||||||
will be retained.
|
|
||||||
receivers (Object, Account, Script, str or list): An Account/Object to send
|
|
||||||
to, or a list of them. If a string, it's an identifier for an external
|
|
||||||
receiver.
|
|
||||||
locks (str): Lock definition string.
|
|
||||||
tags (list): A list of tags or tuples `(tag, category)`.
|
|
||||||
header (str): Mime-type or other optional information for the message
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
The Comm system is created to be very open-ended, so it's fully
|
|
||||||
possible to let a message both go several receivers at the same time,
|
|
||||||
it's up to the command definitions to limit this as desired.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if 'channels' in kwargs:
|
|
||||||
raise DeprecationWarning(
|
|
||||||
"create_message() does not accept 'channel' kwarg anymore "
|
|
||||||
"- channels no longer accept Msg objects."
|
|
||||||
)
|
|
||||||
|
|
||||||
global _Msg
|
|
||||||
if not _Msg:
|
|
||||||
from evennia.comms.models import Msg as _Msg
|
|
||||||
if not message:
|
|
||||||
# we don't allow empty messages.
|
|
||||||
return None
|
|
||||||
new_message = _Msg(db_message=message)
|
|
||||||
new_message.save()
|
|
||||||
for sender in make_iter(senderobj):
|
|
||||||
new_message.senders = sender
|
|
||||||
new_message.header = header
|
|
||||||
for receiver in make_iter(receivers):
|
|
||||||
new_message.receivers = receiver
|
|
||||||
if locks:
|
|
||||||
new_message.locks.add(locks)
|
|
||||||
if tags:
|
|
||||||
new_message.tags.batch_add(*tags)
|
|
||||||
|
|
||||||
new_message.save()
|
|
||||||
return new_message
|
|
||||||
|
|
||||||
|
|
||||||
message = create_message
|
message = create_message
|
||||||
create_msg = create_message
|
create_msg = create_message
|
||||||
|
|
||||||
|
|
||||||
def create_channel(
|
# Create A communication Channel. A Channel serves as a central hub
|
||||||
key, aliases=None, desc=None, locks=None, keep_log=True, typeclass=None, tags=None
|
# for distributing Msgs to groups of people without specifying the
|
||||||
):
|
# receivers explicitly. Instead accounts may 'connect' to the channel
|
||||||
"""
|
# and follow the flow of messages. By default the channel allows
|
||||||
Create A communication Channel. A Channel serves as a central hub
|
# access to all old messages, but this can be turned off with the
|
||||||
for distributing Msgs to groups of people without specifying the
|
# keep_log switch.
|
||||||
receivers explicitly. Instead accounts may 'connect' to the channel
|
#
|
||||||
and follow the flow of messages. By default the channel allows
|
# Args:
|
||||||
access to all old messages, but this can be turned off with the
|
# key (str): This must be unique.
|
||||||
keep_log switch.
|
#
|
||||||
|
# Keyword Args:
|
||||||
Args:
|
# aliases (list of str): List of alternative (likely shorter) keynames.
|
||||||
key (str): This must be unique.
|
# desc (str): A description of the channel, for use in listings.
|
||||||
|
# locks (str): Lockstring.
|
||||||
Keyword Args:
|
# keep_log (bool): Log channel throughput.
|
||||||
aliases (list of str): List of alternative (likely shorter) keynames.
|
# typeclass (str or class): The typeclass of the Channel (not
|
||||||
desc (str): A description of the channel, for use in listings.
|
# often used).
|
||||||
locks (str): Lockstring.
|
# tags (list): A list of tags or tuples `(tag, category)`.
|
||||||
keep_log (bool): Log channel throughput.
|
#
|
||||||
typeclass (str or class): The typeclass of the Channel (not
|
# Returns:
|
||||||
often used).
|
# channel (Channel): A newly created channel.
|
||||||
tags (list): A list of tags or tuples `(tag, category)`.
|
#
|
||||||
|
|
||||||
Returns:
|
|
||||||
channel (Channel): A newly created channel.
|
|
||||||
|
|
||||||
"""
|
|
||||||
typeclass = typeclass if typeclass else settings.BASE_CHANNEL_TYPECLASS
|
|
||||||
|
|
||||||
if isinstance(typeclass, str):
|
|
||||||
# a path is given. Load the actual typeclass
|
|
||||||
typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)
|
|
||||||
|
|
||||||
# create new instance
|
|
||||||
new_channel = typeclass(db_key=key)
|
|
||||||
|
|
||||||
# store call signature for the signal
|
|
||||||
new_channel._createdict = dict(
|
|
||||||
key=key, aliases=aliases, desc=desc, locks=locks, keep_log=keep_log, tags=tags
|
|
||||||
)
|
|
||||||
|
|
||||||
# this will trigger the save signal which in turn calls the
|
|
||||||
# at_first_save hook on the typeclass, where the _createdict can be
|
|
||||||
# used.
|
|
||||||
new_channel.save()
|
|
||||||
|
|
||||||
signals.SIGNAL_CHANNEL_POST_CREATE.send(sender=new_channel)
|
|
||||||
|
|
||||||
return new_channel
|
|
||||||
|
|
||||||
|
|
||||||
|
create_channel = ChannelDB.objects.create_channel
|
||||||
channel = create_channel
|
channel = create_channel
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -476,111 +224,37 @@ channel = create_channel
|
||||||
# Account creation methods
|
# Account creation methods
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# This creates a new account.
|
||||||
|
#
|
||||||
|
# Args:
|
||||||
|
# key (str): The account's name. This should be unique.
|
||||||
|
# email (str or None): Email on valid addr@addr.domain form. If
|
||||||
|
# the empty string, will be set to None.
|
||||||
|
# password (str): Password in cleartext.
|
||||||
|
#
|
||||||
|
# Keyword Args:
|
||||||
|
# typeclass (str): The typeclass to use for the account.
|
||||||
|
# is_superuser (bool): Wether or not this account is to be a superuser
|
||||||
|
# locks (str): Lockstring.
|
||||||
|
# permission (list): List of permission strings.
|
||||||
|
# tags (list): List of Tags on form `(key, category[, data])`
|
||||||
|
# attributes (list): List of Attributes on form
|
||||||
|
# `(key, value [, category, [,lockstring [, default_pass]]])`
|
||||||
|
# report_to (Object): An object with a msg() method to report
|
||||||
|
# errors to. If not given, errors will be logged.
|
||||||
|
#
|
||||||
|
# Returns:
|
||||||
|
# Account: The newly created Account.
|
||||||
|
# Raises:
|
||||||
|
# ValueError: If `key` already exists in database.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Notes:
|
||||||
|
# Usually only the server admin should need to be superuser, all
|
||||||
|
# other access levels can be handled with more fine-grained
|
||||||
|
# permissions or groups. A superuser bypasses all lock checking
|
||||||
|
# operations and is thus not suitable for play-testing the game.
|
||||||
|
|
||||||
def create_account(
|
create_account = AccountDB.objects.create_account
|
||||||
key,
|
|
||||||
email,
|
|
||||||
password,
|
|
||||||
typeclass=None,
|
|
||||||
is_superuser=False,
|
|
||||||
locks=None,
|
|
||||||
permissions=None,
|
|
||||||
tags=None,
|
|
||||||
attributes=None,
|
|
||||||
report_to=None,
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
This creates a new account.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
key (str): The account's name. This should be unique.
|
|
||||||
email (str or None): Email on valid addr@addr.domain form. If
|
|
||||||
the empty string, will be set to None.
|
|
||||||
password (str): Password in cleartext.
|
|
||||||
|
|
||||||
Keyword Args:
|
|
||||||
typeclass (str): The typeclass to use for the account.
|
|
||||||
is_superuser (bool): Wether or not this account is to be a superuser
|
|
||||||
locks (str): Lockstring.
|
|
||||||
permission (list): List of permission strings.
|
|
||||||
tags (list): List of Tags on form `(key, category[, data])`
|
|
||||||
attributes (list): List of Attributes on form
|
|
||||||
`(key, value [, category, [,lockstring [, default_pass]]])`
|
|
||||||
report_to (Object): An object with a msg() method to report
|
|
||||||
errors to. If not given, errors will be logged.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Account: The newly created Account.
|
|
||||||
Raises:
|
|
||||||
ValueError: If `key` already exists in database.
|
|
||||||
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
Usually only the server admin should need to be superuser, all
|
|
||||||
other access levels can be handled with more fine-grained
|
|
||||||
permissions or groups. A superuser bypasses all lock checking
|
|
||||||
operations and is thus not suitable for play-testing the game.
|
|
||||||
|
|
||||||
"""
|
|
||||||
global _AccountDB
|
|
||||||
if not _AccountDB:
|
|
||||||
from evennia.accounts.models import AccountDB as _AccountDB
|
|
||||||
|
|
||||||
typeclass = typeclass if typeclass else settings.BASE_ACCOUNT_TYPECLASS
|
|
||||||
locks = make_iter(locks) if locks is not None else None
|
|
||||||
permissions = make_iter(permissions) if permissions is not None else None
|
|
||||||
tags = make_iter(tags) if tags is not None else None
|
|
||||||
attributes = make_iter(attributes) if attributes is not None else None
|
|
||||||
|
|
||||||
if isinstance(typeclass, str):
|
|
||||||
# a path is given. Load the actual typeclass.
|
|
||||||
typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)
|
|
||||||
|
|
||||||
# setup input for the create command. We use AccountDB as baseclass
|
|
||||||
# here to give us maximum freedom (the typeclasses will load
|
|
||||||
# correctly when each object is recovered).
|
|
||||||
|
|
||||||
if not email:
|
|
||||||
email = None
|
|
||||||
if _AccountDB.objects.filter(username__iexact=key):
|
|
||||||
raise ValueError("An Account with the name '%s' already exists." % key)
|
|
||||||
|
|
||||||
# this handles a given dbref-relocate to an account.
|
|
||||||
report_to = dbid_to_obj(report_to, _AccountDB)
|
|
||||||
|
|
||||||
# create the correct account entity, using the setup from
|
|
||||||
# base django auth.
|
|
||||||
now = timezone.now()
|
|
||||||
email = typeclass.objects.normalize_email(email)
|
|
||||||
new_account = typeclass(
|
|
||||||
username=key,
|
|
||||||
email=email,
|
|
||||||
is_staff=is_superuser,
|
|
||||||
is_superuser=is_superuser,
|
|
||||||
last_login=now,
|
|
||||||
date_joined=now,
|
|
||||||
)
|
|
||||||
if password is not None:
|
|
||||||
# the password may be None for 'fake' accounts, like bots
|
|
||||||
valid, error = new_account.validate_password(password, new_account)
|
|
||||||
if not valid:
|
|
||||||
raise error
|
|
||||||
|
|
||||||
new_account.set_password(password)
|
|
||||||
|
|
||||||
new_account._createdict = dict(
|
|
||||||
locks=locks, permissions=permissions, report_to=report_to, tags=tags, attributes=attributes
|
|
||||||
)
|
|
||||||
# saving will trigger the signal that calls the
|
|
||||||
# at_first_save hook on the typeclass, where the _createdict
|
|
||||||
# can be used.
|
|
||||||
new_account.save()
|
|
||||||
|
|
||||||
# note that we don't send a signal here, that is sent from the Account.create helper method
|
|
||||||
# instead.
|
|
||||||
|
|
||||||
return new_account
|
|
||||||
|
|
||||||
|
|
||||||
# alias
|
# alias
|
||||||
account = create_account
|
account = create_account
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ except OperationalError:
|
||||||
# candidates=None,
|
# candidates=None,
|
||||||
# attribute_name=None):
|
# attribute_name=None):
|
||||||
#
|
#
|
||||||
search_object = ObjectDB.objects.object_search
|
search_object = ObjectDB.objects.search_object
|
||||||
search_objects = search_object
|
search_objects = search_object
|
||||||
object_search = search_object
|
object_search = search_object
|
||||||
objects = search_objects
|
objects = search_objects
|
||||||
|
|
@ -126,7 +126,7 @@ objects = search_objects
|
||||||
# ostring = a string or database id.
|
# ostring = a string or database id.
|
||||||
#
|
#
|
||||||
|
|
||||||
search_account = AccountDB.objects.account_search
|
search_account = AccountDB.objects.search_account
|
||||||
search_accounts = search_account
|
search_accounts = search_account
|
||||||
account_search = search_account
|
account_search = search_account
|
||||||
accounts = search_accounts
|
accounts = search_accounts
|
||||||
|
|
@ -144,7 +144,7 @@ accounts = search_accounts
|
||||||
# on a timer.
|
# on a timer.
|
||||||
#
|
#
|
||||||
|
|
||||||
search_script = ScriptDB.objects.script_search
|
search_script = ScriptDB.objects.search_script
|
||||||
search_scripts = search_script
|
search_scripts = search_script
|
||||||
script_search = search_script
|
script_search = search_script
|
||||||
scripts = search_scripts
|
scripts = search_scripts
|
||||||
|
|
@ -165,7 +165,7 @@ scripts = search_scripts
|
||||||
# one of the other arguments to limit the search.
|
# one of the other arguments to limit the search.
|
||||||
#
|
#
|
||||||
|
|
||||||
search_message = Msg.objects.message_search
|
search_message = Msg.objects.search_message
|
||||||
search_messages = search_message
|
search_messages = search_message
|
||||||
message_search = search_message
|
message_search = search_message
|
||||||
messages = search_messages
|
messages = search_messages
|
||||||
|
|
@ -181,7 +181,7 @@ messages = search_messages
|
||||||
# exact - requires an exact ostring match (not case sensitive)
|
# exact - requires an exact ostring match (not case sensitive)
|
||||||
#
|
#
|
||||||
|
|
||||||
search_channel = ChannelDB.objects.channel_search
|
search_channel = ChannelDB.objects.search_channel
|
||||||
search_channels = search_channel
|
search_channels = search_channel
|
||||||
channel_search = search_channel
|
channel_search = search_channel
|
||||||
channels = search_channels
|
channels = search_channels
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue