Skip to content

Commit 4c68e10

Browse files
committed
fix odd merge conflict
2 parents 640429f + 931caf7 commit 4c68e10

File tree

9 files changed

+217
-84
lines changed

9 files changed

+217
-84
lines changed

cloudbot/bot.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from watchdog.observers import Observer
1515

1616
from cloudbot.client import Client, CLIENTS
17-
from cloudbot.clients.irc import IrcClient, irc_clean
17+
from cloudbot.clients.irc import irc_clean
1818
from cloudbot.config import Config
1919
from cloudbot.event import Event, CommandEvent, RegexEvent, EventType
2020
from cloudbot.hook import Action
@@ -277,6 +277,8 @@ def add_hook(hook, _event, _run_before=False):
277277
# The hook has an action of Action.HALT* so stop adding new tasks
278278
break
279279

280+
matched_command = False
281+
280282
if event.type is EventType.message:
281283
# Commands
282284
if event.chan.lower() == event.nick.lower(): # private message, no command prefix
@@ -297,12 +299,14 @@ def add_hook(hook, _event, _run_before=False):
297299
command_event = CommandEvent(hook=command_hook, text=text,
298300
triggered_command=command, base_event=event)
299301
add_hook(command_hook, command_event)
302+
matched_command = True
300303
else:
301304
potential_matches = []
302305
for potential_match, plugin in self.plugin_manager.commands.items():
303306
if potential_match.startswith(command):
304307
potential_matches.append((potential_match, plugin))
305308
if potential_matches:
309+
matched_command = True
306310
if len(potential_matches) == 1:
307311
command_hook = potential_matches[0][1]
308312
command_event = CommandEvent(hook=command_hook, text=text,
@@ -312,10 +316,11 @@ def add_hook(hook, _event, _run_before=False):
312316
event.notice("Possible matches: {}".format(
313317
formatting.get_text_list([command for command, plugin in potential_matches])))
314318

319+
if event.type in (EventType.message, EventType.action):
315320
# Regex hooks
316321
regex_matched = False
317322
for regex, regex_hook in self.plugin_manager.regex_hooks:
318-
if not regex_hook.run_on_cmd and cmd_match:
323+
if not regex_hook.run_on_cmd and matched_command:
319324
continue
320325

321326
if regex_hook.only_no_match and regex_matched:

config.default.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@
118118
},
119119
"logging": {
120120
"console_debug": false,
121-
"file_debug": true,
121+
"file_debug": false,
122122
"show_plugin_loading": true,
123123
"show_motd": true,
124124
"show_server_info": true,

plugins/cryptocurrency.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ def get_request(ticker, currency):
4949

5050

5151
def alias_wrapper(alias):
52-
def func(text):
53-
return crypto_command(" ".join((alias.name, text)))
52+
def func(text, reply):
53+
return crypto_command(" ".join((alias.name, text)), reply)
5454

5555
func.__doc__ = """- Returns the current {} value""".format(alias.name)
5656
func.__name__ = alias.name + "_alias"

plugins/duckhunt.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from time import time
55

66
from sqlalchemy import Table, Column, String, Integer, PrimaryKeyConstraint, desc, Boolean
7-
from sqlalchemy.exc import DatabaseError
87
from sqlalchemy.sql import select
98

109
from cloudbot import hook
@@ -108,7 +107,7 @@ def save_status(db):
108107
if not res.rowcount:
109108
db.execute(status_table.insert().values(network=network, chan=chan, active=active, duck_kick=duck_kick))
110109

111-
db.commit()
110+
db.commit()
112111

113112

114113
@hook.event([EventType.message, EventType.action], singlethread=True)

plugins/history.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import time
44
from collections import deque
55

6-
from sqlalchemy import Table, Column, String, PrimaryKeyConstraint, Float
6+
from sqlalchemy import Table, Column, String, PrimaryKeyConstraint, Float, select
77

88
from cloudbot import hook
99
from cloudbot.event import EventType
@@ -27,11 +27,19 @@ def track_seen(event, db):
2727
:type db: sqlalchemy.orm.Session
2828
"""
2929
# keep private messages private
30+
now = time.time()
3031
if event.chan[:1] == "#" and not re.findall('^s/.*/.*/$', event.content.lower()):
31-
db.execute(
32-
"insert or replace into seen_user(name, time, quote, chan, host) values(:name,:time,:quote,:chan,:host)",
33-
{'name': event.nick.lower(), 'time': time.time(), 'quote': event.content, 'chan': event.chan,
34-
'host': event.mask})
32+
res = db.execute(
33+
table.update().values(time=now, quote=event.content, host=str(event.mask))
34+
.where(table.c.name == event.nick.lower()).where(table.c.chan == event.chan)
35+
)
36+
if res.rowcount == 0:
37+
db.execute(
38+
table.insert().values(
39+
name=event.nick.lower(), time=now, quote=event.content, chan=event.chan, host=str(event.mask)
40+
)
41+
)
42+
3543
db.commit()
3644

3745

@@ -98,18 +106,13 @@ def seen(text, nick, chan, db, event, is_nick_valid):
98106
if not is_nick_valid(text):
99107
return "I can't look up that name, its impossible to use!"
100108

101-
if '_' in text:
102-
text = text.replace("_", "/_")
103-
104-
last_seen = db.execute("SELECT name, time, quote FROM seen_user WHERE name LIKE :name ESCAPE '/' AND chan = :chan",
105-
{'name': text, 'chan': chan}).fetchone()
106-
107-
text = text.replace("/", "")
109+
last_seen = db.execute(
110+
select([table.c.name, table.c.time, table.c.quote])
111+
.where(table.c.name == text.lower()).where(table.c.chan == chan)
112+
).fetchone()
108113

109114
if last_seen:
110115
reltime = timeformat.time_since(last_seen[1])
111-
if last_seen[0] != text.lower(): # for glob matching
112-
text = last_seen[0]
113116
if last_seen[2][0:1] == "\x01":
114117
return '{} was last seen {} ago: * {} {}'.format(text, reltime, text, last_seen[2][8:-1])
115118
else:

plugins/hook_stats.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
"""
2+
Tracks successful and errored launches of all hooks, allowing users to query the stats
3+
4+
Author:
5+
- linuxdaemon <https://github.com/linuxdaemon>
6+
"""
7+
8+
from collections import defaultdict
9+
10+
from cloudbot import hook
11+
from cloudbot.hook import Priority
12+
from cloudbot.util import web
13+
from cloudbot.util.formatting import gen_markdown_table
14+
15+
16+
def default_hook_counter():
17+
return {'success': 0, 'failure': 0}
18+
19+
20+
def hook_sorter(n):
21+
def _sorter(data):
22+
return sum(data[n].values())
23+
24+
return _sorter
25+
26+
27+
def get_stats(bot):
28+
try:
29+
stats = bot.memory["hook_stats"]
30+
except LookupError:
31+
bot.memory["hook_stats"] = stats = {
32+
'global': defaultdict(default_hook_counter),
33+
'network': defaultdict(lambda: defaultdict(default_hook_counter)),
34+
'channel': defaultdict(lambda: defaultdict(lambda: defaultdict(default_hook_counter))),
35+
}
36+
37+
return stats
38+
39+
40+
@hook.post_hook(priority=Priority.HIGHEST)
41+
def stats_sieve(launched_event, error, bot, launched_hook):
42+
chan = launched_event.chan
43+
conn = launched_event.conn
44+
status = 'success' if error is None else 'failure'
45+
stats = get_stats(bot)
46+
name = launched_hook.plugin.title + '.' + launched_hook.function_name
47+
stats['global'][name][status] += 1
48+
if conn:
49+
stats['network'][conn.name.casefold()][name][status] += 1
50+
51+
if chan:
52+
stats['channel'][conn.name.casefold()][chan.casefold()][name][status] += 1
53+
54+
55+
def do_basic_stats(data):
56+
table = [
57+
(hook_name, str(count['success']), str(count['failure']))
58+
for hook_name, count in sorted(data.items(), key=hook_sorter(1), reverse=True)
59+
]
60+
return ("Hook", "Uses - Success", "Uses - Errored"), table
61+
62+
63+
def do_global_stats(data):
64+
return do_basic_stats(data['global'])
65+
66+
67+
def do_network_stats(data, network):
68+
return do_basic_stats(data['network'][network.casefold()])
69+
70+
71+
def do_channel_stats(data, network, channel):
72+
return do_basic_stats(data['channel'][network.casefold()][channel.casefold()])
73+
74+
75+
def do_hook_stats(data, hook_name):
76+
table = [
77+
(net, chan, hooks[hook_name]) for net, chans in data['network'].items() for chan, hooks in chans.items()
78+
]
79+
return ("Network", "Channel", "Uses - Success", "Uses - Errored"), \
80+
[
81+
(net, chan, str(count['success']), str(count['failure']))
82+
for net, chan, count in sorted(table, key=hook_sorter(2), reverse=True)
83+
]
84+
85+
86+
stats_funcs = {
87+
'global': (do_global_stats, 0),
88+
'network': (do_network_stats, 1),
89+
'channel': (do_channel_stats, 2),
90+
'hook': (do_hook_stats, 1),
91+
}
92+
93+
94+
@hook.command(permissions=["snoonetstaff", "botcontrol"])
95+
def hookstats(text, bot, notice_doc):
96+
"""{global|network <name>|channel <network> <channel>|hook <hook>} - Get hook usage statistics"""
97+
args = text.split()
98+
stats_type = args.pop(0).lower()
99+
100+
data = get_stats(bot)
101+
102+
try:
103+
handler, arg_count = stats_funcs[stats_type]
104+
except LookupError:
105+
notice_doc()
106+
return
107+
108+
if len(args) < arg_count:
109+
notice_doc()
110+
return
111+
112+
headers, data = handler(data, *args[:arg_count])
113+
114+
if not data:
115+
return "No stats available."
116+
117+
table = gen_markdown_table(headers, data)
118+
119+
return web.paste(table, 'md', 'hastebin')

plugins/horoscope.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import requests
44
from bs4 import BeautifulSoup
5-
from sqlalchemy import Table, String, Column
5+
from sqlalchemy import Table, String, Column, select
66

77
from cloudbot import hook
88
from cloudbot.util import database
@@ -15,6 +15,22 @@
1515
)
1616

1717

18+
def get_sign(db, nick):
19+
row = db.execute(select([table.c.sign]).where(table.c.nick == nick.lower())).fetchone()
20+
if not row:
21+
return None
22+
23+
return row[0]
24+
25+
26+
def set_sign(db, nick, sign):
27+
res = db.execute(table.update().values(sign=sign.lower()).where(table.c.nick == nick.lower()))
28+
if res.rowcount == 0:
29+
db.execute(table.insert().values(nick=nick.lower(), sign=sign.lower()))
30+
31+
db.commit()
32+
33+
1834
@hook.command(autohelp=False)
1935
def horoscope(text, db, bot, nick, notice, notice_doc, reply, message):
2036
"""[sign] - get your horoscope"""
@@ -43,11 +59,11 @@ def horoscope(text, db, bot, nick, notice, notice_doc, reply, message):
4359
sign = text.strip().lower()
4460

4561
if not sign:
46-
sign = db.execute("SELECT sign FROM horoscope WHERE "
47-
"nick=lower(:nick)", {'nick': nick}).fetchone()
62+
sign = get_sign(db, nick)
4863
if not sign:
4964
notice_doc()
5065
return
66+
5167
sign = sign[0].strip().lower()
5268

5369
if sign not in signs:
@@ -70,11 +86,9 @@ def horoscope(text, db, bot, nick, notice, notice_doc, reply, message):
7086
soup = BeautifulSoup(request.text)
7187

7288
horoscope_text = soup.find("div", class_="horoscope-content").find("p").text
73-
result = "\x02{}\x02 {}".format(text, horoscope_text)
89+
result = "\x02{}\x02 {}".format(sign, horoscope_text)
7490

7591
if text and not dontsave:
76-
db.execute("insert or replace into horoscope(nick, sign) values (:nick, :sign)",
77-
{'nick': nick.lower(), 'sign': sign})
78-
db.commit()
92+
set_sign(db, nick, sign)
7993

8094
message(result)

0 commit comments

Comments
 (0)