diff --git a/earwigbot/config/permissions.py b/earwigbot/config/permissions.py index b05f215..6375cf3 100644 --- a/earwigbot/config/permissions.py +++ b/earwigbot/config/permissions.py @@ -27,6 +27,12 @@ from threading import Lock __all__ = ["PermissionsDB"] class PermissionsDB(object): + """ + **EarwigBot: Permissions Database Manager** + + Controls the :file:`permissions.db` file, which stores the bot's owners and + admins for the purposes of using certain dangerous IRC commands. + """ ADMIN = 1 OWNER = 2 @@ -68,6 +74,22 @@ class PermissionsDB(object): query = "INSERT INTO users VALUES (?, ?, ?, ?)" with sqlite.connect(self._dbfile) as conn, self._db_access_lock: conn.execute(query, (user.nick, user.ident, user.host, rank)) + return user + + def _del_rank(self, user, rank): + """Remove a User from the database.""" + query = """DELETE FROM users WHERE user_nick = ? AND user_ident = ? AND + user_host = ? AND user_rank = ?""" + try: + for rule in self._data[rank]: + if user in rule: + with self._db_access_lock: + with sqlite.connect(self._dbfile) as conn: + args = (user.nick, user.ident, user.host, rank) + conn.execute(query, args) + return rule + except KeyError: + return None def load(self): """Load permissions from an existing database, or create a new one.""" @@ -94,13 +116,21 @@ class PermissionsDB(object): return self._is_rank(user, rank=self.OWNER) def add_admin(self, nick="*", ident="*", host="*"): - """Add an nick/ident/host combo to the bot admins list.""" + """Add a nick/ident/host combo to the bot admins list.""" return self._set_rank(_User(nick, ident, host), rank=self.ADMIN) def add_owner(self, nick="*", ident="*", host="*"): """Add a nick/ident/host combo to the bot owners list.""" return self._set_rank(_User(nick, ident, host), rank=self.OWNER) + def remove_admin(self, nick="*", ident="*", host="*"): + """Remove a nick/ident/host combo to the bot admins list.""" + return self._del_rank(_User(nick, ident, host), rank=self.ADMIN) + + def remove_owner(self, nick="*", ident="*", host="*"): + """Remove a nick/ident/host combo to the bot owners list.""" + return self._del_rank(_User(nick, ident, host), rank=self.OWNER) + class _User(object): """A class that represents an IRC user for the purpose of testing rules.""" def __init__(self, nick, ident, host): diff --git a/earwigbot/irc/connection.py b/earwigbot/irc/connection.py index da38e3f..c6cb1c6 100644 --- a/earwigbot/irc/connection.py +++ b/earwigbot/irc/connection.py @@ -43,6 +43,7 @@ class IRCConnection(object): self._send_lock = Lock() self._last_recv = time() + self._last_send = 0 self._last_ping = 0 def __repr__(self): @@ -87,6 +88,9 @@ class IRCConnection(object): def _send(self, msg, hidelog=False): """Send data to the server.""" with self._send_lock: + time_since_last = time() - self._last_send + if time_since_last < 0.75: + time.sleep(0.75 - time_since_last) try: self._sock.sendall(msg + "\r\n") except socket.error: @@ -94,6 +98,7 @@ class IRCConnection(object): else: if not hidelog: self.logger.debug(msg) + self._last_send = time() def _split(self, msgs, maxlen, maxsplits=3): """Split a large message into multiple messages smaller than maxlen.""" @@ -158,7 +163,7 @@ class IRCConnection(object): def say(self, target, msg, hidelog=False): """Send a private message to a target on the server.""" - for msg in self._split(msg, 500 - len(target)): + for msg in self._split(msg, 400): msg = "PRIVMSG {0} :{1}".format(target, msg) self._send(msg, hidelog) @@ -177,7 +182,7 @@ class IRCConnection(object): def notice(self, target, msg, hidelog=False): """Send a notice to a target on the server.""" - for msg in self._split(msg, 500 - len(target)): + for msg in self._split(msg, 400): msg = "NOTICE {0} :{1}".format(target, msg) self._send(msg, hidelog) diff --git a/earwigbot/wiki/copyvios/exclusions.py b/earwigbot/wiki/copyvios/exclusions.py index 23c1daf..3600f97 100644 --- a/earwigbot/wiki/copyvios/exclusions.py +++ b/earwigbot/wiki/copyvios/exclusions.py @@ -44,7 +44,7 @@ class ExclusionsDB(object): """ **EarwigBot: Wiki Toolset: Exclusions Database Manager** - Controls the :file:`.exclusions.db` file, which stores URLs excluded from + Controls the :file:`exclusions.db` file, which stores URLs excluded from copyright violation checks on account of being known mirrors, for example. """