Merge branch 'master' into develop

This commit is contained in:
Griatch 2020-04-20 23:15:53 +02:00
commit dc81d275e6
18 changed files with 411 additions and 71 deletions

12
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: griatch
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://www.paypal.me/GriatchEvennia

View file

@ -275,11 +275,11 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
raise RuntimeError("Session not found")
if self.get_puppet(session) == obj:
# already puppeting this object
self.msg("You are already puppeting this object.")
self.msg(_("You are already puppeting this object."))
return
if not obj.access(self, "puppet"):
# no access
self.msg(f"You don't have permission to puppet '{obj.key}'.")
self.msg(_("You don't have permission to puppet '{key}'.").format(key=obj.key))
return
if obj.account:
# object already puppeted
@ -295,12 +295,12 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
else:
txt1 = f"Taking over |c{obj.name}|n from another of your sessions."
txt2 = f"|c{obj.name}|n|R is now acted from another of your sessions.|n"
self.msg(txt1, session=session)
self.msg(txt2, session=obj.sessions.all())
self.msg(_(txt1), session=session)
self.msg(_(txt2), session=obj.sessions.all())
self.unpuppet_object(obj.sessions.get())
elif obj.account.is_connected:
# controlled by another account
self.msg(f"|c{obj.key}|R is already puppeted by another Account.")
self.msg(_("|c{key}|R is already puppeted by another Account.").format(key=obj.key))
return
# do the puppeting
@ -496,7 +496,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
# See if authentication is currently being throttled
if ip and LOGIN_THROTTLE.check(ip):
errors.append("Too many login failures; please try again in a few minutes.")
errors.append(_("Too many login failures; please try again in a few minutes."))
# With throttle active, do not log continued hits-- it is a
# waste of storage and can be abused to make your logs harder to
@ -508,8 +508,8 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
if banned:
# this is a banned IP or name!
errors.append(
"|rYou have been banned and cannot continue from here."
"\nIf you feel this ban is in error, please email an admin.|x"
_("|rYou have been banned and cannot continue from here."
"\nIf you feel this ban is in error, please email an admin.|x")
)
logger.log_sec(f"Authentication Denied (Banned): {username} (IP: {ip}).")
LOGIN_THROTTLE.update(ip, "Too many sightings of banned artifact.")
@ -519,7 +519,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
account = authenticate(username=username, password=password)
if not account:
# User-facing message
errors.append("Username and/or password is incorrect.")
errors.append(_("Username and/or password is incorrect."))
# Log auth failures while throttle is inactive
logger.log_sec(f"Authentication Failure: {username} (IP: {ip}).")
@ -688,7 +688,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
ip = kwargs.get("ip", "")
if ip and CREATION_THROTTLE.check(ip):
errors.append(
"You are creating too many accounts. Please log into an existing account."
_("You are creating too many accounts. Please log into an existing account.")
)
return None, errors
@ -717,8 +717,8 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
if banned:
# this is a banned IP or name!
string = (
"|rYou have been banned and cannot continue from here."
"\nIf you feel this ban is in error, please email an admin.|x"
_("|rYou have been banned and cannot continue from here."
"\nIf you feel this ban is in error, please email an admin.|x")
)
errors.append(string)
return None, errors
@ -733,7 +733,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
except Exception as e:
errors.append(
"There was an error creating the Account. If this problem persists, contact an admin."
_("There was an error creating the Account. If this problem persists, contact an admin.")
)
logger.log_trace()
return None, errors
@ -785,7 +785,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
# We are in the middle between logged in and -not, so we have
# to handle tracebacks ourselves at this point. If we don't,
# we won't see any errors at all.
errors.append("An error occurred. Please e-mail an admin if the problem persists.")
errors.append(_("An error occurred. Please e-mail an admin if the problem persists."))
logger.log_trace()
# Update the throttle to indicate a new account was created from this IP
@ -1253,21 +1253,21 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
if session:
session.msg(logged_in={})
self._send_to_connect_channel(f"|G{self.key} connected|n")
self._send_to_connect_channel(_("|G{key} connected|n").format(key=self.key))
if _MULTISESSION_MODE == 0:
# in this mode we should have only one character available. We
# try to auto-connect to our last conneted object, if any
try:
self.puppet_object(session, self.db._last_puppet)
except RuntimeError:
self.msg("The Character does not exist.")
self.msg(_("The Character does not exist."))
return
elif _MULTISESSION_MODE == 1:
# in this mode all sessions connect to the same puppet.
try:
self.puppet_object(session, self.db._last_puppet)
except RuntimeError:
self.msg("The Character does not exist.")
self.msg(_("The Character does not exist."))
return
elif _MULTISESSION_MODE in (2, 3):
# In this mode we by default end up at a character selection
@ -1305,7 +1305,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
"""
reason = f" ({reason if reason else ''})"
self._send_to_connect_channel(f"|R{self.key} disconnected{reason}|n")
self._send_to_connect_channel(_("|R{key} disconnected{reason}|n").format(key=self.key, reason=reason))
def at_post_disconnect(self, **kwargs):
"""
@ -1411,7 +1411,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
if hasattr(target, "return_appearance"):
return target.return_appearance(self)
else:
return "{} has no in-game appearance.".format(target)
return _("{target} has no in-game appearance.").format(target=target)
else:
# list of targets - make list to disconnect from db
characters = list(tar for tar in target if tar) if target else []
@ -1454,7 +1454,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
if is_su or len(characters) < charmax:
if not characters:
result.append(
"\n\n You don't have any characters yet. See |whelp @charcreate|n for creating one."
_("\n\n You don't have any characters yet. See |whelp @charcreate|n for creating one.")
)
else:
result.append("\n |w@charcreate <name> [=description]|n - create new character")
@ -1534,7 +1534,7 @@ class DefaultGuest(DefaultAccount):
# check if guests are enabled.
if not settings.GUEST_ENABLED:
errors.append("Guest accounts are not enabled on this server.")
errors.append(_("Guest accounts are not enabled on this server."))
return None, errors
try:
@ -1544,7 +1544,7 @@ class DefaultGuest(DefaultAccount):
username = name
break
if not username:
errors.append("All guest accounts are in use. Please try again later.")
errors.append(_("All guest accounts are in use. Please try again later."))
if ip:
LOGIN_THROTTLE.update(ip, "Too many requests for Guest access.")
return None, errors
@ -1572,7 +1572,7 @@ class DefaultGuest(DefaultAccount):
# We are in the middle between logged in and -not, so we have
# to handle tracebacks ourselves at this point. If we don't,
# we won't see any errors at all.
errors.append("An error occurred. Please e-mail an admin if the problem persists.")
errors.append(_("An error occurred. Please e-mail an admin if the problem persists."))
logger.log_trace()
return None, errors
@ -1589,7 +1589,7 @@ class DefaultGuest(DefaultAccount):
overriding the call (unused by default).
"""
self._send_to_connect_channel(f"|G{self.key} connected|n")
self._send_to_connect_channel(_("|G{key} connected|n").format(key=self.key))
self.puppet_object(session, self.db._last_puppet)
def at_server_shutdown(self):

View file

@ -10,6 +10,7 @@ from evennia.accounts.accounts import DefaultAccount
from evennia.scripts.scripts import DefaultScript
from evennia.utils import search
from evennia.utils import utils
from django.utils.translation import gettext as _
_IDLE_TIMEOUT = settings.IDLE_TIMEOUT
@ -328,7 +329,7 @@ class IRCBot(Bot):
chstr = f"{self.db.irc_channel} ({self.db.irc_network}:{self.db.irc_port})"
nicklist = ", ".join(sorted(kwargs["nicklist"], key=lambda n: n.lower()))
for obj in self._nicklist_callers:
obj.msg(f"Nicks at {chstr}:\n {nicklist}")
obj.msg(_("Nicks at {chstr}:\n {nicklist}").format(chstr=chstr, nicklist=nicklist))
self._nicklist_callers = []
return
@ -337,7 +338,7 @@ class IRCBot(Bot):
if hasattr(self, "_ping_callers") and self._ping_callers:
chstr = f"{self.db.irc_channel} ({self.db.irc_network}:{self.db.irc_port})"
for obj in self._ping_callers:
obj.msg(f"IRC ping return from {chstr} took {kwargs['timing']}s.")
obj.msg(_("IRC ping return from {chstr} took {time}s.").format(chstr=chstr, time=kwargs['timing']))
self._ping_callers = []
return

View file

@ -743,7 +743,7 @@ def cmdhandler(
sysarg = raw_string
else:
# fallback to default error text
sysarg = _("Command '%s' is not available.") % raw_string
sysarg = _("Command '{command}' is not available.").format(command=raw_string)
suggestions = string_suggestions(
raw_string,
cmdset.get_all_cmd_keys_and_aliases(caller),
@ -751,9 +751,7 @@ def cmdhandler(
maxnum=3,
)
if suggestions:
sysarg += _(" Maybe you meant %s?") % utils.list_to_string(
suggestions, _("or"), addquote=True
)
sysarg += _(" Maybe you meant {command}?").format(command=utils.list_to_string(suggestions, _("or"), addquote=True))
else:
sysarg += _(' Type "help" for help.')
raise ExecSystemCommand(syscmd, sysarg)

View file

@ -184,7 +184,7 @@ def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False):
raise exc.with_traceback(tb)
else:
# try next suggested path
errstring += _("\n(Unsuccessfully tried '%s')." % python_path)
errstring += _("\n(Unsuccessfully tried '{path}').").format(path=python_path)
continue
try:
cmdsetclass = getattr(module, classname)
@ -194,7 +194,7 @@ def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False):
dum, dum, tb = sys.exc_info()
raise exc.with_traceback(tb)
else:
errstring += _("\n(Unsuccessfully tried '%s')." % python_path)
errstring += _("\n(Unsuccessfully tried '{path}').").format(path=python_path)
continue
_CACHED_CMDSETS[python_path] = cmdsetclass

View file

@ -119,17 +119,17 @@ class ChannelCommand(command.Command):
caller = caller if not hasattr(caller, "account") else caller.account
unmuted = channel.unmute(caller)
if unmuted:
self.msg("You start listening to %s." % channel)
self.msg(_("You start listening to %s.") % channel)
return
self.msg("You were already listening to %s." % channel)
self.msg(_("You were already listening to %s.") % channel)
return
if msg == "off":
caller = caller if not hasattr(caller, "account") else caller.account
muted = channel.mute(caller)
if muted:
self.msg("You stop listening to %s." % channel)
self.msg(_("You stop listening to %s.") % channel)
return
self.msg("You were already not listening to %s." % channel)
self.msg(_("You were already not listening to %s.") % channel)
return
if self.history_start is not None:
# Try to view history
@ -144,7 +144,7 @@ class ChannelCommand(command.Command):
else:
caller = caller if not hasattr(caller, "account") else caller.account
if caller in channel.mutelist:
self.msg("You currently have %s muted." % channel)
self.msg(_("You currently have %s muted.") % channel)
return
channel.msg(msg, senders=self.caller, online=True)

View file

@ -131,7 +131,7 @@ class HelpEntryManager(TypedObjectManager):
for topic in topics:
topic.help_category = default_category
topic.save()
string = "Help database moved to category %s" % default_category
string = _("Help database moved to category {default_category}").format(default_category=default_category)
logger.log_info(string)
def search_help(self, ostring, help_category=None):

Binary file not shown.

View file

@ -0,0 +1,299 @@
msgid ""
msgstr ""
"Project-Id-Version: Evennia Russian Translation v0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-02-20 12:13+0000\n"
"PO-Revision-Date: 2020-04-19 18:32+0000\n"
"Last-Translator: 3eluk\n"
"Language-Team: Russian (Russia)\n"
"Language: ru-RU\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10 >= 2 && "
"n%10<=4 &&(n%100<10||n%100 >= 20)? 1 : 2);\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Loco-Source-Locale: ru_RU\n"
"X-Generator: Loco https://localise.biz/\n"
"X-Loco-Parser: loco_parse_po"
#: accounts/accounts.py:440
msgid "Account being deleted."
msgstr "Аккаунт удаляется."
#: commands/cmdhandler.py:681
msgid "There were multiple matches."
msgstr "Здесь было несколько совпадений."
#: commands/cmdhandler.py:704
#, python-format
msgid "Command '%s' is not available."
msgstr "Команда '%s' недоступна."
#: commands/cmdhandler.py:709
#, python-format
msgid " Maybe you meant %s?"
msgstr "Возможно, вы имели ввиду %s?"
#: commands/cmdhandler.py:709
msgid "or"
msgstr "или"
#: commands/cmdhandler.py:711
msgid " Type \"help\" for help."
msgstr " Введи \"справка\" для получения помощи."
#: commands/cmdsethandler.py:89
msgid ""
"{traceback}\n"
"Error loading cmdset '{path}'\n"
"(Traceback was logged {timestamp})"
msgstr ""
#: commands/cmdsethandler.py:94
msgid ""
"Error loading cmdset: No cmdset class '{classname}' in '{path}'.\n"
"(Traceback was logged {timestamp})"
msgstr ""
#: commands/cmdsethandler.py:98
msgid ""
"{traceback}\n"
"SyntaxError encountered when loading cmdset '{path}'.\n"
"(Traceback was logged {timestamp})"
msgstr ""
#: commands/cmdsethandler.py:103
msgid ""
"{traceback}\n"
"Compile/Run error when loading cmdset '{path}'.\",\n"
"(Traceback was logged {timestamp})"
msgstr ""
#: commands/cmdsethandler.py:108
msgid ""
"\n"
"Error encountered for cmdset at path '{path}'.\n"
"Replacing with fallback '{fallback_path}'.\n"
msgstr ""
#: commands/cmdsethandler.py:114
msgid "Fallback path '{fallback_path}' failed to generate a cmdset."
msgstr ""
#: commands/cmdsethandler.py:182 commands/cmdsethandler.py:192
#, python-format
msgid ""
"\n"
"(Unsuccessfully tried '%s')."
msgstr ""
"\n"
"(Безуспешно пробую '%s')."
#: commands/cmdsethandler.py:311
msgid "custom {mergetype} on cmdset '{cmdset}'"
msgstr ""
#: commands/cmdsethandler.py:314
msgid " <Merged {mergelist} {mergetype}, prio {prio}>: {current}"
msgstr ""
#: commands/cmdsethandler.py:322
msgid ""
" <{key} ({mergetype}, prio {prio}, {permstring})>:\n"
" {keylist}"
msgstr ""
#: commands/cmdsethandler.py:426
msgid "Only CmdSets can be added to the cmdsethandler!"
msgstr ""
#: comms/channelhandler.py:100
msgid "Say what?"
msgstr "Сказать что?"
#: comms/channelhandler.py:105
#, python-format
msgid "Channel '%s' not found."
msgstr "Канал '%s' не обнаружен."
#: comms/channelhandler.py:108
#, python-format
msgid "You are not connected to channel '%s'."
msgstr "Ты не соединён с каналом '%s'."
#: comms/channelhandler.py:112
#, python-format
msgid "You are not permitted to send to channel '%s'."
msgstr "У тебя нет разрешения слать в канал '%s'."
#: comms/channelhandler.py:155
msgid " (channel)"
msgstr " (канал)"
#: locks/lockhandler.py:236
#, python-format
msgid "Lock: lock-function '%s' is not available."
msgstr ""
#: locks/lockhandler.py:249
#, python-format
msgid "Lock: definition '%s' has syntax errors."
msgstr ""
#: locks/lockhandler.py:253
#, python-format
msgid ""
"LockHandler on %(obj)s: access type '%(access_type)s' changed from '%(source)"
"s' to '%(goal)s' "
msgstr ""
#: locks/lockhandler.py:320
msgid "Lock: '{lockdef}' contains no colon (:)."
msgstr ""
#: locks/lockhandler.py:328
msgid "Lock: '{lockdef}' has no access_type (left-side of colon is empty)."
msgstr ""
#: locks/lockhandler.py:336
msgid "Lock: '{lockdef}' has mismatched parentheses."
msgstr ""
#: locks/lockhandler.py:343
msgid "Lock: '{lockdef}' has no valid lock functions."
msgstr ""
#: objects/objects.py:732
#, python-format
msgid "Couldn't perform move ('%s'). Contact an admin."
msgstr "Не удалось выполнить действие ('%s'). Свяжитесь с администратором."
#: objects/objects.py:742
msgid "The destination doesn't exist."
msgstr "Такой точки назначения нету."
#: objects/objects.py:833
#, python-format
msgid "Could not find default home '(#%d)'."
msgstr "Не обнаружен дом по умолчанию '(#%d)'."
#: objects/objects.py:849
msgid "Something went wrong! You are dumped into nowhere. Contact an admin."
msgstr ""
"Что-то пошло не так! Тебя выбрасывает в пустоту. Свяжитесь с администратором."
#: objects/objects.py:915
#, python-format
msgid "Your character %s has been destroyed."
msgstr "Ваш персонаж %s был уничтожен."
#: scripts/scripthandler.py:53
#, python-format
msgid ""
"\n"
" '%(key)s' (%(next_repeat)s/%(interval)s, %(repeats)s repeats): %(desc)s"
msgstr ""
#: scripts/scripts.py:205
#, python-format
msgid ""
"Script %(key)s(#%(dbid)s) of type '%(cname)s': at_repeat() error '%(err)s'."
msgstr ""
#: server/initial_setup.py:28
msgid ""
"\n"
"Welcome to your new |wEvennia|n-based game! Visit http://www.evennia.com if "
"you need\n"
"help, want to contribute, report issues or just join the community.\n"
"As Account #1 you can create a demo/tutorial area with |w@batchcommand "
"tutorial_world.build|n.\n"
" "
msgstr ""
"\n"
"Добро пожаловать в твою новую игру, основанную на |wEvennia|n! Посети http:"
"//www.evennia.com\n"
"если тебе нужна помощь, хочешь помочь, сообщить об ошибках, lили просто "
"присоединиться к сообществу.\n"
"Как Аккаунт №1, ты можешь создать зону для демонстрации/обучения командой "
"|w@batchcommand tutorial_world.build|n.\n"
" "
#: server/initial_setup.py:92
msgid "This is User #1."
msgstr "Это Пользователь №1."
#: server/initial_setup.py:105
msgid "Limbo"
msgstr "Лимб"
#: server/server.py:139
msgid "idle timeout exceeded"
msgstr "время бездействия превышено"
#: server/sessionhandler.py:386
msgid " ... Server restarted."
msgstr " ... Сервер перезапущен."
#: server/sessionhandler.py:606
msgid "Logged in from elsewhere. Disconnecting."
msgstr "Выполнено соединение в другом месте. Отключение."
#: server/sessionhandler.py:634
msgid "Idle timeout exceeded, disconnecting."
msgstr "Время бездействия превышено, отключение."
#: server/validators.py:50
#, python-format
msgid ""
"%s From a terminal client, you can also use a phrase of multiple words if "
"you enclose the password in double quotes."
msgstr ""
"%s Если вы используете терминал, вы можете использовать фразу из нескольких "
"слов если возьмёте пароль в двойные скобки."
#: utils/evmenu.py:192
msgid ""
"Menu node '{nodename}' is either not implemented or caused an error. Make "
"another choice."
msgstr ""
#: utils/evmenu.py:194
msgid "Error in menu node '{nodename}'."
msgstr ""
#: utils/evmenu.py:195
msgid "No description."
msgstr "Нет описания."
#: utils/evmenu.py:196
msgid "Commands: <menu option>, help, quit"
msgstr "Команды: <menu option>, справка, выход"
#: utils/evmenu.py:197
msgid "Commands: <menu option>, help"
msgstr "Команды: <menu option>, справка"
#: utils/evmenu.py:198
msgid "Commands: help, quit"
msgstr ""
#: utils/evmenu.py:199
msgid "Commands: help"
msgstr "Команды: справка"
#: utils/evmenu.py:200
msgid "Choose an option or try 'help'."
msgstr "Выберите опцию или введите \"справка\"."
#: utils/utils.py:1866
#, python-format
msgid "Could not find '%s'."
msgstr "Не обнаружено '%s'."
#: utils/utils.py:1873
#, python-format
msgid ""
"More than one match for '%s' (please narrow target):\n"
msgstr ""
"Больше одного подходящего варианта для '%s' (уточните цель):\n"

View file

@ -246,7 +246,7 @@ class LockHandler(object):
evalstring = " ".join(_RE_OK.findall(evalstring))
eval(evalstring % tuple(True for func in funclist), {}, {})
except Exception:
elist.append(_("Lock: definition '%s' has syntax errors.") % raw_lockstring)
elist.append(_("Lock: definition '{lock_string}' has syntax errors.").format(lock_string=raw_lockstring))
continue
if access_type in locks:
duplicates += 1

View file

@ -8,7 +8,7 @@ from django.contrib import admin
from evennia.typeclasses.admin import AttributeInline, TagInline
from evennia.objects.models import ObjectDB
from django.contrib.admin.utils import flatten_fieldsets
from django.utils.translation import gettext as _
class ObjectAttributeInline(AttributeInline):
"""
@ -61,7 +61,7 @@ class ObjectCreateForm(forms.ModelForm):
required=False,
widget=forms.TextInput(attrs={"size": "78"}),
help_text="Most non-character objects don't need a cmdset"
" and can leave this field blank.",
" and can leave this field blank."
)
raw_id_fields = ("db_destination", "db_location", "db_home")

