refactor bot.channels, privileges and more

This commit is contained in:
iou1name 2019-10-08 11:45:21 -04:00
parent c09b4c04d3
commit d06b8f2fdc
11 changed files with 102 additions and 179 deletions

118
bot.py
View File

@ -62,9 +62,6 @@ class Fulvia(irc.IRCClient):
in them. in them.
""" """
self.users = tools.FulviaMemory()
"""A dictionary of all users the bot is aware of."""
self.memory = tools.FulviaMemory() self.memory = tools.FulviaMemory()
""" """
A thread-safe general purpose dictionary to be used by whatever A thread-safe general purpose dictionary to be used by whatever
@ -243,11 +240,11 @@ class Fulvia(irc.IRCClient):
""" """
nick = user.partition("!")[0].partition("@")[0] nick = user.partition("!")[0].partition("@")[0]
if channel.startswith("#"): if channel.startswith("#"):
opSym = tools.getOpSym(self.channels[channel].privileges[nick]) opSym = self.channels[channel].users[nick].op_level
else: else:
opSym = "" opSym = ''
channel = nick channel = nick
line = "<" + opSym + nick + ">" + " " + message line = f"<{opSym}{nick}> {message}"
self.log(channel, line) self.log(channel, line)
funcs = [] funcs = []
@ -292,19 +289,20 @@ class Fulvia(irc.IRCClient):
def joined(self, channel): def joined(self, channel):
"""Called when the bot joins a new channel.""" """Called when the bot joins a new channel."""
line = "-!- " + self.nickname + " " + "[" + self.username + "@" line = f"-!- {self.nickname} [{self.username}@{self.host}] "
line += self.host + "] has joined " + channel line += f"has joined {channel}"
self.log(channel, line) self.log(channel, line)
print(f"Joined {channel}") print(f"Joined {channel}")
if channel not in self.channels: self.channels[channel] = tools.Channel(channel)
self.channels[channel] = tools.Channel(channel) user = tools.User(self.nickname)
self.channels[channel].users[self.nickname] = user
def left(self, channel, reason=""): def left(self, channel, reason=""):
"""Called when the bot leaves a channel.""" """Called when the bot leaves a channel."""
line = "-!- " + self.nickname + " " + "[" + self.username + "@" line = f"-!- {self.nickname} [{self.username}@{self.host}] "
line += self.host + "] has left " + channel + " [" + reason + "]" line += f"has left {channel} [{reason}]"
self.log(channel, line) self.log(channel, line)
print(f"Parted {channel}") print(f"Parted {channel}")
@ -319,7 +317,7 @@ class Fulvia(irc.IRCClient):
def modeChanged(self, user, channel, add_mode, modes, args): def modeChanged(self, user, channel, add_mode, modes, args):
"""Called when users or channel's modes are changed.""" """Called when users or channel's modes are changed."""
line = "-!- mode/" + channel + " [" line = f"-!- mode/{channel} ["
if add_mode: if add_mode:
line += "+" line += "+"
else: else:
@ -342,11 +340,11 @@ class Fulvia(irc.IRCClient):
elif mode in tools.op_level.keys(): # user mode, op_level mode elif mode in tools.op_level.keys(): # user mode, op_level mode
nick = args[n] nick = args[n]
op_level = tools.op_level[mode] user = self.channels[channel].users[nick]
if add_mode: if add_mode:
self.channels[channel].privileges[nick] += op_level user.op_level += mode
else: else:
self.channels[channel].privileges[nick] -= op_level user.op_level.replace(mode, '', 1)
else: # user mode, non-op_level mode else: # user mode, non-op_level mode
continue continue
@ -359,8 +357,8 @@ class Fulvia(irc.IRCClient):
print(f"Signed on as {self.nickname}") print(f"Signed on as {self.nickname}")
self.whois(self.nickname) self.whois(self.nickname)
line = "*** Signed onto " + self.hostname + " as " line = f"*** Signed onto {self.hostname} as "
line += self.nickname + "!" + self.username + "@" + self.host line += f"{self.nickname}!{self.username}@{self.host}"
self.log(self.hostname, line) self.log(self.hostname, line)
for channel in self.config.core.channels.split(","): for channel in self.config.core.channels.split(","):
@ -369,8 +367,8 @@ class Fulvia(irc.IRCClient):
def kickedFrom(self, channel, kicker, message): def kickedFrom(self, channel, kicker, message):
"""Called when the bot is kicked from a channel.""" """Called when the bot is kicked from a channel."""
line = "-!- " + self.nickname + " was kicked from " + channel line = f"-!- {self.nickname} was kicked from {channel} "
line += " by " + kicker + " [" + message + "]" line += f"by {kicker} [{message}]"
self.log(channel, line) self.log(channel, line)
self.channels.pop(channel) self.channels.pop(channel)
@ -378,16 +376,14 @@ class Fulvia(irc.IRCClient):
def nickChanged(self, nick): def nickChanged(self, nick):
"""Called when the bot changes it's nickname.""" """Called when the bot changes it's nickname."""
line = "-!- you are now known as " + nick line = f"-!- you are now known as {nick}"
user = self.users.pop(self.nickname) for channel_name, channel in self.channels.items():
self.users[nick] = user
for key, channel in self.channels.items():
self.log(key, line) self.log(key, line)
channel.rename_user(self.nickname, nick) user = channel.users.pop(self.nickname)
user.nick = nick user.nick = nick
self.nickname = nick channel.users[nick] = user
## Actions the bot observes other users doing in the channel. ## Actions the bot observes other users doing in the channel.
@ -397,12 +393,11 @@ class Fulvia(irc.IRCClient):
"""Called when the bot sees another user join a channel.""" """Called when the bot sees another user join a channel."""
nick, _, host = user.partition("!") nick, _, host = user.partition("!")
line = "-!- " + nick + " " + "[" + host + "] has joined " + channel line = f"-!- {nick} [{host}] has joined {channel}"
self.log(channel, line) self.log(channel, line)
if nick not in self.users: user = tools.User(nick)
self.users[nick] = tools.User(nick) self.channels[channel].users[nick] = user
self.channels[channel].add_user(self.users[nick])
for func in self._user_joined: for func in self._user_joined:
trigger = Trigger(user, channel, f"{user} has joined", "PRIVMSG", self.config) trigger = Trigger(user, channel, f"{user} has joined", "PRIVMSG", self.config)
@ -415,41 +410,38 @@ class Fulvia(irc.IRCClient):
"""Called when the bot sees another user leave a channel.""" """Called when the bot sees another user leave a channel."""
nick, _, host = user.partition("!") nick, _, host = user.partition("!")
line = "-!- " + nick + " " + "[" + host + "] has left " line = f"-!- {nick} [{host}] has left {channel} [{reason}]"
line += channel + " [" + reason + "]"
self.log(channel, line) self.log(channel, line)
self.channels[channel].remove_user(nick) self.channels[channel].users.pop(nick)
def userQuit(self, user, quitMessage): def userQuit(self, user, quitMessage):
"""Called when the bot sees another user disconnect from the network.""" """Called when the bot sees another user disconnect from the network."""
nick, _, host = user.partition("!") nick, _, host = user.partition("!")
line = "-!- " + nick + " [" + host + "] has quit [" + quitMessage + "]" line = "-!- {nick} [{host}] has quit [{quitMessage}]"
channels = list(self.users[nick].channels.keys()) for channel_name, channel in self.channels.items():
for channel in channels: if not nick in channel.users:
continue
self.log(channel, line) self.log(channel, line)
self.channels[channel].remove_user(nick) channel.users.pop(nick)
self.users.pop(nick)
def userKicked(self, kickee, channel, kicker, message): def userKicked(self, kickee, channel, kicker, message):
""" """
Called when the bot sees another user getting kicked from the channel. Called when the bot sees another user getting kicked from the channel.
""" """
line = "-!- " + kickee + " was kicked from " + channel line =f"-!- {kickee} was kicked from {channel} by {kicker} [{message}]"
line += " by " + kicker + " [" + message + "]"
self.log(channel, line) self.log(channel, line)
self.channels[channel].remove_user(kickee) self.channels[channel].users.pop(kickee)
def topicUpdated(self, user, channel, newTopic): def topicUpdated(self, user, channel, newTopic):
"""Called when the bot sees a user update the channel's topic.""" """Called when the bot sees a user update the channel's topic."""
line = "-!- " + user + " changed the topic of " + channel + " to: " line = f"-!- {user} changed the topic of {channel} to: {newTopic}"
line += newTopic
self.log(channel, line) self.log(channel, line)
self.channels[channel].topic = newTopic self.channels[channel].topic = newTopic
@ -457,15 +449,14 @@ class Fulvia(irc.IRCClient):
def userRenamed(self, oldname, newname): def userRenamed(self, oldname, newname):
"""Called when the bot sees a user change their nickname.""" """Called when the bot sees a user change their nickname."""
line = "-!- " + oldname + " is now known as " + newname line = "-!- {oldname} is now known as {newname}"
user = self.users.pop(oldname) for channel_name, channel in self.channels.items():
self.users[newname] = user self.log(channel_name, line)
for key, channel in user.channels.items():
self.log(key, line)
channel.rename_user(oldname, newname) user = channel.users.pop(oldname)
user.nick = newname user.nick = newname
channel.users[newname] = user
def namesReceived(self, channel, channel_type, nicklist): def namesReceived(self, channel, channel_type, nicklist):
@ -475,12 +466,13 @@ class Fulvia(irc.IRCClient):
""" """
self.channels[channel].channel_type = channel_type self.channels[channel].channel_type = channel_type
for nick in nicklist: for nick in nicklist:
op_level = tools.op_level.get(nick[0], 0) op_level = ''
if op_level > 0: if nick[0] in tools.op_level.keys():
op_level = nick[0]
nick = nick[1:] nick = nick[1:]
self.users[nick] = tools.User(nick) user = tools.User(nick)
self.channels[channel].add_user(self.users[nick]) user.op_level = op_level
self.channels[channel].privileges[nick] = op_level self.channels[channel].users[nick] = user
def whoisUser(self, nick, ident, host, realname): def whoisUser(self, nick, ident, host, realname):
@ -491,6 +483,13 @@ class Fulvia(irc.IRCClient):
self.username = ident self.username = ident
self.host = host self.host = host
self.realname = realname self.realname = realname
else:
for channel_name, channel in self.channels.items():
if nick in channel:
user = channel[nick]
user.ident = ident
user.host = host
user.realname = realname
def whoisIdle(self, nick, idle, signon): def whoisIdle(self, nick, idle, signon):
@ -515,11 +514,10 @@ class Fulvia(irc.IRCClient):
an appropriate length automatically. an appropriate length automatically.
""" """
if user.startswith("#"): if user.startswith("#"):
priv = self.channels[user].privileges[self.nickname] opSym = self.channels[user].users[self.nickname].op_level
opSym = tools.getOpSym(priv)
else: else:
opSym = "" opSym = ''
line = "<" + opSym + self.nickname + ">" + " " + message line = f"<{opSym}{self.nickname}> {message}"
self.log(user, line) self.log(user, line)
irc.IRCClient.msg(self, user, message, length=None) irc.IRCClient.msg(self, user, message, length=None)

