source: timingandestimationplugin/branches/trac1.0/timingandestimationplugin/api.py

Last change on this file was 16684, checked in by Russ Tyndall, 6 years ago

Applying patches from trac-hacks to modernize interfacing with the database re #13080

File size: 11.2 KB
RevLine 
[1119]1import re
2import dbhelper
[1369]3import time
[3784]4from tande_filters import *
[1119]5from ticket_daemon import *
6from usermanual import *
7from trac.ticket import ITicketChangeListener, Ticket
8from trac.core import *
9from trac.env import IEnvironmentSetupParticipant
10from trac.perm import IPermissionRequestor, PermissionSystem
[3784]11from webui import *
[1516]12from ticket_webui import *
[2298]13from query_webui import *
[2390]14from reportmanager import CustomReportManager
[2774]15from statuses import *
[2785]16from reports import all_reports
[7435]17from stopwatch import *
[1119]18
19## report columns
20## id|author|title|query|description
[3784]21
[1119]22class TimeTrackingSetupParticipant(Component):
23    """ This is the config that must be there for this plugin to work:
[3784]24
[1119]25        [ticket-custom]
26        totalhours = text
27        totalhours.value = 0
28        totalhours.label = Total Hours
29
30        billable = checkbox
31        billable.value = 1
32        billable.label = Is this billable?
33
34        hours = text
35        hours.value = 0
36        hours.label = Hours to Add
[3784]37
[1119]38        estimatedhours = text
39        estimatedhours.value = 0
40        estimatedhours.label = Estimated Hours?
[3784]41
[1119]42        """
43    implements(IEnvironmentSetupParticipant)
[2390]44    db_version_key = None
45    db_version = None
46    db_installed_version = None
[3784]47
[1119]48    """Extension point interface for components that need to participate in the
49    creation and upgrading of Trac environments, for example to create
50    additional database tables."""
51    def __init__(self):
[2390]52        # Setup logging
[2774]53        self.statuses_key = 'T&E-statuses'
[2390]54        self.db_version_key = 'TimingAndEstimationPlugin_Db_Version'
[2590]55        self.db_version = 6
[2390]56        # Initialise database schema version tracking.
[8140]57        self.db_installed_version = dbhelper.get_system_value(self.env, \
[3119]58            self.db_version_key) or 0
[2390]59
[1119]60    def environment_created(self):
61        """Called when a new Trac environment is created."""
62        if self.environment_needs_upgrade(None):
63            self.upgrade_environment(None)
[2390]64
[3784]65
[2390]66    def system_needs_upgrade(self):
67        return self.db_installed_version < self.db_version
[3784]68
[2390]69    def do_db_upgrade(self):
[8140]70        self.log.debug( "T&E Beginning DB Upgrade");
[2390]71        if self.db_installed_version < 1:
[9989]72            if not dbhelper.db_table_exists(self.env, 'bill_date'):
73                print "Creating bill_date table"
74                sql = """
75                CREATE TABLE bill_date (
76                time integer,
77                set_when integer,
78                str_value text
79                );"""
80                dbhelper.execute_non_query(self.env,  sql)
[2823]81
[2390]82        if self.db_installed_version < 5:
83            # In this version we convert to using reportmanager.py
84            # The easiest migration path is to remove all the reports!!
85            # They will be added back in later but all custom reports will be lost (deleted)
[9989]86            if dbhelper.db_table_exists(self.env, 'report_version'):
87                print "Dropping report_version table"
88                sql = "DELETE FROM report " \
89                      "WHERE author=%s AND id IN (SELECT report FROM report_version)"
90                dbhelper.execute_non_query(self.env, sql, 'Timing and Estimation Plugin')
[2349]91
[9989]92                sql = "DROP TABLE report_version"
93                dbhelper.execute_non_query(self.env, sql)
[3784]94
95        #version 6 upgraded reports
96
[2390]97        # This statement block always goes at the end this method
[8140]98        dbhelper.set_system_value(self.env, self.db_version_key, self.db_version)
[2390]99        self.db_installed_version = self.db_version
[8140]100        self.log.debug( "T&E End DB Upgrade");
[3784]101
[2785]102    def reports_need_upgrade(self):
[8140]103        self.log.debug("T&E BEGIN Reports need an upgrade check")
[2785]104        mgr = CustomReportManager(self.env, self.log)
[5491]105        db_reports = mgr.get_version_hash_by_group(CustomReportManager.TimingAndEstimationKey)
106        py_reports = {}
[2785]107        for report_group in all_reports:
108            for report in report_group['reports']:
[5491]109                py_reports[report['uuid']]= report['version']
110       
111        diff = [(uuid, version) for (uuid, version) in py_reports.items()
112                if not db_reports.has_key(uuid) or int(db_reports[uuid]) < int(version)]
113               
[3179]114        if len(diff) > 0:
[5491]115            self.log.debug ("T&E needs upgrades for the following reports: %s" %
116                            (diff, ))
[8140]117        self.log.debug("T&E END Reports need an upgrade check")
[3179]118        return len(diff) > 0
[3784]119
[2774]120    def do_reports_upgrade(self, force=False):
[8140]121        self.log.debug( "T&E Beginning Reports Upgrade");
[2390]122        mgr = CustomReportManager(self.env, self.log)
[8140]123        statuses = get_statuses(self.env)
[2774]124        stat_vars = status_variables(statuses)
[3784]125
[2785]126        for report_group in all_reports:
[1119]127            rlist = report_group["reports"]
[2349]128            group_title = report_group["title"]
[1119]129            for report in rlist:
130                title = report["title"]
131                new_version = report["version"]
[3784]132
[2774]133                sql = report["sql"].replace('#STATUSES#', stat_vars)
[2390]134                mgr.add_report(report["title"], "Timing and Estimation Plugin", \
[2774]135                               "Reports Must Be Accessed From the Management Screen",
136                               sql, report["uuid"], report["version"],
137                               CustomReportManager.TimingAndEstimationKey,
138                               group_title, force)
[1119]139
140    def ticket_fields_need_upgrade(self):
141        ticket_custom = "ticket-custom"
142        return not ( self.config.get( ticket_custom, "totalhours" ) and \
143                     self.config.get( ticket_custom, "hours" ) and \
144                     self.config.get( ticket_custom, "estimatedhours"))
[3784]145
[1119]146    def do_ticket_field_upgrade(self):
[8140]147        self.log.debug( "T&E Beginning Custom Field Upgrade");
[1119]148        ticket_custom = "ticket-custom"
[3784]149
[1119]150        self.config.set(ticket_custom,"totalhours", "text")
[1554]151        if not self.config.get( ticket_custom, "totalhours.order") :
152            self.config.set(ticket_custom,"totalhours.order", "4")
[5486]153        if not self.config.get( ticket_custom, "totalhours.value") :
154            self.config.set(ticket_custom,"totalhours.value", "0")
155        if not self.config.get( ticket_custom, "totalhours.label") :
156            self.config.set(ticket_custom,"totalhours.label", "Total Hours")
[1119]157
158        self.config.set(ticket_custom,"billable", "checkbox")
[5486]159        if not self.config.get( ticket_custom, "billable.value") :
160            self.config.set(ticket_custom,"billable.value", "1")
[1554]161        if not self.config.get( ticket_custom, "billable.order") :
162            self.config.set(ticket_custom,"billable.order", "3")
[5486]163        if not self.config.get( ticket_custom, "billable.label") :
164            self.config.set(ticket_custom,"billable.label", "Billable?")
[3784]165
[1119]166        self.config.set(ticket_custom,"hours", "text")
[5486]167        if not self.config.get( ticket_custom, "hours.value") :
168            self.config.set(ticket_custom,"hours.value", "0")
[1554]169        if not self.config.get( ticket_custom, "hours.order") :
170            self.config.set(ticket_custom,"hours.order", "2")
[5486]171        if not self.config.get( ticket_custom, "hours.label") :
172            self.config.set(ticket_custom,"hours.label", "Add Hours to Ticket")
[3784]173
[1119]174        self.config.set(ticket_custom,"estimatedhours", "text")
[5486]175        if not self.config.get( ticket_custom, "estimatedhours.value") :
176            self.config.set(ticket_custom,"estimatedhours.value", "0")
[1554]177        if not self.config.get( ticket_custom, "estimatedhours.order") :
178            self.config.set(ticket_custom,"estimatedhours.order", "1")
[5486]179        if not self.config.get( ticket_custom, "estimatedhours.label") :
180            self.config.set(ticket_custom,"estimatedhours.label", "Estimated Number of Hours")
[1119]181
182        self.config.save();
[8140]183        self.log.debug( "T&E End Custom Field Upgrade");
[1119]184
185    def needs_user_man(self):
[8140]186        maxversion = dbhelper.get_scalar(self.env, "SELECT MAX(version) FROM wiki WHERE name like %s", 0,
[1119]187                                         user_manual_wiki_title)
188        if (not maxversion) or maxversion < user_manual_version:
189            return True
190        return False
191
192    def do_user_man_update(self):
[8140]193        self.log.debug( "T&E Beginning User Manual Upgrade");
[1369]194        when = int(time.time())
[1119]195        sql = """
196        INSERT INTO wiki (name,version,time,author,ipnr,text,comment,readonly)
[1369]197        VALUES ( %s, %s, %s, 'Timing and Estimation Plugin', '127.0.0.1', %s,'',0)
[1119]198        """
[8140]199        dbhelper.execute_non_query(self.env, sql,
[1119]200                                   user_manual_wiki_title,
201                                   user_manual_version,
[1369]202                                   when,
[1119]203                                   user_manual_content)
[8140]204        self.log.debug( "T&E End User Manual Upgrade");
[3784]205
206
[16684]207    def environment_needs_upgrade(self, db=None):
[1119]208        """Called when Trac checks whether the environment needs to be upgraded.
[3784]209
[1119]210        Should return `True` if this participant needs an upgrade to be
211        performed, `False` otherwise.
212
213        """
[8140]214        sysUp = self.system_needs_upgrade()
215        # Dont check for upgrades that will break the transaction
216        # If we dont have a system, then everything needs to be updated
217        res = (sysUp,
218               sysUp or self.reports_need_upgrade(),
219               sysUp or self.have_statuses_changed(),
220               sysUp or self.ticket_fields_need_upgrade(),
221               sysUp or self.needs_user_man())
222        self.log.debug("T&E NEEDS UP?: sys:%s, rep:%s, stats:%s, fields:%s, man:%s" % \
223                       res)
224        r = False;
225        for i in res: r |= i
226        return r
[3784]227
[16684]228    def upgrade_environment(self, db=None):
[1119]229        """Actually perform an environment upgrade.
[3784]230
[1119]231        Implementations of this method should not commit any database
232        transactions. This is done implicitly after all participants have
233        performed the upgrades they need without an error being raised.
234        """
235        def p(s):
236            print s
237            return True
238        print "Timing and Estimation needs an upgrade"
[2390]239        p("Upgrading Database")
240        self.do_db_upgrade()
241        p("Upgrading reports")
[2774]242        self.do_reports_upgrade(force=self.have_statuses_changed())
[3784]243
[2774]244        #make sure we upgrade the statuses string so that we dont need to always rebuild the
245        # reports
[8140]246        stats = get_statuses(self.env)
[2774]247        val = ','.join(list(stats))
[8140]248        dbhelper.set_system_value(self.env, self.statuses_key, val)
[3784]249
[1119]250        if self.ticket_fields_need_upgrade():
251            p("Upgrading fields")
252            self.do_ticket_field_upgrade()
253        if self.needs_user_man():
254            p("Upgrading usermanual")
255            self.do_user_man_update()
256        print "Done Upgrading"
257
[2774]258    def have_statuses_changed(self):
259        """get the statuses from the last time we saved them,
260        compare them to the ones we have now (ignoring '' and None),
261        if we have different ones, throw return true
262        """
[8140]263        s = dbhelper.get_system_value(self.env, self.statuses_key)
[2774]264        if not s:
265            return True
[8140]266        sys_stats = get_statuses(self.env)
[2774]267        s = s.split(',')
[13377]268        #self.env.log.debug('T&E: Statuses: stored:%r , sys:%r' %(s, sys_stats))
[2774]269        sys_stats.symmetric_difference_update(s)
270        sys_stats.difference_update(['', None])
[13377]271        #self.env.log.debug('T&E: Statuses: diff:%r ' %(sys_stats, ))
[2774]272        return len(sys_stats) > 0
Note: See TracBrowser for help on using the repository browser.