5
""" manage todo lists .. by user or by channel .. a time/data string can
6
be provided to set time on a todo item.
9
__copyright__ = 'this file is in the public domain'
11
from gozerbot.generic import strtotime, striptime, getwho, today, lockdec
12
from gozerbot.commands import cmnds
13
from gozerbot.examples import examples
14
from gozerbot.users import users
15
from gozerbot.datadir import datadir
16
from gozerbot.persist import Persist
17
from gozerbot.plughelp import plughelp
18
from gozerbot.aliases import aliases
19
from gozerbot.config import config
20
from gozerplugs.plugs.alarm import alarms
21
import time, thread, os
23
plughelp.add('todo', 'todo lists')
25
todolock = thread.allocate_lock()
26
locked = lockdec(todolock)
32
def __init__(self, name, descr, ttime=None, duration=None, warnsec=None, \
33
priority=None, num=0):
36
self.duration = duration
37
self.warnsec = warnsec
39
self.priority = priority
43
return "name: %s num: %d time: %s duration: %s warnsec: %s \
44
description: %s priority: %s" % (self.name, self.num, \
45
time.ctime(self.time), self.duration, self.warnsec, self.descr, self.priority)
49
""" a dict faking list of todo items .. index is number """
58
def __getitem__(self, num):
61
def __delitem__(self, num):
65
tmplist = self.data.values()
66
tmplist.sort(lambda x, y: cmp(x.priority, y.priority), reverse=True)
67
return tmplist.__iter__()
69
def append(self, item):
73
self.data[self.max] = item
84
def __init__(self, filename):
85
Persist.__init__(self, filename)
88
for key in self.data.keys():
89
todoos = self.data[key]
90
for (k, v) in todoos.data.items():
98
""" return number of todo entries """
102
""" get todoos of <name> """
103
if self.data.has_key(name):
104
return self.data[name]
107
def add(self, name, txt, ttime, warnsec=0):
110
if not self.data.has_key(name):
111
self.data[name] = Todolist()
112
self.data[name].append(Todoitem(name, txt.strip(), ttime, \
115
return len(self.data[name])
118
def addnosave(self, name, txt, ttime):
119
""" add but don't save """
121
if not self.data.has_key(name):
122
self.data[name] = Todolist()
123
self.data[name].append(Todoitem(name, txt, ttime))
127
def reset(self, name):
129
if self.data.has_key(name):
130
self.data[name] = Todolist()
134
def delete(self, name, nr):
135
""" delete todo item """
136
if not self.data.has_key(name):
138
todoos = self.data[name]
140
if todoos[nr].warnsec:
141
alarmnr = 0 - todoos[nr].warnsec
143
alarms.delete(alarmnr)
150
def toolate(self, name):
151
""" show if there are any time related todoos that are too late """
154
for i in self.data[name]:
159
def timetodo(self, name):
160
""" show todoos with time field set """
162
if not self.data.has_key(name):
164
for i in self.data[name]:
169
def withintime(self, name, time1, time2):
170
""" show todoos within time frame """
172
if not self.data.has_key(name):
174
for i in self.data[name]:
175
if i.time >= time1 and i.time < time2:
180
def setprio(self, who, itemnr, prio):
181
""" set priority of todo item """
183
todoitems = self.get(who)
184
todoitems[itemnr].priority = prio
187
except (KeyError, TypeError):
190
def settime(self, who, itemnr, ttime):
191
""" set time of todo item """
193
todoitems = self.get(who)
194
todoitems[itemnr].time = ttime
197
except (KeyError, TypeError):
200
class TodoDb(object):
202
""" database todo interface """
204
def reset(self, name):
205
result = db.execute(""" DELETE FROM todo WHERE name == %s """, name)
209
""" return number of todo's """
210
result = db.execute(""" SELECT COUNT(*) FROM todo """)
214
""" get todo list of <name> """
216
result = db.execute(""" SELECT * FROM todo WHERE name = %s ORDER BY \
217
priority DESC, indx ASC """, name)
221
args = [i[1],i[5], i[2], i[3], i[4], i[6], i[0]]
222
res.append(Todoitem(*args))
225
def getid(self, idnr):
226
""" get todo data of <idnr> """
227
result = db.execute(""" SELECT * FROM todo WHERE indx = %s """, idnr)
231
args = [i[1],i[5], i[2], i[3], i[4], i[6], i[0]]
232
res.append(Todoitem(*args))
236
def setprio(self, who, todonr, prio):
237
""" set priority of todonr """
238
result = db.execute(""" UPDATE todo SET priority = %s WHERE indx \
239
= %s """, (prio, todonr))
242
def getprio(self, todonr):
243
""" get priority of todonr """
244
result = db.execute(""" SELECT name, priority FROM todo WHERE \
245
indx = %s """, todonr)
248
def getwarnsec(self, todonr):
249
""" get priority of todonr """
250
result = db.execute(""" SELECT warnsec FROM todo WHERE \
251
indx = %s """, todonr)
254
def settime(self, who, todonr, ttime):
255
""" set time of todonr """
256
result = db.execute(""" UPDATE todo SET time = %s WHERE indx \
257
= %s """, (ttime, todonr))
260
def add(self, name, txt, ttime, alarmnr=None):
266
result = db.execute(""" INSERT INTO todo(name, time, \
267
descr) VALUES (%s, %s, %s) """, (name, ttime, txt))
269
result = db.execute(""" INSERT INTO todo(name, time, \
270
descr, warnsec) VALUES (%s, %s, %s, %s) """, (name, ttime, txt, 0-alarmnr))
273
result = db.execute(""" INSERT INTO todo(name, descr) \
274
VALUES (%s, %s) """, (name, txt))
277
def delete(self, name, indexnr):
278
""" delete todo item """
281
warnsec = self.getwarnsec(indexnr)[0][0]
283
alarmnr = 0 - warnsec
285
alarms.delete(alarmnr)
286
except (IndexError, TypeError):
288
result = db.execute(""" DELETE FROM todo WHERE name = %s AND \
289
indx = %s """, (name, indexnr))
292
def toolate(self, name):
293
""" show if there are any time related todoos that are too late """
296
result = db.execute(""" SELECT * FROM todo WHERE name = %s AND \
297
time < %s """, (name, now))
301
args = [i[1],i[5], i[2], i[3], i[4], i[6], i[0]]
302
res.append(Todoitem(*args))
305
def withintime(self, name, time1, time2):
306
""" show todo list within time frame """
308
result = db.execute(""" SELECT * FROM todo WHERE name = %s AND \
309
time > %s AND time < %s """, (name, time1, time2))
313
args = [i[1],i[5], i[2], i[3], i[4], i[6], i[0]]
314
res.append(Todoitem(*args))
317
def timetodo(self, name):
320
result = db.execute(""" SELECT * FROM todo WHERE time AND name = %s \
325
args = [i[1],i[5], i[2], i[3], i[4], i[6], i[0]]
326
res.append(Todoitem(*args))
329
def reset(self, name):
330
""" reset todo items of user with <name> """
332
result = db.execute(""" DELETE FROM todo WHERE name = %s """, (name, ))
335
if config['dbenable']:
336
from gozerbot.db import db
339
todo = Todo(datadir + os.sep + 'todo')
344
""" return number of todo entries """
347
def handle_todo(bot, ievent):
348
""" todo [<item>] .. show todo's or set todo item .. a time/date can be \
350
if len(ievent.args) > 0:
351
handle_todo2(bot, ievent)
353
name = users.getname(ievent.userhost)
355
todoos = todo.get(name)
357
ievent.reply('i dont have todo info for %s' % user.name)
359
saytodo(bot, ievent, todoos)
361
def handle_todo2(bot, ievent):
362
""" set todo item """
364
ievent.missing("<what>")
368
name = users.getname(ievent.userhost)
369
ttime = strtotime(what)
371
if not ttime == None:
372
ievent.reply('time detected ' + time.ctime(ttime))
373
what = striptime(what)
374
alarmnr = alarms.add(bot.name, ievent.nick, ttime, what)
375
nr = todo.add(name, what, ttime, alarmnr)
377
nr = todo.add(name, what, None)
378
ievent.reply('todo item %s added' % nr)
380
cmnds.add('todo', handle_todo, 'USER')
381
examples.add('todo', 'todo [<item>] .. show todo items or add a todo item', \
382
'1) todo 2) todo program the bot 3) todo 22:00 sleep')
384
def handle_tododone(bot, ievent):
385
""" todo-done <listofnrs> .. remove todo items """
386
if len(ievent.args) == 0:
387
ievent.missing('<list of nrs>')
391
for i in ievent.args:
394
ievent.reply('%s is not an integer' % i)
396
name = users.getname(ievent.userhost)
399
nrdone += todo.delete(name, i)
401
ievent.reply('%s item deleted' % nrdone)
403
ievent.reply('no items deleted')
405
ievent.reply('%s items deleted' % nrdone)
407
cmnds.add('todo-done', handle_tododone, 'USER')
408
examples.add('todo-done', 'todo-done <listofnrs> .. remove items from \
409
todo list', '1) todo-done 1 2) todo-done 3 5 8')
410
aliases.data['done'] = 'todo-done'
412
def handle_chantodo(bot, ievent):
413
""" todo-chan [<item>] .. show channel todo's or set todo item for \
416
handle_chantodo2(bot, ievent)
418
todoos = todo.get(ievent.channel)
419
saytodo(bot, ievent, todoos)
421
def handle_chantodo2(bot, ievent):
422
""" set todo item for channel"""
424
ttime = strtotime(what)
426
if not ttime == None:
427
ievent.reply('time detected ' + time.ctime(ttime))
428
result = '(%s) ' % ievent.nick + striptime(what)
429
alarmnr = alarms.add(bot.name, ievent.channel, ttime, result)
430
nr = todo.add(ievent.channel, result, ttime, alarmnr)
432
result = '(%s) ' % ievent.nick + what
433
nr = todo.add(ievent.channel, result, None)
434
ievent.reply('todo item %s added' % nr)
436
cmnds.add('todo-chan', handle_chantodo, 'USER')
437
examples.add('todo-chan', 'todo-chan [<item>] .. add channel todo', \
439
aliases.data['chantodo'] = 'todo-chan'
441
def handle_todochandone(bot, ievent):
442
""" todo-chandone <listofnrs> .. remove channel todo item """
444
ievent.missing('<list of nrs>')
446
data = ievent.rest.split()
452
ievent.reply('%s is not an integer' % i)
456
nrdone += todo.delete(ievent.channel, i)
458
ievent.reply('%s item deleted' % nrdone)
460
ievent.reply('no items deleted')
462
ievent.reply('%s items deleted' % nrdone)
464
cmnds.add('todo-chandone', handle_todochandone, 'USER')
465
examples.add('todo-chandone', 'todo-chandone <listofnrs> .. remove item \
466
from channel todo list', 'todo-chandone 2')
467
aliases.data['chandone'] = 'todo-chandone'
469
def handle_settodo(bot, ievent):
470
""" todo-set <name> <txt> .. add a todo to another user's todo list"""
473
what = ' '.join(ievent.args[1:])
475
ievent.missing('<nick> <what>')
478
ievent.missing('<nick> <what>')
480
userhost = getwho(bot, who)
482
ievent.reply("can't find userhost for %s" % who)
484
whouser = users.getname(userhost)
486
ievent.reply("can't find user for %s" % userhost)
488
name = users.getname(ievent.userhost)
489
if not users.permitted(userhost, name, 'todo'):
490
ievent.reply("%s doesn't permit todo sharing for %s " % \
493
what = "%s: %s" % (ievent.nick, what)
494
ttime = strtotime(what)
496
if not ttime == None:
497
ievent.reply('time detected ' + time.ctime(ttime))
498
what = striptime(what)
499
alarmnr = alarms.add(bot.name, who, ttime, what)
500
nr = todo.add(whouser, what, ttime, alarmnr)
502
nr = todo.add(whouser, what, None)
503
ievent.reply('todo item %s added' % nr)
505
cmnds.add('todo-set', handle_settodo, 'USER')
506
examples.add('todo-set', 'todo-set <nick> <txt> .. set todo item of \
507
<nick>', 'todo-set dunker bot proggen')
509
def handle_gettodo(bot, ievent):
510
""" todo-get <nick> .. get todo of another user """
514
ievent.missing('<nick>')
516
userhost = getwho(bot, who)
518
ievent.reply("can't find userhost for %s" % who)
520
whouser = users.getname(userhost)
522
ievent.reply("can't find user for %s" % userhost)
524
name = users.getname(ievent.userhost)
525
if not users.permitted(userhost, name, 'todo'):
526
ievent.reply("%s doesn't permit todo sharing for %s " % (who, name))
528
todoos = todo.get(whouser)
529
saytodo(bot, ievent, todoos)
531
cmnds.add('todo-get', handle_gettodo, ['USER', 'WEB'])
532
examples.add('todo-get', 'todo-get <nick> .. get the todo list of \
533
<nick>', 'todo-get dunker')
535
def handle_todotime(bot, ievent):
536
""" todo-time .. show time related todoos """
537
name = users.getname(ievent.userhost)
538
todoos = todo.timetodo(name)
539
saytodo(bot, ievent, todoos)
541
cmnds.add('todo-time', handle_todotime, 'USER')
542
examples.add('todo-time', 'todo-time .. show todo items with time fields', \
544
aliases.data['tt'] = 'todo-time'
546
def handle_todoweek(bot, ievent):
547
""" todo-week .. show time related todo items for this week """
548
name = users.getname(ievent.userhost)
549
todoos = todo.withintime(name, today(), today()+7*24*60*60)
550
saytodo(bot, ievent, todoos)
552
cmnds.add('todo-week', handle_todoweek, 'USER')
553
examples.add('todo-week', 'todo-week .. todo items for this week', 'todo-week')
555
def handle_today(bot, ievent):
556
""" todo-today .. show time related todo items for today """
557
name = users.getname(ievent.userhost)
558
todoos = todo.withintime(name, today(), today()+24*60*60)
559
saytodo(bot, ievent, todoos)
561
cmnds.add('todo-today', handle_today, 'USER')
562
examples.add('todo-today', 'todo-today .. todo items for today', 'todo-today')
563
aliases.data['today'] = 'todo-today'
565
def handle_tomorrow(bot, ievent):
566
""" todo-tomorrow .. show time related todo items for tomorrow """
567
username = users.getname(ievent.userhost)
570
ttime = strtotime(what)
572
if ttime < today() or ttime > today() + 24*60*60:
573
ievent.reply("%s is not tomorrow" % \
574
time.ctime(ttime + 24*60*60))
577
ievent.reply('time detected ' + time.ctime(ttime))
578
what = striptime(what)
580
ttime = today() + 42*60*60
581
todo.add(username, what, ttime)
582
ievent.reply('todo added')
584
todoos = todo.withintime(username, today()+24*60*60, today()+2*24*60*60)
585
saytodo(bot, ievent, todoos)
587
cmnds.add('todo-tomorrow', handle_tomorrow, 'USER')
588
examples.add('todo-tomorrow', 'todo-tomorrow .. todo items for tomorrow', \
590
aliases.data['tomorrow'] = 'todo-tomorrow'
592
def handle_setpriority(bot, ievent):
593
""" todo-setprio [<channel|name>] <itemnr> <prio> .. show priority \
596
(who, itemnr, prio) = ievent.args
599
(itemnr, prio) = ievent.args
600
who = users.getname(ievent.userhost)
602
ievent.missing('[<channe|namel>] <itemnr> <priority>')
608
ievent.missing('[<channel|name>] <itemnr> <priority>')
611
if not todo.setprio(who, itemnr, prio):
612
ievent.reply('no todo %s found for %s' % (itemnr, who))
614
ievent.reply('priority set')
616
cmnds.add('todo-setprio', handle_setpriority, 'USER')
617
examples.add('todo-setprio', 'todo-setprio [<channel|name>] <itemnr> <prio> \
618
.. set todo priority', '1) todo-setprio #dunkbots 2 5 2) todo-setprio owner \
619
3 10 3) todo-setprio 2 10')
620
aliases.data['setprio'] = 'todo-setprio'
622
def handle_todosettime(bot, ievent):
623
""" todo-settime [<channel|name>] <itemnr> <timestring> .. set time \
625
ttime = strtotime(ievent.txt)
627
ievent.reply("can't detect time")
629
txt = striptime(ievent.txt)
631
(who, itemnr) = txt.split()
634
(itemnr, ) = txt.split()
635
who = users.getname(ievent.userhost)
637
ievent.missing('[<channe|namel>] <itemnr> <timestring>')
642
ievent.missing('[<channel|name>] <itemnr> <timestring>')
645
if not todo.settime(who, itemnr, ttime):
646
ievent.reply('no todo %s found for %s' % (itemnr, who))
648
ievent.reply('time of todo %s set to %s' % (itemnr, time.ctime(ttime)))
650
cmnds.add('todo-settime', handle_todosettime, 'USER')
651
examples.add('todo-settime', 'todo-settime [<channel|name>] <itemnr> \
652
<timestring> .. set todo time', '1) todo-settime #dunkbots 2 13:00 2) \
653
todo-settime owner 3 2-2-2010 3) todo-settime 2 22:00')
655
def handle_getpriority(bot, ievent):
656
""" todo-getprio <[channel|name]> <itemnr> .. get priority of todo \
659
(who, itemnr) = ievent.args
662
itemnr = ievent.args[0]
663
who = users.getname(ievent.userhost)
665
ievent.missing('[<channel|name>] <itemnr>')
670
ievent.missing('[<channel|name>] <itemnr>')
673
todoitems = todo.get(who)
675
ievent.reply('no todoitems known for %s' % who)
678
prio = todoitems[itemnr].priority
680
ievent.reply('no todo item %s known for %s' % (itemnr, who))
682
ievent.reply('priority is %s' % prio)
684
cmnds.add('todo-getprio', handle_getpriority, 'USER')
685
examples.add('todo-getprio', 'todo-getprio [<channel|name>] <itemnr> .. get \
686
todo priority', '1) todo-getprio #dunkbots 5 2) todo-getprio 3')
687
aliases.data['prio'] = 'todo-getprio'
689
def saytodo(bot, ievent, todoos):
690
""" output todo items of <name> """
694
ievent.reply('nothing todo ;]')
698
res += "%s) " % i.num
702
res += "%s %s " % (time.ctime(i.time), i.descr)
704
res += "%s " % i.descr
706
res += "[%+d] " % i.priority
707
result.append(res.strip())
709
ievent.reply("todolist of %s: " % ievent.nick, result, nritems=True)