Package moap :: Package command :: Module tracadmin
[hide private]
[frames] | no frames]

Source Code for Module moap.command.tracadmin

  1  # -*- Mode: Python -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3   
  4  import os 
  5   
  6  from moap.util import util, usermap 
  7   
  8  # table name, column, filter query, multiple values possible 
  9  USER_TABLES = [ 
 10      ('permission',        'username',  None, False), 
 11      ('auth_cookie',       'name',      None, False), 
 12  # it looks like the lines with authenticated == 0 are hashes, and with == 1 
 13  # are usernames 
 14      ('session',           'sid',       'authenticated=1', False), 
 15      ('session_attribute', 'sid',       'authenticated=1', False), 
 16      ('wiki',              'author',    None, False), 
 17      ('attachment',        'author',    None, False), 
 18      ('ticket',            'owner',     None, False), 
 19      ('ticket',            'reporter',  None, False), 
 20      ('ticket_change',     'author',    None, False), 
 21      ('ticket_change',     'oldvalue', 
 22          "(field='qa_contact' OR field='owner')", True), 
 23      ('ticket_change',     'newvalue',  
 24          "(field='qa_contact' OR field='owner' OR field='reporter')", True), 
 25  ] 
 26   
27 -class List(util.LogCommand):
28 summary = "list users in Trac database" 29
30 - def do(self, args):
31 users = {} 32 33 cxn = self.parentCommand.parentCommand.cxn 34 c = cxn.cursor() 35 36 for table, column, where, multiple in USER_TABLES: 37 query = "SELECT %s FROM %s" % (column, table) 38 if where: 39 query += " WHERE %s" % where 40 41 self.debug('Executing query %s' % query) 42 c.execute(query) 43 for row in c: 44 if not row[0]: 45 continue 46 47 # fields like qa_contact can have multiple users, separated 48 # with , 49 if multiple: 50 names = row[0].split(',') 51 if len(names) > 1: 52 self.debug('Found multiple names: %s' % row[0]) 53 for name in names: 54 users[name] = True 55 else: 56 # verification 57 if row[0].find(',') > -1: 58 self.warning( 59 "table '%s', column '%s'" 60 " has multiple value '%s'." % ( 61 table, column, row[0])) 62 continue 63 users[row[0]] = True 64 65 # filter out "special" users 66 for user in ['', 'anonymous', 'authenticated']: 67 try: 68 del users[user] 69 except KeyError: 70 pass 71 72 userList = users.keys() 73 userList.sort() 74 for user in userList: 75 self.stdout.write("%s\n" % user)
76
77 -class Rename(util.LogCommand):
78 summary = "rename a user in the Trac database" 79 80 description = """Rename a user in the Trac database. 81 82 This updates all tables in the trac database where usernames are stored. 83 This operation obviously is non-reversible, so use with care. 84 85 Only tested with the sqlite backend of Trac, but since it uses the Trac 86 database API it should work with any backend. 87 """ 88
89 - def addOptions(self):
90 self.parser.add_option('-u', '--usermap', 91 action="store", dest="usermap", 92 help="path to a file containing oldname:newname entries")
93
94 - def do(self, args):
95 umap = usermap.UserMap() 96 97 if self.options.usermap: 98 umap.parseFromPath(self.options.usermap) 99 else: 100 try: 101 old = args[0] 102 except IndexError: 103 self.stderr.write( 104 'Please specify the old username to change.\n') 105 return 3 106 107 try: 108 new = args[1] 109 except IndexError: 110 self.stderr.write( 111 'Please specify the new username to change to.\n') 112 return 3 113 114 umap = usermap.UserMap() 115 umap.parse("%s:%s" % (old, new)) 116 117 for old, new in umap: 118 self.renameUser(old, new)
119
120 - def renameUser(self, old, new):
121 self.debug('Renaming %s to %s' % (old, new)) 122 123 cxn = self.parentCommand.parentCommand.cxn 124 125 for table, column, where, multiple in USER_TABLES: 126 c = cxn.cursor() 127 128 # first do all renames for non-multiple fields 129 query = "UPDATE %(table)s SET %(column)s='%(new)s'" \ 130 " WHERE %(column)s='%(old)s'" % locals() 131 if where: 132 query += " AND %s" % where 133 134 self.debug('Executing query %s' % query) 135 c.execute(query) 136 137 # now take tables into account that have multiple fields 138 if multiple: 139 c = cxn.cursor() 140 query = "SELECT %(column)s FROM %(table)s" \ 141 " WHERE %(column)s LIKE '%%,%%' " % locals() 142 if where: 143 query += " AND %s" % where 144 self.debug('Executing query %s' % query) 145 c.execute(query) 146 multiples = {} 147 for row in c: 148 if not row[0]: 149 continue 150 names = row[0].split(',') 151 if not old in names: 152 continue 153 multiples[row[0]] = True 154 155 for oldValue in multiples.keys(): 156 # now that we know what to look for, we can update 157 self.stdout.write("Table '%s', column '%s' has value '%s'. " 158 "Please fix this manually.\n" % ( 159 table, column, oldValue)) 160 names = oldValue.split(',') 161 newNames = [] 162 for name in names: 163 if name == old: 164 newNames.append(new) 165 else: 166 newNames.append(name) 167 newValue = ",".join(newNames) 168 169 query = "UPDATE %(table)s SET %(column)s='%(newValue)s'" \ 170 " WHERE %(column)s='%(oldValue)s'" % locals() 171 if where: 172 query += " AND %s" % where 173 174 self.debug('Executing query %s' % query) 175 c.execute(query) 176 177 178 # now commit all the changes 179 cxn.commit()
180 181
182 -class User(util.LogCommand):
183 description = "Manage users." 184 subCommandClasses = [List, Rename]
185
186 -class TracAdmin(util.LogCommand):
187 """ 188 @ivar path: path to the Trac project environment 189 @ivar cxn: connection to Trac database 190 @ivar environment: Trac environment 191 @type environment: L{trac.env.Environment} 192 """ 193 usage = "tracadmin %command" 194 summary = "interact with a server-side trac installation" 195 description = """Interact with a server-side trac installation. 196 197 This can be useful for maintainers of Trac installations. 198 """ 199 subCommandClasses = [User] 200
201 - def addOptions(self):
202 self.parser.add_option('-p', '--project', 203 action="store", dest="project", 204 help="path to Trac project")
205
206 - def handleOptions(self, options):
207 self.path = options.project 208 209 if not self.path: 210 self.path = os.getcwd() 211 212 # verify it is a trac project 213 dbPath = os.path.join(self.path, 'db', 'trac.db') 214 if not os.path.exists(dbPath): 215 self.stderr.write("%s is not a Trac project.\n" % self.path) 216 return 3 217 218 from trac import env 219 self.environment = env.Environment(self.path) 220 self.cxn = self.environment.get_db_cnx()
221