Compare commits

..

No commits in common. "29f360067a867a161f0ba367afc2e38032305f46" and "a1786b3d859138632ea82fc71c8cfd26e3fd4d6b" have entirely different histories.

16 changed files with 45 additions and 101 deletions

10
bot.py
View File

@ -72,16 +72,10 @@ class Fulvia(irc.IRCClient):
self._commands = {} self._commands = {}
""" """
A dictionary containingv all commands to look for and the name A dictionary containing all all commands to look for and the name
of the function they call. of the function they call.
""" """
self.cmd_priv = {}
"""
A dictionary with command names as keys and required privilege
levels as values.
"""
self.doc = {} self.doc = {}
""" """
A dictionary of command names to their docstring and example, if A dictionary of command names to their docstring and example, if
@ -138,7 +132,6 @@ class Fulvia(irc.IRCClient):
self._callables[func.__name__] = func self._callables[func.__name__] = func
for command in func.commands: for command in func.commands:
self._commands[command] = func.__name__ self._commands[command] = func.__name__
self.cmd_priv[command] = func.priv
if func.hook: if func.hook:
self._callables[func.__name__] = func self._callables[func.__name__] = func
@ -167,7 +160,6 @@ class Fulvia(irc.IRCClient):
self._callables.pop(func.__name__) self._callables.pop(func.__name__)
for command in func.commands: for command in func.commands:
self._commands.pop(command) self._commands.pop(command)
self.cmd_priv.pop(command)
if func.hook: if func.hook:
self._callables.pop(func.__name__) self._callables.pop(func.__name__)

7
db.py
View File

@ -4,7 +4,6 @@ The bot's database connection class.
""" """
import os import os
import sqlite3 import sqlite3
import threading
class FulviaDB(object): class FulviaDB(object):
""" """
@ -14,7 +13,6 @@ class FulviaDB(object):
def __init__(self, config): def __init__(self, config):
path = config.core.db_filename path = config.core.db_filename
self.filename = path self.filename = path
self.db_lock = threading.Lock()
def connect(self): def connect(self):
"""Return a raw database connection object.""" """Return a raw database connection object."""
@ -28,8 +26,5 @@ class FulviaDB(object):
called per PEP 249. called per PEP 249.
""" """
with self.connect() as conn: with self.connect() as conn:
self.db_lock.acquire()
cur = conn.cursor() cur = conn.cursor()
res = cur.execute(*args, **kwargs) return cur.execute(*args, **kwargs)
self.db_lock.release()
return res

View File

@ -85,12 +85,11 @@ def process_callable(func, config):
func._docs = {} func._docs = {}
func.example = getattr(func, "example", [(None, None)]) 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)
if hasattr(func, 'commands'): if hasattr(func, 'commands'):
if hasattr(func, 'example'): if hasattr(func, 'example'):

View File

@ -86,7 +86,7 @@ def rate(user=0, channel=0, server=0):
basis, in a channel, or across the server (bot). A value of zero means no basis, in a channel, or across the server (bot). A value of zero means no
limit. If a function is given a rate of 20, that function may only be used limit. If a function is given a rate of 20, that function may only be used
once every 20 seconds in the scope corresponding to the parameter. once every 20 seconds in the scope corresponding to the parameter.
Users on the admin list in Fulvia's configuration are exempted from rate Users on the admin list in Sopels configuration are exempted from rate
limits. limits.
Rate-limited functions that use scheduled future commands should import Rate-limited functions that use scheduled future commands should import
@ -178,8 +178,6 @@ 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
@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:
@ -201,8 +199,6 @@ 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
@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

@ -86,7 +86,7 @@ def me(bot, trigger):
@module.commands('selfmode') @module.commands('selfmode')
@module.example(".mode +B") @module.example(".mode +B")
def self_mode(bot, trigger): def self_mode(bot, trigger):
"""Set a user mode on Fulvia. Can only be done in privmsg by an admin.""" """Set a user mode on Sopel. Can only be done in privmsg by an admin."""
mode = trigger.group(3) mode = trigger.group(3)
add_mode = mode.startswith("+") add_mode = mode.startswith("+")
bot.mode(bot.nickname, add_mode, mode) bot.mode(bot.nickname, add_mode, mode)