View file

@ -1059,7 +1059,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
# See if we need to kick the account off.
for session in self.sessions.all():
session.msg(_("Your character %s has been destroyed.") % self.key)
session.msg(_("Your character {key} has been destroyed.").format(key=self.key))
# no need to disconnect, Account just jumps to OOC mode.
# sever the connection (important!)
if self.account:

View file

@ -465,11 +465,12 @@ def getKeyPair(pubkeyfile, privkeyfile):
if not (os.path.exists(pubkeyfile) and os.path.exists(privkeyfile)):
# No keypair exists. Generate a new RSA keypair
from Crypto.PublicKey import RSA
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa
rsa_key = Key(RSA.generate(_KEY_LENGTH))
public_key_string = rsa_key.public().toString(type="OPENSSH")
private_key_string = rsa_key.toString(type="OPENSSH")
rsa_key = Key(rsa.generate_private_key(public_exponent=65537, key_size=_KEY_LENGTH, backend=default_backend()))
public_key_string = rsa_key.public().toString(type="OPENSSH").decode()
private_key_string = rsa_key.toString(type="OPENSSH").decode()
# save keys for the future.
with open(privkeyfile, "wt") as pfile:

View file

@ -4,7 +4,7 @@ Master configuration file for Evennia.
NOTE: NO MODIFICATIONS SHOULD BE MADE TO THIS FILE!
All settings changes should be done by copy-pasting the variable and
its value to <gamedir>/conf/settings.py.
its value to <gamedir>/server/conf/settings.py.
Hint: Don't copy&paste over more from this file than you actually want
to change. Anything you don't copy&paste will thus retain its default

