~ubuntu-branches/ubuntu/gutsy/moin/gutsy

« back to all changes in this revision

Viewing changes to MoinMoin/script/account/check.py

  • Committer: Bazaar Package Importer
  • Author(s): Sivan Greenberg
  • Date: 2006-07-09 19:28:02 UTC
  • Revision ID: james.westby@ubuntu.com-20060709192802-oaeuvt4v3e9300uj
Tags: 1.5.3-1ubuntu1
* Merge new debian version.
* Reapply Ubuntu changes:
    + debian/rules:
      - Comment out usage of control.ubuntu.in (doesn't fit!).
    + debian/control.in:
      - Dropped python2.3 binary package.
    + debian/control:
      - Dropped python2.3 binary, again.
      - Dropped python2.3-dev from Build-Depends-Indep.
    + debian/patches/001-attachment-xss-fix.patch:
      - Dropped this patch. It's now in upstream's distribution.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: iso-8859-1 -*-
 
2
"""
 
3
    MoinMoin - check / process user accounts
 
4
 
 
5
    @copyright: 2003-2006 by MoinMoin:ThomasWaldmann
 
6
    @license: GNU GPL, see COPYING for details.
 
7
 
 
8
    Why is this needed?
 
9
    ===================
 
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.
 
14
 
 
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).
 
19
 
 
20
    How to use this tool?
 
21
    =====================
 
22
 
 
23
    General syntax: moin [options] account check [check-options]
 
24
    
 
25
    [options] usually should be:
 
26
        --config-dir=/path/to/my/cfg/ --wiki-url=wiki.example.org/
 
27
    
 
28
    [check-options] see below:
 
29
    
 
30
    0. Check the settings at top of the code!
 
31
       Making a backup of your wiki might be also a great idea.
 
32
       
 
33
    1. Best is to first look at duplicate user names:
 
34
       moin ... account check --usersunique
 
35
 
 
36
       If everything looks OK there, you may save that to disk:
 
37
       moin ... account check --usersunique --save
 
38
 
 
39
    2. Now, check also for duplicate email addresses:
 
40
       moin ... account check --emailsunique
 
41
 
 
42
       If everything looks OK, you may save that to disk:
 
43
       moin ... account check --emailsunique --save
 
44
 
 
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
 
47
 
 
48
    4. After cleaning up, do 1. and 2. again. There should be no output now, if
 
49
       everything is OK.
 
50
       
 
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
 
54
        
 
55
"""
 
56
 
 
57
# ----------------------------------------------------------------------------
 
58
# if a user subsribes to magicpages, it means that he wants to keep
 
59
# exactly THIS account - this will avoid deleting it.
 
60
magicpages = [
 
61
    "ThisAccountIsCorrect", 
 
62
    "DieserAccountIstRichtig",
 
63
]
 
64
 
 
65
# ----------------------------------------------------------------------------
 
66
 
 
67
import os
 
68
 
 
69
from MoinMoin.script._util import MoinScript
 
70
from MoinMoin import user, wikiutil
 
71
 
 
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."
 
81
        )
 
82
        self._addFlag("emailsunique",
 
83
            "Makes user emails unique;"
 
84
            " default is to show, use --save to save it."
 
85
        )
 
86
        self._addFlag("wikinames",
 
87
            "Convert user account names to wikinames (camel-case)."
 
88
        )
 
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."
 
94
        )
 
95
        self._addFlag("save",
 
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."
 
99
        )
 
100
        self._addFlag("removepasswords",
 
101
            "Remove pre-1.1 cleartext passwords from accounts."
 
102
        )
 
103
 
 
104
    def _addFlag(self, name, help):
 
105
        self.parser.add_option("--" + name,
 
106
            action="store_true", dest=name, default=0, help=help)
 
107
 
 
108
    def collect_data(self):
 
109
        import re
 
110
        request = self.request
 
111
        for uid in user.getUserList(request):
 
112
            u = user.User(request, uid)
 