View File

@ -78,25 +78,9 @@ def process_callable(func, config):
""" """
prefix = config.core.prefix prefix = config.core.prefix
func.example = getattr(func, "example", [(None, None)])
func.thread = getattr(func, "thread", True) func.thread = getattr(func, "thread", True)
func.hook = getattr(func, "hook", False) func.hook = getattr(func, "hook", False)
func.rate = getattr(func, "rate", 0) func.rate = getattr(func, "rate", 0)
func.channel_rate = getattr(func, "channel_rate", 0) func.channel_rate = getattr(func, "channel_rate", 0)
func.global_rate = getattr(func, "global_rate", 0) func.global_rate = getattr(func, "global_rate", 0)
func.priv = getattr(func, "priv", 0)
func.user_joined = getattr(func, "user_joined", False) func.user_joined = getattr(func, "user_joined", False)
if hasattr(func, 'commands'):
if len(func.commands) > 1:
func.aliases = func.commands[1:]
else:
func.aliases = []
if hasattr(func, 'example'):
for n, example in enumerate(func.example):
ex_input = example[0]
if not ex_input:
continue
if ex_input[0] != prefix:
ex_input = prefix + ex_input
func.example[n] = (ex_input, example[1])

View File

@ -146,32 +146,6 @@ def require_chanmsg(message=None):
return actual_decorator return actual_decorator
def require_privilege(level, message=None):
"""
Decorate a function to require at least the given channel permission.
`level` can be one of the privilege levels defined in this module. If the
user does not have the privilege, `message` will be said if given. If it is
a private message, no checking will be done.
"""
def actual_decorator(function):
function.priv = level
@functools.wraps(function)
def guarded(bot, trigger, *args, **kwargs):
# If this is a privmsg, ignore privilege requirements
if trigger.is_privmsg or trigger.admin:
return function(bot, trigger, *args, **kwargs)
channel_privs = bot.channels[trigger.channel].privileges
allowed = channel_privs.get(trigger.nick, 0) >= level
if not allowed:
if message and not callable(message):
bot.msg(message)
else:
return function(bot, trigger, *args, **kwargs)
return guarded
return actual_decorator
def require_admin(message=None): def require_admin(message=None):
""" """
Decorate a function to require the triggering user to be a bot admin. Decorate a function to require the triggering user to be a bot admin.
@ -179,8 +153,7 @@ def require_admin(message=None):
If they are not, `message` will be said if given. If they are not, `message` will be said if given.
""" """
def actual_decorator(function): def actual_decorator(function):
function.priv = 5 function.require_admin = True
@functools.wraps(function) @functools.wraps(function)
def guarded(bot, trigger, *args, **kwargs): def guarded(bot, trigger, *args, **kwargs):
if not trigger.admin: if not trigger.admin:
@ -202,8 +175,7 @@ def require_owner(message=None):
If they are not, `message` will be said if given. If they are not, `message` will be said if given.
""" """
def actual_decorator(function): def actual_decorator(function):
function.priv = 10 function.require_owner = True
@functools.wraps(function) @functools.wraps(function)
def guarded(bot, trigger, *args, **kwargs): def guarded(bot, trigger, *args, **kwargs):
if not trigger.owner: if not trigger.owner:

