source: timingandestimationplugin/branches/trac0.11/timingandestimationplugin/ticket_daemon.py

Last change on this file was 6902, checked in by Russ Tyndall, 14 years ago

fixes #6043 during ticket field validation dont throw exceptions if the field isnt there

File size: 6.5 KB
RevLine 
[5162]1from trac.ticket import ITicketChangeListener, Ticket, ITicketManipulator
[1119]2from trac.core import *
[1710]3import datetime
[1119]4
[1710]5def identity(x):
6    return x;
7
[6268]8def convertfloat(x):
9    "some european countries use , as the decimal separator"
10    x = str(x).strip()
11    if len(x) > 0:
12        return float(x.replace(',','.'))
13    else: 
14        return 0.0
15
16
[2015]17try:
18    import trac.util.datefmt
19    to_timestamp = trac.util.datefmt.to_timestamp
20except Exception:
21    to_timestamp = identity
[1710]22
[2015]23
[1119]24def save_custom_field_value( db, ticket_id, field, value ):
25    cursor = db.cursor();
[5162]26    cursor.execute("SELECT * FROM ticket_custom "
[1119]27                   "WHERE ticket=%s and name=%s", (ticket_id, field))
28    if cursor.fetchone():
29        cursor.execute("UPDATE ticket_custom SET value=%s "
30                       "WHERE ticket=%s AND name=%s",
31                       (value, ticket_id, field))
32    else:
[1578]33        cursor.execute("INSERT INTO ticket_custom (ticket,name, "
[1119]34                       "value) VALUES(%s,%s,%s)",
[1578]35                       (ticket_id, field, value))
[2893]36    db.commit()
[5162]37
[4164]38DONTUPDATE = "DONTUPDATE"
39
[4166]40def save_ticket_change( db, ticket_id, author, change_time, field, oldvalue, newvalue, log, dontinsert=False):
[5162]41    """tries to save a ticket change,
42
43       dontinsert means do not add the change if it didnt already exist
[4166]44    """
[1710]45    if type(change_time) == datetime.datetime:
46        change_time = to_timestamp(change_time)
[1119]47    cursor = db.cursor();
[5162]48    sql = """SELECT * FROM ticket_change
49             WHERE ticket=%s and author=%s and time=%s and field=%s"""
50
[1710]51    cursor.execute(sql, (ticket_id, author, change_time, field))
[1119]52    if cursor.fetchone():
[4164]53        if oldvalue == DONTUPDATE:
[5162]54            cursor.execute("""UPDATE ticket_change  SET  newvalue=%s
[1710]55                       WHERE ticket=%s and author=%s and time=%s and field=%s""",
[4164]56                           ( newvalue, ticket_id, author, change_time, field))
57
58        else:
[5162]59            cursor.execute("""UPDATE ticket_change  SET oldvalue=%s, newvalue=%s
[4164]60                       WHERE ticket=%s and author=%s and time=%s and field=%s""",
61                           (oldvalue, newvalue, ticket_id, author, change_time, field))
[1119]62    else:
[4164]63        if oldvalue == DONTUPDATE:
64            oldvalue = '0'
[4166]65        if not dontinsert:
[5162]66            cursor.execute("""INSERT INTO ticket_change  (ticket,time,author,field, oldvalue, newvalue)
[1710]67                        VALUES(%s, %s, %s, %s, %s, %s)""",
[4166]68                           (ticket_id, change_time, author, field, oldvalue, newvalue))
[2893]69    db.commit()
[1119]70
71class TimeTrackingTicketObserver(Component):
72    implements(ITicketChangeListener)
73    def __init__(self):
74        pass
75
76    def watch_hours(self, ticket):
[5162]77
[1119]78        def readTicketValue(name, tipe, default=0):
[5162]79            if ticket.values.has_key(name):
[1119]80                return tipe(ticket.values[name] or default)
81            else:
82                cursor = self.env.get_db_cnx().cursor()
[1840]83                cursor.execute("SELECT * FROM ticket_custom where ticket=%s and name=%s" , (ticket.id, name))
[1119]84                val = cursor.fetchone()
85                if val:
86                    return tipe(val[2] or default)
87                return default
[4233]88
[6268]89
[4157]90        hours = readTicketValue("hours", convertfloat)
91        totalHours = readTicketValue("totalhours", convertfloat)
[1119]92
[4164]93        db = self.env.get_db_cnx()
94        ticket_id = ticket.id
95        cl = ticket.get_changelog()
[5162]96
[4233]97        self.log.debug("found hours: "+str(hours ));
[4164]98        #self.log.debug("Dir_ticket:"+str(dir(ticket)))
99        #self.log.debug("ticket.values:"+str(ticket.values))
[5162]100        #self.log.debug("changelog:"+str(cl))
101
[4166]102        most_recent_change = None
[4164]103        if cl:
104            most_recent_change = cl[-1];
105            change_time = most_recent_change[0]
106            author = most_recent_change[1]
107        else:
108            change_time = ticket.time_created
109            author = ticket.values["reporter"]
[4233]110
[5162]111
[4233]112        ## SAVE estimated hour
[5162]113        estimatedhours = readTicketValue("estimatedhours", convertfloat)
[4233]114        self.log.debug("found Estimated hours:"+str(estimatedhours))
[4164]115        db = self.env.get_db_cnx()
[4233]116        save_ticket_change( db, ticket_id, author, change_time, "estimatedhours", DONTUPDATE, str(estimatedhours), self.log, True)
[4164]117        save_custom_field_value( db, ticket.id, "estimatedhours", str(estimatedhours))
118        db.commit();
[4233]119        #######################
[4164]120
[4233]121
[5162]122        ## If our hours changed
123        if not hours == 0:
[1119]124            newtotal = str(totalHours+hours)
[4233]125            save_ticket_change( db, ticket_id, author, change_time, "hours", '0.0', str(hours), self.log)
[1710]126            save_ticket_change( db, ticket_id, author, change_time, "totalhours", str(totalHours), str(newtotal), self.log)
[1119]127            save_custom_field_value( db, ticket_id, "hours", '0')
[5162]128            save_custom_field_value( db, ticket_id, "totalhours", str(newtotal) )
[4233]129        ########################
[1119]130
[4233]131    # END of watch_hours
132
[1119]133    def ticket_created(self, ticket):
134        """Called when a ticket is created."""
135        self.watch_hours(ticket)
136
[5162]137
[1286]138    def ticket_changed(self, ticket, comment, author, old_values):
[1119]139        """Called when a ticket is modified.
[5162]140
[1119]141        `old_values` is a dictionary containing the previous values of the
142        fields that have changed.
143        """
144        self.watch_hours(ticket)
145
146    def ticket_deleted(self, ticket):
147        """Called when a ticket is deleted."""
[5162]148
149
150class TimeTrackingTicketValidator(Component):
151    implements(ITicketManipulator)
152
153    def __init__(self):
154        pass
155
156    def prepare_ticket(req, ticket, fields, actions):
157        """not currently called"""
158
159    def validate_ticket(self, req, ticket):
160        """Validate a ticket after it's been populated from user input.
161
162        Must return a list of `(field, message)` tuples, one for each problem
163        detected. `field` can be `None` to indicate an overall problem with the
164        ticket. Therefore, a return value of `[]` means everything is OK."""
165        errors = []
166        #some european countries use , as the decimal separator
167        try:
168            convertfloat(ticket.values['hours'])
[6902]169        except KeyError:
170            self.log.exception("The hours field was not submitted")
[5162]171        except ValueError:
172            errors.append(('Add Hours to Ticket', 'Value must be a number'))
173        try:
174            convertfloat(ticket.values['estimatedhours'])
[6902]175        except KeyError:
176            self.log.exception("The estimatedhours field was not submitted")
[5162]177        except ValueError:
178            errors.append(('Estimated Number of Hours', 'Value must be a number'))
179        return errors
Note: See TracBrowser for help on using the repository browser.