1
# -*- coding: iso-8859-1 -*-
3
MoinMoin - check / process user accounts
5
@copyright: 2003-2006 by MoinMoin:ThomasWaldmann
6
@license: GNU GPL, see COPYING for details.
10
When using ACLs, a wiki user name has to be unique, there must not be
11
multiple accounts having the same username. The problem is, that this
12
was possible before the introduction of ACLs and many users, who forgot
13
their ID, simply created a new ID using the same user name.
15
Because access rights (when using ACLs) depend on the NAME (not the ID),
16
this must be cleaned up before using ACLs or users will have difficulties
17
changing settings and saving their account data (system won't accept the
18
save, if the user name and email is not unique).
23
General syntax: moin [options] account check [check-options]
25
[options] usually should be:
26
--config-dir=/path/to/my/cfg/ --wiki-url=wiki.example.org/
28
[check-options] see below:
30
0. Check the settings at top of the code!
31
Making a backup of your wiki might be also a great idea.
33
1. Best is to first look at duplicate user names:
34
moin ... account check --usersunique
36
If everything looks OK there, you may save that to disk:
37
moin ... account check --usersunique --save
39
2. Now, check also for duplicate email addresses:
40
moin ... account check --emailsunique
42
If everything looks OK, you may save that to disk:
43
moin ... account check --emailsunique --save
45
3. If the announced action is incorrect, you may choose to better manually
46
disable some accounts: moin ... account disable --uid 1234567.8.90
48
4. After cleaning up, do 1. and 2. again. There should be no output now, if
51
5. Optionally you may want to make wikinames out of the user names
52
moin ... account check --wikinames
53
moin ... account check --wikinames --save
57
# ----------------------------------------------------------------------------
58
# if a user subsribes to magicpages, it means that he wants to keep
59
# exactly THIS account - this will avoid deleting it.
61
"ThisAccountIsCorrect",
62
"DieserAccountIstRichtig",
65
# ----------------------------------------------------------------------------
69
from MoinMoin.script._util import MoinScript
70
from MoinMoin import user, wikiutil
72
class PluginScript(MoinScript):
73
def __init__(self, argv, def_values):
74
MoinScript.__init__(self, argv, def_values)
75
self._addFlag("usersunique",
76
"Makes user names unique (by appending the ID to"
77
" name and email, disabling subscribed pages and"
78
" disabling all, but the latest saved user account);"
79
" default is to SHOW what will be happening, you"
80
" need to give the --save option to really do it."
82
self._addFlag("emailsunique",
83
"Makes user emails unique;"
84
" default is to show, use --save to save it."
86
self._addFlag("wikinames",
87
"Convert user account names to wikinames (camel-case)."
89
self._addFlag("lastsaved",
90
"Normally the account most recently USED will"
91
" survive and the others will be disabled."
92
" Using --lastsaved, the account most recently"
93
" SAVED will survive."
96
"If specified as LAST option, will allow the other"
97
" options to save user accounts back to disk."
98
" If not specified, no settings will be changed permanently."
100
self._addFlag("removepasswords",
101
"Remove pre-1.1 cleartext passwords from accounts."
104
def _addFlag(self, name, help):
105
self.parser.add_option("--" + name,
106
action="store_true", dest=name, default=0, help=help)
108
def collect_data(self):
110
request = self.request
111
for uid in user.getUserList(request):
112
u = user.User(request, uid)
115
# collect name duplicates:
116
if u.name in self.names:
117
self.names[u.name].append(uid)
119
self.names[u.name] = [uid]
121
# collect email duplicates:
123
if u.email in self.emails:
124
self.emails[u.email].append(uid)
126
self.emails[u.email] = [uid]
128
# collect account with no or invalid email address set:
129
if not u.email or not re.match(".*@.*\..*", u.email):
130
self.uids_noemail[uid] = u.name
132
def hasmagicpage(self, uid):
134
return u.isSubscribedTo(magicpages)
136
def disableUser(self, uid):
138
print " %-20s %-30r %-35r" % (uid, u.name, u.email),
139
keepthis = self.hasmagicpage(uid)
141
print "- keeping (magicpage)!"
142
u.save() # update timestamp, so this will be latest next run
143
elif not u.disabled: # only disable once
145
u.name = "%s-%s" % (u.name, uid)
147
u.email = "%s-%s" % (u.email, uid)
148
u.subscribed_pages = "" # avoid using email
149
if self.options.save:
153
print "- would be disabled."
155
def getsortvalue(self, uid, user):
156
t_ls = float(user.last_saved) # when user did last SAVE of his account data
157
if self.options.lastsaved:
159
else: # last USED (we check the page trail for that)
161
t_lu = float(os.path.getmtime(os.path.join(self.request.cfg.user_dir, "%s.trail" % uid)))
163
t_lu = t_ls # better than having nothing
166
def process(self, uidlist):
170
sortlist.append((self.getsortvalue(uid, u), uid))
173
# disable all, but the last/latest one
174
for t, uid in sortlist[:-1]:
175
self.disableUser(uid)
176
# show what will be kept
177
uid = sortlist[-1][1]
179
print " %-20s %-30r %-35r - keeping%s!" % (uid, u.name, u.email, self.hasmagicpage(uid) and " (magicpage)" or "")
181
def make_users_unique(self):
182
for name, uids in self.names.items():
186
def make_emails_unique(self):
187
for email, uids in self.emails.items():
191
def make_WikiNames(self):
193
for uid, u in self.users.items():
196
if not wikiutil.isStrictWikiname(u.name):
197
newname = string.capwords(u.name).replace(" ", "").replace("-", "")
198
if not wikiutil.isStrictWikiname(newname):
199
print " %-20s %-30r - no WikiName, giving up" % (uid, u.name)
201
print " %-20s %-30r - no WikiName -> %r" % (uid, u.name, newname)
202
if self.options.save:
206
def remove_passwords(self):
207
for uid, u in self.users.items():
208
# user.User already clears the old cleartext passwords on loading,
209
# so nothing to do here!
211
# we can't encrypt the cleartext password as it is cleared
212
# already. and we would not trust it anyway, so we don't WANT
214
# Just save the account data without cleartext password:
215
print " %-20s %-25s - saving" % (uid, u.name)
221
# we don't expect non-option arguments
222
if len(self.args) != 0:
223
self.parser.error("incorrect number of arguments")
225
# check for correct option combination
226
flags_given = (self.options.usersunique
227
or self.options.emailsunique
228
or self.options.wikinames
229
or self.options.removepasswords)
231
# no option given ==> show usage
233
self.parser.print_help()
238
self.users = {} # uid : UserObject
239
self.names = {} # name : [uid, uid, uid]
240
self.emails = {} # email : [uid, uid, uid]
241
self.uids_noemail = {} # uid : name
244
if self.options.usersunique:
245
self.make_users_unique()
246
if self.options.emailsunique:
247
self.make_emails_unique()
248
if self.options.wikinames:
249
self.make_WikiNames()
250
if self.options.removepasswords:
251
self.remove_passwords()