Skip to content

Commit

Permalink
Merge pull request #961 from sopel-irc/account-tracking
Browse files Browse the repository at this point in the history
Add tracking of users and their accounts
  • Loading branch information
embolalia committed Dec 20, 2015
2 parents 35b23e6 + 941ec2b commit ade8419
Show file tree
Hide file tree
Showing 5 changed files with 335 additions and 72 deletions.
62 changes: 47 additions & 15 deletions sopel/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@
py3 = False


class _CapReq(object):
def __init__(self, prefix, module, failure=None, arg=None, success=None):
def nop(bot, cap):
pass
# TODO at some point, reorder those args to be sane
self.prefix = prefix
self.module = module
self.arg = arg
self.failure = failure or nop
self.success = success or nop


class Sopel(irc.Bot):
def __init__(self, config, daemon=False):
irc.Bot.__init__(self, config)
Expand Down Expand Up @@ -85,20 +97,30 @@ def __init__(self, config, daemon=False):
self.enabled_capabilities = set()
"""A set containing the IRCv3 capabilities that the bot has enabled."""
self._cap_reqs = dict()
"""A dictionary of capability requests
Maps the capability name to a list of tuples of the prefix ('-', '=',
or ''), the name of the requesting module, the function to call if the
the request is rejected, and the argument to the capability (or None).
"""
"""A dictionary of capability names to a list of requests"""

self.privileges = dict()
"""A dictionary of channels to their users and privilege levels
Deprecated from 6.2.0; use bot.channels instead.
The value associated with each channel is a dictionary of Identifiers to a
bitwise integer value, determined by combining the appropriate constants
from `module`."""

self.channels = tools.SopelMemory() # name to chan obj
"""A map of the channels that Sopel is in.
The keys are Identifiers of the channel names, and map to Channel
objects which contain the users in the channel and their permissions.
"""
self.users = tools.SopelMemory() # name to user obj
"""A map of the users that Sopel is aware of.
In order for Sopel to be aware of a user, it must be in at least one
channel which they are also in.
"""

self.db = SopelDB(config)
"""The bot's database."""

Expand Down Expand Up @@ -267,7 +289,7 @@ def call(self, func, sopel, trigger):

def dispatch(self, pretrigger):
args = pretrigger.args
event, args, text = pretrigger.event, args, args[-1]
event, args, text = pretrigger.event, args, args[-1] if args else ''

if self.config.core.nick_blocks or self.config.core.host_blocks:
nick_blocked = self._nick_blocked(pretrigger.nick)
Expand All @@ -283,7 +305,9 @@ def dispatch(self, pretrigger):
match = regexp.match(text)
if not match:
continue
trigger = Trigger(self.config, pretrigger, match)
user_obj = self.users.get(pretrigger.nick)
account = user_obj.account if user_obj else None
trigger = Trigger(self.config, pretrigger, match, account)
wrapper = self.SopelWrapper(self, trigger)

for func in funcs:
Expand Down Expand Up @@ -364,7 +388,8 @@ def _shutdown(self):
)
)

def cap_req(self, module_name, capability, arg=None, failure_callback=None):
def cap_req(self, module_name, capability, arg=None, failure_callback=None,
success_callback=None):
"""Tell Sopel to request a capability when it starts.
By prefixing the capability with `-`, it will be ensured that the
Expand All @@ -387,7 +412,12 @@ def cap_req(self, module_name, capability, arg=None, failure_callback=None):
request, the `failure_callback` function will be called, if provided.
The arguments will be a `Sopel` object, and the capability which was
rejected. This can be used to disable callables which rely on the
capability. In future versions
capability. It will be be called either if the server NAKs the request,
or if the server enabled it and later DELs it.
The `success_callback` function will be called upon acknowledgement of
the capability from the server, whether during the initial capability
negotiation, or later.
If ``arg`` is given, and does not exactly match what the server
provides or what other modules have requested for that capability, it is
Expand All @@ -398,16 +428,17 @@ def cap_req(self, module_name, capability, arg=None, failure_callback=None):
prefix = capability[0]

entry = self._cap_reqs.get(cap, [])
if any((ent[3] != arg for ent in entry)):
if any((ent.arg != arg for ent in entry)):
raise Exception('Capability conflict')

if prefix == '-':
if self.connection_registered and cap in self.enabled_capabilities:
raise Exception('Can not change capabilities after server '
'connection has been completed.')
if any((ent[0] != '-' for ent in entry)):
if any((ent.prefix != '-' for ent in entry)):
raise Exception('Capability conflict')
entry.append((prefix, module_name, failure_callback, arg))
entry.append(_CapReq(prefix, module_name, failure_callback, arg,
success_callback))
self._cap_reqs[cap] = entry
else:
if prefix != '=':
Expand All @@ -419,7 +450,8 @@ def cap_req(self, module_name, capability, arg=None, failure_callback=None):
'connection has been completed.')
# Non-mandatory will callback at the same time as if the server
# rejected it.
if any((ent[0] == '-' for ent in entry)) and prefix == '=':
if any((ent.prefix == '-' for ent in entry)) and prefix == '=':
raise Exception('Capability conflict')
entry.append((prefix, module_name, failure_callback, arg))
entry.append(_CapReq(prefix, module_name, failure_callback, arg,
success_callback))
self._cap_reqs[cap] = entry
Loading

0 comments on commit ade8419

Please sign in to comment.