View File

@ -73,7 +73,7 @@ def unban(bot, trigger):
@module.require_chanmsg @module.require_chanmsg
@module.require_privilege(OP, 'You are not a channel operator.') @module.require_privilege(OP, 'You are not a channel operator.')
@module.commands('kickban') @module.commands('kickban', 'kb')
def kickban(bot, trigger): def kickban(bot, trigger):
""" """
This gives admins the ability to kickban a user. This gives admins the ability to kickban a user.

View File

@ -218,7 +218,9 @@ def roll(bot, trigger):
trigger.group(2), pretty_str, result)) trigger.group(2), pretty_str, result))
@module.commands("choice", "choose") @module.commands("choice")
@module.commands("ch")
@module.commands("choose")
@module.example(".choose opt1,opt2,opt3") @module.example(".choose opt1,opt2,opt3")
def choose(bot, trigger): def choose(bot, trigger):
""" """

View File

@ -21,7 +21,7 @@ class Hangman():
self.blanks[n] = ' ' self.blanks[n] = ' '
def _PickWord(self): def _PickWord(self):
with open("/home/iou1name/fulvia/static/wordlist.txt",'r') as file: with open("/home/iou1name/.sopel/wordlist.txt",'r') as file:
lines = file.readlines() lines = file.readlines()
wrd = list(lines[ random.randint(0, len(lines))-1 ].strip()) wrd = list(lines[ random.randint(0, len(lines))-1 ].strip())
return wrd return wrd

View File

@ -22,18 +22,12 @@ def help(bot, trigger):
ex = random.choice(examples) ex = random.choice(examples)
bot.msg(docstring) bot.msg(docstring)
if ex[0]: if ex:
bot.msg("Ex. In: " + ex[0]) bot.msg("Ex. In: " + ex[0])
if ex[1]: if ex[1]:
bot.msg("Ex. Out: " + ex[1]) bot.msg("Ex. Out: " + ex[1])
else: else:
if not trigger.admin and not trigger.owner: cmds = sorted(bot.doc.keys())
cmds = [cmd for cmd, priv in bot.cmd_priv.items() if priv < 5]
elif trigger.admin and not trigger.owner:
cmds = [cmd for cmd, priv in bot.cmd_priv.items() if priv <= 5]
else:
cmds = bot.cmd_priv.keys()
cmds = sorted(cmds)
msg = "Available commands: " + ", ".join(cmds) msg = "Available commands: " + ", ".join(cmds)
bot.msg(msg) bot.msg(msg)

View File

@ -18,7 +18,7 @@ def interactive_shell(bot, trigger):
if bot.memory['iconsole_running']: if bot.memory['iconsole_running']:
return bot.say('Console already running') return bot.say('Console already running')
banner1 = 'Fulvia interactive shell (embedded IPython)' banner1 = 'Sopel interactive shell (embedded IPython)'
banner2 = '`bot` and `trigger` are available. To exit, type exit' banner2 = '`bot` and `trigger` are available. To exit, type exit'
exitmsg = 'Interactive shell closed' exitmsg = 'Interactive shell closed'

View File

@ -10,9 +10,5 @@ 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()) msg = " ".join(bot.channels[trigger.channel].users)
if "Ishd" in names: bot.say(msg)
names.remove("Ishd")
if "Ishd2" in names:
names.remove("Ishd2")
bot.say(" ".join(names))

View File