View File

@ -28,9 +28,9 @@ def adalwulf_(bot, trigger):
"""Renames adalwulf__.""" """Renames adalwulf__."""
if not trigger.nick.startswith('defaultnick'): if not trigger.nick.startswith('defaultnick'):
return return
names = bot.channels[trigger.channel].users nicks = bot.channels[trigger.channel].users.keys()
adals = [nick for nick in names if nick.startswith('Adalwulf__')] adals = [nick for nick in nicks if nick.startswith('Adalwulf__')]
adals += [nick for nick in names if nick.startswith('Adalwulf_|')] adals += [nick for nick in nicks if nick.startswith('Adalwulf_|')]
old_nick = trigger.nick old_nick = trigger.nick
new_nick = new_bot_name(len(adals) + 1) new_nick = new_bot_name(len(adals) + 1)
bot.sendLine(f"SANICK {old_nick} {new_nick}") bot.sendLine(f"SANICK {old_nick} {new_nick}")
@ -40,12 +40,12 @@ def adalwulf_(bot, trigger):
@commands('rename_hydra') @commands('rename_hydra')
def rename_hydra(bot, trigger): def rename_hydra(bot, trigger):
"""Renames defaultnick's appropriately.""" """Renames defaultnick's appropriately."""
for nick in list(bot.channels[trigger.channel].users.keys()): for nick in bot.channels[trigger.channel].users.keys():
if not nick.startswith('defaultnick'): if not nick.startswith('defaultnick'):
continue continue
names = bot.channels[trigger.channel].users nicks = bot.channels[trigger.channel].users.keys()
adals = [nick for nick in names if nick.startswith('Adalwulf__')] adals = [nick for nick in nicks if nick.startswith('Adalwulf__')]
adals += [nick for nick in names if nick.startswith('Adalwulf_|')] adals += [nick for nick in nicks if nick.startswith('Adalwulf_|')]
old_nick = nick old_nick = nick
new_nick = new_bot_name(len(adals) + 1) new_nick = new_bot_name(len(adals) + 1)
print(f"SANICK {old_nick} {new_nick}") print(f"SANICK {old_nick} {new_nick}")

