File: check.py

package info (click to toggle)
moin 1.9.9-1%2Bdeb9u1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 76,024 kB
  • sloc: python: 143,896; java: 10,704; php: 2,385; perl: 1,574; xml: 371; makefile: 214; sh: 81; sed: 5
file content (236 lines) | stat: -rw-r--r-- 8,510 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# -*- coding: iso-8859-1 -*-
"""
MoinMoin - check / process user accounts

@copyright: 2003-2006 MoinMoin:ThomasWaldmann
@license: GNU GPL, see COPYING for details.
"""

# ----------------------------------------------------------------------------
# if a user subscribes to magicpages, it means that he wants to keep
# exactly THIS account - this will avoid deleting it.
magicpages = [
    "ThisAccountIsCorrect",
    "DieserAccountIstRichtig",
]

# ----------------------------------------------------------------------------

import os, sys

from MoinMoin.script import MoinScript
from MoinMoin import user, wikiutil

class PluginScript(MoinScript):
    """\
Purpose:
========
When using ACLs, a wiki user name has to be unique, there must not be
multiple accounts having the same username. The problem is, that this
was possible before the introduction of ACLs and many users, who forgot
their ID, simply created a new ID using the same user name.

Because access rights (when using ACLs) depend on the NAME (not the ID),
this must be cleaned up before using ACLs or users will have difficulties
changing settings and saving their account data (system won't accept the
save, if the user name and email is not unique).

Detailed Instructions:
======================

General syntax: moin [options] account check [check-options]

[options] usually should be:
    --config-dir=/path/to/my/cfg/ --wiki-url=http://wiki.example.org/

[check-options] see below:

    0. Check the settings at top of the code!
       Making a backup of your wiki might be also a great idea.

    1. Best is to first look at duplicate user names:
       moin ... account check --usersunique

       If everything looks OK there, you may save that to disk:
       moin ... account check --usersunique --save

    2. Now, check also for duplicate email addresses:
       moin ... account check --emailsunique

       If everything looks OK, you may save that to disk:
       moin ... account check --emailsunique --save

    3. If the announced action is incorrect, you may choose to better manually
       disable some accounts: moin ... account disable --uid 1234567.8.90

    4. After cleaning up, do 1. and 2. again. There should be no output now, if
       everything is OK.

    5. Optionally you may want to make wikinames out of the user names
       moin ... account check --wikinames
       moin ... account check --wikinames --save
"""

    def __init__(self, argv, def_values):
        MoinScript.__init__(self, argv, def_values)
        self._addFlag("usersunique",
            "Makes user names unique (by appending the ID to"
            " name and email, disabling subscribed pages and"
            " disabling all, but the latest saved user account);"
            " default is to SHOW what will be happening, you"
            " need to give the --save option to really do it."
        )
        self._addFlag("emailsunique",
            "Makes user emails unique;"
            " default is to show, use --save to save it."
        )
        self._addFlag("wikinames",
            "Convert user account names to wikinames (camel-case)."
        )
        self._addFlag("save",
            "If specified as LAST option, will allow the other"
            " options to save user accounts back to disk."
            " If not specified, no settings will be changed permanently."
        )
        self._addFlag("removepasswords",
            "Remove pre-1.1 cleartext passwords from accounts."
        )

    def _addFlag(self, name, help):
        self.parser.add_option("--" + name,
            action="store_true", dest=name, default=0, help=help)

    def collect_data(self):
        import re
        request = self.request
        for uid in user.getUserList(request):
            u = user.User(request, uid)
            self.users[uid] = u

            # collect name duplicates:
            if u.name in self.names:
                self.names[u.name].append(uid)
            else:
                self.names[u.name] = [uid]

            # collect email duplicates:
            if u.email:
                if u.email in self.emails:
                    self.emails[u.email].append(uid)
                else:
                    self.emails[u.email] = [uid]

            # collect account with no or invalid email address set:
            if not u.email or not re.match(".*@.*\..*", u.email):
                self.uids_noemail[uid] = u.name

    def hasmagicpage(self, uid):
        u = self.users[uid]
        return u.isSubscribedTo(magicpages)

    def disableUser(self, uid):
        u = self.users[uid]
        print " %-20s %-30r %-35r" % (uid, u.name, u.email),
        keepthis = self.hasmagicpage(uid)
        if keepthis:
            print "- keeping (magicpage)!"
            u.save() # update timestamp, so this will be latest next run
        elif not u.disabled: # only disable once
            u.disabled = 1
            u.name = "%s-%s" % (u.name, uid)
            if u.email:
                u.email = "%s-%s" % (u.email, uid)
            u.subscribed_pages = "" # avoid using email
            if self.options.save:
                u.save()
                print "- disabled."
            else:
                print "- would be disabled."

    def getsortvalue(self, uid, user):
        return float(user.last_saved) # when user did last SAVE of his account data

    def process(self, uidlist):
        sortlist = []
        for uid in uidlist:
            u = self.users[uid]
            sortlist.append((self.getsortvalue(uid, u), uid))
        sortlist.sort()
        #print sortlist
        # disable all, but the last/latest one
        for dummy, uid in sortlist[:-1]:
            self.disableUser(uid)
        # show what will be kept
        uid = sortlist[-1][1]
        u = self.users[uid]
        print " %-20s %-30r %-35r - keeping%s!" % (uid, u.name, u.email, self.hasmagicpage(uid) and " (magicpage)" or "")

    def make_users_unique(self):
        for name, uids in self.names.items():
            if len(uids) > 1:
                self.process(uids)

    def make_emails_unique(self):
        for email, uids in self.emails.items():
            if len(uids) > 1:
                self.process(uids)

    def make_WikiNames(self):
        for uid, u in self.users.items():
            if u.disabled:
                continue
            if not wikiutil.isStrictWikiname(u.name):
                newname = u.name.capwords().replace(" ", "").replace("-", "")
                if not wikiutil.isStrictWikiname(newname):
                    print " %-20s %-30r - no WikiName, giving up" % (uid, u.name)
                else:
                    print " %-20s %-30r - no WikiName -> %r" % (uid, u.name, newname)
                    if self.options.save:
                        u.name = newname
                        u.save()

    def remove_passwords(self):
        for uid, u in self.users.items():
            # user.User already clears the old cleartext passwords on loading,
            # so nothing to do here!
            if self.options.save:
                # we can't encrypt the cleartext password as it is cleared
                # already. and we would not trust it anyway, so we don't WANT
                # to do that either!
                # Just save the account data without cleartext password:
                print " %-20s %-25s - saving" % (uid, u.name)
                u.save()

    def mainloop(self):
        # we don't expect non-option arguments
        if len(self.args) != 0:
            self.parser.error("incorrect number of arguments")

        # check for correct option combination
        flags_given = (self.options.usersunique
                    or self.options.emailsunique
                    or self.options.wikinames
                    or self.options.removepasswords)

        # no option given ==> show usage
        if not flags_given:
            self.parser.print_help()
            sys.exit(1)

        self.init_request()

        self.users = {} # uid : UserObject
        self.names = {} # name : [uid, uid, uid]
        self.emails = {} # email : [uid, uid, uid]
        self.uids_noemail = {} # uid : name

        self.collect_data()
        if self.options.usersunique:
            self.make_users_unique()
        if self.options.emailsunique:
            self.make_emails_unique()
        if self.options.wikinames:
            self.make_WikiNames()
        if self.options.removepasswords:
            self.remove_passwords()