View file

@ -31,7 +31,8 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
# Attribute manager methods
def get_attribute(
self, key=None, category=None, value=None, strvalue=None, obj=None, attrtype=None
self, key=None, category=None, value=None, strvalue=None, obj=None, attrtype=None, **kwargs
):
"""
Return Attribute objects by key, by category, by value, by
@ -55,6 +56,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
attrype (str, optional): An attribute-type to search for.
By default this is either `None` (normal Attributes) or
`"nick"`.
kwargs (any): Currently unused. Reserved for future use.
Returns:
attributes (list): The matching Attributes.
@ -102,7 +104,8 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
key=key, category=category, value=value, strvalue=strvalue, obj=obj
)
def get_by_attribute(self, key=None, category=None, value=None, strvalue=None, attrtype=None):
def get_by_attribute(self, key=None, category=None, value=None,
strvalue=None, attrtype=None, **kwargs):
"""
Return objects having attributes with the given key, category,
value, strvalue or combination of those criteria.
@ -122,6 +125,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
attrype (str, optional): An attribute-type to search for.
By default this is either `None` (normal Attributes) or
`"nick"`.
kwargs (any): Currently unused. Reserved for future use.
Returns:
obj (list): Objects having the matching Attributes.
@ -488,12 +492,12 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager):
def get_typeclass_totals(self, *args, **kwargs) -> object:
"""
Returns a queryset of typeclass composition statistics.
Returns:
qs (Queryset): A queryset of dicts containing the typeclass (name),
qs (Queryset): A queryset of dicts containing the typeclass (name),
the count of objects with that typeclass and a float representing
the percentage of objects associated with the typeclass.
"""
return (
self.values("db_typeclass_path")

View file

@ -205,27 +205,31 @@ help_entries = search_help
# not the attribute object itself (this is usually what you want)
def search_object_attribute(key=None, category=None, value=None, strvalue=None):
def search_object_attribute(key=None, category=None, value=None,
strvalue=None, attrtype=None, **kwargs):
return ObjectDB.objects.get_by_attribute(
key=key, category=category, value=value, strvalue=strvalue
key=key, category=category, value=value, strvalue=strvalue, attrtype=attrtype, **kwargs
)
def search_account_attribute(key=None, category=None, value=None, strvalue=None):
def search_account_attribute(key=None, category=None, value=None,
strvalue=None, attrtype=None, **kwargs):
return AccountDB.objects.get_by_attribute(
key=key, category=category, value=value, strvalue=strvalue
key=key, category=category, value=value, strvalue=strvalue, attrtype=attrtype, **kwargs
)
def search_script_attribute(key=None, category=None, value=None, strvalue=None):
def search_script_attribute(key=None, category=None, value=None,
strvalue=None, attrtype=None, **kwargs):
return ScriptDB.objects.get_by_attribute(
key=key, category=category, value=value, strvalue=strvalue
key=key, category=category, value=value, strvalue=strvalue, attrtype=attrtype, **kwargs
)
def search_channel_attribute(key=None, category=None, value=None, strvalue=None):
def search_channel_attribute(key=None, category=None, value=None,
strvalue=None, attrtype=None, **kwargs):
return Channel.objects.get_by_attribute(
key=key, category=category, value=value, strvalue=strvalue
key=key, category=category, value=value, strvalue=strvalue, attrtype=attrtype, **kwargs
)
@ -243,7 +247,7 @@ search_attribute_object = ObjectDB.objects.get_attribute
# object itself (this is usually what you want)
def search_object_by_tag(key=None, category=None):
def search_object_by_tag(key=None, category=None, tagtype=None, **kwargs):
"""
Find object based on tag or category.
@ -252,6 +256,11 @@ def search_object_by_tag(key=None, category=None):
category (str, optional): The category of tag
to search for. If not set, uncategorized
tags will be searched.
tagtype (str, optional): 'type' of Tag, by default
this is either `None` (a normal Tag), `alias` or
`permission`. This always apply to all queried tags.
kwargs (any): Other optional parameter that may be supported
by the manager method.
Returns:
matches (list): List of Objects with tags matching
@ -259,13 +268,13 @@ def search_object_by_tag(key=None, category=None):
matches were found.
"""
return ObjectDB.objects.get_by_tag(key=key, category=category)
return ObjectDB.objects.get_by_tag(key=key, category=category, tagtype=tagtype, **kwargs)
search_tag = search_object_by_tag # this is the most common case
def search_account_tag(key=None, category=None):
def search_account_tag(key=None, category=None, tagtype=None, **kwargs):
"""
Find account based on tag or category.
@ -274,6 +283,11 @@ def search_account_tag(key=None, category=None):
category (str, optional): The category of tag
to search for. If not set, uncategorized
tags will be searched.
tagtype (str, optional): 'type' of Tag, by default
this is either `None` (a normal Tag), `alias` or
`permission`. This always apply to all queried tags.
kwargs (any): Other optional parameter that may be supported
by the manager method.
Returns:
matches (list): List of Accounts with tags matching
@ -281,10 +295,10 @@ def search_account_tag(key=None, category=None):
matches were found.
"""
return AccountDB.objects.get_by_tag(key=key, category=category)
return AccountDB.objects.get_by_tag(key=key, category=category, tagtype=tagtype, **kwargs)
def search_script_tag(key=None, category=None):
def search_script_tag(key=None, category=None, tagtype=None, **kwargs):
"""
Find script based on tag or category.
@ -293,6 +307,11 @@ def search_script_tag(key=None, category=None):
category (str, optional): The category of tag
to search for. If not set, uncategorized
tags will be searched.
tagtype (str, optional): 'type' of Tag, by default
this is either `None` (a normal Tag), `alias` or
`permission`. This always apply to all queried tags.
kwargs (any): Other optional parameter that may be supported
by the manager method.
Returns:
matches (list): List of Scripts with tags matching
@ -300,10 +319,10 @@ def search_script_tag(key=None, category=None):
matches were found.
"""
return ScriptDB.objects.get_by_tag(key=key, category=category)
return ScriptDB.objects.get_by_tag(key=key, category=category, tagtype=tagtype, **kwargs)
def search_channel_tag(key=None, category=None):
def search_channel_tag(key=None, category=None, tagtype=None, **kwargs):
"""
Find channel based on tag or category.
@ -312,6 +331,11 @@ def search_channel_tag(key=None, category=None):
category (str, optional): The category of tag
to search for. If not set, uncategorized
tags will be searched.
tagtype (str, optional): 'type' of Tag, by default
this is either `None` (a normal Tag), `alias` or
`permission`. This always apply to all queried tags.
kwargs (any): Other optional parameter that may be supported
by the manager method.
Returns:
matches (list): List of Channels with tags matching
@ -319,7 +343,7 @@ def search_channel_tag(key=None, category=None):
matches were found.
"""
return Channel.objects.get_by_tag(key=key, category=category)
return Channel.objects.get_by_tag(key=key, category=category, tagtype=tagtype, **kwargs)
# search for tag objects (not the objects they are attached to

View file

@ -2041,7 +2041,7 @@ def at_search_result(matches, caller, query="", quiet=False, **kwargs):
if multimatch_string:
error = "%s\n" % multimatch_string
else:
error = _("More than one match for '%s' (please narrow target):\n" % query)
error = _("More than one match for '{query}' (please narrow target):\n").format(query=query)
for num, result in enumerate(matches):
# we need to consider Commands, where .aliases is a list

View file

@ -15,6 +15,7 @@ from django.core.exceptions import ValidationError as _error
from django.core.validators import validate_email as _val_email
from evennia.utils.ansi import strip_ansi
from evennia.utils.utils import string_partial_matching as _partial
from django.utils.translation import gettext as _
_TZ_DICT = {str(tz): _pytz.timezone(tz) for tz in _pytz.common_timezones}
@ -58,7 +59,7 @@ def datetime(entry, option_key="Datetime", account=None, from_tz=None, **kwargs)
"""
if not entry:
raise ValueError(f"No {option_key} entered!")
raise ValueError(_("No {option_key} entered!").format(option_key=option_key))
if not from_tz:
from_tz = _pytz.UTC
if account:
@ -66,7 +67,7 @@ def datetime(entry, option_key="Datetime", account=None, from_tz=None, **kwargs)
try:
from_tz = _pytz.timezone(acct_tz)
except Exception as err:
raise ValueError(f"Timezone string '{acct_tz}' is not a valid timezone ({err})")
raise ValueError(_("Timezone string '{acct_tz}' is not a valid timezone ({err})").format(acct_tz=acct_tz, err=err))
else:
from_tz = _pytz.UTC