mirror of
https://github.com/evennia/evennia.git
synced 2026-03-31 04:57:16 +02:00
Continuing unittest work
This commit is contained in:
parent
be8b4b82de
commit
aa5a07f6d0
4 changed files with 401 additions and 42 deletions
|
|
@ -59,6 +59,7 @@ class AccountCmdSet(CmdSet):
|
|||
self.add(admin.CmdNewPassword())
|
||||
|
||||
# Comm commands
|
||||
self.add(comms.CmdChannel())
|
||||
self.add(comms.CmdAddCom())
|
||||
self.add(comms.CmdDelCom())
|
||||
self.add(comms.CmdAllCom())
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ __all__ = (
|
|||
"CmdAddCom",
|
||||
"CmdDelCom",
|
||||
"CmdAllCom",
|
||||
"CmdChannels",
|
||||
#"CmdChannels",
|
||||
"CmdCdestroy",
|
||||
"CmdCBoot",
|
||||
"CmdCemit",
|
||||
|
|
@ -55,25 +55,27 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
Talk on and manage in-game channels.
|
||||
|
||||
Usage:
|
||||
channel channelname [= <msg>]
|
||||
channel
|
||||
channel/list
|
||||
channel/all
|
||||
channel/history channelname [= index]
|
||||
channel/sub channelname [= alias]
|
||||
channel/unsub channelname[,channelname, ...]
|
||||
channel/alias channelname = alias
|
||||
channel/unalias channelname = alias
|
||||
channel/mute channelname[,channelname,...]
|
||||
channel/unmute channelname[,channelname,...]
|
||||
channel/create channelname;alias;alias:typeclass [= description]
|
||||
channel/destroy channelname [= reason]
|
||||
channel/lock channelname = lockstring
|
||||
channel/desc channelname = description
|
||||
channel/boot[/quiet] channelname = subscribername [: reason]
|
||||
channel/ban channelname
|
||||
channel/ban[/quiet] channelname = subscribername [: reason]
|
||||
channel/who channelname
|
||||
channel channelname [= <msg>]
|
||||
channel
|
||||
channel/list
|
||||
channel/all
|
||||
channel/history channelname [= index]
|
||||
channel/sub channelname [= alias]
|
||||
channel/unsub channelname[,channelname, ...]
|
||||
channel/alias channelname = alias
|
||||
channel/unalias channelname = alias
|
||||
channel/mute channelname[,channelname,...]
|
||||
channel/unmute channelname[,channelname,...]
|
||||
channel/create channelname;alias;alias:typeclass [= description]
|
||||
channel/destroy channelname [= reason]
|
||||
channel/desc channelname = description
|
||||
channel/lock channelname = lockstring
|
||||
channel/unlock channelname = lockstring
|
||||
channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]
|
||||
channel/ban channelname (list bans)
|
||||
channel/ban[/quiet] channelname[, channelname, ...] = subscribername [: reason]
|
||||
channel/unban[/quiet] channelname[, channelname, ...] = subscribername
|
||||
channel/who channelname
|
||||
|
||||
This handles all operations on channels.
|
||||
|
||||
|
|
@ -82,8 +84,8 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
aliases = ["chan", "channels"]
|
||||
locks = "cmd: not pperm(channel_banned)"
|
||||
switch_options = (
|
||||
"history", "sub", "unsub", "mute", "alias", "unalias", "create",
|
||||
"destroy", "desc", "boot", "who")
|
||||
"list", "all", "history", "sub", "unsub", "mute", "unmute", "alias", "unalias",
|
||||
"create", "destroy", "desc", "lock", "unlock", "boot", "ban", "unban", "who",)
|
||||
|
||||
def search_channel(self, channelname, exact=False):
|
||||
"""
|
||||
|
|
@ -152,7 +154,7 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
caller = self.caller
|
||||
|
||||
log_file = channel.attributes.get(
|
||||
"log_file", default=channel.log_file.format(channelkey=channel.key))
|
||||
"log_file", default=channel.log_to_file.format(channel_key=channel.key))
|
||||
|
||||
def send_msg(lines):
|
||||
return caller.msg(
|
||||
|
|
@ -336,7 +338,8 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
def set_lock(self, channel, lockstring):
|
||||
"""
|
||||
Set a lockstring on a channel.
|
||||
Set a lockstring on a channel. Permissions must have been
|
||||
checked before this call.
|
||||
|
||||
Args:
|
||||
channel (Channel): The channel to operate on.
|
||||
|
|
@ -353,6 +356,26 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
return False, err
|
||||
return True, ""
|
||||
|
||||
def unset_lock(self, channel, lockstring):
|
||||
"""
|
||||
Remove locks in a lockstring on a channel. Permissions must have been
|
||||
checked before this call.
|
||||
|
||||
Args:
|
||||
channel (Channel): The channel to operate on.
|
||||
lockstring (str): A lockstring on the form 'type:lockfunc();...'
|
||||
|
||||
Returns:
|
||||
bool, str: True, None if setting lock was successful. If False,
|
||||
the second part is an error string.
|
||||
|
||||
"""
|
||||
try:
|
||||
channel.locks.remove(lockstring)
|
||||
except LockException as err:
|
||||
return False, err
|
||||
return True, ""
|
||||
|
||||
def set_desc(self, channel, description):
|
||||
"""
|
||||
Set a channel description. This is shown in listings etc.
|
||||
|
|
@ -443,6 +466,19 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
return True, ""
|
||||
return False, f"{target} was not previously banned from this channel."
|
||||
|
||||
def channel_list_bans(self, channel):
|
||||
"""
|
||||
Show a channel's bans.
|
||||
|
||||
Args:
|
||||
channel (Channel): The channel to operate on.
|
||||
|
||||
Returns:
|
||||
list: A list of strings, each the name of a banned user.
|
||||
|
||||
"""
|
||||
return [banned.key for banned in channel.banlist]
|
||||
|
||||
def channel_list_who(self, channel):
|
||||
"""
|
||||
Show a list of online people is subscribing to a channel. This will check
|
||||
|
|
@ -492,7 +528,7 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
"""
|
||||
caller = self.caller
|
||||
subscribed_channels = channelcls.objects.get_subscriptions(caller)
|
||||
subscribed_channels = list(channelcls.objects.get_subscriptions(caller))
|
||||
unsubscribed_available_channels = [
|
||||
chan
|
||||
for chan in channelcls.objects.get_all_channels()
|
||||
|
|
@ -531,6 +567,7 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
",".join(nick.db_key for nick in make_iter(nicks)
|
||||
if nick and nick.value[3].lower() == clower),
|
||||
chan.db.desc))
|
||||
return comtable
|
||||
|
||||
def display_all_channels(self, subscribed, available):
|
||||
"""
|
||||
|
|
@ -583,10 +620,11 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
Main functionality of command.
|
||||
"""
|
||||
# from evennia import set_trace;set_trace()
|
||||
|
||||
caller = self.caller
|
||||
switches = self.switches
|
||||
channel_names = self.lhslist
|
||||
channel_names = [name for name in self.lhslist if name]
|
||||
|
||||
if not channel_names:
|
||||
if 'all' in switches:
|
||||
|
|
@ -604,9 +642,13 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
table = self.display_subbed_channels(subscribed)
|
||||
|
||||
self.msg("\n|wChannel subscriptions|n "
|
||||
f"(use |w/all|n to see all available)\n{table}")
|
||||
f"(use |w/all|n to see all available):\n{table}")
|
||||
return
|
||||
|
||||
if not self.switches and not self.args:
|
||||
caller.msg("Usage[/switches]: channel [= message]")
|
||||
return
|
||||
|
||||
if 'create' in switches:
|
||||
# create a new channel
|
||||
config = self.lhs
|
||||
|
|
@ -636,19 +678,28 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
self.msg("Multiple possible channel matches/alias for "
|
||||
"'{channel_name}':\n" + ", ".join(chan.key for chan in channel))
|
||||
return
|
||||
channels.append(channel)
|
||||
channels.extend(channel)
|
||||
|
||||
# we have at least one channel at this point
|
||||
channel = channels[0]
|
||||
|
||||
if not switches:
|
||||
# send a message to channel(s)
|
||||
message = self.rhs
|
||||
if not message:
|
||||
self.msg("To send: channel <channel-name-or-alias> = <message>")
|
||||
return
|
||||
for chan in channels:
|
||||
self.msg_channel(chan, message)
|
||||
if self.rhs:
|
||||
# send message to channel
|
||||
self.msg_channel(channel, self.rhs.strip())
|
||||
else:
|
||||
# inspect a given channel
|
||||
subscribed, available = self.list_channels()
|
||||
if channel in subscribed:
|
||||
table = self.display_subbed_channels[channel]
|
||||
self.msg(
|
||||
"\n|wSubscribed to Channel|n "
|
||||
f"(use |w/all|n to see all available)\n{table}")
|
||||
elif channel in available:
|
||||
table = self.display_all_channels([], [channel])
|
||||
self.msg(
|
||||
"\n|wNot subscribed Channel|n (use /list to "
|
||||
f"show all subscriptions)\n{table}")
|
||||
return
|
||||
|
||||
if 'history' in switches or 'hist' in switches:
|
||||
|
|
@ -734,8 +785,151 @@ class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|||
self.msg("You can only delete channels you control.")
|
||||
return
|
||||
|
||||
def _perform_delete(caller, prompt, result):
|
||||
def _perform_delete(caller, *args, **kwargs):
|
||||
self.destroy_channel(channel, message=reason)
|
||||
caller.msg(f"Channel {channel.key} was successfully deleted.")
|
||||
|
||||
ask_yes_no(
|
||||
caller,
|
||||
f"Are you sure you want to delete channel '{channel.key}'"
|
||||
"(make sure name is correct!)? This will disconnect and "
|
||||
"remove all users' aliases. {yesno}?",
|
||||
_perform_delete,
|
||||
"Aborted."
|
||||
)
|
||||
|
||||
if 'lock' in switches:
|
||||
# add a lockstring to channel
|
||||
lockstring = self.rhs.strip()
|
||||
|
||||
if not lockstring:
|
||||
self.msg("Usage: channel/lock channelname = lockstring")
|
||||
return
|
||||
|
||||
if not channel.access(caller, "control"):
|
||||
self.msg("You need 'control'-access to change locks on this channel.")
|
||||
return
|
||||
|
||||
success, err = self.set_lock(channel, self.rhs)
|
||||
if success:
|
||||
caller.msg("Added/updated lock on channel.")
|
||||
else:
|
||||
caller.msg(f"Could not add/update lock: {err}")
|
||||
return
|
||||
|
||||
if 'unlock' in switches:
|
||||
# remove/update lockstring from channel
|
||||
lockstring = self.rhs.strip()
|
||||
|
||||
if not lockstring:
|
||||
self.msg("Usage: channel/unlock channelname = lockstring")
|
||||
return
|
||||
|
||||
if not channel.access(caller, "control"):
|
||||
self.msg("You need 'control'-access to change locks on this channel.")
|
||||
return
|
||||
|
||||
success, err = self.set_lock(channel, self.rhs)
|
||||
if success:
|
||||
caller.msg("Removed lock on channel.")
|
||||
else:
|
||||
caller.msg(f"Could not remove lock: {err}")
|
||||
return
|
||||
|
||||
if 'boot' in switches:
|
||||
# boot a user from channel(s)
|
||||
|
||||
if not self.rhs:
|
||||
caller.msg("Usage: channel/boot channel[,channel,...] = username [:reason]")
|
||||
return
|
||||
|
||||
target_str, *reason = self.rhs.rsplit(":", 1)
|
||||
reason = reason[0].strip() if reason else ""
|
||||
|
||||
for chan in channels:
|
||||
|
||||
if not chan.access(caller, "admin"):
|
||||
self.msg("You need 'control'-access to boot a user from {chan.key}.")
|
||||
return
|
||||
|
||||
# the target must be a member of all given channels
|
||||
target = self.search(target_str, candidates=chan.subscriptions.all())
|
||||
if not target:
|
||||
caller.msg(f"Cannot boot '{target_str}' - not in channel {chan.key}.")
|
||||
return
|
||||
|
||||
def _boot_user(caller, *args, **kwargs):
|
||||
for chan in channels:
|
||||
success, err = self.boot_user(chan, target, quiet=False, reason=reason)
|
||||
if success:
|
||||
caller.msg(f"Booted {target.key} from channel {chan.key}.")
|
||||
else:
|
||||
caller.msg(f"Cannot boot {target.key} from channel {chan.key}: {err}")
|
||||
|
||||
channames = ", ".join(chan.key for chan in channels)
|
||||
ask_yes_no(
|
||||
caller,
|
||||
f"Are you sure you want to boot user {target.key} from "
|
||||
f"channel(s) {channames} (make sure name/channels are correct) "
|
||||
"{yesno}?",
|
||||
_boot_user,
|
||||
"Aborted.",
|
||||
default="Y"
|
||||
)
|
||||
return
|
||||
|
||||
if 'ban' in switches:
|
||||
# ban a user from channel(s)
|
||||
|
||||
if not self.rhs:
|
||||
# view bans for channels
|
||||
|
||||
if not channel.access(caller, "control"):
|
||||
self.msg("You need 'control'-access to view bans on channel {channel.key}")
|
||||
return
|
||||
|
||||
bans = ["Channel bans "
|
||||
"(to ban, use channel/ban channel[,channel,...] = username [:reason]"]
|
||||
bans.expand(self.channel_list_bans(channel))
|
||||
self.msg("\n".join(bans))
|
||||
return
|
||||
|
||||
target_str, *reason = self.rhs.rsplit(":", 1)
|
||||
reason = reason[0].strip() if reason else ""
|
||||
|
||||
for chan in channels:
|
||||
# the target must be a member of all given channels
|
||||
target = self.search(target_str, candidates=chan.subscriptions.all())
|
||||
if not target:
|
||||
caller.msg(f"Cannot ban '{target_str}' - not in channel {chan.key}.")
|
||||
return
|
||||
|
||||
def _ban_user(caller, *args, **kwargs):
|
||||
for chan in channels:
|
||||
success, err = self.ban_user(chan, target, quiet=False, reason=reason)
|
||||
if success:
|
||||
caller.msg(f"Banned {target.key} from channel {chan.key}.")
|
||||
else:
|
||||
caller.msg(f"Cannot boot {target.key} from channel {chan.key}: {err}")
|
||||
|
||||
channames = ", ".join(chan.key for chan in channels)
|
||||
ask_yes_no(
|
||||
caller,
|
||||
f"Are you sure you want to ban user {target.key} from "
|
||||
f"channel(s) {channames} (make sure name/channels are correct) "
|
||||
"{yesno}?",
|
||||
_ban_user,
|
||||
"Aborted.",
|
||||
)
|
||||
return
|
||||
|
||||
if "who" in switches:
|
||||
# view who's a member of a channel
|
||||
|
||||
who_list = [f"Subscribed to {channel.key}:"]
|
||||
who_list.expand(self.channel_list_who(channel))
|
||||
caller.msg("\n".join(who_list))
|
||||
return
|
||||
|
||||
|
||||
class CmdAddCom(COMMAND_DEFAULT_CLASS):
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ class CommandTest(EvenniaTest):
|
|||
else:
|
||||
# a single expected string and thus a single receiver (defaults to caller)
|
||||
receiver = receiver if receiver else caller
|
||||
receiver_mapping[receiver] = str(msg).strip() if msg else None
|
||||
receiver_mapping[receiver] = str(msg).strip() if msg is not None else None
|
||||
|
||||
unmocked_msg_methods = {}
|
||||
for receiver in receiver_mapping:
|
||||
|
|
@ -1647,6 +1647,170 @@ class TestComms(CommandTest):
|
|||
)
|
||||
|
||||
|
||||
from evennia.utils.create import create_channel # noqa
|
||||
|
||||
class TestCommsChannel(CommandTest):
|
||||
"""
|
||||
Test the central `channel` command.
|
||||
|
||||
"""
|
||||
def setUp(self):
|
||||
super(CommandTest, self).setUp()
|
||||
self.channel = create_channel(
|
||||
key="testchannel",
|
||||
desc="A test channel")
|
||||
self.channel.connect(self.char1)
|
||||
|
||||
def tearDown(self):
|
||||
self.channel.delete()
|
||||
|
||||
# test channel command
|
||||
def test_channel__noarg(self):
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"",
|
||||
"Usage"
|
||||
)
|
||||
|
||||
def test_channel__msg(self):
|
||||
self.channel.msg = Mock()
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"testchannel = Test message",
|
||||
""
|
||||
)
|
||||
self.channel.msg.assert_called_with("Test message", senders=self.char1)
|
||||
|
||||
def test_channel__list(self):
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"/list",
|
||||
"Channel subscriptions"
|
||||
)
|
||||
|
||||
def test_channel__all(self):
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"/all",
|
||||
"Available channels"
|
||||
)
|
||||
|
||||
def test_channel__history(self):
|
||||
with patch("evennia.commands.default.comms.tail_log_file") as mock_tail:
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"/history testchannel",
|
||||
""
|
||||
)
|
||||
mock_tail.assert_called()
|
||||
|
||||
def test_channel__sub(self):
|
||||
self.channel.disconnect(self.char1)
|
||||
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"/sub testchannel",
|
||||
"You are now subscribed"
|
||||
)
|
||||
self.assertTrue(self.char1 in self.channel.subscriptions)
|
||||
|
||||
def test_channel__unsub(self):
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"/unsub testchannel",
|
||||
"You un-subscribed"
|
||||
)
|
||||
self.assertFalse(self.char1 in self.channel.subscriptions)
|
||||
|
||||
def test_channel__alias(self):
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"/alias testchannel = foo",
|
||||
""
|
||||
)
|
||||
self.assertEqual(self.chan1.aliases.get('foo'), "")
|
||||
|
||||
def test_channel__unalias(self):
|
||||
|
||||
self.chan1.aliases.add("foo", "", "channel")
|
||||
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"/unalias testchannel = foo",
|
||||
""
|
||||
)
|
||||
self.assertEqual(self.chan1.aliases.get('foo'), None)
|
||||
|
||||
def test_channel__mute(self):
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"/mute testchannel",
|
||||
""
|
||||
)
|
||||
self.assertTrue(self.char1 in self.channel.mutelist)
|
||||
|
||||
def test_channel__unmute(self):
|
||||
self.channel.mute(self.char1)
|
||||
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"/unmute testchannel = Char1",
|
||||
""
|
||||
)
|
||||
self.assertFalse(self.char1 in self.channel.mutelist)
|
||||
|
||||
def test_channel__create(self):
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"/create testchannel2",
|
||||
""
|
||||
)
|
||||
|
||||
def test_channel__destroy(self):
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"/create testchannel2",
|
||||
""
|
||||
)
|
||||
|
||||
def test_channel__desc(self):
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"/desc testchannel = Another description",
|
||||
""
|
||||
)
|
||||
|
||||
def test_channel__lock(self):
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"/lock testchannel = foo:bar()",
|
||||
""
|
||||
)
|
||||
self.assertEqual(self.channel.locks.all(), [])
|
||||
|
||||
def test_channel__unlock(self):
|
||||
self.channel.locks.add("foo:bar()")
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"/unlock testchannel = foo:bar()",
|
||||
""
|
||||
)
|
||||
self.assertEqual(self.channel.locks.all(), [])
|
||||
|
||||
def test_channel__boot(self):
|
||||
pass
|
||||
|
||||
def test_channel__ban(self):
|
||||
pass
|
||||
|
||||
def test_channel__who(self):
|
||||
self.call(
|
||||
comms.CmdChannel(),
|
||||
"/who testchannel",
|
||||
""
|
||||
)
|
||||
|
||||
|
||||
class TestBatchProcess(CommandTest):
|
||||
|
||||
@patch("evennia.contrib.tutorial_examples.red_button.repeat")
|
||||
|
|
|
|||
|
|
@ -1710,7 +1710,7 @@ def ask_yes_no(caller, prompt, yes_action, no_action, default=None,
|
|||
|
||||
Args:
|
||||
prompt (str): The yes/no question to ask. This takes an optional formatting
|
||||
marker `{suffix}` which will be filled with 'Y/N', [Y]/N or Y/[N]
|
||||
marker `{yesno}` which will be filled with 'Y/N', [Y]/N or Y/[N]
|
||||
depending on the setting of `default`. If `allow_abort`, then the
|
||||
`A(bort)` will also be available.
|
||||
yes_action (callable or str): If a callable, this will be called
|
||||
|
|
@ -1736,9 +1736,9 @@ def ask_yes_no(caller, prompt, yes_action, no_action, default=None,
|
|||
|
||||
Example:
|
||||
|
||||
ask_yes_no(caller, "Are you happy {suffix}?",
|
||||
ask_yes_no(caller, "Are you happy {yesno}?",
|
||||
"you answered yes", "you answered no")
|
||||
ask_yes_no(caller, "Are you sad {suffix}?",
|
||||
ask_yes_no(caller, "Are you sad {yesno}?",
|
||||
_callable_yes, _callable_no, allow_abort=True)
|
||||
|
||||
"""
|
||||
|
|
@ -1760,7 +1760,7 @@ def ask_yes_no(caller, prompt, yes_action, no_action, default=None,
|
|||
kwargs['no_txt'] = str(no_action)
|
||||
no_action = _callable_no_txt
|
||||
|
||||
# prepare the prompt with suffix
|
||||
# prepare the prompt with yesno suffix
|
||||
suffix = "Y/N"
|
||||
abort_txt = "/Abort" if allow_abort else ""
|
||||
if default:
|
||||
|
|
@ -1773,7 +1773,7 @@ def ask_yes_no(caller, prompt, yes_action, no_action, default=None,
|
|||
allow_abort = True
|
||||
abort_txt = "/[A]bort"
|
||||
suffix += abort_txt
|
||||
prompt = prompt.format(suffix=suffix)
|
||||
prompt = prompt.format(yesno=suffix)
|
||||
|
||||
caller.ndb._yes_no_question = _Prompt()
|
||||
caller.ndb._yes_no_question.session = session
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue