Continuing implementing new channel command
This commit is contained in:
parent
2776aa2e20
commit
6d973f3617
2 changed files with 641 additions and 344 deletions
|
|
@ -18,6 +18,7 @@ from evennia.locks.lockhandler import LockException
|
||||||
from evennia.utils import create, logger, utils, evtable
|
from evennia.utils import create, logger, utils, evtable
|
||||||
from evennia.utils.logger import tail_log_file
|
from evennia.utils.logger import tail_log_file
|
||||||
from evennia.utils.utils import make_iter, class_from_module
|
from evennia.utils.utils import make_iter, class_from_module
|
||||||
|
from evennia.utils import evmore
|
||||||
|
|
||||||
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
||||||
CHANNEL_DEFAULT_TYPECLASS = class_from_module(
|
CHANNEL_DEFAULT_TYPECLASS = class_from_module(
|
||||||
|
|
@ -49,7 +50,43 @@ _DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
|
||||||
# helper functions to make it easier to override the main CmdChannel
|
# helper functions to make it easier to override the main CmdChannel
|
||||||
# command and to keep the legacy addcom etc commands around.
|
# command and to keep the legacy addcom etc commands around.
|
||||||
|
|
||||||
def search_channel(caller, channelname, exact=False):
|
|
||||||
|
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
|
||||||
|
|
||||||
|
This handles all operations on channels.
|
||||||
|
|
||||||
|
"""
|
||||||
|
key = "channel"
|
||||||
|
aliases = ["chan", "channels"]
|
||||||
|
locks = "cmd: not pperm(channel_banned)"
|
||||||
|
switch_options = (
|
||||||
|
"history", "sub", "unsub", "mute", "alias", "unalias", "create",
|
||||||
|
"destroy", "desc", "boot", "who")
|
||||||
|
|
||||||
|
def search_channel(self, channelname, exact=False):
|
||||||
"""
|
"""
|
||||||
Helper function for searching for a single channel with some error
|
Helper function for searching for a single channel with some error
|
||||||
handling.
|
handling.
|
||||||
|
|
@ -64,9 +101,10 @@ def search_channel(caller, channelname, exact=False):
|
||||||
list: A list of zero, one or more channels found.
|
list: A list of zero, one or more channels found.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
No permission checks will be done here.
|
The 'listen' and 'control' accesses are checked before returning.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
caller = self.caller
|
||||||
# first see if this is a personal alias
|
# first see if this is a personal alias
|
||||||
channelname = caller.nicks.get(key=channelname, category="channel") or channelname
|
channelname = caller.nicks.get(key=channelname, category="channel") or channelname
|
||||||
|
|
||||||
|
|
@ -77,7 +115,6 @@ def search_channel(caller, channelname, exact=False):
|
||||||
# try fuzzy matching as well
|
# try fuzzy matching as well
|
||||||
channels = CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(channelname, exact=exact)
|
channels = CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(channelname, exact=exact)
|
||||||
|
|
||||||
|
|
||||||
# check permissions
|
# check permissions
|
||||||
channels = [channel for channel in channels
|
channels = [channel for channel in channels
|
||||||
if channel.access(caller, 'listen') or channel.access(caller, 'control')]
|
if channel.access(caller, 'listen') or channel.access(caller, 'control')]
|
||||||
|
|
@ -88,35 +125,33 @@ def search_channel(caller, channelname, exact=False):
|
||||||
return list(channels)
|
return list(channels)
|
||||||
return [channels[0]]
|
return [channels[0]]
|
||||||
|
|
||||||
|
def msg_channel(self, channel, message, **kwargs):
|
||||||
def msg_channel(caller, channel, message, **kwargs):
|
|
||||||
"""
|
"""
|
||||||
Send a message to a given channel. At this point
|
Send a message to a given channel. At this point
|
||||||
any permissions should already be done.
|
any permissions should already be done.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
caller (Object or Account): The entity sending the message.
|
|
||||||
channel (Channel): The channel to send to.
|
channel (Channel): The channel to send to.
|
||||||
message (str): The message to send.
|
message (str): The message to send.
|
||||||
**kwargs: Unused by default. These kwargs will be passed into
|
**kwargs: Unused by default. These kwargs will be passed into
|
||||||
all channel messaging hooks for custom overriding.
|
all channel messaging hooks for custom overriding.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
channel.msg(message, senders=caller, **kwargs)
|
channel.msg(message, senders=self.caller, **kwargs)
|
||||||
|
|
||||||
|
def get_channel_history(self, channel, start_index=0):
|
||||||
def get_channel_history(caller, channel, start_index=0):
|
|
||||||
"""
|
"""
|
||||||
View a channel's history.
|
View a channel's history.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
caller (Object or Account): The entity performing the action.
|
|
||||||
channel (Channel): The channel to access.
|
channel (Channel): The channel to access.
|
||||||
message (str): The message to send.
|
message (str): The message to send.
|
||||||
**kwargs: Unused by default. These kwargs will be passed into
|
**kwargs: Unused by default. These kwargs will be passed into
|
||||||
all channel messaging hooks for custom overriding.
|
all channel messaging hooks for custom overriding.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
caller = self.caller
|
||||||
|
|
||||||
log_file = channel.attributes.get(
|
log_file = channel.attributes.get(
|
||||||
"log_file", default=channel.log_file.format(channelkey=channel.key))
|
"log_file", default=channel.log_file.format(channelkey=channel.key))
|
||||||
|
|
||||||
|
|
@ -127,13 +162,12 @@ def get_channel_history(caller, channel, start_index=0):
|
||||||
# asynchronously tail the log file
|
# asynchronously tail the log file
|
||||||
tail_log_file(log_file, start_index, 20, callback=send_msg)
|
tail_log_file(log_file, start_index, 20, callback=send_msg)
|
||||||
|
|
||||||
def sub_to_channel(caller, channel):
|
def sub_to_channel(self, channel):
|
||||||
"""
|
"""
|
||||||
Subscribe to a channel. Note that all permissions should
|
Subscribe to a channel. Note that all permissions should
|
||||||
be checked before this step.
|
be checked before this step.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
caller (Object or Account): The entity performing the action.
|
|
||||||
channel (Channel): The channel to access.
|
channel (Channel): The channel to access.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -141,19 +175,19 @@ def sub_to_channel(caller, channel):
|
||||||
the second part is an error string.
|
the second part is an error string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
caller = self.caller
|
||||||
|
|
||||||
if channel.has_connection(caller):
|
if channel.has_connection(caller):
|
||||||
return False, f"Already listening to channel {channel.key}."
|
return False, f"Already listening to channel {channel.key}."
|
||||||
result = channel.connect(caller)
|
result = channel.connect(caller)
|
||||||
return result, "" if result else f"Were not allowed to subscribe to channel {channel.key}"
|
return result, "" if result else f"Were not allowed to subscribe to channel {channel.key}"
|
||||||
|
|
||||||
|
def unsub_from_channel(self, channel):
|
||||||
def unsub_to_channel(caller, channel):
|
|
||||||
"""
|
"""
|
||||||
Un-Subscribe to a channel. Note that all permissions should
|
Un-Subscribe to a channel. Note that all permissions should
|
||||||
be checked before this step.
|
be checked before this step.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
caller (Object or Account): The entity performing the action.
|
|
||||||
channel (Channel): The channel to unsub from.
|
channel (Channel): The channel to unsub from.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -161,6 +195,8 @@ def unsub_to_channel(caller, channel):
|
||||||
the second part is an error string.
|
the second part is an error string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
caller = self.caller
|
||||||
|
|
||||||
if not channel.has_connection(caller):
|
if not channel.has_connection(caller):
|
||||||
return False, f"Not listening to channel {channel.key}."
|
return False, f"Not listening to channel {channel.key}."
|
||||||
# clear nicks
|
# clear nicks
|
||||||
|
|
@ -174,26 +210,22 @@ def unsub_to_channel(caller, channel):
|
||||||
result = channel.disconnect(caller)
|
result = channel.disconnect(caller)
|
||||||
return result, "" if result else f"Could not unsubscribe from channel {channel.key}"
|
return result, "" if result else f"Could not unsubscribe from channel {channel.key}"
|
||||||
|
|
||||||
|
def add_alias(self, channel, alias):
|
||||||
def add_alias(caller, channel, alias):
|
|
||||||
"""
|
"""
|
||||||
Add a new alias for the user to use with this channel.
|
Add a new alias for the user to use with this channel.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
caller (Object or Account): The entity performing the action.
|
|
||||||
channel (Channel): The channel to alias.
|
channel (Channel): The channel to alias.
|
||||||
alias (str): The personal alias to use for this channel.
|
alias (str): The personal alias to use for this channel.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
caller.nicks.add(alias, channel.key, category="channel")
|
self.caller.nicks.add(alias, channel.key, category="channel")
|
||||||
|
|
||||||
|
def remove_alias(self, alias):
|
||||||
def remove_alias(caller, alias):
|
|
||||||
"""
|
"""
|
||||||
Remove an alias from a given channel.
|
Remove an alias from a given channel.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
caller (Object or Account): The entity performing the action.
|
|
||||||
alias (str, optional): The alias to remove, or `None` for all.
|
alias (str, optional): The alias to remove, or `None` for all.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -201,36 +233,33 @@ def remove_alias(caller, alias):
|
||||||
the second part is an error string.
|
the second part is an error string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
caller = self.caller
|
||||||
channame = caller.nicks.get(key=alias, category="channel")
|
channame = caller.nicks.get(key=alias, category="channel")
|
||||||
if channame:
|
if channame:
|
||||||
caller.nicks.remove(key=alias, category="channel")
|
caller.nicks.remove(key=alias, category="channel")
|
||||||
return True, ""
|
return True, ""
|
||||||
return False, "No such alias was defined."
|
return False, "No such alias was defined."
|
||||||
|
|
||||||
|
def mute_channel(self, channel):
|
||||||
def mute_channel(caller, channel):
|
|
||||||
"""
|
"""
|
||||||
Temporarily mute a channel.
|
Temporarily mute a channel.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
caller (Object or Account): The entity performing the action.
|
|
||||||
channel (Channel): The channel to alias.
|
channel (Channel): The channel to alias.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool, str: True, None if muting successful. If False,
|
bool, str: True, None if muting successful. If False,
|
||||||
the second part is an error string.
|
the second part is an error string.
|
||||||
"""
|
"""
|
||||||
if channel.mute(caller):
|
if channel.mute(self.caller):
|
||||||
return True, ""
|
return True, ""
|
||||||
return False, f"Channel {channel.key} was already muted."
|
return False, f"Channel {channel.key} was already muted."
|
||||||
|
|
||||||
|
def unmute_channel(self, channel):
|
||||||
def unmute_channel(caller, channel):
|
|
||||||
"""
|
"""
|
||||||
Unmute a channel.
|
Unmute a channel.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
caller (Object or Account): The entity performing the action.
|
|
||||||
channel (Channel): The channel to alias.
|
channel (Channel): The channel to alias.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -238,19 +267,17 @@ def unmute_channel(caller, channel):
|
||||||
the second part is an error string.
|
the second part is an error string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if channel.unmute(caller):
|
if channel.unmute(self.caller):
|
||||||
return True, ""
|
return True, ""
|
||||||
return False, f"Channel {channel.key} was already unmuted."
|
return False, f"Channel {channel.key} was already unmuted."
|
||||||
|
|
||||||
|
def create_channel(self, name, description, typeclass=None, aliases=None):
|
||||||
def create_channel(caller, name, description, aliases=None):
|
|
||||||
"""
|
"""
|
||||||
Create a new channel. Its name must not previously exist
|
Create a new channel. Its name must not previously exist
|
||||||
(users can alias as needed). Will also connect to the
|
(users can alias as needed). Will also connect to the
|
||||||
new channel.
|
new channel.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
caller (Object or Account): The entity performing the action.
|
|
||||||
name (str): The new channel name/key.
|
name (str): The new channel name/key.
|
||||||
description (str): This is used in listings.
|
description (str): This is used in listings.
|
||||||
aliases (list): A list of strings - alternative aliases for the channel
|
aliases (list): A list of strings - alternative aliases for the channel
|
||||||
|
|
@ -262,6 +289,10 @@ def create_channel(caller, name, description, aliases=None):
|
||||||
the second part is an error string.
|
the second part is an error string.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
caller = self.caller
|
||||||
|
if typeclass:
|
||||||
|
pass
|
||||||
|
|
||||||
if CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(name, exact=True):
|
if CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(name, exact=True):
|
||||||
return False, f"Channel {name} already exists."
|
return False, f"Channel {name} already exists."
|
||||||
# set up the new channel
|
# set up the new channel
|
||||||
|
|
@ -270,19 +301,26 @@ def create_channel(caller, name, description, aliases=None):
|
||||||
new_chan.connect(caller)
|
new_chan.connect(caller)
|
||||||
return new_chan, ""
|
return new_chan, ""
|
||||||
|
|
||||||
def destroy_channel(caller, channel, message=None):
|
def destroy_channel(self, channel, message=None):
|
||||||
"""
|
"""
|
||||||
Destroy an existing channel. Access should be checked before
|
Destroy an existing channel. Access should be checked before
|
||||||
calling this function.
|
calling this function.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
caller (Object or Account): The entity performing the action.
|
|
||||||
channel (Channel): The channel to alias.
|
channel (Channel): The channel to alias.
|
||||||
message (str, optional): Final message to send onto the channel
|
message (str, optional): Final message to send onto the channel
|
||||||
before destroying it. If not given, a default message is
|
before destroying it. If not given, a default message is
|
||||||
used. Set to the empty string for no message.
|
used. Set to the empty string for no message.
|
||||||
|
|
||||||
|
if typeclass:
|
||||||
|
pass
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
caller = self.caller
|
||||||
|
|
||||||
|
# set up the new channel
|
||||||
|
lockstring = "send:all();listen:all();control:id(%s)" % caller.id
|
||||||
|
|
||||||
channel_key = channel.key
|
channel_key = channel.key
|
||||||
if message is None:
|
if message is None:
|
||||||
message = (f"|rChannel {channel_key} is being destroyed. "
|
message = (f"|rChannel {channel_key} is being destroyed. "
|
||||||
|
|
@ -294,13 +332,11 @@ def destroy_channel(caller, channel, message=None):
|
||||||
"Channel {} was deleted by {}".format(channel_key, caller)
|
"Channel {} was deleted by {}".format(channel_key, caller)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def set_lock(self, channel, lockstring):
|
||||||
def set_lock(caller, channel, lockstring):
|
|
||||||
"""
|
"""
|
||||||
Set a lockstring on a channel.
|
Set a lockstring on a channel.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
caller (Object or Account): The entity performing the action.
|
|
||||||
channel (Channel): The channel to operate on.
|
channel (Channel): The channel to operate on.
|
||||||
lockstring (str): A lockstring on the form 'type:lockfunc();...'
|
lockstring (str): A lockstring on the form 'type:lockfunc();...'
|
||||||
|
|
||||||
|
|
@ -315,8 +351,7 @@ def set_lock(caller, channel, lockstring):
|
||||||
return False, err
|
return False, err
|
||||||
return True, ""
|
return True, ""
|
||||||
|
|
||||||
|
def set_desc(self, channel, description):
|
||||||
def set_desc(caller, channel, description):
|
|
||||||
"""
|
"""
|
||||||
Set a channel description. This is shown in listings etc.
|
Set a channel description. This is shown in listings etc.
|
||||||
|
|
||||||
|
|
@ -332,13 +367,12 @@ def set_desc(caller, channel, description):
|
||||||
"""
|
"""
|
||||||
channel.db.desc = description
|
channel.db.desc = description
|
||||||
|
|
||||||
def boot_user(caller, channel, target, quiet=False, reason=""):
|
def boot_user(self, channel, target, quiet=False, reason=""):
|
||||||
"""
|
"""
|
||||||
Boot a user from a channel, with optional reason. This will
|
Boot a user from a channel, with optional reason. This will
|
||||||
also remove all their aliases for this channel.
|
also remove all their aliases for this channel.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
caller (Object or Account): The entity performing the action.
|
|
||||||
channel (Channel): The channel to operate on.
|
channel (Channel): The channel to operate on.
|
||||||
target (Object or Account): The entity to boot.
|
target (Object or Account): The entity to boot.
|
||||||
quiet (bool, optional): Whether or not to announce to channel.
|
quiet (bool, optional): Whether or not to announce to channel.
|
||||||
|
|
@ -367,64 +401,327 @@ def boot_user(caller, channel, target, quiet=False, reason=""):
|
||||||
logger.log_sec(f"Channel Boot: {target} (Channel: {channel}, "
|
logger.log_sec(f"Channel Boot: {target} (Channel: {channel}, "
|
||||||
f"Reason: {reason}, Caller: {caller}")
|
f"Reason: {reason}, Caller: {caller}")
|
||||||
|
|
||||||
|
def ban_user(self, channel, target, quiet=False, reason=""):
|
||||||
def ban_user(caller, channel, target, quiet=False, reason=""):
|
|
||||||
"""
|
"""
|
||||||
Ban a user from a channel, by locking them out. This will also
|
Ban a user from a channel, by locking them out. This will also
|
||||||
boot them, if they are currently connected.
|
boot them, if they are currently connected.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
caller (Object or Account): The entity performing the action.
|
|
||||||
channel (Channel): The channel to operate on.
|
channel (Channel): The channel to operate on.
|
||||||
target (Object or Account): The entity to ban
|
target (Object or Account): The entity to ban
|
||||||
quiet (bool, optional): Whether or not to announce to channel.
|
quiet (bool, optional): Whether or not to announce to channel.
|
||||||
reason (str, optional): A reason for the ban
|
reason (str, optional): A reason for the ban
|
||||||
|
|
||||||
"""
|
Returns:
|
||||||
result, err = boot_user(caller, channel, target, quiet=quiet, reason=reason)
|
bool, str: True, None if banning was successful. If False,
|
||||||
|
the second part is an error string.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CmdChannel(COMMAND_DEFAULT_CLASS):
|
|
||||||
"""
|
|
||||||
Talk on and manage in-game channels.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
channel channelname [= <msg>]
|
|
||||||
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 [= description]
|
|
||||||
channel/destroy channelname [: reason]
|
|
||||||
channel/lock channelname = lockstring
|
|
||||||
channel/desc channelname = description
|
|
||||||
channel/boot[/quiet] channelname = subscribername [: reason]
|
|
||||||
channel/who channelname
|
|
||||||
channel/list
|
|
||||||
channels
|
|
||||||
|
|
||||||
This handles all operations on channels.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
key = "channel"
|
boot_user(self.caller, channel, target, quiet=quiet, reason=reason)
|
||||||
aliases = ["chan", "channels"]
|
if channel.ban(target):
|
||||||
locks = "cmd: not pperm(channel_banned)"
|
return True, ""
|
||||||
switch_options = (
|
return False, f"{target} is already banned from this channel."
|
||||||
"history", "sub", "unsub", "mute", "alias", "unalias", "create",
|
|
||||||
"destroy", "desc", "boot", "who")
|
|
||||||
|
|
||||||
def parse(self):
|
def unban_user(self, channel, target):
|
||||||
super().parse()
|
"""
|
||||||
self.channelnames = self.lhslist
|
Un-Ban a user from a channel. This will not reconnect them
|
||||||
|
to the channel, just allow them to connect again (assuming
|
||||||
|
they have the suitable 'listen' lock like everyone else).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
channel (Channel): The channel to operate on.
|
||||||
|
target (Object or Account): The entity to unban
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool, str: True, None if unbanning was successful. If False,
|
||||||
|
the second part is an error string.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if channel.unban(target):
|
||||||
|
return True, ""
|
||||||
|
return False, f"{target} was not previously banned from this channel."
|
||||||
|
|
||||||
|
def channel_list_who(self, channel):
|
||||||
|
"""
|
||||||
|
Show a list of online people is subscribing to a channel. This will check
|
||||||
|
the 'control' permission of `caller` to determine if only online users
|
||||||
|
should be returned or everyone.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
channel (Channel): The channel to operate on.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: A list of prepared strings, with name + markers for if they are
|
||||||
|
muted or offline.
|
||||||
|
|
||||||
|
"""
|
||||||
|
caller = self.caller
|
||||||
|
mute_list = list(channel.mutelist)
|
||||||
|
online_list = channel.subscriptions.online()
|
||||||
|
if channel.access(caller, 'control'):
|
||||||
|
# for those with channel control, show also offline users
|
||||||
|
all_subs = list(channel.subscriptions.all())
|
||||||
|
else:
|
||||||
|
# for others, only show online users
|
||||||
|
all_subs = online_list
|
||||||
|
|
||||||
|
who_list = []
|
||||||
|
for subscriber in all_subs:
|
||||||
|
name = subscriber.get_display_name(caller)
|
||||||
|
conditions = ("muted" if subscriber in mute_list else "",
|
||||||
|
"offline" if subscriber not in online_list else "")
|
||||||
|
cond_text = "(" + ", ".join(conditions) + ")" if conditions else ""
|
||||||
|
who_list.append(f"{name}{cond_text}")
|
||||||
|
|
||||||
|
return who_list
|
||||||
|
|
||||||
|
def list_channels(self, channelcls=CHANNEL_DEFAULT_TYPECLASS):
|
||||||
|
"""
|
||||||
|
Return a available channels.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
channelcls (Channel, optional): The channel-class to query on. Defaults
|
||||||
|
to the default channel class from settings.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: A tuple `(subbed_chans, available_chans)` with the channels
|
||||||
|
currently subscribed to, and those we have 'listen' access to but
|
||||||
|
don't actually sub to yet.
|
||||||
|
|
||||||
|
"""
|
||||||
|
caller = self.caller
|
||||||
|
subscribed_channels = channelcls.objects.get_subscriptions(caller)
|
||||||
|
unsubscribed_available_channels = [
|
||||||
|
chan
|
||||||
|
for chan in channelcls.objects.get_all_channels()
|
||||||
|
if chan not in subscribed_channels and chan.access(caller, "listen")
|
||||||
|
]
|
||||||
|
return subscribed_channels, unsubscribed_available_channels
|
||||||
|
|
||||||
|
def display_subbed_channels(self, subscribed):
|
||||||
|
"""
|
||||||
|
Display channels subscribed to.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
subscribed (list): List of subscribed channels
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
EvTable: Table to display.
|
||||||
|
|
||||||
|
"""
|
||||||
|
caller = self.caller
|
||||||
|
|
||||||
|
comtable = self.styled_table(
|
||||||
|
"|wchannel|n",
|
||||||
|
"|wmy aliases|n",
|
||||||
|
"|wdescription|n",
|
||||||
|
align="l",
|
||||||
|
maxwidth=_DEFAULT_WIDTH
|
||||||
|
)
|
||||||
|
|
||||||
|
for chan in subscribed:
|
||||||
|
clower = chan.key.lower()
|
||||||
|
nicks = caller.nicks.get(category="channel", return_obj=True)
|
||||||
|
comtable.add_row(
|
||||||
|
*("{}{}".format(
|
||||||
|
chan.key,
|
||||||
|
"({})".format(",".join(chan.aliases.all())) if chan.aliases.all() else ""),
|
||||||
|
",".join(nick.db_key for nick in make_iter(nicks)
|
||||||
|
if nick and nick.value[3].lower() == clower),
|
||||||
|
chan.db.desc))
|
||||||
|
|
||||||
|
def display_all_channels(self, subscribed, available):
|
||||||
|
"""
|
||||||
|
Display all available channels
|
||||||
|
|
||||||
|
Args:
|
||||||
|
subscribed (list): List of subscribed channels
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
EvTable: Table to display.
|
||||||
|
|
||||||
|
"""
|
||||||
|
caller = self.caller
|
||||||
|
|
||||||
|
comtable = self.styled_table(
|
||||||
|
"|wsub|n",
|
||||||
|
"|wchannel|n",
|
||||||
|
"|wmy aliases|n",
|
||||||
|
"|wlocks|n",
|
||||||
|
"|wdescription|n",
|
||||||
|
maxwidth=_DEFAULT_WIDTH,
|
||||||
|
)
|
||||||
|
channels = subscribed + available
|
||||||
|
|
||||||
|
for chan in channels:
|
||||||
|
clower = chan.key.lower()
|
||||||
|
nicks = caller.nicks.get(category="channel", return_obj=True)
|
||||||
|
nicks = nicks or []
|
||||||
|
if chan not in subscribed:
|
||||||
|
substatus = "|rNo|n"
|
||||||
|
elif caller in chan.mutelist:
|
||||||
|
substatus = "|rMuted|n"
|
||||||
|
else:
|
||||||
|
substatus = "|gYes|n"
|
||||||
|
comtable.add_row(
|
||||||
|
*(substatus,
|
||||||
|
"{}{}".format(
|
||||||
|
chan.key,
|
||||||
|
"({})".format(",".join(chan.aliases.all())) if chan.aliases.all() else ""),
|
||||||
|
",".join(nick.db_key for nick in make_iter(nicks)
|
||||||
|
if nick.value[3].lower() == clower),
|
||||||
|
str(chan.locks),
|
||||||
|
chan.db.desc))
|
||||||
|
comtable.reformat_column(0, width=9)
|
||||||
|
comtable.reformat_column(3, width=14)
|
||||||
|
|
||||||
|
return comtable
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
pass
|
"""
|
||||||
|
Main functionality of command.
|
||||||
|
"""
|
||||||
|
|
||||||
|
caller = self.caller
|
||||||
|
switches = self.switches
|
||||||
|
channel_names = self.lhslist
|
||||||
|
|
||||||
|
if not channel_names:
|
||||||
|
if 'all' in switches:
|
||||||
|
# show all available channels
|
||||||
|
subscribed, available = self.list_channels()
|
||||||
|
table = self.display_all_channels(subscribed, available)
|
||||||
|
|
||||||
|
self.msg(
|
||||||
|
"\n|wAvailable channels|n (use /list to "
|
||||||
|
f"only show subscriptions)\n{table}")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# (empty or /list) show only subscribed channels
|
||||||
|
subscribed, _ = self.list_channels()
|
||||||
|
table = self.display_subbed_channels(subscribed)
|
||||||
|
|
||||||
|
self.msg("\n|wChannel subscriptions|n "
|
||||||
|
f"(use |w/all|n to see all available)\n{table}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if 'create' in switches:
|
||||||
|
# create a new channel
|
||||||
|
config = self.lhs
|
||||||
|
if not config:
|
||||||
|
self.msg("To create: channel/create name[;aliases][:typeclass] [= description]")
|
||||||
|
return
|
||||||
|
name, *typeclass = config.rsplit(":", 1)
|
||||||
|
typeclass = typeclass[0] if typeclass else None
|
||||||
|
name, *aliases = name.rsplit(";")
|
||||||
|
description = self.rhs or ""
|
||||||
|
self.create_channel(name, description, typeclass=typeclass, aliases=aliases)
|
||||||
|
|
||||||
|
|
||||||
|
channels = []
|
||||||
|
for channel_name in channel_names:
|
||||||
|
# find a channel by fuzzy-matching. This also checks
|
||||||
|
# 'listen/control' perms.
|
||||||
|
channel = self.search_channel(channel_name, exact=False)
|
||||||
|
if not channel:
|
||||||
|
self.msg(f"No channel found matching '{channel_name}'.")
|
||||||
|
return
|
||||||
|
elif len(channel) > 1:
|
||||||
|
self.msg("Multiple possible channel matches/alias for "
|
||||||
|
"'{channel_name}':\n" + ", ".join(chan.key for chan in channel))
|
||||||
|
return
|
||||||
|
channels.append(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)
|
||||||
|
return
|
||||||
|
|
||||||
|
if 'history' in switches or 'hist' in switches:
|
||||||
|
# view channel history
|
||||||
|
|
||||||
|
index = self.rhs or 0
|
||||||
|
try:
|
||||||
|
index = max(0, int(index))
|
||||||
|
except ValueError:
|
||||||
|
self.msg("The history index (describing how many lines to go back) "
|
||||||
|
"must be an integer >= 0.")
|
||||||
|
return
|
||||||
|
self.get_channel_history(channel, start_index=index)
|
||||||
|
return
|
||||||
|
|
||||||
|
if 'sub' in switches:
|
||||||
|
# subscribe to a channel
|
||||||
|
success, err = self.sub_to_channel(channel)
|
||||||
|
if success:
|
||||||
|
self.msg("You are now subscribed "
|
||||||
|
f"to the channel {channel.key}. Use /alias to "
|
||||||
|
"be able to use different names to refer to the channel.")
|
||||||
|
else:
|
||||||
|
self.msg(err)
|
||||||
|
return
|
||||||
|
|
||||||
|
if 'unsub' in switches:
|
||||||
|
# un-subscribe from a channel
|
||||||
|
success, err = self.unsub_from_channel(channel)
|
||||||
|
if success:
|
||||||
|
self.msg(f"You un-subscribed from channel {channel.key}. "
|
||||||
|
"All aliases were cleared.")
|
||||||
|
else:
|
||||||
|
self.msg(err)
|
||||||
|
return
|
||||||
|
|
||||||
|
if 'alias' in switches:
|
||||||
|
# create a new personal alias for a channel
|
||||||
|
alias = self.rhs
|
||||||
|
if not alias:
|
||||||
|
self.msg("Specify the alias as channel/alias channelname = alias")
|
||||||
|
return
|
||||||
|
self.add_alias(channel, alias)
|
||||||
|
self.msg(f"Added/updated your alias '{alias}' for channel {channel.key}.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if 'unalias' in switches:
|
||||||
|
# remove a personal alias for a channel
|
||||||
|
alias = self.rhs
|
||||||
|
if not alias:
|
||||||
|
self.msg("Specify the alias to remove as channel/unalias channelname = alias")
|
||||||
|
return
|
||||||
|
success, err = self.remove_alias(channel, alias)
|
||||||
|
if success:
|
||||||
|
self.msg(f"Removed your alias '{alias}' for channel {channel.key}")
|
||||||
|
else:
|
||||||
|
self.msg(err)
|
||||||
|
return
|
||||||
|
|
||||||
|
if 'mute' in switches:
|
||||||
|
# mute a given channel
|
||||||
|
success, err = self.mute_channel(channel)
|
||||||
|
if success:
|
||||||
|
self.msg(f"Muted channel {channel.key}.")
|
||||||
|
else:
|
||||||
|
self.msg(err)
|
||||||
|
return
|
||||||
|
|
||||||
|
if 'unmute' in switches:
|
||||||
|
# unmute a given channel
|
||||||
|
success, err = self.unmute_channel(channel)
|
||||||
|
if success:
|
||||||
|
self.msg(f"Un-muted channel {channel.key}.")
|
||||||
|
else:
|
||||||
|
self.msg(err)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
new_chan, err = self.create_channel()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,7 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# check access
|
# check access
|
||||||
if not self.access(subscriber, "listen"):
|
if subscriber in self.banlist or not self.access(subscriber, "listen"):
|
||||||
return False
|
return False
|
||||||
# pre-join hook
|
# pre-join hook
|
||||||
connect = self.pre_join_channel(subscriber)
|
connect = self.pre_join_channel(subscriber)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue