TracWebAdminDevelopment: trac-0.8.1-webadmin-patch.diff

File trac-0.8.1-webadmin-patch.diff, 32.9 kB (added by jeoffwilks@gmail.com, 7 years ago)

Brad's webadmin patch-05, modified to work with Debian Sarge 'trac' package installation. (Trac version 0.8.1-2, based on rev 1310)

  • htdocs/css/admin.css

    old new  
     1 
     2td.targets { 
     3 padding-right: 2em; 
     4} 
     5 
     6#targets_nav ul { 
     7 padding: 0px; 
     8} 
     9 
     10#targets_nav ul li a { 
     11 list-style: none; 
     12 display: block; 
     13 padding: .25em .25em; 
     14 padding-left: 1em; 
     15 padding-right: 1em; 
     16} 
     17 
     18#targets_nav li.target { 
     19 list-style: none; 
     20 border: 1px solid transparent; 
     21} 
     22 
     23#targets_nav li.curr_target {  
     24 list-style: none; 
     25 color: #000;  
     26 background: #f7f7f7; 
     27 border: 1px solid #fb2; 
     28} 
     29 
     30span.curr_target { 
     31 color: red; 
     32} 
     33 
     34table.listing { 
     35 margin-top: 0; 
     36} 
     37 
     38.addnew { 
     39 text-align: center; 
     40 font-size: 85%; 
     41 font-weight: bold; 
     42 border solid 1px lightgray; 
     43} 
     44 
     45/* Styles for the editor form */ 
     46#edit fieldset { margin: 1em 0 } 
     47#edit em { color: #888; font-size: smaller } 
     48#edit .disabled em { color: #d7d7d7 } 
     49#edit .field { margin-top: 1.3em } 
     50#edit label { padding-left: .2em } 
     51#edit textarea#description { width: 97% } 
  • templates/admin.cs

    old new  
     1<?cs set:html.stylesheet = 'css/admin.css' ?> 
     2<?cs include "header.cs"?> 
     3<?cs include "macros.cs"?> 
     4 
     5<div id="ctxtnav" class="nav"> 
     6 <h2>Admin Navigation</h2> 
     7 <ul> 
     8  <?cs if:admin.general_href ?> 
     9   <li><a href="<?cs var:admin.general_href ?>">General Settings</a></li> 
     10  <?cs /if ?> 
     11  <?cs if:admin.general_href ?> 
     12   <li><a href="<?cs var:admin.ticket_href ?>">Ticket Attributes</a></li> 
     13  <?cs /if ?> 
     14  <?cs if:admin.user_href ?> 
     15   <li class="last"><a href="<?cs var:admin.user_href ?>">User Management</a></li> 
     16  <?cs /if ?> 
     17 </ul> 
     18</div> 
     19 
     20<?cs if:admin.type == "general" ?> 
     21 <?cs include:"admin-general.cs" ?> 
     22<?cs elif:admin.type == "ticket" ?> 
     23 <?cs include:"admin-ticket.cs" ?> 
     24<?cs elif:admin.type == "user" ?> 
     25 <?cs include:"admin-user.cs" ?> 
     26<?cs /if ?> 
     27 
     28 
     29<div id="help"> 
     30 <strong>Note:</strong> See <a href="<?cs 
     31   var:trac.href.wiki ?>/TracWebAdmin">TracWebAdmin</a> 
     32   for help on using the administration pages. 
     33</div> 
     34 
     35 
     36<?cs include:"footer.cs"?> 
  • templates/admin-general.cs

    old new  
     1<div id="content" class="admin"> 
     2    <h1>General Settings</h1> 
     3 
     4</div> 
  • templates/admin-ticket.cs

    old new  
     1<div id="content" class="admin"> 
     2    <h1>Ticket Attributes</h1> 
     3 <table class="admin"> 
     4  <tr> 
     5   <td class="targets" valign="top"> 
     6    <h3>Edit attributes of type:</h3> 
     7    <div id="targets_nav"> 
     8     <ul><?cs each:target = admin.targets ?> 
     9      <li class="<?cs if:target == admin.curr_target ?>curr_target<?cs  
     10       else ?>target<?cs /if ?>"> 
     11       <a href="<?cs var:cgi_location ?><?cs var:admin.path ?><?cs  
     12       var:target ?>"><?cs var:target ?></a> 
     13      </li><?cs /each ?> 
     14     </ul> 
     15    </div> 
     16   </td> 
     17   <td class="attribs" valign="top"> 
     18    <?cs if:admin.mode == "view" ?> 
     19     <h3>Attributes of type:  
     20      <span class="curr_target"><?cs var:admin.curr_target ?></span> 
     21     </h3> 
     22     <?cs if attrib.message ?> 
     23      <div class="error"><?cs var attrib.message ?></div> 
     24     <?cs else ?> 
     25      <?cs def:attrib_hdr(header) ?> 
     26      <a class="addnew" href="<?cs  
     27       var:cgi_location ?><?cs var:admin.path ?><?cs var:admin.curr_target 
     28       ?>?action=new">add new <?cs var:admin.curr_target ?></a> 
     29      <table id="attriblist" class="listing" style="margin-top: 0.5em;"> 
     30       <thead> 
     31        <tr> 
     32         <?cs set numcols = #0 ?> 
     33         <?cs each header = attrib.headers ?> 
     34          <?cs if $header ?> 
     35           <th><?cs var:header ?></th> 
     36          <?cs /if ?> 
     37          <?cs set numcols = numcols + #1 ?> 
     38         <?cs /each ?> 
     39         <th colspan="2"></th> 
     40        </tr> 
     41       </thead> 
     42      <?cs /def ?> 
     43  
     44      <?cs def:attrib_cell(class,contents) ?> 
     45       <td class="<?cs var:$class ?>"> 
     46        <?cs if $contents.type == "date" ?> 
     47         <?cs var:$contents.date ?> 
     48        <?cs else ?> 
     49         <?cs var:$contents ?> 
     50        <?cs /if ?> 
     51         
     52       </td> 
     53       <?cs set col = $col + #1 ?> 
     54      <?cs /def ?> 
     55     <?cs /if ?> 
     56      <?cs set idx = #0 ?> 
     57      <?cs set group = '' ?> 
     58  
     59 
     60      <?cs each row = attrib.items ?> 
     61       <?cs if group != row.__group__ || idx == #0 ?> 
     62         <?cs if:idx != #0 ?></tbody><?cs /if ?> 
     63         <?cs set group = row.__group__ ?> 
     64         <?cs call:attrib_hdr(group) ?> 
     65         <tbody> 
     66       <?cs /if ?> 
     67 
     68       <?cs set rstem='' ?> 
     69       <?cs if idx % #2 ?> 
     70         <?cs set row_class=$rstem+'even' ?> 
     71       <?cs else ?> 
     72         <?cs set row_class=$rstem+'odd' ?> 
     73       <?cs /if ?> 
     74 
     75       <tr class="<?cs var: row_class ?>"> 
     76       <?cs set idx = idx + #1 ?> 
     77       <?cs set col = #0 ?> 
     78       <?cs each cell = row ?> 
     79        <?cs if $col == 0 ?> 
     80         <?cs set link = $cell ?> 
     81        <?cs /if ?> 
     82        <?cs call:attrib_cell(name(cell), $cell) ?> 
     83       <?cs /each ?> 
     84       <td><a href="<?cs var:cgi_location ?><?cs var:admin.path ?><?cs 
     85        var:admin.curr_target ?>?id=<?cs var:link ?>&action=edit">edit 
     86        </a></td> 
     87       <td><a href="<?cs var:cgi_location ?><?cs var:admin.path ?><?cs 
     88        var:admin.curr_target ?>?id=<?cs var:link ?>&action=delete">delete 
     89        </a></td> 
     90       </tr> 
     91     <?cs /each ?> 
     92    </tbody> 
     93   </table> 
     94  <?cs if attrib.numrows > 20 ?> 
     95    <a class="addnew" href="<?cs  
     96     var:cgi_location ?><?cs var:admin.path ?><?cs var:admin.curr_target 
     97     ?>?action=new">add new <?cs var:admin.curr_target ?></a> 
     98  <?cs /if ?> 
     99   
     100   
     101    <?cs elif:admin.mode == "edit" || admin.mode == "new" ?> 
     102    <h3><?cs var:admin.mode ?> <?cs var:admin.curr_target ?>: <span  
     103     class="curr_target"> 
     104     <?cs if:admin.mode == "edit" ?><?cs var:admin.attrib.name ?><?cs /if ?> 
     105     </span> 
     106    </h3> 
     107            <form id="edit" action="<?cs var:cgi_location ?>" method="post"> 
     108            <input type="hidden" name="mode" value="admin" /> 
     109            <input type="hidden" name="target" value="<?cs  
     110             var:admin.curr_target ?>" /> 
     111            <input type="hidden" name="id" value="<?cs  
     112             var:admin.attrib.name ?>" /> 
     113            <input type="hidden" name="action" value="commit_changes" /> 
     114      <?cs each:fld = admin.data ?> 
     115       <div class="field"> 
     116        <fieldset class="iefix"> 
     117         <label for="<?cs var:fld.fieldname ?>"><?cs var:fld.fieldname ?><?cs if  
     118          fld.fieldtype == "wiki" ?> (you may use <a tabindex="42" href="<?cs 
     119          var:trac.href.wiki ?>/WikiFormatting">WikiFormatting</a> here):<?cs  
     120          /if ?></label><br /> 
     121         <?cs if fld.fieldtype == "string" ?> 
     122          <input type="text"  
     123           id="<?cs var:fld.fieldname ?>"  
     124           name="<?cs var:fld.fieldname ?>"  
     125           size="32"  
     126           value="<?cs var:fld.value ?>" /> 
     127         <?cs elif fld.fieldtype == "date" ?> 
     128          <input type="text"  
     129           id="<?cs var:fld.fieldname ?>"  
     130           name="<?cs var:fld.fieldname ?>"  
     131           size="32"  
     132           value="<?cs var:fld.value ?>" /> 
     133           <em>Format: <?cs var:admin.attrib.date_hint ?></em> 
     134         <?cs elif fld.fieldtype == "wiki" ?> 
     135          <textarea  
     136           id="<?cs var:fld.fieldname ?>"  
     137           name="<?cs var:fld.fieldname ?>"  
     138           class="wikitext"  
     139           rows="10" cols="78"><?cs var:fld.value ?></textarea> 
     140         <?cs else ?> 
     141          invalid type 
     142         <?cs /if ?> 
     143        </fieldset> 
     144       </div> 
     145      <?cs /each ?> 
     146      <div class="buttons"> 
     147       <?cs if:admin.mode == "new" 
     148        ?><input type="submit" name="save" value="Add Attribute" /><?cs 
     149       else 
     150        ?><input type="submit" name="save" value="Save Changes" /><?cs 
     151       /if ?> 
     152       <input type="submit" name="cancel" value="Cancel" /> 
     153       <?cs if:admin.mode == "edit" ?> 
     154        <p>Note: Changing the field 'name' will result in all tickets with that 
     155          attribute being updated to the new value.</p><?cs /if ?> 
     156      </div> 
     157      <script type="text/javascript" src="<?cs 
     158       var:htdocs_location ?>js/wikitoolbar.js"></script>        
     159     </form> 
     160    <?cs elif:admin.mode == "delete" ?> 
     161    <form id="delete" action="<?cs var:cgi_location ?>" method="post"> 
     162     <input type="hidden" name="mode" value="admin" /> 
     163         <input type="hidden" name="target" value="<?cs  
     164          var:admin.curr_target ?>" /> 
     165         <input type="hidden" name="id" value="<?cs var:admin.attrib.name ?>" /> 
     166         <input type="hidden" name="action" value="confirm_delete" /> 
     167     <p><strong>Are you sure you want to delete <?cs var:admin.curr_target ?>: 
     168      <?cs var:admin.attrib.name ?>?</strong></p> 
     169     <input type="checkbox" id="chk_retarget" name="chk_retarget"  
     170      checked="checked" 
     171      onclick="enableControl('target', this.checked)"/> 
     172     <label for="retarget">Retarget associated tickets to  
     173      <?cs var:admin.curr_target ?></label> 
     174     <select name="retarget" id="retarget"> 
     175      <option value="">None</option><?cs 
     176       each:other = retargets ?><?cs if:other != admin.attrib.name ?> 
     177        <option><?cs var:other ?></option><?cs  
     178       /if ?><?cs /each ?> 
     179     </select> 
     180     <div class="buttons"> 
     181      <input type="submit" name="cancel" value="Cancel" /> 
     182      <input type="submit" name="delete" value= 
     183       "Delete <?cs var:admin.curr_target ?>" /> 
     184     </div> 
     185    </form> 
     186    <?cs /if ?> 
     187   </td> 
     188  </tr> 
     189 </table> 
     190 
     191 
     192 
     193 
     194</div> 
  • templates/admin-user.cs

    old new  
     1<div id="content" class="admin"> 
     2    <h1>User Management</h1> 
     3 
     4</div> 
  • templates/header.cs

    old new  
    115115  call:navlink("New Ticket", trac.href.newticket, "newticket", 
    116116               trac.acl.TICKET_CREATE, "7") ?><?cs 
    117117  call:navlink("Search", trac.href.search, "search", 
    118                trac.acl.SEARCH_VIEW, "4") ?></ul> 
     118               trac.acl.SEARCH_VIEW, "4") ?><?cs 
     119  call:navlink("Admin", trac.href.admin, "admin", 
     120               trac.acl.TRAC_ADMIN, "") ?></ul> 
    119121</div> 
    120122 
    121123<div id="main"> 
  • trac/Admin.py

    old new  
     1# -*- coding: iso8859-1 -*- 
     2# 
     3# Copyright (C) 2005 Edgewall Software 
     4# Copyright (C) 2005 Brad Anderson <brad@dsource.org> 
     5# 
     6# Trac is free software; you can redistribute it and/or 
     7# modify it under the terms of the GNU General Public License as 
     8# published by the Free Software Foundation; either version 2 of the 
     9# License, or (at your option) any later version. 
     10# 
     11# Trac is distributed in the hope that it will be useful, 
     12# but WITHOUT ANY WARRANTY; without even the implied warranty of 
     13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
     14# General Public License for more details. 
     15# 
     16# You should have received a copy of the GNU General Public License 
     17# along with this program; if not, write to the Free Software 
     18# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
     19# 
     20# Author: Brad Anderson <brad@dsource.org> 
     21 
     22import time 
     23 
     24import perm 
     25import urllib 
     26import string 
     27from util import * 
     28from Module import Module 
     29 
     30 
     31 
     32class Admin(Module): 
     33    template_name = 'admin.cs' 
     34 
     35    def render(self): 
     36         
     37        self.req.hdf.setValue('title', 'Admin') 
     38         
     39        if self.perm.has_permission(perm.TRAC_ADMIN): 
     40            self.req.hdf.setValue('admin.general_href', 
     41                             self.env.href.admin('general', None)) 
     42         
     43        if self.perm.has_permission(perm.TICKET_ADMIN): 
     44            self.req.hdf.setValue('admin.ticket_href', 
     45                             self.env.href.admin('ticket', 'component')) 
     46         
     47        if self.perm.has_permission(perm.TRAC_ADMIN): 
     48            self.req.hdf.setValue('admin.user_href', 
     49                             self.env.href.admin('user', 'users')) 
     50                              
     51        type = self.args.get('type', 'ticket').lower() 
     52        self.req.hdf.setValue('admin.type', type) 
     53        self.req.hdf.setValue('admin.path', '/admin/%s/' % type) 
     54         
     55        if type == 'general': 
     56            self.admin = AdminGeneral(self) 
     57        elif type == 'ticket': 
     58            self.admin = AdminTicket(self) 
     59        elif type == 'user': 
     60            self.admin = AdminUser(self) 
     61         
     62        self.admin.render() 
     63         
     64class AdminGeneral(Admin): 
     65    def __init__(self, admin_parent): 
     66        self.req = admin_parent.req 
     67    self.perm = admin_parent.perm 
     68        self.env = admin_parent.env 
     69        self.db = admin_parent.db 
     70        self.args = admin_parent.args 
     71     
     72    def render (self): 
     73        self.perm.assert_permission(perm.TRAC_ADMIN) 
     74         
     75     
     76class AdminTicket(Admin): 
     77    def __init__(self, admin_parent): 
     78    self.req = admin_parent.req 
     79        self.perm = admin_parent.perm 
     80        self.env = admin_parent.env 
     81        self.db = admin_parent.db 
     82    self.args = admin_parent.args 
     83 
     84    def save_attrib(self, target, id): 
     85        self.perm.assert_permission(perm.TRAC_ADMIN) 
     86        if self.args.has_key('save'): 
     87            name = self.args.get('name', '') 
     88            if not name: 
     89                raise TracError('You must provide a name for the %s.' % target, 
     90                                'Required Field Missing') 
     91             
     92            if id == '-1': 
     93                self.create_attrib(target, name) 
     94            else: 
     95                self.update_attrib(target, id, name) 
     96 
     97    def formatVal(self, val, fieldtype): 
     98        """formats the val parameter to be better suited (escaped) for SQL 
     99           strings to be executed by cursor.execute()""" 
     100         
     101        # TODO: handle single and double quotes in val right here 
     102         
     103        # check some things based on metadata, add quotes to val 
     104        if fieldtype == 'date': 
     105            if val == '': 
     106                val = '0' 
     107            else: 
     108                val = "%s" % parse_date(val) 
     109        elif fieldtype in ('string','wiki') and val == '': 
     110            val = 'null' 
     111        else: 
     112            val = "'%s'" % val 
     113        return val 
     114         
     115    def create_attrib(self, target, name): 
     116         
     117        self.perm.assert_permission(perm.TRAC_ADMIN) 
     118        cursor = self.db.cursor() 
     119        self.env.log.debug("Creating new %s '%s'" % (target, name)) 
     120         
     121        meta = self.get_attrib_metadata(target) 
     122        fields = meta[0] 
     123        types  = meta[1] 
     124        table  = meta[2] 
     125        where  = meta[3] 
     126        values = [] 
     127         
     128        # loop thru fields, getting values list 
     129    flds = zip(fields, types) 
     130        for f in flds: 
     131            # add to values 
     132            val = self.args.get(f[0], '') 
     133            formattedval = self.formatVal(val, f[1]) 
     134        # self.env.log.debug("create_attrib(): field=%s val=%s type=%s fmtd=%s" % (f[0], val, f[1], formattedval) ) 
     135            values.append( formattedval ) 
     136 
     137        # special case for enum 
     138        if table == "enum": 
     139            fields.insert(0, 'type') 
     140            values.insert(0, self.formatVal(target, 'string') ) 
     141             
     142        # self.env.log.debug("create_attrib() fields: %s" % fields) 
     143        # self.env.log.debug("create_attrib() values: %s" % values) 
     144        
     145    fieldlist = string.join(fields, ',') 
     146        valueslist = string.join(values, ',') 
     147                     
     148        # self.env.log.debug("create_attrib() fieldlist : %s" % (fieldlist)) 
     149        # self.env.log.debug("create_attrib() valueslist: %s" % (valueslist)) 
     150             
     151        sql = "INSERT INTO %s (%s) VALUES (%s)" % (table, fieldlist, valueslist) 
     152        self.env.log.debug("create_attrib() sql      : %s" % (sql)) 
     153         
     154        cursor.execute(sql) 
     155        self.db.commit() 
     156        self.req.redirect(self.env.href.admin('ticket', target)) 
     157 
     158    def update_attrib(self, target, id, name): 
     159         
     160        self.perm.assert_permission(perm.TRAC_ADMIN) 
     161        cursor = self.db.cursor() 
     162        self.env.log.debug( "Updating %s '%s'" % (target,id) ) 
     163 
     164        if self.args.has_key('save'): 
     165            self.env.log.info("Updating %s field of all tickets " 
     166                              "associated with %s '%s'" % (target, target, id) ) 
     167            cursor.execute("UPDATE ticket SET %s = '%s' " 
     168                           "WHERE %s = '%s'" % (target, name, target, id) ) 
     169            self.db.commit() 
     170 
     171            self.env.log.info("Updating %s '%s' to '%s'" % (target, id, name) ) 
     172            meta = self.get_attrib_metadata(target) 
     173            fields = meta[0] 
     174            types  = meta[1] 
     175            table  = meta[2] 
     176            where  = meta[3] 
     177            set = "" 
     178             
     179            flds = zip(fields,types) 
     180            for f in flds: 
     181                val = self.args.get(f[0], "") 
     182                val = self.formatVal(val, f[1]) 
     183 
     184                self.env.log.debug( "update_attrib:  %s %s" % (f[0],val) ) 
     185                set += ", %s=%s" % (f[0], val) 
     186            set = set[2:] 
     187             
     188            if len(where) > 0: 
     189                where += " and " 
     190            where += "name='%s'" % id 
     191             
     192            sql = "update %s set %s where %s" % (table, set, where) 
     193            # raise TracError("save_attrib sql: '%s'" % sql) 
     194            cursor.execute(sql) 
     195            self.db.commit() 
     196             
     197            cursor.close() 
     198             
     199        self.req.redirect(self.env.href.admin('ticket', target)) 
     200             
     201    def delete_attrib(self, target, id): 
     202        self.perm.assert_permission(perm.TRAC_ADMIN) 
     203         
     204        if self.args.has_key('delete'): 
     205            cursor = self.db.cursor() 
     206            if self.args.has_key('chk_retarget'): 
     207                retarget = self.args.get('retarget') 
     208                if retarget: 
     209                    self.env.log.info('Retargeting %s field of all ' 
     210                        'tickets associated with %s=%s to %s=%s' %  
     211                        (target, target, id, target, retarget)) 
     212                    cursor.execute( 'UPDATE ticket SET %s = %s ' 
     213                        'WHERE %s = %s', (target, retarget, target, id) ) 
     214 
     215                else: 
     216                    self.env.log.info('Resetting %s field of all ' 
     217                        'tickets associated with %s=%s' % (target, target, id)) 
     218                    cursor.execute( 'UPDATE ticket SET %s = NULL ' 
     219                        'WHERE %s = %s', (target, target, id) ) 
     220 
     221 
     222            self.env.log.debug('Deleting %s %s' % (target, id)) 
     223            meta = self.get_attrib_metadata(target) 
     224            table  = meta[2] 
     225            where  = meta[3] 
     226             
     227            sql  = "DELETE FROM %s " % table 
     228            sql += "WHERE name = %s " % self.formatVal(id, 'string') 
     229            if where: 
     230                sql += "AND %s " % where 
     231            self.env.log.debug('delete_attrib - sql(delete from target ' 
     232                               'table): %s' % (sql)) 
     233            cursor.execute(sql) 
     234            self.db.commit() 
     235             
     236        self.req.redirect(self.env.href.admin('ticket', target)) 
     237         
     238    # all of this info could be in the db as a metadata table 
     239    def get_attrib_metadata(self, target): 
     240         
     241        if target == 'component': 
     242            fields = ['name', 'owner'] 
     243            types = ['string', 'string'] 
     244            table = 'component' 
     245            where = '' 
     246        elif target == 'version': 
     247            fields = ['name', 'time'] 
     248            types = ['string', 'date'] 
     249            table = 'version' 
     250            where = '' 
     251        elif target == 'severity' or target == 'priority' or \ 
     252             target == 'status' or target == 'resolution': 
     253            fields = ['name', 'value'] 
     254            types = ['string', 'string'] 
     255            table='enum' 
     256            where='type = \'%s\'' % target 
     257        elif target == 'milestone': 
     258            fields = ['name', 'time', 'descr'] 
     259            types = ['string', 'date', 'wiki'] 
     260            table = 'milestone' 
     261            where = '' 
     262         
     263        meta = (fields, types, table, where) 
     264        return meta 
     265                 
     266    def get_attrib_data(self, target, id): 
     267         
     268        meta = self.get_attrib_metadata(target) 
     269        fields = meta[0] 
     270        types  = meta[1] 
     271        table  = meta[2] 
     272        where  = meta[3] 
     273 
     274        if id != -1: 
     275            sql_select = string.join(fields, ',') 
     276            sql = 'SELECT %s ' \ 
     277                  'FROM %s ' \ 
     278                  'WHERE name = \'%s\'' % (sql_select, table, id) 
     279            if where: 
     280                sql += ' and %s' % where 
     281             
     282            cursor = self.db.cursor() 
     283            cursor.execute(sql) 
     284            row = cursor.fetchone() 
     285            cursor.close() 
     286            if not row: 
     287                raise TracError('Attribute \'%s\' does not exist.' % id, 
     288                                'Invalid Attribute') 
     289                                 
     290            values = row 
     291        else: 
     292            # new attrib value, so fill values with blanks 
     293            values = [] 
     294            for field in fields: 
     295                values.append('') 
     296         
     297        return [values, fields, types] 
     298 
     299    def get_target_attributes(self, target='component'): 
     300         
     301        sql_select = '' 
     302     
     303        meta = self.get_attrib_metadata(target) 
     304        fields = meta[0] 
     305        types  = meta[1] 
     306        table  = meta[2] 
     307        where  = meta[3] 
     308         
     309        sql_select = string.join(fields, ',') 
     310        sql = 'SELECT %s ' \ 
     311              'FROM %s ' % (sql_select, table) 
     312        if where: 
     313            sql += 'WHERE %s' % where 
     314         
     315        cursor = self.db.cursor() 
     316        cursor.execute(sql) 
     317         
     318        # FIXME: fetchall should probably not be used. 
     319        info = cursor.fetchall() 
     320        cols = cursor.description 
     321 
     322        return [cols, info, types] 
     323 
     324 
     325    def render (self): 
     326        self.perm.assert_permission(perm.TICKET_ADMIN) 
     327         
     328    target = self.args.get('target', 'component') 
     329        # to highlight the current target on page 
     330    add_to_hdf(target, self.req.hdf, 'admin.curr_target')  
     331        # self.env.log.debug("admin target '%s'" % target) 
     332 
     333        action = self.args.get('action', 'view') 
     334 
     335        if self.args.has_key('id'): 
     336            id = urllib.unquote( self.args.get('id', '') ) 
     337             
     338        # self.env.log.debug("admin id '%s'" % id) 
     339 
     340         
     341        if action == 'new': 
     342            self.render_editor(target, -1) 
     343        elif action == 'edit': 
     344            self.render_editor(target, id) 
     345        elif action == 'delete': 
     346            self.render_confirm(target, id) 
     347        elif action == 'commit_changes': 
     348            self.save_attrib(target, id) 
     349        elif action == 'confirm_delete': 
     350            self.delete_attrib(target, id) 
     351        else: 
     352            self.render_view(target) 
     353 
     354        # menu on left 
     355        targets = ['component', 'version', 'severity', 'priority', 'status', 
     356                   'resolution', 'milestone'] 
     357         
     358        # add custom fields to the list of targets for admin 
     359#  # Until they're moved into a db table and out of ini, don't bother with admin 
     360#        for f in get_custom_fields(self.env): 
     361#            if f['type'] == 'select' or f['type'] == 'radio': 
     362#                target = { 'name': f['name'] } 
     363#                targets.append(target) 
     364 
     365        add_to_hdf(targets, self.req.hdf, 'admin.targets') 
     366 
     367 
     368    def render_confirm(self, target, id): 
     369         
     370        self.req.hdf.setValue('title', 'Attribute: %s' % id) 
     371        self.req.hdf.setValue('admin.mode', 'delete')         
     372         
     373        add_to_hdf(id, self.req.hdf, 'admin.attrib.name') 
     374 
     375        # get choices for retargeting 
     376        meta = self.get_attrib_metadata(target) 
     377        table  = meta[2] 
     378        where  = meta[3] 
     379                 
     380        cursor = self.db.cursor() 
     381        if where: 
     382            where = "AND %s" % where 
     383        else: 
     384            where = "" 
     385        sql = "SELECT name FROM %s WHERE name != '' %s " \ 
     386              "ORDER BY name" % (table, where) 
     387        cursor.execute(sql) 
     388        retargets = [] 
     389        retarget_no = 0 
     390        while 1: 
     391            row = cursor.fetchone() 
     392            if not row: 
     393                break 
     394            self.req.hdf.setValue('retargets.%d' % retarget_no, row['name']) 
     395            retarget_no += 1 
     396        cursor.close() 
     397 
     398    def render_editor(self, target, id=None): 
     399 
     400        data = [] 
     401        [values, fields, types] = \ 
     402            self.get_attrib_data(target, id) 
     403 
     404        for v, f, t in zip(values, fields, types): 
     405            if t == 'date': 
     406                if v == 0 or v == '': 
     407                    v = '' 
     408                else: 
     409                    v = time.strftime('%m/%d/%Y', time.localtime(v)) 
     410            # self.env.log.debug("render_editor: value='%s', field='%s', type='%s'" % (v, f, t)) 
     411            data.append( dict([('fieldname',f),('fieldtype',t),('value',v)]) ) 
     412             
     413        if id == -1: 
     414            self.req.hdf.setValue('title', 'New Attribute') 
     415            self.req.hdf.setValue('admin.mode', 'new') 
     416        else: 
     417            self.req.hdf.setValue('title', 'Attribute: %s' % id) 
     418            self.req.hdf.setValue('admin.mode', 'edit') 
     419         
     420        add_to_hdf(data, self.req.hdf, 'admin.data') 
     421        add_to_hdf(id, self.req.hdf, 'admin.attrib.name') 
     422        add_to_hdf(get_date_format_hint(), self.req.hdf, 'admin.attrib.date_hint') 
     423 
     424    def render_view(self, target): 
     425 
     426        self.req.hdf.setValue('admin.mode', 'view') 
     427 
     428        try: 
     429            [self.cols, self.rows, self.types] = \ 
     430                self.get_target_attributes(target) 
     431        except Exception, e: 
     432            self.error = e 
     433            self.req.hdf.setValue('attrib.message', 
     434                                  'Attribute data error: %s' % e) 
     435            return None 
     436 
     437        # Convert the header info to HDF-format 
     438        idx = 0 
     439        for col in self.cols: 
     440            title=col[0].capitalize() 
     441            prefix = 'attrib.headers.%d' % idx 
     442            self.req.hdf.setValue('%s.real' % prefix, col[0]) 
     443            self.req.hdf.setValue(prefix, title) 
     444             
     445            idx = idx + 1 
     446 
     447        # Convert the rows and cells to HDF-format 
     448        row_idx = 0 
     449        for row in self.rows: 
     450            col_idx = 0 
     451            numrows = len(row) 
     452            for cell in row: 
     453                cell = str(cell) 
     454                column = self.cols[col_idx][0] 
     455                type = self.types[col_idx] 
     456                value = {} 
     457                value['type'] = type 
     458                 
     459                if type == 'date' and cell != 'None' and cell != '0': 
     460                    t = time.localtime(int(cell)) 
     461                    value['date'] = time.strftime('%m/%d/%Y', t) 
     462                    value['time'] = time.strftime('%X', t) 
     463                    value['datetime'] = time.strftime('%c', t) 
     464                    value['gmt'] = time.strftime('%a, %d %b %Y %H:%M:%S GMT', 
     465                                                 time.gmtime(int(cell))) 
     466                         
     467                prefix = 'attrib.items.%d.%s' % (row_idx, str(column)) 
     468                self.req.hdf.setValue(prefix, escape(str(cell))) 
     469                for key in value.keys(): 
     470                    self.req.hdf.setValue(prefix + '.' + key, str(value[key])) 
     471 
     472                col_idx += 1 
     473            row_idx += 1 
     474        self.req.hdf.setValue('attrib.numrows', str(row_idx)) 
     475 
     476class AdminUser(Admin): 
     477    def __init__(self, admin_parent): 
     478        self.req = admin_parent.req 
     479    self.perm = admin_parent.perm 
     480        self.env = admin_parent.env 
     481        self.db = admin_parent.db 
     482        self.args = admin_parent.args 
     483 
     484    def render (self): 
     485        self.perm.assert_permission(perm.TRAC_ADMIN) 
  • trac/core.py

    old new  
    5959    'attachment'  : ('File', 'Attachment', 0), 
    6060    'roadmap'     : ('Roadmap', 'Roadmap', 0), 
    6161    'settings'    : ('Settings', 'Settings', 0), 
    62     'milestone'   : ('Milestone', 'Milestone', 0) 
     62    'milestone'   : ('Milestone', 'Milestone', 0), 
     63    'admin'       : ('Admin', 'Admin', 0) 
    6364    } 
    6465 
    6566class TracFieldStorage(cgi.FieldStorage): 
     
    127128        if match.group(1): 
    128129            set_if_missing(args, 'id', urllib.unquote(match.group(1))) 
    129130        return args 
     131#    match = re.search('^/admin(?:/([^\?]+))?(?:/(.*)/?)?', path_info) 
     132    match = re.search('^/admin/(general|ticket|user)(?:/([^\?]+))?(?:/(.*)/?)?', path_info) 
     133    if match: 
     134        set_if_missing(args, 'mode', 'admin') 
     135        if match.group(1): 
     136            set_if_missing(args, 'type', match.group(1)) 
     137        if match.group(2): 
     138            set_if_missing(args, 'target', urllib.unquote_plus(match.group(2))) 
     139        return args 
    130140    return args 
    131141 
    132142def parse_args(command, path_info, query_string, 
     
    230240    hdf.setValue('trac.href.login', env.href.login()) 
    231241    hdf.setValue('trac.href.logout', env.href.logout()) 
    232242    hdf.setValue('trac.href.settings', env.href.settings()) 
     243    hdf.setValue('trac.href.admin', env.href.admin('ticket', 'component')) 
    233244    hdf.setValue('trac.href.homepage', 'http://trac.edgewall.com/') 
    234245    hdf.setValue('trac.version', __version__) 
    235246    hdf.setValue('trac.time', time.strftime('%c', time.localtime())) 
  • trac/Href.py

    old new  
    9797            href = href + '?show=' + show 
    9898        return href 
    9999 
     100    def admin(self, type, target): 
     101        if target == None: 
     102            target='' 
     103        href = href_join(self.base, 'admin/%s/%s' % (type, target)) 
     104        return href 
     105 
    100106    def milestone(self, milestone, action=None): 
    101107        params = [] 
    102108        if milestone: 
  • trac/Milestone.py

    old new  
    114114                datestr = self.args.get('date', '') 
    115115                date = 0 
    116116                if datestr: 
    117                     date = self.parse_date(datestr) 
     117                    date = parse_date(datestr) 
    118118            descr = self.args.get('descr', '') 
    119119            if not id: 
    120120                self.create_milestone(name, date, descr) 
     
    125125        else: 
    126126            self.req.redirect(self.env.href.roadmap()) 
    127127 
    128     def parse_date(self, datestr): 
    129         seconds = None 
    130         datestr = datestr.strip() 
    131         for format in ['%x %X', '%x, %X', '%X %x', '%X, %x', '%x', '%c', 
    132                        '%b %d, %Y']: 
    133             try: 
    134                 date = time.strptime(datestr, format) 
    135                 seconds = time.mktime(date) 
    136                 break 
    137             except ValueError: 
    138                 continue 
    139         if seconds == None: 
    140             raise TracError('%s is not a known date format.' % datestr, 
    141                             'Invalid Date Format') 
    142         return seconds 
    143  
    144128    def create_milestone(self, name, date=0, descr=''): 
    145129        self.perm.assert_permission(perm.MILESTONE_CREATE) 
    146130        if not name: 
  • trac/util.py

    old new  
    268268def get_date_format_hint(): 
    269269    t = time.localtime(0) 
    270270    t = (1999, 10, 29, t[3], t[4], t[5], t[6], t[7], t[8]) 
    271     tmpl = time.strftime('%x', t) 
     271    tmpl = time.strftime('%m/%d/%Y', t) 
    272272    return tmpl.replace('1999', 'YYYY', 1).replace('99', 'YY', 1) \ 
    273273               .replace('29', 'DD', 1).replace('10', 'MM') 
    274274 
    275275 
     276def parse_date(datestr): 
     277    seconds = None 
     278    datestr = datestr.strip() 
     279    for format in ['%m/%d/%Y', '%x', '%x %X', '%x, %X', '%X %x', '%X, %x', '%x', '%c', 
     280                   '%b %d, %Y']: 
     281        try: 
     282            date = time.strptime(datestr, format) 
     283            seconds = time.mktime(date) 
     284            break 
     285        except ValueError: 
     286            continue 
     287    if seconds == None: 
     288        raise TracError('%s is not a known date format.' % datestr, 
     289                        'Invalid Date Format') 
     290    return seconds 
     291 
    276292class TracError(Exception): 
    277293    def __init__(self, message, title=None, show_traceback=0): 
    278294        Exception.__init__(self, message)