Watch For New Channels, JOIN, and +a. Basic Nick_Commands for channel Listing

This commit is contained in:
root 2019-05-01 12:30:41 +00:00 committed by deathbybandaid
commit 4d2156be1c
23 changed files with 824 additions and 0 deletions

57
.gitignore vendored Normal file
View File

@ -0,0 +1,57 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/

23
COPYING Normal file
View File

@ -0,0 +1,23 @@
Eiffel Forum License, version 2
1. Permission is hereby granted to use, copy, modify and/or
distribute this package, provided that:
* copyright notices are retained unchanged,
* any distribution of this package, whether modified or not,
includes this license text.
2. Permission is hereby also granted to distribute binary programs
which depend on this package. If the binary program depends on a
modified version of this package, you are encouraged to publicly
release the modified version of this package.
***********************
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT WARRANTY. ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE TO ANY PARTY FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THIS PACKAGE.
***********************

View File

@ -0,0 +1,40 @@
#!/bin/bash
# This install was run on Proxmox Ubuntu 18.10
apt update
apt upgrade -y
dpkg-reconfigure locales
apt install -y git
apt install -y python3-dev python3-pip
apt install -y python3-enchant libaspell-dev
wget https://raw.githubusercontent.com/sopel-irc/sopel/master/requirements.txt
pip3 install -r requirements.txt
rm requirements.txt
wget https://raw.githubusercontent.com/sopel-irc/sopel/master/dev-requirements.txt
pip3 install -r dev-requirements.txt
rm dev-requirements.txt
wget https://raw.githubusercontent.com/SpiceBot/SpiceBot/development/Installation%20Files/requirements.txt
pip3 install -r requirements.txt
rm requirements.txt
pip3 install sopel
mkdir /usr/local/lib/python3.6/dist-packages/sopel/modules/stock
mv /usr/local/lib/python3.6/dist-packages/sopel/modules/* /usr/local/lib/python3.6/dist-packages/sopel/modules/stock/
useradd sopel
passwd sopel
mkdir /home/sopel
chown sopel:sopel /home/sopel
usermod -aG sudo sopel
git clone https://github.com/SpiceBot/SpiceBot.git /home/sopel/SpiceBot
cd /home/sopel/SpiceBot
git checkout dev
cp /home/sopel/SpiceBot/System-Files/Config/SpiceBot.cfg /home/sopel/SpiceBot.cfg
cp /home/sopel/SpiceBot/System-Files/systemd/SpiceBot.service /lib/systemd/system/SpiceBot.service
systemctl enable SpiceBot.service

8
MANIFEST.in Normal file
View File

@ -0,0 +1,8 @@
include NEWS
include COPYING
include README.md
include *requirements.txt
recursive-include tests *
recursive-exclude * __pycache__
recursive-exclude * *.py[co]

0
NEWS Normal file
View File

13
README.md Normal file
View File

@ -0,0 +1,13 @@
# SpiceBot
SpiceBot aims to run SpiceBot as an IRC service
# This code is bad, and the author doesn't feel bad
Use at your own risk. Problems are not my fault™.
# Installation
````
git clone https://github.com/SpiceBot/SpiceBot.git
cd SpiceBot
pip3 install .
````

View File

@ -0,0 +1,16 @@
[core]
name = SpiceBot
nick = SpiceBot
user = SpiceBot/SpiceBot
auth_method = server
auth_password = **********
admins = deathbybandaid,dysonparkes
host = 192.168.5.10
use_ssl = false
port = 5000
owner = deathbybandaid
channels = #spicebot
prefix = \.|!
homedir = /home/sopel/.sopel/
db_filename = /home/sopel/.sopel/SpiceBot.db
extra =

View File

@ -0,0 +1,17 @@
[Unit]
Description=Sopel IRC bot
Documentation=http://sopel.chat/
After=network.target
[Service]
Type=simple
User=sopel
PIDFile=/run/sopel/sopel-sopel.pid
ExecStart=/usr/local/bin/sopel -c /home/sopel/.sopel/SpiceBot.cfg
Restart=on-failure
RestartPreventExitStatus=2
RestartSec=30
Environment=LC_ALL=en_US.UTF-8
[Install]
WantedBy=multi-user.target

0
dev-requirements.txt Normal file
View File

4
requirements.txt Normal file
View File

@ -0,0 +1,4 @@
sopel>=6.0,<7
spicemanip>=0.1.6
gitpython
sopel-modules.osd

43
setup.py Executable file
View File

@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
import os
import sys
from setuptools import setup, find_packages
if __name__ == '__main__':
print('Sopel does not correctly load modules installed with setup.py '
'directly. Please use "pip install .", or add {}/sopel_modules to '
'core.extra in your config.'.format(
os.path.dirname(os.path.abspath(__file__))),
file=sys.stderr)
with open('README.md') as readme_file:
readme = readme_file.read()
with open('NEWS') as history_file:
history = history_file.read()
with open('requirements.txt') as requirements_file:
requirements = [req for req in requirements_file.readlines()]
with open('dev-requirements.txt') as dev_requirements_file:
dev_requirements = [req for req in dev_requirements_file.readlines()]
setup(
name='sopel_modules.SpiceBot',
version='0.1.0',
description='SpiceBot aims to run SpiceBot as an IRC service',
long_description=readme + '\n\n' + history,
author='Sam Zick',
author_email='sam@deathbybandaid.net',
url='https://github.com/SpiceBot/SpiceBot',
packages=find_packages('.'),
namespace_packages=['sopel_modules'],
include_package_data=True,
install_requires=requirements,
tests_require=dev_requirements,
test_suite='tests',
license='Eiffel Forum License, version 2',
)

View File

@ -0,0 +1,367 @@
#!/usr/bin/env python
# coding=utf-8
from __future__ import unicode_literals, absolute_import, print_function, division
# sopel imports
import sopel.module
from sopel.tools import stderr
from sopel.config.types import StaticSection, ValidatedAttribute
from sopel.module import OP, ADMIN, VOICE, OWNER, HALFOP
HOP = HALFOP
import time
import re
import spicemanip
import sopel_modules.osd
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs, inlist
class SpiceBot_Channels_MainSection(StaticSection):
announcenew = ValidatedAttribute('announcenew', default=False)
joinall = ValidatedAttribute('joinall', default=False)
operadmin = ValidatedAttribute('operadmin', default=False)
def configure(config):
config.define_section("SpiceBot_Channels", SpiceBot_Channels_MainSection, validate=False)
config.SpiceBot_Channels.configure_setting('announcenew', 'SpiceBot_Channels Announce New Channels')
config.SpiceBot_Channels.configure_setting('announcenew', 'SpiceBot_Channels JOIN New Channels')
config.SpiceBot_Channels.configure_setting('announcenew', 'SpiceBot_Channels OPER ADMIN MODE')
def setup(bot):
stderr("[SpiceBot_Channels] Initial Setup processing...")
bot.config.define_section("SpiceBot_Channels", SpiceBot_Channels_MainSection, validate=False)
bot.memory['SpiceBot_Channels'] = dict()
bot.memory['SpiceBot_Channels']['channels'] = dict()
bot.memory['SpiceBot_Channels']['InitialProcess'] = False
bot.memory['SpiceBot_Channels']['ProcessLock'] = False
@sopel.module.event('001')
@sopel.module.rule('.*')
def trigger_channel_list_initial(bot, trigger):
# Unkickable
bot.write(('SAMODE', bot.nick, '+q'))
bot.write(['LIST'])
bot.memory['SpiceBot_Channels']['ProcessLock'] = True
stderr("[SpiceBot_Channels] Initial Channel list populating...")
starttime = time.time()
while not bot.memory['SpiceBot_Channels']['InitialProcess']:
timesince = time.time() - starttime
if timesince < 60:
pass
else:
stderr("[SpiceBot_Channels] Initial Channel list populating Timed Out.")
bot.memory['SpiceBot_Channels']['InitialProcess'] = True
channel_list_current(bot)
foundchannelcount = len(bot.memory['SpiceBot_Channels']['channels'].keys())
stderr("[SpiceBot_Channels] Channel listing finished! " + str(foundchannelcount) + " channel(s) found.")
# JOIN
if bot.config.SpiceBot_Channels.joinall:
for channel in bot.memory['SpiceBot_Channels']['channels'].keys():
if channel not in bot.channels.keys():
bot.write(('JOIN', bot.nick, bot.memory['SpiceBot_Channels']['channels'][channel]['name']))
if channel not in bot.channels.keys():
bot.write(('SAJOIN', bot.nick, bot.memory['SpiceBot_Channels']['channels'][channel]['name']))
# Chan ADMIN +a
for channel in bot.channels.keys():
if bot.config.SpiceBot_Channels.operadmin:
if not bot.channels[channel].privileges[bot.nick] < ADMIN:
bot.write(('SAMODE', channel, "+a", bot.nick))
channel_privs(bot, channel)
if "*" in bot.memory['SpiceBot_Channels']['channels']:
del bot.memory['SpiceBot_Channels']['channels']["*"]
while True:
time.sleep(1800)
oldlist = list(bot.memory['SpiceBot_Channels']['channels'].keys())
bot.write(['LIST'])
bot.memory['SpiceBot_Channels']['ProcessLock'] = True
while bot.memory['SpiceBot_Channels']['ProcessLock']:
pass
newlist = [item.lower() for item in oldlist if item.lower() not in bot.memory['SpiceBot_Channels']['channels']]
if "*" in newlist:
newlist.remove("*")
if len(newlist) and bot.config.SpiceBot_Channels.announcenew:
bot.osd(["The Following channel(s) are new:", spicemanip.main(newlist, 'andlist')], bot.channels.keys())
# JOIN
if bot.config.SpiceBot_Channels.joinall:
for channel in bot.memory['SpiceBot_Channels']['channels'].keys():
if channel not in bot.channels.keys():
bot.write(('JOIN', bot.nick, bot.memory['SpiceBot_Channels']['channels'][channel]['name']))
if channel not in bot.channels.keys():
bot.write(('SAJOIN', bot.nick, bot.memory['SpiceBot_Channels']['channels'][channel]['name']))
# Chan ADMIN +a
for channel in bot.channels.keys():
if bot.config.SpiceBot_Channels.operadmin:
if not bot.channels[channel].privileges[bot.nick] < ADMIN:
bot.write(('SAMODE', channel, "+a", bot.nick))
channel_privs(bot, channel)
if "*" in bot.memory['SpiceBot_Channels']['channels']:
del bot.memory['SpiceBot_Channels']['channels']["*"]
@sopel.module.event('321')
@sopel.module.rule('.*')
def watch_chanlist_start(bot, trigger):
bot.memory['SpiceBot_Channels']['ProcessLock'] = True
@sopel.module.event('322')
@sopel.module.rule('.*')
def watch_chanlist_populate(bot, trigger):
channel, _, topic = trigger.args[1:]
if channel.lower() not in bot.memory['SpiceBot_Channels']['channels']:
bot.memory['SpiceBot_Channels']['channels'][channel.lower()] = dict()
bot.memory['SpiceBot_Channels']['channels'][channel.lower()]['name'] = channel
bot.memory['SpiceBot_Channels']['channels'][channel.lower()]['topic'] = topic_compile(topic)
bot.memory['SpiceBot_Channels']['ProcessLock'] = True
@sopel.module.event('323')
@sopel.module.rule('.*')
def watch_chanlist_complete(bot, trigger):
bot.memory['SpiceBot_Channels']['ProcessLock'] = False
if not bot.memory['SpiceBot_Channels']['InitialProcess']:
bot.memory['SpiceBot_Channels']['InitialProcess'] = True
@sopel.module.nickname_commands('channels', 'channel')
def nickname_comand_chanstats(bot, trigger):
triggerargs = sopel_triggerargs(bot, trigger, 'nickname_command')
if not len(triggerargs):
commandused = 'list'
else:
commandused = spicemanip.main(triggerargs, 1).lower()
triggerargs = spicemanip.main(triggerargs, '2+', 'list')
channel_list_current(bot)
if commandused == 'list':
chanlist = spicemanip.main(bot.channels.keys(), 'andlist')
bot.osd("You can find me in " + chanlist)
return
elif commandused == 'total':
botcount = len(bot.channels.keys())
servercount = len(bot.memory['SpiceBot_Channels']['channels'].keys())
bot.osd("I am in " + str(botcount) + " of " + str(servercount) + " channel(s) available on this server.")
return
elif commandused == 'random':
channel = spicemanip.main(bot.memory['SpiceBot_Channels']['channels'], 'random')
topic = bot.memory['SpiceBot_Channels']['channels'][channel]['topic']
msg = ["Random channel for you: {}.".format(bot.memory['SpiceBot_Channels']['channels'][channel]['name'])]
if topic and not topic.isspace():
msg.append("The topic is: {}".format(topic))
else:
msg.append("Its topic is empty.")
bot.osd(msg)
return
elif commandused == 'update':
if not trigger.admin:
bot.osd("You do not have permission to update the channel listing.")
return
bot.write(['LIST'])
bot.osd(["[SpiceBot_Channels]", "I am now updating the channel listing for this server."])
bot.memory['SpiceBot_Channels']['ProcessLock'] = True
while bot.memory['SpiceBot_Channels']['ProcessLock']:
pass
foundchannelcount = len(bot.memory['SpiceBot_Channels']['channels'].keys())
bot.osd("[SpiceBot_Channels]", "Channel listing finished!", str(foundchannelcount) + " channel(s) found.")
return
elif commandused == 'topic':
if not len(triggerargs):
bot.osd("Channel name input missing.")
return
channel = spicemanip.main(triggerargs, 1)
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
bot.osd("Channel name {} not valid.".format(channel))
return
topic = bot.memory['SpiceBot_Channels']['channels'][channel.lower()]['topic']
channel = bot.memory['SpiceBot_Channels']['channels'][channel.lower()]['name']
bot.osd("Topic for {}: {}".format(channel, topic))
return
# OP list
if commandused == 'op':
channel = spicemanip.main(triggerargs, 1)
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
bot.osd("Channel name {} not valid.".format(channel))
return
if not inlist(bot, channel.lower(), bot.channels.keys()):
bot.osd("I need to be in {} to see nick privileges.".format(channel))
return
channel_privs(bot, channel)
dispmsg = []
if not len(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()]):
dispmsg.append("There are no Channel " + commandused.upper() + "s for " + str(channel))
else:
oplist = spicemanip.main(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()], 'andlist')
dispmsg.append("Channel " + commandused.upper() + "s for " + str(channel) + " are: " + oplist)
bot.osd(dispmsg, trigger.nick, 'notice')
return
# HOP list
if commandused == 'hop':
channel = spicemanip.main(triggerargs, 1)
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
bot.osd("Channel name {} not valid.".format(channel))
return
if not inlist(bot, channel.lower(), bot.channels.keys()):
bot.osd("I need to be in {} to see nick privileges.".format(channel))
return
channel_privs(bot, channel)
dispmsg = []
if not len(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()]):
dispmsg.append("There are no Channel " + commandused.upper() + "s for " + str(channel))
else:
oplist = spicemanip.main(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()], 'andlist')
dispmsg.append("Channel " + commandused.upper() + "s for " + str(channel) + " are: " + oplist)
bot.osd(dispmsg, trigger.nick, 'notice')
return
# Voice List
if commandused == 'voice':
channel = spicemanip.main(triggerargs, 1)
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
bot.osd("Channel name {} not valid.".format(channel))
return
if not inlist(bot, channel.lower(), bot.channels.keys()):
bot.osd("I need to be in {} to see nick privileges.".format(channel))
return
channel_privs(bot, channel)
dispmsg = []
if not len(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()]):
dispmsg.append("There are no Channel " + commandused.upper() + "s for " + str(channel))
else:
oplist = spicemanip.main(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()], 'andlist')
dispmsg.append("Channel " + commandused.upper() + "s for " + str(channel) + " are: " + oplist)
bot.osd(dispmsg, trigger.nick, 'notice')
return
# owner List
if commandused == 'owner':
channel = spicemanip.main(triggerargs, 1)
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
bot.osd("Channel name {} not valid.".format(channel))
return
if not inlist(bot, channel.lower(), bot.channels.keys()):
bot.osd("I need to be in {} to see nick privileges.".format(channel))
return
channel_privs(bot, channel)
dispmsg = []
if not len(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()]):
dispmsg.append("There are no Channel " + commandused.upper() + "s for " + str(channel))
else:
oplist = spicemanip.main(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()], 'andlist')
dispmsg.append("Channel " + commandused.upper() + "s for " + str(channel) + " are: " + oplist)
bot.osd(dispmsg, trigger.nick, 'notice')
return
# admin List
if commandused == 'admin':
channel = spicemanip.main(triggerargs, 1)
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
bot.osd("Channel name {} not valid.".format(channel))
return
if not inlist(bot, channel.lower(), bot.channels.keys()):
bot.osd("I need to be in {} to see nick privileges.".format(channel))
return
channel_privs(bot, channel)
dispmsg = []
if not len(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()]):
dispmsg.append("There are no Channel " + commandused.upper() + "s for " + str(channel))
else:
oplist = spicemanip.main(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()], 'andlist')
dispmsg.append("Channel " + commandused.upper() + "s for " + str(channel) + " are: " + oplist)
bot.osd(dispmsg, trigger.nick, 'notice')
return
# Users List
if commandused == 'users':
channel = spicemanip.main(triggerargs, 1)
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
bot.osd("Channel name {} not valid.".format(channel))
return
if not inlist(bot, channel.lower(), bot.channels.keys()):
bot.osd("I need to be in {} to see user list.".format(channel))
return
dispmsg = []
if not len(bot.channels[channel].privileges.keys()):
dispmsg.append("There are no Channel users for " + str(channel))
else:
userslist = spicemanip.main(bot.channels[channel].privileges.keys(), 'andlist')
dispmsg.append("Channel users for " + str(channel) + " are: " + userslist)
bot.osd(dispmsg, trigger.nick, 'notice')
return
def channel_list_current(bot):
newlist = [item for item in bot.channels.keys() if item.lower() not in bot.memory['SpiceBot_Channels']['channels']]
for channel in newlist:
topic = bot.channels[channel].topic
bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()] = dict()
bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()]['name'] = str(channel)
bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()]['topic'] = topic_compile(topic)
channel_privs(bot, channel)
if "*" in bot.memory['SpiceBot_Channels']:
bot.memory['SpiceBot_Channels'].remove("*")
def topic_compile(topic):
actual_topic = re.compile(r'^\[\+[a-zA-Z]+\] (.*)')
topic = re.sub(actual_topic, r'\1', topic)
return topic
def channel_privs(bot, channel):
if channel not in bot.memory['SpiceBot_Channels']['channels'].keys():
topic = bot.channels[channel].topic
bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()] = dict()
bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()]['name'] = str(channel)
bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()]['topic'] = topic_compile(topic)
for chan in bot.memory['SpiceBot_Channels']['channels'].keys():
for privtype in ['VOICE', 'HOP', 'OP', 'ADMIN', 'OWNER']:
if privtype not in bot.memory['SpiceBot_Channels']['channels'][str(chan).lower()].keys():
bot.memory['SpiceBot_Channels']['channels'][str(chan).lower()][privtype] = []
for user in bot.channels[channel].privileges.keys():
try:
privnum = bot.channels[channel].privileges[user] or 0
except KeyError:
privnum = 0
for privtype in ['VOICE', 'HOP', 'OP', 'ADMIN', 'OWNER']:
if privnum == eval(privtype) or (privnum >= eval(privtype) and privtype == 'OWNER'):
if user not in bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][privtype]:
bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][privtype].append(user)
else:
if user in bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][privtype]:
bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][privtype].remove(user)

View File

@ -0,0 +1,6 @@
# coding=utf-8
"""Event Parsing from IRC
"""
from __future__ import unicode_literals, absolute_import, print_function, division
from .Channels import *

View File

@ -0,0 +1,76 @@
#!/usr/bin/env python
# coding=utf-8
from __future__ import unicode_literals, absolute_import, print_function, division
# sopel imports
import sopel.module
from sopel.tools import stderr, Identifier
from sopel.db import _deserialize, SopelDB
import json
def setup(bot):
# Inject Database Functions
stderr("[SpiceBot_Databaseaddons] Implanting Database functions into bot.")
SopelDB.reset_nick_value = SopelDBCache.reset_nick_value
SopelDB.adjust_nick_value = SopelDBCache.adjust_nick_value
SopelDB.reset_channel_value = SopelDBCache.reset_channel_value
SopelDB.adjust_channel_value = SopelDBCache.adjust_channel_value
SopelDB._create_table = SopelDBCache._create_table
class SopelDBCache:
"""Dynamic Table Creation"""
def _create_table(self, tablename):
self.execute('CREATE TABLE IF NOT EXISTS ? (mainid STRING, key STRING, value STRING, PRIMARY KEY (mainid, key))', tablename)
"""Nicks"""
def reset_nick_value(self, nick, key):
"""Resets the value for a given key to be associated with the nick."""
nick = Identifier(nick)
nick_id = self.get_nick_id(nick)
self.execute('DELETE FROM nick_values WHERE nick_id = ? AND key = ?', [nick_id, key])
def adjust_nick_value(self, nick, key, value):
"""Adjusts the value for a given key to be associated with the nick."""
nick = Identifier(nick)
result = self.execute(
'SELECT value FROM nicknames JOIN nick_values '
'ON nicknames.nick_id = nick_values.nick_id '
'WHERE slug = ? AND key = ?',
[nick.lower(), key]
).fetchone()
if result is not None:
result = result[0]
current_value = _deserialize(result)
value = current_value + value
value = json.dumps(value, ensure_ascii=False)
nick_id = self.get_nick_id(nick)
self.execute('INSERT OR REPLACE INTO nick_values VALUES (?, ?, ?)',
[nick_id, key, value])
"""Channels"""
def reset_channel_value(self, channel, key):
"""Resets the value for a given key to be associated with a channel."""
channel = Identifier(channel).lower()
self.execute('DELETE FROM channel_values WHERE channel = ? AND key = ?', [channel, key])
def adjust_channel_value(self, channel, key, value):
"""Adjusts the value for a given key to be associated with the channel."""
channel = Identifier(channel).lower()
result = self.execute(
'SELECT value FROM channel_values WHERE channel = ? AND key = ?',
[channel, key]
).fetchone()
if result is not None:
result = result[0]
current_value = _deserialize(result)
value = current_value + value
value = json.dumps(value, ensure_ascii=False)
self.execute('INSERT OR REPLACE INTO channel_values VALUES (?, ?, ?)',
[channel, key, value])

View File

@ -0,0 +1,6 @@
# coding=utf-8
"""Useful miscellaneous tools and shortcuts for SpiceBot Sopel modules
"""
from __future__ import unicode_literals, absolute_import, print_function, division
from .Databaseaddons import *

View File

@ -0,0 +1,12 @@
#!/usr/bin/env python
# coding=utf-8
from __future__ import unicode_literals, absolute_import, print_function, division
# sopel imports
import sopel.module
from sopel.tools import stderr
def setup(bot):
stderr("[SpiceBot_DatabaseCache] Setting up Database Cache.")
bot.memory['SpiceBot_DatabaseCache'] = dict()

View File

@ -0,0 +1,6 @@
# coding=utf-8
"""Useful miscellaneous tools and shortcuts for SpiceBot Sopel modules
"""
from __future__ import unicode_literals, absolute_import, print_function, division
from .DatabaseCache import *

View File

@ -0,0 +1,64 @@
#!/usr/bin/env python
# coding=utf-8
from __future__ import unicode_literals, absolute_import, print_function, division
# sopel imports
import sopel.module
"""Dyanmic Table Creation"""
def db_create_table(bot, tablename):
bot.db._create_table(tablename)
"""Database Direct"""
# Get a value
def db_get_nick_value(bot, nick, key):
database_value = bot.db.get_nick_value(nick, key) or None
return database_value
# set a value
def db_set_nick_value(bot, nick, key, value):
bot.db.set_nick_value(nick, key, value)
# DELETE a value
def db_reset_value(bot, nick, key):
bot.db.reset_nick_value(nick, key)
# add or subtract from current value
def db_adjust_value(bot, nick, key, value):
bot.db.adjust_nick_value(nick, key, value)
# list stored in database, add or remove elements
def db_adjust_list(bot, nick, entries, key, adjustmentdirection):
if not isinstance(entries, list):
entries = [entries]
adjustlist = db_get_nick_value(bot, nick, key) or []
adjustlistnew = []
for x in adjustlist:
adjustlistnew.append(x)
db_reset_value(bot, nick, key)
adjustlist = []
if adjustmentdirection == 'add':
for y in entries:
if y not in adjustlistnew:
adjustlistnew.append(y)
elif adjustmentdirection == 'del':
for y in entries:
if y in adjustlistnew:
adjustlistnew.remove(y)
for x in adjustlistnew:
if x not in adjustlist:
adjustlist.append(x)
if adjustlist == []:
db_reset_value(bot, nick, key)
else:
db_set_nick_value(bot, nick, key, adjustlist)

View File

@ -0,0 +1,6 @@
# coding=utf-8
"""Useful miscellaneous tools and shortcuts for SpiceBot Sopel modules
"""
from __future__ import unicode_literals, absolute_import, print_function, division
from .DatabaseTools import *

View File

@ -0,0 +1,44 @@
# coding=utf-8
"""Useful miscellaneous tools and shortcuts for SpiceBot Sopel modules
"""
from __future__ import unicode_literals, absolute_import, print_function, division
import collections
import spicemanip
def sopel_triggerargs(bot, trigger, command_type):
triggerargs = []
if len(trigger.args) > 1:
triggerargs = spicemanip.main(trigger.args[1], 'create')
triggerargs = spicemanip.main(triggerargs, 'create')
if command_type in ['module_command']:
triggerargs = spicemanip.main(triggerargs, '2+', 'list')
elif command_type in ['nickname_command']:
triggerargs = spicemanip.main(triggerargs, '3+', 'list')
return triggerargs
def inlist(bot, searchterm, searchlist):
# verify we are searching a list
if isinstance(searchlist, collections.abc.KeysView) or isinstance(searchlist, dict):
searchlist = [x for x in searchlist]
if not isinstance(searchlist, list):
searchlist = [searchlist]
rebuildlist = []
for searchitem in searchlist:
rebuildlist.append(str(searchitem))
searchterm = str(searchterm)
if searchterm in rebuildlist:
return True
elif searchterm.lower() in [searching.lower() for searching in rebuildlist]:
return True
else:
return False

View File

@ -0,0 +1 @@
__import__('pkg_resources').declare_namespace(__name__)

1
tests/__init__.py Normal file
View File

@ -0,0 +1 @@
# coding=utf-8

View File

@ -0,0 +1,14 @@
#!/usr/bin/env python
# coding=utf-8
from __future__ import unicode_literals, absolute_import, division, print_function
import unittest
from sopel_modules.SpiceBot import *
class TestSpiceBot(unittest.TestCase):
def setUp(self):
pass
def testSomething(self):
pass