View File

@ -9,18 +9,17 @@ import re
import module import module
from tools import op_level, configureHostMask from tools import op_level, configureHostMask
OP = op_level["op"] op = ['~', '!', '@', '%']
HALFOP = op_level["halfop"]
@module.require_chanmsg @module.require_chanmsg
@module.require_privilege(OP, 'You are not a channel operator.') @module.require_admin
@module.commands('kick') @module.commands('kick')
@module.example(".kick faggot being a faggot") @module.example(".kick faggot being a faggot")
def kick(bot, trigger): def kick(bot, trigger):
""" """
Kick a user from the channel. Kick a user from the channel.
""" """
if bot.channels[trigger.channel].privileges[bot.nick] < HALFOP: if bot.channels[trigger.channel].users[bot.nick].op_level not in op:
return bot.reply("I'm not a channel operator!") return bot.reply("I'm not a channel operator!")
if not trigger.group(2): if not trigger.group(2):
return bot.reply("Who do you want me to kick?") return bot.reply("Who do you want me to kick?")
@ -36,7 +35,7 @@ def kick(bot, trigger):
@module.require_chanmsg @module.require_chanmsg
@module.require_privilege(OP, 'You are not a channel operator.') @module.require_admin
@module.commands('ban') @module.commands('ban')
@module.example(".ban faggot") @module.example(".ban faggot")
def ban(bot, trigger): def ban(bot, trigger):
@ -44,7 +43,7 @@ def ban(bot, trigger):
This give admins the ability to ban a user. This give admins the ability to ban a user.
The bot must be a Channel Operator for this command to work. The bot must be a Channel Operator for this command to work.
""" """
if bot.channels[trigger.channel].privileges[bot.nick] < HALFOP: if bot.channels[trigger.channel].users[bot.nick].op_level not in op:
return bot.reply("I'm not a channel operator!") return bot.reply("I'm not a channel operator!")
if not trigger.group(2): if not trigger.group(2):
return bot.reply("Who do you want me to ban?") return bot.reply("Who do you want me to ban?")
@ -54,7 +53,7 @@ def ban(bot, trigger):
@module.require_chanmsg @module.require_chanmsg
@module.require_privilege(OP, 'You are not a channel operator.') @module.require_admin
@module.commands('unban') @module.commands('unban')
@module.example(".unban faggot") @module.example(".unban faggot")
def unban(bot, trigger): def unban(bot, trigger):
@ -62,7 +61,7 @@ def unban(bot, trigger):
This give admins the ability to unban a user. This give admins the ability to unban a user.
The bot must be a Channel Operator for this command to work. The bot must be a Channel Operator for this command to work.
""" """
if bot.channels[trigger.channel].privileges[bot.nick] < HALFOP: if bot.channels[trigger.channel].users[bot.nick].op_level not in op:
return bot.reply("I'm not a channel operator!") return bot.reply("I'm not a channel operator!")
if not trigger.group(2): if not trigger.group(2):
return bot.reply("Who do you want me to ban?") return bot.reply("Who do you want me to ban?")
@ -72,7 +71,7 @@ def unban(bot, trigger):
@module.require_chanmsg @module.require_chanmsg
@module.require_privilege(OP, 'You are not a channel operator.') @module.require_admin
@module.commands('kickban') @module.commands('kickban')
def kickban(bot, trigger): def kickban(bot, trigger):
""" """
@ -80,7 +79,7 @@ def kickban(bot, trigger):
The bot must be a Channel Operator for this command to work. The bot must be a Channel Operator for this command to work.
.kickban [#chan] user1 user!*@module.* get out of here .kickban [#chan] user1 user!*@module.* get out of here
""" """
if bot.channels[trigger.channel].privileges[bot.nick] < HALFOP: if bot.channels[trigger.channel].users[bot.nick].op_level not in op:
return bot.reply("I'm not a channel operator!") return bot.reply("I'm not a channel operator!")
if not trigger.group(2): if not trigger.group(2):
return bot.reply("Who do you want me to ban?") return bot.reply("Who do you want me to ban?")
@ -98,7 +97,7 @@ def kickban(bot, trigger):
@module.require_chanmsg @module.require_chanmsg
@module.require_privilege(OP, 'You are not a channel operator.') @module.require_admin
@module.commands('settopic') @module.commands('settopic')
@module.example(".settopic We're discussing penises, would you like to join?") @module.example(".settopic We're discussing penises, would you like to join?")
def settopic(bot, trigger): def settopic(bot, trigger):
@ -106,7 +105,7 @@ def settopic(bot, trigger):
This gives ops the ability to change the topic. This gives ops the ability to change the topic.
The bot must be a Channel Operator for this command to work. The bot must be a Channel Operator for this command to work.
""" """
if bot.channels[trigger.channel].privileges[bot.nick] < HALFOP: if bot.channels[trigger.channel].users[bot.nick].op_level not in op:
return bot.reply("I'm not a channel operator!") return bot.reply("I'm not a channel operator!")
if not trigger.group(2): if not trigger.group(2):
return bot.reply("What do you want the topic set to?") return bot.reply("What do you want the topic set to?")

View File

@ -14,6 +14,6 @@ def announce(bot, trigger):
if not trigger.admin: if not trigger.admin:
bot.reply("Sorry, I can't let you do that") bot.reply("Sorry, I can't let you do that")
return return
for channel in bot.channels: for channel in bot.channels.keys():
bot.msg(channel, f"[ANNOUNCEMENT] {trigger.group(2)}") bot.msg(channel, f"[ANNOUNCEMENT] {trigger.group(2)}")
bot.reply('Announce complete.') bot.reply('Announce complete.')

View File

@ -54,7 +54,7 @@ def banheall(bot, trigger):
except (IndexError, KeyError, ValueError, TypeError): except (IndexError, KeyError, ValueError, TypeError):
period = 0 period = 0
for nick in bot.channels[trigger.channel].users: for nick in bot.channels[trigger.channel].users.keys():
banmask = configureHostMask(nick) banmask = configureHostMask(nick)
bot.mode(trigger.channel, True, "b", mask=banmask) bot.mode(trigger.channel, True, "b", mask=banmask)
@ -66,7 +66,7 @@ def banheall(bot, trigger):
bot.msg(f"Banned \x0304them all\x03 for \x0309{str(period)}\x03 seconds.") bot.msg(f"Banned \x0304them all\x03 for \x0309{str(period)}\x03 seconds.")
time.sleep(period) time.sleep(period)
for nick in bot.channels[trigger.channel].users: for nick in bot.channels[trigger.channel].users.keys():
banmask = configureHostMask(nick) banmask = configureHostMask(nick)
bot.mode(trigger.channel, False, "b", mask=banmask) bot.mode(trigger.channel, False, "b", mask=banmask)

View File

@ -44,13 +44,11 @@ def help(bot, trigger):
bot.msg("Ex. Out: " + ex[1]) bot.msg("Ex. Out: " + ex[1])
else: else:
if trigger.owner: funcs = [func for cmd, func in bot.commands.items()]
funcs = [func for cmd, func in bot.commands.items()] if not trigger.owner:
elif trigger.admin: funcs = [f for f in funcs if not hasattr(f, 'require_owner')]
funcs = [func for cmd, func in bot.commands.items() if cmd.priv <= 5] if not trigger.admin:
else: funcs = [f for f in funcs if not hasattr(f, 'require_admin')]
priv = bot.channels[trigger.channel].privileges[trigger.nick]
funcs = [func for cmd, func in bot.commands.items() if cmd.priv <= priv]
cmds = {func.commands[0] for func in funcs} cmds = {func.commands[0] for func in funcs}
cmds = sorted(list(cmds)) cmds = sorted(list(cmds))

View File

@ -10,8 +10,8 @@ def pingAll(bot, trigger):
Says the nick of everyone in the channel. Great way to get thier Says the nick of everyone in the channel. Great way to get thier
attention, or just annoy them. attention, or just annoy them.
""" """
names = list(bot.channels[trigger.channel].users.keys()) nicks = list(bot.channels[trigger.channel].users.keys())
for nigger in ["Ishd", "Ishd2", "Ishd_"]: for nigger in ["Ishd", "Ishd2", "Ishd_"]:
if nigger in names: if nigger in nicks:
names.remove(nigger) nicks.remove(nigger)
bot.msg(" ".join(names)) bot.msg(" ".join(nicks))

View File

@ -24,7 +24,6 @@ class MonitorThread(threading.Thread):
self.stop = threading.Event() self.stop = threading.Event()
def run(self): def run(self):
# while not self._bot.channels.keys():
while not self._bot.stillConnected(): while not self._bot.stillConnected():
time.sleep(1) time.sleep(1)
# don't try to say anything if we're not fully connected yet # don't try to say anything if we're not fully connected yet

View File

@ -111,8 +111,8 @@ class FulviaMemoryDefault(defaultdict):
return result return result
class User(object): class User:
"""A representation of a user Fulvia is aware of.""" """A representation of a user in a channel."""
def __init__(self, nick): def __init__(self, nick):
self.nick = nick self.nick = nick
"""The user's nickname.""" """The user's nickname."""
@ -124,18 +124,21 @@ class User(object):
self.host = "" self.host = ""
"""The user's hostname.""" """The user's hostname."""
self.channels = {} self.realname = ""
"""The channels the user is in.""" """The user's realname."""
self.away = None self.away = None
"""Whether the user is marked as away.""" """Whether the user is marked as away."""
hostmask = property(lambda self: '{}!{}@{}'.format(self.nick, self.user, self.op_level = ''
self.host)) """The user's op level in this channel."""
"""The user's full hostmask."""
def hostmask(self):
"""Returns the user's full hostmask."""
return f"{self.nick}!{self.user}@{self.host}"
class Channel(object): class Channel:
"""A representation of a channel Fulvia is in.""" """A representation of a channel Fulvia is in."""
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
@ -151,41 +154,11 @@ class Channel(object):
"""The topic of the channel.""" """The topic of the channel."""
self.users = {} self.users = {}
"""The users in the channel. A set to ensure there are no duplicates.""" """The users in the channel."""
self.privileges = {}
"""The op levels of the users in the channel."""
self.modes = set() self.modes = set()
"""The current modes on the channel.""" """The current modes on the channel."""
def remove_user(self, nick):
"""
Removes a user from the channel.
"""
user = self.users.pop(nick, None)
self.privileges.pop(nick, None)
if user != None:
user.channels.pop(self.name, None)
def add_user(self, user):
"""
Adds a user to the channel.
"""
assert isinstance(user, User)
self.users[user.nick] = user
self.privileges[user.nick] = 0
user.channels[self.name] = self
def rename_user(self, old, new):
"""
Renames the user.
"""
if old in self.users:
self.users[new] = self.users.pop(old)
if old in self.privileges:
self.privileges[new] = self.privileges.pop(old)
def configureHostMask(mask): def configureHostMask(mask):
""" """