113
            self.users[uid] = u
 
114
    
 
115
            # collect name duplicates:
 
116
            if u.name in self.names:
 
117
                self.names[u.name].append(uid)
 
118
            else:
 
119
                self.names[u.name] = [uid]
 
120
    
 
121
            # collect email duplicates:
 
122
            if u.email:
 
123
                if u.email in self.emails:
 
124
                    self.emails[u.email].append(uid)
 
125
                else:
 
126
                    self.emails[u.email] = [uid]
 
127
    
 
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
 
131
    
 
132
    def hasmagicpage(self, uid):
 
133
        u = self.users[uid]
 
134
        return u.isSubscribedTo(magicpages)
 
135
    
 
136
    def disableUser(self, uid):
 
137
        u = self.users[uid]
 
138
        print " %-20s %-30r %-35r" % (uid, u.name, u.email),
 
139
        keepthis = self.hasmagicpage(uid)
 
140
        if keepthis:
 
141
            print "- keeping (magicpage)!"
 
142
            u.save() # update timestamp, so this will be latest next run
 
143
        elif not u.disabled: # only disable once
 
144
            u.disabled = 1
 
145
            u.name = "%s-%s" % (u.name, uid)
 
146
            if u.email:
 
147
                u.email = "%s-%s" % (u.email, uid)
 
148
            u.subscribed_pages = "" # avoid using email
 
149
            if self.options.save:
 
150
                u.save()
 
151
                print "- disabled."
 
152
            else:
 
153
                print "- would be disabled."
 
154
    
 
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:
 
158
            return t_ls
 
159
        else: # last USED (we check the page trail for that)
 
160
            try:
 
161
                t_lu = float(os.path.getmtime(os.path.join(self.request.cfg.user_dir, "%s.trail" % uid)))
 
162
            except OSError:
 
163
                t_lu = t_ls # better than having nothing
 
164
            return t_lu
 
165
    
 
166
    def process(self, uidlist):
 
167
        sortlist = []
 
168
        for uid in uidlist:
 
169
            u = self.users[uid]
 
170
            sortlist.append((self.getsortvalue(uid, u), uid))
 
171
        sortlist.sort()
 
172
        #print sortlist
 
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]
 
178
        u = self.users[uid]
 
179
        print " %-20s %-30r %-35r - keeping%s!" % (uid, u.name, u.email, self.hasmagicpage(uid) and " (magicpage)" or "")
 
180
    
 
181
    def make_users_unique(self):
 
182
        for name, uids in self.names.items():
 
183
            if len(uids) > 1:
 
184
                self.process(uids)
 
185
    
 
186
    def make_emails_unique(self):
 
187
        for email, uids in self.emails.items():
 
188
            if len(uids) > 1:
 
189
                self.process(uids)
 
190
    
 
191
    def make_WikiNames(self):
 
192
        import string
 
193
        for uid, u in self.users.items():
 
194
            if u.disabled:
 
195
                continue
 
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)
 
200
                else:
 
201
                    print " %-20s %-30r - no WikiName -> %r" % (uid, u.name, newname)
 
202
                    if self.options.save:
 
203
                        u.name = newname
 
204
                        u.save()
 
205
 
 
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!
 
210
            if save:
 
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
 
213
                # to do that either!
 
214
                # Just save the account data without cleartext password:
 
215
                print " %-20s %-25s - saving" % (uid, u.name)
 
216
                u.save()
 
217
 
 
218
    def mainloop(self):
 
219
        import os, sys
 
220
 
 
221
        # we don't expect non-option arguments
 
222
        if len(self.args) != 0:
 
223
            self.parser.error("incorrect number of arguments")
 
224
 
 
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)
 
230
 
 
231
        # no option given ==> show usage
 
232
        if not flags_given:
 
233
            self.parser.print_help()
 
234
            sys.exit(1)
 
235
 
 
236
        self.init_request()
 
237
 
 
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
 
242
 
 
243
        self.collect_data()
 
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()
 
252