5
""" information items .. keyword/description pairs """
7
__copyright__ = 'this file is in the public domain'
9
from gozerbot.tests import tests
10
from gozerbot.commands import cmnds
11
from gozerbot.examples import examples
12
from gozerbot.redispatcher import rebefore, reafter
13
from gozerbot.ignore import shouldignore
14
from gozerbot.datadir import datadir
15
from gozerbot.persist.persist import Persist
16
from gozerbot.generic import lockdec, cchar, rlog, handle_exception
17
from gozerbot.aliases import aliases
18
from gozerbot.plughelp import plughelp
19
from gozerbot.callbacks import callbacks
20
from gozerbot.users import users
21
from gozerbot.config import config
22
from gozerbot.database.alchemy import Base, create_all, query, Session, dblocked
23
from datetime import datetime
24
from time import localtime
25
from sqlalchemy import Column, String, Integer, Text, DateTime, ForeignKey, Sequence
26
import sqlalchemy as sa
28
class InfoItems(Base):
29
__tablename__ = 'infoitems'
30
__table_args__ = {'useexisting': True}
31
indx = Column('indx', Integer, primary_key=True)
32
item = Column('item', String(255), nullable=False)
33
description = Column('description', Text, nullable=False)
34
userhost = Column('userhost', String(255), ForeignKey('userhosts.userhost'), nullable=False)
35
time = Column('time', DateTime, nullable=False)
37
def __init__(self, item, description, userhost, ttime=None):
38
self.time = ttime and ttime or datetime.now()
39
self.item = item.lower()
40
self.description = description
41
self.userhost = userhost
46
rlog(10, 'infoitem', 'upgrading')
48
dbdir = datadir + os.sep + 'db' + os.sep + 'infoitem.db'
49
if os.path.exists(dbdir):
51
from gozerbot.database.db import Db
52
db = Db(dbtype='sqlite')
53
db.connect('db/infoitem.db')
54
result = db.execute(""" SELECT * FROM infoitems """)
62
oldfile = datadir + os.sep + 'old' + os.sep + 'infoitems'
64
from gozerbot.utils.generic import dosed
65
from gozerbot.compat.persist import Persist
66
oldinfo = Persist(oldfile)
70
for item, descrlist in oldinfo.data.iteritems():
71
for descr in descrlist:
73
info.add(item, descr, 'none', 0)
78
if "No such file" in str(ex):
79
rlog(10, 'infoitem', 'nothing to upgrade')
81
rlog(10, 'infoitem', "can't upgrade: %s" % str(ex))
83
rlog(10, 'infoitem', 'upgraded %s infoitems' % str(teller))
86
import thread, os, time
88
plughelp.add('infoitem', 'also known as factoids .. info can be retrieved \
89
by keyword or searched')
91
infolock = thread.allocate_lock()
93
# create lock descriptor
94
locked = lockdec(infolock)
96
class InfoitemsDb(object):
98
""" information items """
101
def add(self, item, description, userhost, ttime, channel="", name=""):
107
newitem = InfoItems(item, description, userhost, datetime.fromtimestamp(ttime))
112
except Exception, ex:
113
rlog(10, 'infoitem', "can't add item: %s" % str(ex))
118
""" get infoitems """
120
result = [r.description for r in query(InfoItems).filter_by(item=item)]
124
def delete(self, indexnr):
125
""" delete item with indexnr """
126
item = Session.query(InfoItems).filter_by(indx=indexnr).first()
133
except Exception, ex:
134
rlog(10, 'infoitem', "can't delete item %s: %s" % (str(indexnr), str(ex)))
139
def deltxt(self, item, txt):
140
""" delete item with matching txt """
141
items = Session.query(InfoItems).filter(InfoItems.item==item
142
).filter(InfoItems.description.like('%%%s%%' % txt)).all()
146
for n, i in enumerate(items):
151
except Exception, ex:
152
rlog(10, 'infoitem', "can't delete items like %s: %s" % (str(txt), str(ex)))
157
""" return number of items """
158
count = query(sa.func.count(InfoItems.indx)).first()[0]
161
def searchitem(self, search):
163
result = query(InfoItems).filter(InfoItems.item.like('%%%s%%' % search)).all()
166
def searchdescr(self, search):
167
""" search descriptions """
168
result = query(InfoItems).filter(InfoItems.description.like('%%%s%%' % search)).all()
173
create_all('infoitem')
177
""" return number of infoitems """
180
def search(what, queue):
181
rlog(10, 'infoitem', 'searched for %s' % what)
182
result = info.searchitem(what)
187
queue.put_nowait(i.description)
188
result = info.searchdescr(what)
192
queue.put_nowait("[%s] %s" % (i.item, i.description))
194
def infopre(bot, ievent):
195
""" see if info callback needs to be called """
196
cc = cchar(bot, ievent)
197
if ievent.origtxt and ievent.origtxt[0] in cc and not ievent.usercmnd \
201
def infocb(bot, ievent):
202
""" implement a !infoitem callback """
203
if not shouldignore(ievent.userhost):
204
if 'handle_question' in bot.state['allowed'] or users.allowed(ievent.userhost, 'USER'):
205
data = info.get(ievent.txt)
207
ievent.reply('%s is ' % ievent.txt, data , dot=True)
209
callbacks.add('PRIVMSG', infocb, infopre)
211
def handle_infoupgrade(bot, ievent):
213
if '-f' in ievent.optionset:
216
ievent.reply('there are already infoitems in the main database .. not upgrading')
217
ievent.reply('use the -f option to force an upgrade')
219
ievent.reply('upgrading infoitems')
221
ievent.reply('%s items upgraded' % nritems)
223
cmnds.add('info-upgrade', handle_infoupgrade, 'OPER', options={'-f': ''})
225
def handle_infosize(bot, ievent):
226
""" info-size .. show number of information items """
227
ievent.reply("we have %s infoitems" % info.size())
229
cmnds.add('info-size', handle_infosize, ['USER', 'WEB', 'CLOUD'])
230
examples.add('info-size', 'show number of infoitems', 'info-size')
231
tests.add('info-size', 'we have (\d+) infoitems')
233
def handle_addinfoitem(bot, ievent):
234
""" <keyword> = <description> .. add information item """
236
(what, description) = ievent.groups
238
ievent.reply('i need <item> <description>')
240
if len(description) < 3:
241
ievent.reply('i need at least 3 chars for the description')
244
ret = info.add(what, description, ievent.userhost, time.time())
246
ievent.reply('item added')
248
ievent.reply('unable to add item')
250
rebefore.add(10, '^(.+?)\s+=\s+(.+)$', handle_addinfoitem, ['USER', \
251
'INFOADD'], allowqueue=False)
252
examples.add('=', 'add description to item', 'dunk = top')
253
tests.add('gozerbot = top bot', 'item added')
255
def handle_question(bot, ievent):
256
""" <keyword>? .. ask for information item description """
258
what = ievent.groups[0]
262
ievent.reply('i need a argument')
264
what = what.strip().lower()
265
infoitems = info.get(what)
267
ievent.reply("%s is " % what, infoitems, dot=True)
269
ievent.reply('nothing known about %s' % what)
271
reafter.add(10, '^(.+)\?$', handle_question, ['USER', 'WEB', 'JCOLL', \
272
'CLOUD'], allowqueue=True)
273
reafter.add(10, '^\?(.+)$', handle_question, ['USER', 'WEB', 'JCOLL', \
274
'CLOUD'], allowqueue=True)
275
cmnds.add('?', handle_question, ['USER', 'INFOADD'], allowqueue=False)
276
examples.add('?', 'show infoitems of <what>', '1) test? 2) ?test')
277
tests.add('gozerbot?', 'top bot')
278
tests.add('?gozerbot', 'top bot')
280
def handle_forget(bot, ievent):
281
""" forget <keyword> <txttomatch> .. remove information item where \
282
description matches txt given """
283
if len(ievent.args) > 1:
284
what = ' '.join(ievent.args[:-1])
285
txt = ievent.args[-1]
287
ievent.missing('<item> <txttomatch> (min 3 chars)')
290
ievent.reply('i need txt with at least 3 characters')
292
what = what.strip().lower()
294
nrtimes = info.deltxt(what, txt)
296
ievent.reply('no records matching %s found' % what)
299
ievent.reply('%d items deleted' % nrtimes)
301
ievent.reply('item deleted')
303
ievent.reply('delete %s of %s failed' % (txt, what))
305
cmnds.add('info-forget', handle_forget, ['FORGET', 'OPER'])
306
examples.add('info-forget', 'forget <item> containing <txt>', 'info-forget \
308
aliases.data['forget'] = 'info-forget'
309
tests.add('gozerbot2 = top bot').add('info-forget gozerbot2 top', 'item deleted')
311
def handle_searchdescr(bot, ievent):
312
""" info-sd <txttosearchfor> .. search information items descriptions """
314
ievent.missing('<txt>')
318
what = what.strip().lower()
319
result = info.searchdescr(what)
323
res.append("[%s] %s" % (i.item, i.description))
324
ievent.reply("the following matches %s: " % what, res, dot=True)
326
ievent.reply('none found')
328
cmnds.add('info-sd', handle_searchdescr, ['USER', 'WEB', 'CLOUD'])
329
examples.add('info-sd', 'info-sd <txt> .. search description of \
330
infoitems', 'info-sd http')
331
aliases.data['sd'] = 'info-sd'
332
aliases.data['sl'] = 'info-sd'
333
tests.add('gozerbot = top bot').add('info-sd top', 'top bot')
335
def handle_searchitem(bot, ievent):
336
""" info-si <txt> .. search information keywords """
338
ievent.missing('<txt>')
342
what = what.strip().lower()
343
result = info.searchitem(what)
347
res.append("[%s] %s" % (i.item, i.description))
348
ievent.reply("the following matches %s: " % what, res, dot=True)
350
ievent.reply('none found')
352
cmnds.add('info-si', handle_searchitem, ['USER', 'WEB', 'CLOUD'])
353
examples.add('info-si', 'info-si <txt> .. search the infoitems keys', \
355
aliases.data['si'] = 'info-si'
356
tests.add('gozerbot = top bot').add('info-si gozer', 'gozerbot')