1
2
3
4 import os
5
6 from moap.util import util, usermap
7
8
9 USER_TABLES = [
10 ('permission', 'username', None, False),
11 ('auth_cookie', 'name', None, False),
12
13
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
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
48
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
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
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
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
90 self.parser.add_option('-u', '--usermap',
91 action="store", dest="usermap",
92 help="path to a file containing oldname:newname entries")
93
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
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
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
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
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
179 cxn.commit()
180
181
182 -class User(util.LogCommand):
185
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
201 self.parser.add_option('-p', '--project',
202 action="store", dest="project",
203 help="path to Trac project")
204
206 self.path = options.project
207
208 if not self.path:
209 self.path = os.getcwd()
210
211
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