Changeset 25970

Show
Ignore:
Timestamp:
12/05/08 23:16:38 (5 weeks ago)
Author:
hirobe
Message:

TicketStatusLogModelProviderと管理ページの追加

Location:
platform/trac/plugins/querychart/trunk
Files:
2 added
3 modified

Legend:

Unmodified
Added
Removed
  • platform/trac/plugins/querychart/trunk/querychart/__init__.py

    r17195 r25970  
    22 
    33from macro import * 
     4from model import * 
     5from admin import * 
  • platform/trac/plugins/querychart/trunk/querychart/model.py

    r25697 r25970  
    22 
    33from trac.core import * 
    4 from trac.env import IEnvironmentSetupParticipant 
    5 from trac.db import Table, Column, Index 
    6  
    7 from trac.ticket.api import ITicketChangeListener 
    84 
    95from trac.util.datefmt import format_date,to_datetime 
     6from trac.config import Option, ListOption 
     7 
     8from trac.ticket.api import ITicketManipulator 
     9from trac.ticket.model import Ticket 
     10 
    1011 
    1112class TicketStatusLogModelProvider(Component): 
    12     implements(IEnvironmentSetupParticipant,ITicketChangeListener) 
     13    implements(ITicketManipulator) 
     14    #sample:'assigned:last_assigned, accepted,reopened, closed:last_closed' 
     15    ListOption('querychart', 'order', default='assigned, accepted,reopened, closed', 
     16                       doc='status order') 
     17     
    1318 
    14     SCHEMA = [ 
    15         Table('ticket_status_dt', key = ('ticket', 'status'))[ 
    16               Column('ticket'), 
    17               Column('status'), 
    18               Column('time', type = 'integer'), 
    19               Index(['status', 'time'])] 
    20         ] 
    21  
    22     # IEnvironmentSetupParticipant methods 
    23     def environment_created(self): 
    24         self._upgrade_db(self.env.get_db_cnx()) 
    25  
    26     def environment_needs_upgrade(self, db): 
    27         cursor = db.cursor() 
    28         #if self._need_migration(db): 
    29         #    return True 
    30         try: 
    31             cursor.execute("select count(*) from ticket_status_dt") 
    32              
    33             cursor.fetchone() 
    34             return False 
    35         except: 
    36             db.rollback() 
    37             return True 
    38  
    39     def upgrade_environment(self, db): 
    40         self._upgrade_db(db) 
    41  
    42 #    def _need_migration(self, db): 
    43 #        cursor = db.cursor() 
    44 #        try: 
    45 #            cursor.execute("select count(*) from wiki_namespace") 
    46 #            cursor.fetchone() 
    47 #            self.env.log.debug("tractags needs to migrate old data") 
    48 #            return True 
    49 #        except: 
    50 #            db.rollback() 
    51 #            return False 
    52  
    53     def _upgrade_db(self, db): 
    54         try: 
    55             try: 
    56                 from trac.db import DatabaseManager 
    57                 db_backend, _ = DatabaseManager(self.env)._get_connector() 
    58             except ImportError: 
    59                 db_backend = self.env.get_db_cnx() 
    60  
    61             cursor = db.cursor() 
    62             for table in self.SCHEMA: 
    63                 for stmt in db_backend.to_sql(table): 
    64                     self.env.log.debug(stmt) 
    65                     cursor.execute(stmt) 
    66                      
    67             db.commit() 
    68  
    69             cursor = db.cursor() 
    70             cursor.execute("SELECT id from ticket") 
    71             for id, in cursor: 
    72                 rebuild_status_log(self.env,id,db) 
    73             db.commit() 
    74  
    75 #TODO:データを集計する 
    76  
    77 #            # Migrate old data 
    78 #            if self._need_migration(db): 
    79 #                cursor = db.cursor() 
    80 #                cursor.execute("INSERT INTO tags (tagspace, name, tag) SELECT " 
    81 #                               "'wiki', name, namespace FROM wiki_namespace") 
    82 #                cursor.execute("DROP TABLE wiki_namespace") 
    83 #                db.commit() 
    84         except: 
    85             db.rollback() 
    86             raise 
    87  
    88     """Extension point interface for components that require notification 
    89     when tickets are created, modified, or deleted.""" 
    90  
    91     def ticket_created(self,ticket): 
    92         """Called when a ticket is created.""" 
    93  
    94     def ticket_changed(self,ticket, comment, author, old_values): 
    95         """Called when a ticket is modified. 
     19    def validate_ticket(self,req, ticket): 
     20        """If status chaned, then set date to custom field.""" 
     21        status_dt = set_status_dt(self.env,ticket.id,ticket['status'],ticket['changetime']) 
     22        if ticket._old.has_key('status'): 
     23            for m in status_dt: 
     24                ticket[m] = status_dt[m] 
    9625         
    97         `old_values` is a dictionary containing the previous values of the 
    98         fields that have changed. 
    99         """ 
    100          
    101         if not old_values.has_key('status'): 
    102             return True 
    103         rebuild_status_log(self.env,ticket.id) 
    104         return True 
    105              
    106  
    107     def ticket_deleted(self,ticket): 
    108         """Called when a ticket is deleted.""" 
    109         delete_status_log(self.env,ticket) 
     26        return [] 
    11027 
    11128 
    112 def rebuild_status_log(env,ticket_id,db=None): 
    113     #db, handle_ta = self._get_db_for_write(db) 
     29def set_status_dt(env,ticket_id,new_status=None,new_time=None,db=None): 
     30 
     31    order_lst = env.config.getlist('querychart', 'order') 
     32    order =[] 
     33    custom_fields = {} 
     34    for m in order_lst: 
     35        ms = m.split(':') 
     36        if len(ms) >= 2: 
     37            order.append(ms[0]) 
     38            custom_fields[ms[0]] = ':'.join(ms[1:]) 
     39        else: 
     40            order.append(m) 
     41 
    11442    if not db: 
    11543        db = env.get_db_cnx() 
    116         handle_ta = True 
    117     else: 
    118         handle_ta = False 
    11944 
    120     delete_status_log(env,ticket_id,db) 
     45    cursor = db.cursor() 
     46    cursor.execute("SELECT newvalue,time,ticket ,field from ticket_change where ticket=%s" 
     47                   " and field=%s"  
     48                   " order by time",(ticket_id,'status')) 
     49    history=[(row[0],to_datetime(row[1])) for row in cursor] 
     50    if new_status: 
     51        history.append((new_status,new_time)) 
     52     
     53    result ={} 
     54    for new_status,time in history: 
     55        #orderの順に日付が入ることを規定する 
     56        #古い更新から見ていき、 
     57        #新しいステータスより前のステータスが空なら日付を入れる 
     58        #新しいステータスより後のステータスは強制的に空にする 
     59        idx = order.index(new_status) 
     60        formated_date = format_date(to_datetime(time)) 
     61         
     62        for m_idx in range(len(order)-1, 0,-1): 
     63            if not order[m_idx] in custom_fields: 
     64                continue 
     65 
     66            m_field = custom_fields[order[m_idx]] 
     67            if not m_field in result: 
     68                result[m_field] = None 
     69 
     70            if idx==m_idx: 
     71                result[m_field]=formated_date 
     72            elif idx<m_idx: 
     73                result[m_field]=None 
     74            else: 
     75                if result[m_field]==None: 
     76                    result[m_field]=formated_date 
     77                else: 
     78                    formated_date=result[m_field] 
     79    return result 
    12180 
    12281     
    123     cursor = db.cursor() 
    124     cursor.execute("SELECT ticket,field,newvalue,oldvalue,time from ticket_change where ticket=%s" 
    125                    " and field=%s"  
    126                    " order by time",(ticket_id,'status')) 
    127      
    128     _assigned='assigned' 
    129     _accepted='accepted' 
    130     _closed='closed' 
    131     _reopened ='reopened' 
    132     # see http://trac.edgewall.org/wiki/TracWorkflow 
    133  
    134     #member={_assigned:0,_accepted:1,_repoened:2,_closed:3} 
    135     order=[_assigned,_accepted,_reopened,_closed] 
    136     member=[_assigned,_accepted,_closed] 
    137     dates = {_assigned:None,_accepted:None,_closed:None,_reopened:None} 
    138     #orderの順に日付が入ることを規定する 
    139     #古い更新から見ていき、 
    140     #新しいステータスより前のステータスが空なら日付を入れる 
    141     # ただし、skip_enabled はからになることを許す。 
    142     #新しいステータスより後のステータスは強制的に空にする 
    143     for ticket,field,newvalue,oldvalue,time in cursor: 
    144         if newvalue in order: 
    145             idx = order.index(newvalue) 
    146             dates[newvalue] = time 
    147             for after in order[idx+1:]: 
    148                 dates[after]=None 
    149     for target in member: 
    150         if dates[target]: 
    151             idx = order.index(target) 
    152             for pre in order[:idx]: 
    153                 if dates[pre]==None or dates[pre]> dates[target]: 
    154                     if pre in member: 
    155                         dates[pre]=dates[target] 
    156  
    157     cursor = db.cursor()         
    158     for m in dates: 
    159         if dates[m] != None: 
    160             cursor.execute("insert into ticket_status_dt (ticket,status,time) " 
    161                            "values(%s,%s,%s)", (ticket_id,m,dates[m])) 
    162  
    163      
    164     for m in dates: 
    165         field_name ="last_"+m 
    166         formated_date = format_date(to_datetime(dates[m])) 
    167         cursor.execute("SELECT value from ticket_custom " 
    168                        "where ticket=%s and name=%s",(ticket_id,field_name)) 
    169         row = cursor.fetchone() 
    170         if row: 
    171             if dates[m] != None: 
    172                 if row[0]!=formated_date: 
    173                     cursor.execute("UPDATE ticket_custom SET value=%s " 
    174                                    "where ticket=%s and name=%s", 
    175                                    (formated_date,ticket_id,field_name)) 
    176                  
    177             else: 
    178                     cursor.execute("DELETE FROM ticket_custom " 
    179                                    "where ticket=%s and name=%s", 
    180                                    (ticket_id,field_name)) 
    181         else: 
    182             if dates[m] != None: 
    183                 cursor.execute("INSERT into ticket_custom (ticket,name,value)" 
    184                                "values (%s,%s,%s) ", 
    185                                (ticket_id,field_name,formated_date)) 
    186                  
    187  
    188     if handle_ta: 
    189         db.commit() 
    190              
    191  
    192 def delete_status_log(env,ticket_id,db=None): 
    193     if not db: 
    194         db = env.get_db_cnx() 
    195         handle_ta = True 
    196     else: 
    197         handle_ta = False 
    198  
    199     #db, handle_ta = self._get_db_for_write(db) 
    200     cursor = db.cursor() 
    201     cursor.execute("DELETE FROM ticket_status_dt WHERE ticket=%s", (ticket_id,)) 
    202  
    203     if handle_ta: 
    204         db.commit() 
    205      
  • platform/trac/plugins/querychart/trunk/setup.py

    r17195 r25970  
    55setup( 
    66    name='TracQueryChart', 
    7     version='0.1', 
     7    version='0.2', 
    88    author='Kazuya Hirobe', 
    9     author_email='', 
     9    author_email = "k.hirobe@gmail.com", 
     10    description = "Provides macro to draw ticket chart.", 
     11    license = "New BSD", 
     12    keywords = "trac plugin chart ticket query", 
    1013    url='', 
    11     description='Macro whick draw ticket graph with flot', 
    1214    zip_safe=True, 
    1315    packages=['querychart'],