Co-exist @-prefixes for management commands. Resolve 2353.
This commit is contained in:
parent
297daf5492
commit
7cfb9e3b42
18 changed files with 840 additions and 711 deletions
|
|
@ -18,6 +18,9 @@ from evennia.utils.evtable import EvTable
|
|||
from evennia.utils.ansi import ANSIString
|
||||
|
||||
|
||||
CMD_IGNORE_PREFIXES = settings.CMD_IGNORE_PREFIXES
|
||||
|
||||
|
||||
class InterruptCommand(Exception):
|
||||
|
||||
"""Cleanly interrupt a command."""
|
||||
|
|
@ -97,12 +100,19 @@ def _init_command(cls, **kwargs):
|
|||
cls.help_category = cls.help_category.lower()
|
||||
|
||||
# pre-prepare a help index entry for quicker lookup
|
||||
# strip the @- etc to allow help to be agnostic
|
||||
stripped_key = cls.key[1:] if cls.key and cls.key[0] in CMD_IGNORE_PREFIXES else ""
|
||||
stripped_aliases = (
|
||||
" ".join(al for al in cls.aliases
|
||||
if al and al[0] in CMD_IGNORE_PREFIXES for al in cls.aliases)
|
||||
)
|
||||
cls.search_index_entry = {
|
||||
"key": cls.key,
|
||||
"aliases": " ".join(cls.aliases),
|
||||
"no_prefix": f"{stripped_key} {stripped_aliases}",
|
||||
"category": cls.help_category,
|
||||
"text": cls.__doc__,
|
||||
"tags": "",
|
||||
"tags": ""
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ class CmdSetObjAlias(COMMAND_DEFAULT_CLASS):
|
|||
by everyone.
|
||||
"""
|
||||
|
||||
key = "alias"
|
||||
key = "@alias"
|
||||
aliases = "setobjalias"
|
||||
switch_options = ("category",)
|
||||
locks = "cmd:perm(setobjalias) or perm(Builder)"
|
||||
|
|
@ -266,7 +266,7 @@ class CmdCopy(ObjManipCommand):
|
|||
one exact copy of the original object will be created with the name *_copy.
|
||||
"""
|
||||
|
||||
key = "copy"
|
||||
key = "@copy"
|
||||
locks = "cmd:perm(copy) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
|
|
@ -357,7 +357,7 @@ class CmdCpAttr(ObjManipCommand):
|
|||
If you don't supply a source object, yourself is used.
|
||||
"""
|
||||
|
||||
key = "cpattr"
|
||||
key = "@cpattr"
|
||||
switch_options = ("move",)
|
||||
locks = "cmd:perm(cpattr) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
|
@ -496,7 +496,7 @@ class CmdMvAttr(ObjManipCommand):
|
|||
object. If you don't supply a source object, yourself is used.
|
||||
"""
|
||||
|
||||
key = "mvattr"
|
||||
key = "@mvattr"
|
||||
switch_options = ("copy",)
|
||||
locks = "cmd:perm(mvattr) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
|
@ -545,7 +545,7 @@ class CmdCreate(ObjManipCommand):
|
|||
|
||||
"""
|
||||
|
||||
key = "create"
|
||||
key = "@create"
|
||||
switch_options = ("drop",)
|
||||
locks = "cmd:perm(create) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
|
@ -637,8 +637,7 @@ class CmdDesc(COMMAND_DEFAULT_CLASS):
|
|||
describe the current room.
|
||||
"""
|
||||
|
||||
key = "desc"
|
||||
aliases = "describe"
|
||||
key = "@desc"
|
||||
switch_options = ("edit",)
|
||||
locks = "cmd:perm(desc) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
|
@ -722,8 +721,8 @@ class CmdDestroy(COMMAND_DEFAULT_CLASS):
|
|||
You can specify the /force switch to bypass this confirmation.
|
||||
"""
|
||||
|
||||
key = "destroy"
|
||||
aliases = ["delete", "del"]
|
||||
key = "@destroy"
|
||||
aliases = ["@delete", "@del"]
|
||||
switch_options = ("override", "force")
|
||||
locks = "cmd:perm(destroy) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
|
@ -864,7 +863,7 @@ class CmdDig(ObjManipCommand):
|
|||
would be 'north;no;n'.
|
||||
"""
|
||||
|
||||
key = "dig"
|
||||
key = "@dig"
|
||||
switch_options = ("teleport",)
|
||||
locks = "cmd:perm(dig) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
|
@ -1020,8 +1019,8 @@ class CmdTunnel(COMMAND_DEFAULT_CLASS):
|
|||
For more flexibility and power in creating rooms, use dig.
|
||||
"""
|
||||
|
||||
key = "tunnel"
|
||||
aliases = ["tun"]
|
||||
key = "@tunnel"
|
||||
aliases = ["@tun"]
|
||||
switch_options = ("oneway", "tel")
|
||||
locks = "cmd: perm(tunnel) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
|
@ -1114,7 +1113,7 @@ class CmdLink(COMMAND_DEFAULT_CLASS):
|
|||
currently set destination.
|
||||
"""
|
||||
|
||||
key = "link"
|
||||
key = "@link"
|
||||
locks = "cmd:perm(link) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
|
|
@ -1251,7 +1250,7 @@ class CmdSetHome(CmdLink):
|
|||
If no location is given, just view the object's home location.
|
||||
"""
|
||||
|
||||
key = "sethome"
|
||||
key = "@sethome"
|
||||
locks = "cmd:perm(sethome) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
|
|
@ -1303,8 +1302,7 @@ class CmdListCmdSets(COMMAND_DEFAULT_CLASS):
|
|||
to a user. Defaults to yourself.
|
||||
"""
|
||||
|
||||
key = "cmdsets"
|
||||
aliases = "listcmsets"
|
||||
key = "@cmdsets"
|
||||
locks = "cmd:perm(listcmdsets) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
|
|
@ -1334,8 +1332,8 @@ class CmdName(ObjManipCommand):
|
|||
|
||||
"""
|
||||
|
||||
key = "name"
|
||||
aliases = ["rename"]
|
||||
key = "@name"
|
||||
aliases = ["@rename"]
|
||||
locks = "cmd:perm(rename) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
|
|
@ -1412,7 +1410,7 @@ class CmdOpen(ObjManipCommand):
|
|||
|
||||
"""
|
||||
|
||||
key = "open"
|
||||
key = "@open"
|
||||
locks = "cmd:perm(open) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
|
|
@ -1614,7 +1612,7 @@ class CmdSetAttribute(ObjManipCommand):
|
|||
|
||||
"""
|
||||
|
||||
key = "set"
|
||||
key = "@set"
|
||||
locks = "cmd:perm(set) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
nested_re = re.compile(r"\[.*?\]")
|
||||
|
|
@ -1978,8 +1976,8 @@ class CmdTypeclass(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
"""
|
||||
|
||||
key = "typeclass"
|
||||
aliases = ["type", "parent", "swap", "update", "typeclasses"]
|
||||
key = "@typeclass"
|
||||
aliases = ["@type", "@parent", "@swap", "@update", "@typeclasses"]
|
||||
switch_options = ("show", "examine", "update", "reset", "force", "list", "prototype")
|
||||
locks = "cmd:perm(typeclass) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
|
@ -2035,7 +2033,7 @@ class CmdTypeclass(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
caller = self.caller
|
||||
|
||||
if "list" in self.switches or self.cmdname == 'typeclasses':
|
||||
if "list" in self.switches or self.cmdname in ('typeclasses', '@typeclasses'):
|
||||
tclasses = get_all_typeclasses()
|
||||
contribs = [key for key in sorted(tclasses) if key.startswith("evennia.contrib")] or [
|
||||
"<None loaded>"
|
||||
|
|
@ -2135,10 +2133,10 @@ class CmdTypeclass(COMMAND_DEFAULT_CLASS):
|
|||
caller.msg(string)
|
||||
return
|
||||
|
||||
if self.cmdstring == "swap":
|
||||
if self.cmdstring in ("swap", "@swap"):
|
||||
self.switches.append("force")
|
||||
self.switches.append("reset")
|
||||
elif self.cmdstring == "update":
|
||||
elif self.cmdstring in ("update", "@update"):
|
||||
self.switches.append("force")
|
||||
self.switches.append("update")
|
||||
|
||||
|
|
@ -2229,7 +2227,7 @@ class CmdWipe(ObjManipCommand):
|
|||
matching the given attribute-wildcard search string.
|
||||
"""
|
||||
|
||||
key = "wipe"
|
||||
key = "@wipe"
|
||||
locks = "cmd:perm(wipe) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
|
|
@ -2298,8 +2296,8 @@ class CmdLock(ObjManipCommand):
|
|||
'get:id(25); delete:perm(Builder)'
|
||||
"""
|
||||
|
||||
key = "lock"
|
||||
aliases = ["locks"]
|
||||
key = "@lock"
|
||||
aliases = ["@locks"]
|
||||
locks = "cmd: perm(locks) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
||||
|
|
@ -2419,8 +2417,8 @@ class CmdExamine(ObjManipCommand):
|
|||
|
||||
"""
|
||||
|
||||
key = "examine"
|
||||
aliases = ["ex", "exam"]
|
||||
key = "@examine"
|
||||
aliases = ["@ex", "@exam"]
|
||||
locks = "cmd:perm(examine) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
arg_regex = r"(/\w+?(\s|$))|\s|$"
|
||||
|
|
@ -2829,8 +2827,8 @@ class CmdFind(COMMAND_DEFAULT_CLASS):
|
|||
one is given.
|
||||
"""
|
||||
|
||||
key = "find"
|
||||
aliases = "search, locate"
|
||||
key = "@find"
|
||||
aliases = ["@search", "@locate"]
|
||||
switch_options = ("room", "exit", "char", "exact", "loc", "startswith")
|
||||
locks = "cmd:perm(find) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
|
@ -3112,8 +3110,8 @@ class CmdScripts(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
"""
|
||||
|
||||
key = "scripts"
|
||||
aliases = ["script"]
|
||||
key = "@scripts"
|
||||
aliases = ["@script"]
|
||||
switch_options = ("create", "start", "stop", "pause", "delete")
|
||||
locks = "cmd:perm(scripts) or perm(Builder)"
|
||||
help_category = "System"
|
||||
|
|
@ -3255,8 +3253,7 @@ class CmdObjects(COMMAND_DEFAULT_CLASS):
|
|||
given, <nr> defaults to 10.
|
||||
"""
|
||||
|
||||
key = "objects"
|
||||
aliases = ["listobjects", "listobjs", "stats", "db"]
|
||||
key = "@objects"
|
||||
locks = "cmd:perm(listobjects) or perm(Builder)"
|
||||
help_category = "System"
|
||||
|
||||
|
|
@ -3365,8 +3362,8 @@ class CmdTeleport(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
"""
|
||||
|
||||
key = "tel"
|
||||
aliases = "teleport"
|
||||
key = "@teleport"
|
||||
aliases = "@tel"
|
||||
switch_options = ("quiet", "intoexit", "tonone", "loc")
|
||||
rhs_split = ("=", " to ") # Prefer = delimiter, but allow " to " usage.
|
||||
locks = "cmd:perm(teleport) or perm(Builder)"
|
||||
|
|
@ -3495,8 +3492,8 @@ class CmdTag(COMMAND_DEFAULT_CLASS):
|
|||
enough to for most grouping schemes.
|
||||
"""
|
||||
|
||||
key = "tag"
|
||||
aliases = ["tags"]
|
||||
key = "@tag"
|
||||
aliases = ["@tags"]
|
||||
options = ("search", "del")
|
||||
locks = "cmd:perm(tag) or perm(Builder)"
|
||||
help_category = "Building"
|
||||
|
|
@ -3682,8 +3679,8 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
"""
|
||||
|
||||
key = "spawn"
|
||||
aliases = ["olc"]
|
||||
key = "@spawn"
|
||||
aliases = ["@olc"]
|
||||
switch_options = (
|
||||
"noloc",
|
||||
"search",
|
||||
|
|
|
|||
|
|
@ -60,18 +60,18 @@ class AccountCmdSet(CmdSet):
|
|||
|
||||
# Comm commands
|
||||
self.add(comms.CmdChannel())
|
||||
# self.add(comms.CmdChannels())
|
||||
self.add(comms.CmdAddCom())
|
||||
self.add(comms.CmdDelCom())
|
||||
self.add(comms.CmdAllCom())
|
||||
self.add(comms.CmdCdestroy())
|
||||
self.add(comms.CmdChannelCreate())
|
||||
self.add(comms.CmdClock())
|
||||
self.add(comms.CmdCBoot())
|
||||
self.add(comms.CmdCWho())
|
||||
self.add(comms.CmdCdesc())
|
||||
self.add(comms.CmdPage())
|
||||
self.add(comms.CmdIRC2Chan())
|
||||
self.add(comms.CmdIRCStatus())
|
||||
self.add(comms.CmdRSS2Chan())
|
||||
self.add(comms.CmdGrapevine2Chan())
|
||||
# self.add(comms.CmdChannels())
|
||||
# self.add(comms.CmdAddCom())
|
||||
# self.add(comms.CmdDelCom())
|
||||
# self.add(comms.CmdAllCom())
|
||||
# self.add(comms.CmdCdestroy())
|
||||
# self.add(comms.CmdChannelCreate())
|
||||
# self.add(comms.CmdClock())
|
||||
# self.add(comms.CmdCBoot())
|
||||
# self.add(comms.CmdCWho())
|
||||
# self.add(comms.CmdCdesc())
|
||||
|
|
|
|||
|
|
@ -28,16 +28,6 @@ __all__ = (
|
|||
"CmdChannel",
|
||||
"CmdObjectChannel",
|
||||
|
||||
"CmdAddCom",
|
||||
"CmdDelCom",
|
||||
"CmdAllCom",
|
||||
"CmdCdestroy",
|
||||
"CmdCBoot",
|
||||
"CmdCWho",
|
||||
"CmdChannelCreate",
|
||||
"CmdClock",
|
||||
"CmdCdesc",
|
||||
|
||||
"CmdPage",
|
||||
|
||||
"CmdIRC2Chan",
|
||||
|
|
@ -217,8 +207,8 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
ban mychannel1,mychannel2= EvilUser : Was banned for spamming.
|
||||
|
||||
"""
|
||||
key = "channel"
|
||||
aliases = ["chan", "channels"]
|
||||
key = "@channel"
|
||||
aliases = ["@chan", "@channels"]
|
||||
help_category = "Comms"
|
||||
# these cmd: lock controls access to the channel command itself
|
||||
# the admin: lock controls access to /boot/ban/unban switches
|
||||
|
|
@ -1253,488 +1243,6 @@ class CmdObjectChannel(CmdChannel):
|
|||
account_caller = False
|
||||
|
||||
|
||||
class CmdAddCom(CmdChannel):
|
||||
"""
|
||||
Add a channel alias and/or subscribe to a channel
|
||||
|
||||
Usage:
|
||||
addcom [alias=] <channel>
|
||||
|
||||
Joins a given channel. If alias is given, this will allow you to
|
||||
refer to the channel by this alias rather than the full channel
|
||||
name. Subsequent calls of this command can be used to add multiple
|
||||
aliases to an already joined channel.
|
||||
"""
|
||||
|
||||
key = "addcom"
|
||||
aliases = ["aliaschan", "chanalias"]
|
||||
help_category = "Comms"
|
||||
locks = "cmd:not pperm(channel_banned)"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Implement the command"""
|
||||
|
||||
caller = self.caller
|
||||
args = self.args
|
||||
|
||||
if not args:
|
||||
self.msg("Usage: addcom [alias =] channelname.")
|
||||
return
|
||||
|
||||
if self.rhs:
|
||||
# rhs holds the channelname
|
||||
channelname = self.rhs
|
||||
alias = self.lhs
|
||||
else:
|
||||
channelname = self.args
|
||||
alias = None
|
||||
|
||||
channel = self.search_channel(channelname)
|
||||
if not channel:
|
||||
return
|
||||
|
||||
string = ""
|
||||
if not channel.has_connection(caller):
|
||||
# we want to connect as well.
|
||||
success, err = self.sub_to_channel(channel)
|
||||
if success:
|
||||
# if this would have returned True, the account is connected
|
||||
self.msg(f"You now listen to the channel {channel.key}")
|
||||
else:
|
||||
self.msg(f"{channel.key}: You are not allowed to join this channel.")
|
||||
return
|
||||
|
||||
if channel.unmute(caller):
|
||||
self.msg(f"You unmute channel {channel.key}.")
|
||||
else:
|
||||
self.msg(f"You are already connected to channel {channel.key}.")
|
||||
|
||||
if alias:
|
||||
# create a nick and add it to the caller.
|
||||
self.add_alias(channel, alias)
|
||||
self.msg(f" You can now refer to the channel {channel} with the alias '{alias}'.")
|
||||
else:
|
||||
string += " No alias added."
|
||||
self.msg(string)
|
||||
|
||||
|
||||
class CmdDelCom(CmdChannel):
|
||||
"""
|
||||
remove a channel alias and/or unsubscribe from channel
|
||||
|
||||
Usage:
|
||||
delcom <alias or channel>
|
||||
delcom/all <channel>
|
||||
|
||||
If the full channel name is given, unsubscribe from the
|
||||
channel. If an alias is given, remove the alias but don't
|
||||
unsubscribe. If the 'all' switch is used, remove all aliases
|
||||
for that channel.
|
||||
"""
|
||||
|
||||
key = "delcom"
|
||||
aliases = ["delaliaschan", "delchanalias"]
|
||||
help_category = "Comms"
|
||||
locks = "cmd:not perm(channel_banned)"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Implementing the command. """
|
||||
|
||||
caller = self.caller
|
||||
|
||||
if not self.args:
|
||||
self.msg("Usage: delcom <alias or channel>")
|
||||
return
|
||||
ostring = self.args.lower().strip()
|
||||
|
||||
channel = self.search_channel(ostring)
|
||||
if not channel:
|
||||
return
|
||||
|
||||
if not channel.has_connection(caller):
|
||||
self.msg("You are not listening to that channel.")
|
||||
return
|
||||
|
||||
if ostring == channel.key.lower():
|
||||
# an exact channel name - unsubscribe
|
||||
delnicks = "all" in self.switches
|
||||
# find all nicks linked to this channel and delete them
|
||||
if delnicks:
|
||||
aliases = self.get_channel_aliases(channel)
|
||||
for alias in aliases:
|
||||
self.remove_alias(alias)
|
||||
success, err = self.unsub_from_channel(channel)
|
||||
if success:
|
||||
wipednicks = " Eventual aliases were removed." if delnicks else ""
|
||||
self.msg(f"You stop listening to channel '{channel.key}'.{wipednicks}")
|
||||
else:
|
||||
self.msg(err)
|
||||
return
|
||||
else:
|
||||
# we are removing a channel nick
|
||||
self.remove_alias(ostring)
|
||||
self.msg(f"Any alias '{ostring}' for channel {channel.key} was cleared.")
|
||||
|
||||
|
||||
class CmdAllCom(CmdChannel):
|
||||
"""
|
||||
perform admin operations on all channels
|
||||
|
||||
Usage:
|
||||
allcom [on | off | who | destroy]
|
||||
|
||||
Allows the user to universally turn off or on all channels they are on, as
|
||||
well as perform a 'who' for all channels they are on. Destroy deletes all
|
||||
channels that you control.
|
||||
|
||||
Without argument, works like comlist.
|
||||
"""
|
||||
|
||||
key = "allcom"
|
||||
aliases = [] # important to not inherit parent's aliases
|
||||
locks = "cmd: not pperm(channel_banned)"
|
||||
help_category = "Comms"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Runs the function"""
|
||||
|
||||
caller = self.caller
|
||||
args = self.args
|
||||
if not args:
|
||||
subscribed, available = self.list_channels()
|
||||
table = self.display_all_channels(subscribed, available)
|
||||
self.msg(
|
||||
"\n|wAvailable channels:\n{table}")
|
||||
return
|
||||
return
|
||||
|
||||
if args == "on":
|
||||
# get names of all channels available to listen to
|
||||
# and activate them all
|
||||
channels = [
|
||||
chan
|
||||
for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels()
|
||||
if chan.access(caller, "listen")
|
||||
]
|
||||
for channel in channels:
|
||||
self.execute_cmd("addcom %s" % channel.key)
|
||||
elif args == "off":
|
||||
# get names all subscribed channels and disconnect from them all
|
||||
channels = CHANNEL_DEFAULT_TYPECLASS.objects.get_subscriptions(caller)
|
||||
for channel in channels:
|
||||
self.execute_cmd("delcom %s" % channel.key)
|
||||
elif args == "destroy":
|
||||
# destroy all channels you control
|
||||
channels = [
|
||||
chan
|
||||
for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels()
|
||||
if chan.access(caller, "control")
|
||||
]
|
||||
for channel in channels:
|
||||
self.execute_cmd("cdestroy %s" % channel.key)
|
||||
elif args == "who":
|
||||
# run a who, listing the subscribers on visible channels.
|
||||
string = "\n|CChannel subscriptions|n"
|
||||
channels = [
|
||||
chan
|
||||
for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels()
|
||||
if chan.access(caller, "listen")
|
||||
]
|
||||
if not channels:
|
||||
string += "No channels."
|
||||
for channel in channels:
|
||||
string += "\n|w%s:|n\n %s" % (channel.key, channel.wholist)
|
||||
self.msg(string.strip())
|
||||
else:
|
||||
# wrong input
|
||||
self.msg("Usage: allcom on | off | who | clear")
|
||||
|
||||
class CmdCdestroy(CmdChannel):
|
||||
"""
|
||||
destroy a channel you created
|
||||
|
||||
Usage:
|
||||
cdestroy <channel>
|
||||
|
||||
Destroys a channel that you control.
|
||||
"""
|
||||
|
||||
key = "cdestroy"
|
||||
aliases = []
|
||||
help_category = "Comms"
|
||||
locks = "cmd: not pperm(channel_banned)"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Destroy objects cleanly."""
|
||||
|
||||
caller = self.caller
|
||||
|
||||
if not self.args:
|
||||
self.msg("Usage: cdestroy <channelname>")
|
||||
return
|
||||
|
||||
channel = self.search_channel(self.args)
|
||||
|
||||
if not channel:
|
||||
self.msg("Could not find channel %s." % self.args)
|
||||
return
|
||||
if not channel.access(caller, "control"):
|
||||
self.msg("You are not allowed to do that.")
|
||||
return
|
||||
channel_key = channel.key
|
||||
message = f"{channel.key} is being destroyed. Make sure to change your aliases."
|
||||
self.destroy_channel(channel, message)
|
||||
self.msg("Channel '%s' was destroyed." % channel_key)
|
||||
logger.log_sec(
|
||||
"Channel Deleted: %s (Caller: %s, IP: %s)."
|
||||
% (channel_key, caller, self.session.address)
|
||||
)
|
||||
|
||||
|
||||
class CmdCBoot(CmdChannel):
|
||||
"""
|
||||
kick an account from a channel you control
|
||||
|
||||
Usage:
|
||||
cboot[/quiet] <channel> = <account> [:reason]
|
||||
|
||||
Switch:
|
||||
quiet - don't notify the channel
|
||||
|
||||
Kicks an account or object from a channel you control.
|
||||
|
||||
"""
|
||||
|
||||
key = "cboot"
|
||||
aliases = []
|
||||
switch_options = ("quiet",)
|
||||
locks = "cmd: not pperm(channel_banned)"
|
||||
help_category = "Comms"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""implement the function"""
|
||||
|
||||
if not self.args or not self.rhs:
|
||||
string = "Usage: cboot[/quiet] <channel> = <account> [:reason]"
|
||||
self.msg(string)
|
||||
return
|
||||
|
||||
channel = self.search_channel(self.lhs)
|
||||
if not channel:
|
||||
return
|
||||
|
||||
reason = ""
|
||||
if ":" in self.rhs:
|
||||
target, reason = self.rhs.rsplit(":", 1)
|
||||
is_account = target.strip().startswith("*")
|
||||
searchstring = target.lstrip("*")
|
||||
else:
|
||||
is_account = target.strip().startswith("*")
|
||||
searchstring = self.rhs.lstrip("*")
|
||||
|
||||
target = self.caller.search(searchstring, account=is_account)
|
||||
if not target:
|
||||
return
|
||||
if reason:
|
||||
reason = " (reason: %s)" % reason
|
||||
if not channel.access(self.caller, "control"):
|
||||
string = "You don't control this channel."
|
||||
self.msg(string)
|
||||
return
|
||||
|
||||
success, err = self.boot_user(target, quiet='quiet' in self.switches)
|
||||
if success:
|
||||
self.msg(f"Booted {target.key} from {channel.key}")
|
||||
logger.log_sec(
|
||||
"Channel Boot: %s (Channel: %s, Reason: %s, Caller: %s, IP: %s)."
|
||||
% (self.caller, channel, reason, self.caller, self.session.address)
|
||||
)
|
||||
else:
|
||||
self.msg(err)
|
||||
|
||||
|
||||
class CmdCWho(CmdChannel):
|
||||
"""
|
||||
show who is listening to a channel
|
||||
|
||||
Usage:
|
||||
cwho <channel>
|
||||
|
||||
List who is connected to a given channel you have access to.
|
||||
"""
|
||||
|
||||
key = "cwho"
|
||||
aliases = []
|
||||
locks = "cmd: not pperm(channel_banned)"
|
||||
help_category = "Comms"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""implement function"""
|
||||
|
||||
if not self.args:
|
||||
string = "Usage: cwho <channel>"
|
||||
self.msg(string)
|
||||
return
|
||||
|
||||
channel = self.search_channel(self.lhs)
|
||||
if not channel:
|
||||
return
|
||||
if not channel.access(self.caller, "listen"):
|
||||
string = "You can't access this channel."
|
||||
self.msg(string)
|
||||
return
|
||||
string = "\n|CChannel subscriptions|n"
|
||||
string += "\n|w%s:|n\n %s" % (channel.key, channel.wholist)
|
||||
self.msg(string.strip())
|
||||
|
||||
|
||||
class CmdChannelCreate(CmdChannel):
|
||||
"""
|
||||
create a new channel
|
||||
|
||||
Usage:
|
||||
ccreate <new channel>[;alias;alias...] = description
|
||||
|
||||
Creates a new channel owned by you.
|
||||
"""
|
||||
|
||||
key = "ccreate"
|
||||
aliases = "channelcreate"
|
||||
locks = "cmd:not pperm(channel_banned) and pperm(Player)"
|
||||
help_category = "Comms"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Implement the command"""
|
||||
|
||||
if not self.args:
|
||||
self.msg("Usage ccreate <channelname>[;alias;alias..] = description")
|
||||
return
|
||||
|
||||
description = ""
|
||||
|
||||
if self.rhs:
|
||||
description = self.rhs
|
||||
lhs = self.lhs
|
||||
channame = lhs
|
||||
aliases = None
|
||||
if ";" in lhs:
|
||||
channame, aliases = lhs.split(";", 1)
|
||||
aliases = [alias.strip().lower() for alias in aliases.split(";")]
|
||||
|
||||
new_chan, err = self.create_channel(channame, description, aliases=aliases)
|
||||
if new_chan:
|
||||
self.msg(f"Created channel {new_chan.key} and connected to it.")
|
||||
else:
|
||||
self.msg(err)
|
||||
|
||||
|
||||
class CmdClock(CmdChannel):
|
||||
"""
|
||||
change channel locks of a channel you control
|
||||
|
||||
Usage:
|
||||
clock <channel> [= <lockstring>]
|
||||
|
||||
Changes the lock access restrictions of a channel. If no
|
||||
lockstring was given, view the current lock definitions.
|
||||
"""
|
||||
|
||||
key = "clock"
|
||||
aliases = ["clock"]
|
||||
locks = "cmd:not pperm(channel_banned) and perm(Admin)"
|
||||
help_category = "Comms"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""run the function"""
|
||||
|
||||
if not self.args:
|
||||
string = "Usage: clock channel [= lockstring]"
|
||||
self.msg(string)
|
||||
return
|
||||
|
||||
channel = self.search_channel(self.lhs)
|
||||
if not channel:
|
||||
return
|
||||
|
||||
if not self.rhs:
|
||||
# no =, so just view the current locks
|
||||
self.msg(f"Current locks on {channel.key}\n{channel.locks}")
|
||||
return
|
||||
# we want to add/change a lock.
|
||||
if not channel.access(self.caller, "control"):
|
||||
string = "You don't control this channel."
|
||||
self.msg(string)
|
||||
return
|
||||
# Try to add the lock
|
||||
success, err = self.set_lock(channel, self.rhs)
|
||||
if success:
|
||||
self.msg(f"Lock(s) applied. Current locks on {channel.key}:\n{channel.locks}")
|
||||
else:
|
||||
self.msg(err)
|
||||
|
||||
class CmdCdesc(CmdChannel):
|
||||
"""
|
||||
describe a channel you control
|
||||
|
||||
Usage:
|
||||
cdesc <channel> = <description>
|
||||
|
||||
Changes the description of the channel as shown in
|
||||
channel lists.
|
||||
|
||||
"""
|
||||
|
||||
key = "cdesc"
|
||||
aliases = []
|
||||
locks = "cmd:not pperm(channel_banned)"
|
||||
help_category = "Comms"
|
||||
|
||||
# this is used by the COMMAND_DEFAULT_CLASS parent
|
||||
account_caller = True
|
||||
|
||||
def func(self):
|
||||
"""Implement command"""
|
||||
|
||||
caller = self.caller
|
||||
|
||||
if not self.rhs:
|
||||
self.msg("Usage: cdesc <channel> = <description>")
|
||||
return
|
||||
channel = self.search_channel(self.lhs)
|
||||
if not channel:
|
||||
return
|
||||
# check permissions
|
||||
if not channel.access(caller, "control"):
|
||||
self.msg("You cannot admin this channel.")
|
||||
return
|
||||
self.set_desc(channel, self.rhs)
|
||||
self.msg(f"Description of channel '{channel.key}' set to '{self.rhs}'.")
|
||||
|
||||
|
||||
class CmdPage(COMMAND_DEFAULT_CLASS):
|
||||
"""
|
||||
send a private message to another account
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ outside the game in modules given by ``settings.FILE_HELP_ENTRY_MODULES``.
|
|||
|
||||
"""
|
||||
|
||||
import re
|
||||
from itertools import chain
|
||||
from dataclasses import dataclass
|
||||
from django.conf import settings
|
||||
from collections import defaultdict
|
||||
|
|
@ -24,6 +26,7 @@ from evennia.utils.utils import (
|
|||
)
|
||||
from evennia.help.utils import help_search_with_index, parse_entry_for_subcategories
|
||||
|
||||
CMD_IGNORE_PREFIXES = settings.CMD_IGNORE_PREFIXES
|
||||
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
||||
HELP_MORE_ENABLED = settings.HELP_MORE_ENABLED
|
||||
DEFAULT_HELP_CATEGORY = settings.DEFAULT_HELP_CATEGORY
|
||||
|
|
@ -46,6 +49,7 @@ class HelpCategory:
|
|||
"key": self.key,
|
||||
"aliases": "",
|
||||
"category": self.key,
|
||||
"no_prefix": "",
|
||||
"tags": "",
|
||||
"text": "",
|
||||
}
|
||||
|
|
@ -403,7 +407,7 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
|
|||
key: entry for key, entry in file_help_topics.items()
|
||||
if self.can_list_topic(entry, caller)}
|
||||
else:
|
||||
# query
|
||||
# query - check the read lock on entries
|
||||
cmd_help_topics = {
|
||||
cmd.auto_help_display_key
|
||||
if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd
|
||||
|
|
@ -437,7 +441,8 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
|
|||
search_fields = [
|
||||
{"field_name": "key", "boost": 10},
|
||||
{"field_name": "aliases", "boost": 9},
|
||||
{"field_name": "category", "boost": 8},
|
||||
{"field_name": "no_prefix", "boost": 8},
|
||||
{"field_name": "category", "boost": 7},
|
||||
{"field_name": "tags", "boost": 1}, # tags are not used by default
|
||||
]
|
||||
match, suggestions = None, None
|
||||
|
|
@ -479,6 +484,27 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
|
|||
self.topic = ""
|
||||
self.subtopics = []
|
||||
|
||||
def strip_cmd_prefix(self, key, all_keys):
|
||||
"""
|
||||
Conditional strip of a command prefix, such as @ in @desc. By default
|
||||
this will be hidden unless there is a duplicate without the prefix
|
||||
in the full command set (such as @open and open).
|
||||
|
||||
Args:
|
||||
key (str): Command key to analyze.
|
||||
all_cmds (list): All command-keys (and potentially aliases).
|
||||
|
||||
Returns:
|
||||
str: Potentially modified key to use in help display.
|
||||
|
||||
"""
|
||||
if key and key[0] in CMD_IGNORE_PREFIXES and key[1:] not in all_keys:
|
||||
# filter out e.g. `@` prefixes from display if there is duplicate
|
||||
# with the prefix in the set (such as @open/open)
|
||||
return key[1:]
|
||||
return key
|
||||
|
||||
|
||||
def func(self):
|
||||
"""
|
||||
Run the dynamic help entry creator.
|
||||
|
|
@ -500,7 +526,12 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
|
|||
# group by category (cmds are listed separately)
|
||||
cmd_help_by_category = defaultdict(list)
|
||||
file_db_help_by_category = defaultdict(list)
|
||||
|
||||
# get a collection of all keys + aliases to be able to strip prefixes like @
|
||||
key_and_aliases = set(chain(*(cmd._keyaliases for cmd in cmd_help_topics.values())))
|
||||
|
||||
for key, cmd in cmd_help_topics.items():
|
||||
key = self.strip_cmd_prefix(key, key_and_aliases)
|
||||
cmd_help_by_category[cmd.help_category].append(key)
|
||||
for key, entry in file_db_help_topics.items():
|
||||
file_db_help_by_category[entry.help_category].append(key)
|
||||
|
|
@ -548,7 +579,7 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
|
|||
{"field_name": "text", "boost": 1},
|
||||
]
|
||||
|
||||
for match_query in [query, f"{query}*"]:
|
||||
for match_query in [query, f"{query}*", f"*{query}"]:
|
||||
_, suggestions = help_search_with_index(
|
||||
match_query, entries,
|
||||
suggestion_maxnum=self.suggestion_maxnum,
|
||||
|
|
@ -559,7 +590,7 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
|
|||
help_text += (
|
||||
"\n... But matches where found within the help "
|
||||
"texts of the suggestions below.")
|
||||
break
|
||||
# break
|
||||
|
||||
output = self.format_help_entry(
|
||||
topic=None, # this will give a no-match style title
|
||||
|
|
@ -652,10 +683,19 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
|
|||
# we reached the bottom of the topic tree
|
||||
help_text = subtopic_map[None]
|
||||
|
||||
# get a collection of all keys + aliases to be able to strip prefixes like @
|
||||
key_and_aliases = set(chain(*(cmd._keyaliases for cmd in cmd_help_topics.values())))
|
||||
topic = self.strip_cmd_prefix(topic, key_and_aliases)
|
||||
if subtopics:
|
||||
aliases = None
|
||||
else:
|
||||
aliases = [self.strip_cmd_prefix(alias, key_and_aliases) for alias in aliases]
|
||||
suggested = [self.strip_cmd_prefix(sugg, key_and_aliases) for sugg in suggested]
|
||||
|
||||
output = self.format_help_entry(
|
||||
topic=topic,
|
||||
help_text=help_text,
|
||||
aliases=aliases if not subtopics else None,
|
||||
aliases=aliases,
|
||||
subtopics=subtopic_index,
|
||||
suggested=suggested,
|
||||
click_topics=clickable_topics
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@ class CmdReload(COMMAND_DEFAULT_CLASS):
|
|||
reset to purge) and at_reload() hooks will be called.
|
||||
"""
|
||||
|
||||
key = "reload"
|
||||
aliases = ["restart"]
|
||||
key = "@reload"
|
||||
aliases = ["@restart"]
|
||||
locks = "cmd:perm(reload) or perm(Developer)"
|
||||
help_category = "System"
|
||||
|
||||
|
|
@ -98,8 +98,8 @@ class CmdReset(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
"""
|
||||
|
||||
key = "reset"
|
||||
aliases = ["reboot"]
|
||||
key = "@reset"
|
||||
aliases = ["@reboot"]
|
||||
locks = "cmd:perm(reload) or perm(Developer)"
|
||||
help_category = "System"
|
||||
|
||||
|
|
@ -122,7 +122,7 @@ class CmdShutdown(COMMAND_DEFAULT_CLASS):
|
|||
Gracefully shut down both Server and Portal.
|
||||
"""
|
||||
|
||||
key = "shutdown"
|
||||
key = "@shutdown"
|
||||
locks = "cmd:perm(shutdown) or perm(Developer)"
|
||||
help_category = "System"
|
||||
|
||||
|
|
@ -345,8 +345,8 @@ class CmdPy(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
"""
|
||||
|
||||
key = "py"
|
||||
aliases = ["!"]
|
||||
key = "@py"
|
||||
aliases = ["@!"]
|
||||
switch_options = ("time", "edit", "clientraw", "noecho")
|
||||
locks = "cmd:perm(py) or perm(Developer)"
|
||||
help_category = "System"
|
||||
|
|
@ -427,8 +427,8 @@ class CmdAccounts(COMMAND_DEFAULT_CLASS):
|
|||
If not given, <nr> defaults to 10.
|
||||
"""
|
||||
|
||||
key = "accounts"
|
||||
aliases = ["account", "listaccounts"]
|
||||
key = "@accounts"
|
||||
aliases = ["@account"]
|
||||
switch_options = ("delete",)
|
||||
locks = "cmd:perm(listaccounts) or perm(Admin)"
|
||||
help_category = "System"
|
||||
|
|
@ -541,8 +541,8 @@ class CmdService(COMMAND_DEFAULT_CLASS):
|
|||
in the list.
|
||||
"""
|
||||
|
||||
key = "service"
|
||||
aliases = ["services"]
|
||||
key = "@service"
|
||||
aliases = ["@services"]
|
||||
switch_options = ("list", "start", "stop", "delete")
|
||||
locks = "cmd:perm(service) or perm(Developer)"
|
||||
help_category = "System"
|
||||
|
|
@ -642,8 +642,8 @@ class CmdAbout(COMMAND_DEFAULT_CLASS):
|
|||
Display info about the game engine.
|
||||
"""
|
||||
|
||||
key = "about"
|
||||
aliases = "version"
|
||||
key = "@about"
|
||||
aliases = "@version"
|
||||
locks = "cmd:all()"
|
||||
help_category = "System"
|
||||
|
||||
|
|
@ -690,8 +690,8 @@ class CmdTime(COMMAND_DEFAULT_CLASS):
|
|||
and the current time stamp.
|
||||
"""
|
||||
|
||||
key = "time"
|
||||
aliases = "uptime"
|
||||
key = "@time"
|
||||
aliases = "@uptime"
|
||||
locks = "cmd:perm(time) or perm(Player)"
|
||||
help_category = "System"
|
||||
|
||||
|
|
@ -758,8 +758,8 @@ class CmdServerLoad(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
"""
|
||||
|
||||
key = "server"
|
||||
aliases = ["serverload", "serverprocess"]
|
||||
key = "@server"
|
||||
aliases = ["@serverload"]
|
||||
switch_options = ("mem", "flushmem")
|
||||
locks = "cmd:perm(list) or perm(Developer)"
|
||||
help_category = "System"
|
||||
|
|
@ -907,7 +907,7 @@ class CmdTickers(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
"""
|
||||
|
||||
key = "tickers"
|
||||
key = "@tickers"
|
||||
help_category = "System"
|
||||
locks = "cmd:perm(tickers) or perm(Builder)"
|
||||
|
||||
|
|
@ -964,8 +964,8 @@ class CmdTasks(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
"""
|
||||
|
||||
key = "tasks"
|
||||
aliases = ["delays", "task"]
|
||||
key = "@tasks"
|
||||
aliases = ["@delays", "@task"]
|
||||
switch_options = ("pause", "unpause", "do_task", "call", "remove", "cancel")
|
||||
locks = "perm(Developer)"
|
||||
help_category = "System"
|
||||
|
|
|
|||
|
|
@ -993,7 +993,7 @@ class TestBuilding(CommandTest):
|
|||
self.call(
|
||||
building.CmdCpAttr(),
|
||||
"/copy Obj2/test2 = Obj2/test3",
|
||||
'cpattr: Extra switch "/copy" ignored.|\nCopied Obj2.test2 -> Obj2.test3. '
|
||||
'@cpattr: Extra switch "/copy" ignored.|\nCopied Obj2.test2 -> Obj2.test3. '
|
||||
"(value: 'value2')",
|
||||
)
|
||||
self.call(building.CmdMvAttr(), "", "Usage: ")
|
||||
|
|
@ -1864,90 +1864,6 @@ class TestBuilding(CommandTest):
|
|||
)
|
||||
|
||||
|
||||
class TestComms(CommandTest):
|
||||
def setUp(self):
|
||||
super(CommandTest, self).setUp()
|
||||
self.call(
|
||||
comms.CmdChannelCreate(),
|
||||
"testchan;test=Test Channel",
|
||||
"Created channel testchan and connected to it.",
|
||||
receiver=self.account,
|
||||
)
|
||||
|
||||
def test_toggle_com(self):
|
||||
self.call(
|
||||
comms.CmdAddCom(),
|
||||
"tc = testchan",
|
||||
"You are already connected to channel testchan.| You can now",
|
||||
receiver=self.account,
|
||||
)
|
||||
self.call(
|
||||
comms.CmdDelCom(),
|
||||
"tc",
|
||||
"Any alias 'tc' for channel testchan was cleared.",
|
||||
receiver=self.account,
|
||||
)
|
||||
|
||||
def test_all_com(self):
|
||||
self.call(
|
||||
comms.CmdAllCom(),
|
||||
"",
|
||||
"Available channels:",
|
||||
receiver=self.account,
|
||||
)
|
||||
|
||||
def test_clock(self):
|
||||
self.call(
|
||||
comms.CmdClock(),
|
||||
"testchan=send:all()",
|
||||
"Lock(s) applied. Current locks on testchan:",
|
||||
receiver=self.account,
|
||||
)
|
||||
|
||||
def test_cdesc(self):
|
||||
self.call(
|
||||
comms.CmdCdesc(),
|
||||
"testchan = Test Channel",
|
||||
"Description of channel 'testchan' set to 'Test Channel'.",
|
||||
receiver=self.account,
|
||||
)
|
||||
|
||||
def test_cwho(self):
|
||||
self.call(
|
||||
comms.CmdCWho(),
|
||||
"testchan",
|
||||
"Channel subscriptions\ntestchan:\n TestAccount",
|
||||
receiver=self.account,
|
||||
)
|
||||
|
||||
def test_page(self):
|
||||
self.call(
|
||||
comms.CmdPage(),
|
||||
"TestAccount2 = Test",
|
||||
"TestAccount2 is offline. They will see your message if they list their pages later."
|
||||
"|You paged TestAccount2 with: 'Test'.",
|
||||
receiver=self.account,
|
||||
)
|
||||
|
||||
def test_cboot(self):
|
||||
# No one else connected to boot
|
||||
self.call(
|
||||
comms.CmdCBoot(),
|
||||
"",
|
||||
"Usage: cboot[/quiet] <channel> = <account> [:reason]",
|
||||
receiver=self.account,
|
||||
)
|
||||
|
||||
def test_cdestroy(self):
|
||||
self.call(
|
||||
comms.CmdCdestroy(),
|
||||
"testchan",
|
||||
"[testchan] TestAccount: testchan is being destroyed. Make sure to change your aliases."
|
||||
"|Channel 'testchan' was destroyed.",
|
||||
receiver=self.account,
|
||||
)
|
||||
|
||||
|
||||
from evennia.utils.create import create_channel # noqa
|
||||
|
||||
class TestCommsChannel(CommandTest):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue