This mod is an addition to the TimeLog mod.
The TimelogAuditor automatically parses messages which are added to an issue. It creates and links a timelog-entry for each line that starts with a description and ends with a roundup Interval (see roundup.date). If you add a property title to the TimeLog class, the descriptions for each timelog will be saved.
Sample message:
Re: Fix Flicker Bug
Hello Jack
I fixed the bug that bugged you.
Bug-Fixing 2:30
Testing 0:15
Relaxing 2w 3d 2:20:05
detectors/timelogauditor.py:
#
# timelogAuditor scans messages for timelogs.
#
# $Id$
import re
from roundup.date import Interval
def timelogAuditor(db, cl, nodeid, newvalues):
''' Check if a new messages where added to the issue and scan them
for timelogs in the following format
[title] [interval] <endofline>
Programming 2h
Consulting 2h30m
Implementing Bug-Fix 30m
if newvalues has an attribute 'messages', then we either are dealing
with a new issue (create-auditor) or the attribute 'messages' was
changed for an existing issue (set-auditor).
'''
# return quickly if there is no new message
if not newvalues.has_key('messages'):
return
# parse the new messages for timelogs
timelogs = []
for msgid in determineNewMessages(cl, nodeid, newvalues):
timelogs += parseMessage(db, msgid)
# add links for timelogs to the current issue
if timelogs:
if newvalues.has_key('times'):
times = newvalues['times']
elif nodeid:
times = db.issue.get(nodeid, 'times')
else:
times = []
times += timelogs
newvalues['times'] = times
def parseMessage(db, msgid, time_re = re.compile(r'''
\s*(?P<title>(.*?)) # title
\s*(?P<time>[-+]?(?:\d+\s*[ymwd]\s*)* # [+-] [#y] [#m] [#w] [#d]
[012]?\d:\d+(?:\:\d+)?)\s*$ # [[[H]H:MM]:SS]
''', re.IGNORECASE|re.VERBOSE)):
''' parse the messages content field and return an array of timelogs
'''
msg_content = db.msg.get(msgid, 'content')
if not msg_content:
raise KeyException("no content found for message: %s\n" %(msgid))
timelogs = []
for line in msg_content.split("\n"):
m = time_re.match(line)
if m:
title = m.group("title")
time_str = m.group("time")
interval = Interval(time_str)
# if there is a property title=String() in timelog, then fill it
if db.timelog.getprops().has_key("title"):
timelogs += db.timelog.create(period=interval, title=title),
else:
timelogs += db.timelog.create(period=interval),
return timelogs
def determineNewMessages(cl, nodeid, newvalues):
if not newvalues.has_key('messages'):
return []
# return all messages for a new node
if nodeid is None:
return newvalues['messages']
# return only new messages for an existing node
messages = []
old_messages = cl.get(nodeid, 'messages')
return [msgid for msgid in newvalues['messages'] if msgid not in old_messages]
def init(db):
''' we need to audit issue-changes to catch new messages instead
of attaching an auditor directly to the message class.
this is the only way to have the issue ready when linking the
new timelogs.
'''
db.issue.audit('set', timelogAuditor)
db.issue.audit('create', timelogAuditor)
# vim: set filetype=python ts=4 sw=4 et si
| subtopics: |