@ -16,7 +16,7 @@ class Scramble():
random.shuffle(self.shuffled) random.shuffle(self.shuffled)
def _PickWord(self): def _PickWord(self):
with open("/home/iou1name/fulvia/static/words6.txt",'r') as file: with open("/home/iou1name/.sopel/words6.txt",'r') as file:
lines = file.readlines() lines = file.readlines()
wrd = list(lines[ random.randint(0, len(lines))-1 ].strip()) wrd = list(lines[ random.randint(0, len(lines))-1 ].strip())
return wrd return wrd
@ -29,7 +29,7 @@ class Scramble():
def isAnagram(givenWord, givenGuess): def isAnagram(givenWord, givenGuess):
word = [x for x in givenWord] word = [x for x in givenWord]
guess = [x for x in givenGuess] guess = [x for x in givenGuess]
with open('/home/iou1name/fulvia/static/words6.txt', 'r') as file: with open('/home/iou1name/.sopel/words6.txt', 'r') as file:
words = file.readlines() words = file.readlines()
if not ''.join(guess)+'\n' in words: if not ''.join(guess)+'\n' in words:
return "notaword" return "notaword"

View File

@ -3,7 +3,6 @@
When was this user last seen. When was this user last seen.
""" """
import time import time
import argparse
import threading import threading
from datetime import datetime from datetime import datetime
from sqlite3 import OperationalError from sqlite3 import OperationalError
@ -21,7 +20,8 @@ def load_database(bot):
seens = bot.db.execute("SELECT * FROM seen").fetchall() seens = bot.db.execute("SELECT * FROM seen").fetchall()
for seen in seens: for seen in seens:
nick, seen = seen[0], seen[1:] nick, timestamp, channel, message = seen
seen = (timestamp, channel, message)
data[nick] = seen data[nick] = seen
return data return data
@ -34,12 +34,9 @@ def setup(bot):
except OperationalError: except OperationalError:
cur.execute("CREATE TABLE seen(" cur.execute("CREATE TABLE seen("
"nick TEXT PRIMARY KEY," "nick TEXT PRIMARY KEY,"
"first_timestamp INTEGER," "timestamp INTEGER,"
"first_channel TEXT," "channel TEXT,"
"first_message TEXT," "message TEXT)")
"last_timestamp INTEGER,"
"last_channel TEXT,"
"last_message TEXT)")
con.commit() con.commit()
con.close() con.close()
@ -53,47 +50,33 @@ def setup(bot):
+"with \"Just going to the store for some smokes babe I'll be right back\"") +"with \"Just going to the store for some smokes babe I'll be right back\"")
@example(".seen Soma_QM", "I haven't seen Soma_QM") @example(".seen Soma_QM", "I haven't seen Soma_QM")
def seen(bot, trigger): def seen(bot, trigger):
""" """Reports when and where the user was last seen."""
Reports when and where the user was last/first seen. nick = trigger.group(3)
--last [-l] reports when the user was last seen. This is the default. last = False
--first [-f] reports when the user was first seen. if nick == "-l" or nick == "--last":
--message [-m] includes the first/last message the user sent. last = True
""" nick = trigger.group(4)
if not trigger.group(2):
return bot.reply("Seen who?")
parser = argparse.ArgumentParser() if not nick:
parser.add_argument("nick") return bot.say("Seen who?")
parser.add_argument("-l", "--last", action="store_true", default=True)
parser.add_argument("-f", "--first", action="store_true")
parser.add_argument("-m", "--message", action="store_true")
args = parser.parse_args(trigger.group[3:])
if args.nick == bot.nick: if nick == bot.nick:
return bot.reply("I'm right here!") return bot.reply("I'm right here!")
if args.nick in bot.memory["seen"]: if nick in bot.memory["seen"]:
if args.first: timestamp, channel, message = bot.memory["seen"][nick]
timestamp, channel, message = bot.memory["seen"][args.nick][:3]
else: else:
timestamp, channel, message = bot.memory["seen"][args.nick][3:] return bot.msg(f"I haven't seen \x0308{nick}")
else:
return bot.msg(f"I haven't seen \x0308{args.nick}")
timestamp = datetime.fromtimestamp(timestamp) timestamp = datetime.fromtimestamp(timestamp)
t_format = bot.config.core.default_time_format t_format = bot.config.core.default_time_format
timestamp = datetime.strftime(timestamp, t_format) timestamp = datetime.strftime(timestamp, t_format)
reltime = relativeTime(bot.config, datetime.now(), timestamp) reltime = relativeTime(bot.config, datetime.now(), timestamp)
if args.first: msg = f"Last heard from \x0308{nick}\x03 at {timestamp} " \
msg = "First"
else:
msg = "Last"
msg += f" heard from \x0308{args.nick}\x03 at {timestamp} " \
+ f"(\x0312{reltime} ago\x03) in \x0312{channel}" + f"(\x0312{reltime} ago\x03) in \x0312{channel}"
if args.message: if last:
msg += f'\x03 with "\x0308{message}\x03"' msg += f'\x03 with "\x0308{message}\x03"'
bot.say(msg) bot.say(msg)
@ -106,9 +89,7 @@ def dump_seen_db(bot):
bot.memory["seen_lock"].acquire() bot.memory["seen_lock"].acquire()
for nick, seen in bot.memory["seen"].items(): for nick, seen in bot.memory["seen"].items():
bot.db.execute("INSERT OR REPLACE INTO seen " bot.db.execute("INSERT OR REPLACE INTO seen "
"(nick, first_timestamp, first_channel, first_message," "(nick, timestamp, channel, message) VALUES (?, ?, ?, ?)",
"last_timestamp, last_channel, last_message)"
"VALUES (?, ?, ?, ?, ?, ?, ?)",
(nick,) + seen) (nick,) + seen)
bot.memory["seen_lock"].release() bot.memory["seen_lock"].release()
@ -116,12 +97,7 @@ def dump_seen_db(bot):
@hook(True) @hook(True)
@require_chanmsg @require_chanmsg
def seen_hook(bot, trigger): def seen_hook(bot, trigger):
last = (time.time(), trigger.channel, trigger.group(0)) seen = (time.time(), trigger.channel, trigger.group(0))
if not trigger.nick in bot.memory["seen"]:
first = (time.time(), trigger.channel, trigger.group(0))
else:
first = bot.memory["seen"][trigger.nick][:3]
seen = first + last
bot.memory["seen"][trigger.nick] = seen bot.memory["seen"][trigger.nick] = seen
if time.time() - bot.memory["seen_last_dump"] > 60: if time.time() - bot.memory["seen_last_dump"] > 60:

View File

@ -14,14 +14,7 @@ def setup(bot):
@commands('uptime') @commands('uptime')
def uptime(bot, trigger): def uptime(bot, trigger):
""".uptime - Returns the uptime of Fulvia.""" """.uptime - Returns the uptime of Sopel."""
delta = datetime.timedelta(seconds=round((datetime.datetime.now() - delta = datetime.timedelta(seconds=round((datetime.datetime.now() -
bot.memory["uptime"]).total_seconds())) bot.memory["uptime"]).total_seconds()))
bot.say(f"I've been sitting here for {delta} and I keep going!") bot.say(f"I've been sitting here for {delta} and I keep going!")
@commands('updick')
def updick(bot, trigger):
""".updick - Returns the uptime of Fulvia, measured in dicks."""
delta = datetime.datetime.now() - bot.memory["uptime"]
bot.say("8" + "="*delta.days + "D")

1
run.py
View File

@ -3,6 +3,7 @@
Initializes the bot. Initializes the bot.
""" """
import os import os
import sys
from twisted.internet import reactor from twisted.internet import reactor

View File

@ -77,7 +77,7 @@ class Trigger():
""" """
A datetime object at which the message was received by the IRC server. A datetime object at which the message was received by the IRC server.
If the server does not support server-time, then `time` will be the time If the server does not support server-time, then `time` will be the time
that the message was received by Fulvia. that the message was received by Sopel.
""" """
self.raw = "" self.raw = ""