~ubuntu-branches/ubuntu/utopic/gozerbot/utopic

« back to all changes in this revision

Viewing changes to build/lib/gplugs/alchemy/infoitem.py

  • Committer: Package Import Robot
  • Author(s): Jeremy Malcolm
  • Date: 2012-04-03 21:58:28 UTC
  • mfrom: (3.1.11 sid)
  • Revision ID: package-import@ubuntu.com-20120403215828-6mik0tzug5na93la
Tags: 0.99.1-2
* Removes logfiles on purge (Closes: #668767)
* Reverted location of installed files back to /usr/lib/gozerbot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# plugs/infoitem.py
 
2
#
 
3
#
 
4
 
 
5
""" information items .. keyword/description pairs """
 
6
 
 
7
__copyright__ = 'this file is in the public domain'
 
8
 
 
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
 
27
 
 
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)
 
36
 
 
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
 
42
 
 
43
## BEGIN UPGRADE PART
 
44
 
 
45
def upgrade():
 
46
    rlog(10, 'infoitem', 'upgrading')
 
47
    teller = 0
 
48
    dbdir = datadir + os.sep + 'db' + os.sep + 'infoitem.db'
 
49
    if os.path.exists(dbdir):
 
50
        try:
 
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 """)
 
55
            if result:
 
56
                for i in result:
 
57
                    info.add(*i[1:])
 
58
                    teller += 1
 
59
        except Exception, ex:
 
60
            handle_exception()
 
61
    else:
 
62
        oldfile = datadir + os.sep + 'old' + os.sep + 'infoitems'
 
63
        try:
 
64
            from gozerbot.utils.generic import dosed
 
65
            from gozerbot.compat.persist import Persist
 
66
            oldinfo = Persist(oldfile)
 
67
            assert(oldinfo)
 
68
            if not oldinfo.data:
 
69
                return
 
70
            for item, descrlist in oldinfo.data.iteritems():
 
71
                for descr in descrlist:
 
72
                    try:
 
73
                        info.add(item, descr, 'none', 0)
 
74
                    except Exception, ex:
 
75
                        handle_exception()
 
76
                    teller += 1
 
77
        except IOError, ex:
 
78
            if "No such file" in str(ex):
 
79
                rlog(10, 'infoitem', 'nothing to upgrade')
 
80
        except Exception, ex:
 
81
            rlog(10, 'infoitem', "can't upgrade: %s" % str(ex))
 
82
            return
 
83
    rlog(10, 'infoitem', 'upgraded %s infoitems' % str(teller))
 
84
    return teller
 
85
 
 
86
import thread, os, time
 
87
 
 
88
plughelp.add('infoitem', 'also known as factoids .. info can be retrieved \
 
89
by keyword or searched')
 
90
 
 
91
infolock = thread.allocate_lock()
 
92
 
 
93
# create lock descriptor
 
94
locked = lockdec(infolock)
 
95
 
 
96
class InfoitemsDb(object):
 
97
 
 
98
    """ information items """
 
99
 
 
100
    @dblocked
 
101
    def add(self, item, description, userhost, ttime, channel="", name=""):
 
102
        """ add an item """
 
103
        item = item.lower()
 
104
        result = 0
 
105
        try:
 
106
            #Session.begin()
 
107
            newitem = InfoItems(item, description, userhost, datetime.fromtimestamp(ttime))
 
108
            Session.add(newitem)
 
109
            #Session.commit()
 
110
            #Session.close()
 
111
            result = 1
 
112
        except Exception, ex:
 
113
            rlog(10, 'infoitem', "can't add item: %s" % str(ex))
 
114
            raise ex
 
115
        return result
 
116
 
 
117
    def get(self, item):
 
118
        """ get infoitems """
 
119
        item = item.lower()
 
120
        result = [r.description for r in query(InfoItems).filter_by(item=item)]
 
121
        return result
 
122
 
 
123
    @dblocked
 
124
    def delete(self, indexnr):
 
125
        """ delete item with indexnr  """
 
126
        item = Session.query(InfoItems).filter_by(indx=indexnr).first()
 
127
        try:
 
128
            #Session.begin()
 
129
            Session.delete(item)
 
130
            #Session.commit()
 
131
            #Session.close()
 
132
            result = 1
 
133
        except Exception, ex:
 
134
            rlog(10, 'infoitem', "can't delete item %s: %s" % (str(indexnr), str(ex)))
 
135
            raise ex
 
136
        return result
 
137
 
 
138
    @dblocked
 
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()
 
143
        result = 0
 
144
        try:
 
145
            #Session.begin()
 
146
            for n, i in enumerate(items):
 
147
                Session.delete(i)
 
148
                result = n + 1
 
149
            #Session.commit()
 
150
            #Session.close()
 
151
        except Exception, ex:
 
152
            rlog(10, 'infoitem', "can't delete items like %s: %s" % (str(txt), str(ex)))
 
153
            raise ex
 
154
        return result
 
155
 
 
156
    def size(self):
 
157
        """ return number of items """
 
158
        count = query(sa.func.count(InfoItems.indx)).first()[0]
 
159
        return count
 
160
 
 
161
    def searchitem(self, search):
 
162
        """ search items """
 
163
        result = query(InfoItems).filter(InfoItems.item.like('%%%s%%' % search)).all()
 
164
        return result
 
165
 
 
166
    def searchdescr(self, search):
 
167
        """ search descriptions """
 
168
        result = query(InfoItems).filter(InfoItems.description.like('%%%s%%' % search)).all()
 
169
        return result
 
170
 
 
171
 
 
172
info = InfoitemsDb()
 
173
create_all('infoitem')
 
174
assert(info)
 
175
 
 
176
def size():
 
177
    """ return number of infoitems """
 
178
    return info.size()
 
179
 
 
180
def search(what, queue):
 
181
    rlog(10, 'infoitem', 'searched for %s' % what)
 
182
    result = info.searchitem(what)   
 
183
    if not result:
 
184
        return
 
185
    res = []
 
186
    for i in result:
 
187
        queue.put_nowait(i.description)
 
188
    result = info.searchdescr(what)   
 
189
    if not result:
 
190
        return
 
191
    for i in result:
 
192
        queue.put_nowait("[%s] %s" % (i.item, i.description))
 
193
 
 
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 \
 
198
and ievent.txt:
 
199
        return 1
 
200
 
 
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)
 
206
             if data:
 
207
                ievent.reply('%s is ' % ievent.txt, data , dot=True)
 
208
 
 
209
callbacks.add('PRIVMSG', infocb, infopre)
 
210
 
 
211
def handle_infoupgrade(bot, ievent):
 
212
    if info.size():
 
213
         if '-f' in ievent.optionset:
 
214
             pass
 
215
         else:
 
216
             ievent.reply('there are already infoitems in the main database .. not upgrading')
 
217
             ievent.reply('use the -f option to force an upgrade')
 
218
             return
 
219
    ievent.reply('upgrading infoitems')
 
220
    nritems = upgrade()
 
221
    ievent.reply('%s items upgraded' % nritems)
 
222
 
 
223
cmnds.add('info-upgrade', handle_infoupgrade, 'OPER', options={'-f': ''})
 
224
 
 
225
def handle_infosize(bot, ievent):
 
226
    """ info-size .. show number of information items """
 
227
    ievent.reply("we have %s infoitems" % info.size())
 
228
 
 
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')
 
232
 
 
233
def handle_addinfoitem(bot, ievent):
 
234
    """ <keyword> = <description> .. add information item """
 
235
    try:
 
236
        (what, description) = ievent.groups
 
237
    except ValueError:
 
238
        ievent.reply('i need <item> <description>')
 
239
        return
 
240
    if len(description) < 3:
 
241
        ievent.reply('i need at least 3 chars for the description')
 
242
        return
 
243
    what = what.strip()
 
244
    ret = info.add(what, description, ievent.userhost, time.time())
 
245
    if ret:
 
246
        ievent.reply('item added')
 
247
    else:
 
248
        ievent.reply('unable to add item')
 
249
 
 
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')
 
254
 
 
255
def handle_question(bot, ievent):
 
256
    """ <keyword>? .. ask for information item description """
 
257
    try:
 
258
        what = ievent.groups[0]
 
259
    except TypeError:
 
260
        what = ievent.rest
 
261
    except IndexError:
 
262
        ievent.reply('i need a argument')
 
263
        return
 
264
    what = what.strip().lower()
 
265
    infoitems = info.get(what)
 
266
    if infoitems:
 
267
        ievent.reply("%s is " % what, infoitems, dot=True)
 
268
    else:
 
269
        ievent.reply('nothing known about %s' % what)
 
270
 
 
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')
 
279
 
 
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]
 
286
    else:
 
287
        ievent.missing('<item> <txttomatch> (min 3 chars)')
 
288
        return
 
289
    if len(txt) < 3:
 
290
        ievent.reply('i need txt with at least 3 characters')
 
291
        return
 
292
    what = what.strip().lower()
 
293
    try:
 
294
        nrtimes = info.deltxt(what, txt)
 
295
    except KeyError:
 
296
        ievent.reply('no records matching %s found' % what)
 
297
        return
 
298
    if nrtimes > 1:
 
299
        ievent.reply('%d items deleted' % nrtimes)
 
300
    elif nrtimes:
 
301
        ievent.reply('item deleted')
 
302
    else:
 
303
        ievent.reply('delete %s of %s failed' % (txt, what))
 
304
 
 
305
cmnds.add('info-forget', handle_forget, ['FORGET', 'OPER'])
 
306
examples.add('info-forget', 'forget <item> containing <txt>', 'info-forget \
 
307
dunk bla')
 
308
aliases.data['forget'] = 'info-forget'
 
309
tests.add('gozerbot2 = top bot').add('info-forget gozerbot2 top', 'item deleted')
 
310
 
 
311
def handle_searchdescr(bot, ievent):
 
312
    """ info-sd <txttosearchfor> .. search information items descriptions """
 
313
    if not ievent.rest:
 
314
        ievent.missing('<txt>')
 
315
        return
 
316
    else:
 
317
        what = ievent.rest
 
318
    what = what.strip().lower()
 
319
    result = info.searchdescr(what)
 
320
    if result: 
 
321
        res = []
 
322
        for i in result:
 
323
            res.append("[%s] %s" % (i.item, i.description))
 
324
        ievent.reply("the following matches %s: " % what, res, dot=True)
 
325
    else:
 
326
        ievent.reply('none found')
 
327
 
 
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')
 
334
 
 
335
def handle_searchitem(bot, ievent):
 
336
    """ info-si <txt> .. search information keywords """
 
337
    if not ievent.rest:
 
338
        ievent.missing('<txt>')
 
339
        return
 
340
    else:
 
341
        what = ievent.rest
 
342
    what = what.strip().lower()
 
343
    result = info.searchitem(what)
 
344
    if result:
 
345
        res = []
 
346
        for i in result:
 
347
            res.append("[%s] %s" % (i.item, i.description))
 
348
        ievent.reply("the following matches %s: " % what, res, dot=True)
 
349
    else:
 
350
        ievent.reply('none found')
 
351
 
 
352
cmnds.add('info-si', handle_searchitem, ['USER', 'WEB', 'CLOUD'])
 
353
examples.add('info-si', 'info-si <txt> ..  search the infoitems keys', \
 
354
'info-si test')
 
355
aliases.data['si'] = 'info-si'
 
356
tests.add('gozerbot = top bot').add('info-si gozer', 'gozerbot')