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

Last change on this file was 8141, checked in by Russ Tyndall, 13 years ago

Converting to use new trac12 DB convensions. version 0.9.8b

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