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 summary = "interact with a server-side trac installation" 194 description = """Interact with a server-side trac installation. 195 196 This can be useful for maintainers of Trac installations. 197 """ 198 subCommandClasses = [User] 199
200 - def addOptions(self):
201 self.parser.add_option('-p', '--project', 202 action="store", dest="project", 203 help="path to Trac project")
204
205 - def handleOptions(self, options):
206 self.path = options.project 207 208 if not self.path: 209 self.path = os.getcwd() 210 211 # verify it is a trac project 212 dbPath = os.path.join(self.path, 'db', 'trac.db') 213 if not os.path.exists(dbPath): 214 self.stderr.write("%s is not a Trac project.\n" % self.path) 215 return 3 216 217 from trac import env 218 self.environment = env.Environment(self.path) 219 self.cxn = self.environment.get_db_cnx()
220