|
tw@14
|
1 |
# -*- coding: iso-8859-1 -*-
|
|
tw@14
|
2 |
"""
|
|
tw@14
|
3 |
MoinMoin - Despam action
|
|
tw@2286
|
4 |
|
|
tw@14
|
5 |
Mass revert changes done by some specific author / bot.
|
|
tw@14
|
6 |
|
|
tw@14
|
7 |
@copyright: 2005 by ???, Thomas Waldmann
|
|
tw@14
|
8 |
@license: GNU GPL, see COPYING for details.
|
|
tw@14
|
9 |
"""
|
|
tw@14
|
10 |
|
|
tw@3094
|
11 |
DAYS = 30 # we look for spam edits in the last x days
|
|
tw@3094
|
12 |
|
|
tw@101
|
13 |
import time
|
|
tw@14
|
14 |
|
|
tw@14
|
15 |
from MoinMoin.logfile import editlog
|
|
tw@14
|
16 |
from MoinMoin.util.dataset import TupleDataset, Column
|
|
tw@14
|
17 |
from MoinMoin.widget.browser import DataBrowserWidget
|
|
tw@14
|
18 |
from MoinMoin import wikiutil, Page, PageEditor
|
|
tw@14
|
19 |
from MoinMoin.macro import RecentChanges
|
|
tw@14
|
20 |
|
|
tw@3094
|
21 |
def render(editor_tuple):
|
|
tw@3094
|
22 |
etype, evalue = editor_tuple
|
|
tw@3094
|
23 |
if etype in ('ip', 'email', ):
|
|
tw@3094
|
24 |
ret = evalue
|
|
tw@3094
|
25 |
elif etype == 'interwiki':
|
|
tw@3094
|
26 |
ewiki, euser = evalue
|
|
tw@3094
|
27 |
if ewiki == 'Self':
|
|
tw@3094
|
28 |
ret = euser
|
|
tw@3094
|
29 |
else:
|
|
tw@3094
|
30 |
ret = '%s:%s' % evalue
|
|
tw@3094
|
31 |
else:
|
|
tw@3094
|
32 |
ret = repr(editor_tuple)
|
|
tw@3094
|
33 |
return ret
|
|
tw@3094
|
34 |
|
|
tw@14
|
35 |
def show_editors(request, pagename, timestamp):
|
|
tw@889
|
36 |
_ = request.getText
|
|
tw@889
|
37 |
|
|
tw@14
|
38 |
timestamp = int(timestamp * 1000000)
|
|
tw@14
|
39 |
log = editlog.EditLog(request)
|
|
tw@14
|
40 |
editors = {}
|
|
tw@14
|
41 |
pages = {}
|
|
tw@14
|
42 |
for line in log.reverse():
|
|
tw@14
|
43 |
if line.ed_time_usecs < timestamp:
|
|
tw@14
|
44 |
break
|
|
tw@889
|
45 |
|
|
tw@14
|
46 |
if not request.user.may.read(line.pagename):
|
|
tw@14
|
47 |
continue
|
|
tw@889
|
48 |
|
|
tw@3094
|
49 |
editor = line.getInterwikiEditorData(request)
|
|
tw@551
|
50 |
if not line.pagename in pages:
|
|
tw@14
|
51 |
pages[line.pagename] = 1
|
|
tw@14
|
52 |
editors[editor] = editors.get(editor, 0) + 1
|
|
tw@889
|
53 |
|
|
tw@14
|
54 |
editors = [(nr, editor) for editor, nr in editors.iteritems()]
|
|
tw@14
|
55 |
editors.sort()
|
|
tw@3094
|
56 |
editors.reverse()
|
|
tw@14
|
57 |
|
|
tw@14
|
58 |
pg = Page.Page(request, pagename)
|
|
tw@14
|
59 |
|
|
tw@14
|
60 |
dataset = TupleDataset()
|
|
tw@14
|
61 |
dataset.columns = [Column('editor', label=_("Editor"), align='left'),
|
|
tw@14
|
62 |
Column('pages', label=_("Pages"), align='right'),
|
|
tw@14
|
63 |
Column('link', label='', align='left')]
|
|
tw@14
|
64 |
for nr, editor in editors:
|
|
tw@3094
|
65 |
dataset.addRow((render(editor), unicode(nr),
|
|
tw@1341
|
66 |
pg.link_to(request, text=_("Select Author"),
|
|
tw@1341
|
67 |
querystr={
|
|
tw@1341
|
68 |
'action': 'Despam',
|
|
tw@4552
|
69 |
'editor': repr(editor),
|
|
tw@1341
|
70 |
})))
|
|
tw@889
|
71 |
|
|
tw@14
|
72 |
table = DataBrowserWidget(request)
|
|
tw@14
|
73 |
table.setData(dataset)
|
|
rb@4093
|
74 |
return table.render(method="GET")
|
|
tw@14
|
75 |
|
|
tw@14
|
76 |
class tmp:
|
|
tw@14
|
77 |
pass
|
|
tw@14
|
78 |
|
|
tw@14
|
79 |
def show_pages(request, pagename, editor, timestamp):
|
|
tw@889
|
80 |
_ = request.getText
|
|
tw@889
|
81 |
|
|
tw@14
|
82 |
timestamp = int(timestamp * 1000000)
|
|
tw@14
|
83 |
log = editlog.EditLog(request)
|
|
tw@14
|
84 |
pages = {}
|
|
tw@14
|
85 |
# mimic macro object for use of RecentChanges subfunctions
|
|
tw@14
|
86 |
macro = tmp()
|
|
tw@14
|
87 |
macro.request = request
|
|
tw@622
|
88 |
macro.formatter = request.html_formatter
|
|
tw@14
|
89 |
|
|
tw@230
|
90 |
request.write("<table>")
|
|
tw@14
|
91 |
for line in log.reverse():
|
|
tw@14
|
92 |
if line.ed_time_usecs < timestamp:
|
|
tw@14
|
93 |
break
|
|
tw@889
|
94 |
|
|
tw@14
|
95 |
if not request.user.may.read(line.pagename):
|
|
tw@14
|
96 |
continue
|
|
tw@230
|
97 |
|
|
tw@551
|
98 |
if not line.pagename in pages:
|
|
tw@14
|
99 |
pages[line.pagename] = 1
|
|
tw@3094
|
100 |
if repr(line.getInterwikiEditorData(request)) == editor:
|
|
tw@230
|
101 |
line.time_tuple = request.user.getTime(wikiutil.version2timestamp(line.ed_time_usecs))
|
|
tw@14
|
102 |
request.write(RecentChanges.format_page_edits(macro, [line], timestamp))
|
|
tw@14
|
103 |
|
|
tw@14
|
104 |
request.write('''
|
|
tw@230
|
105 |
</table>
|
|
tw@14
|
106 |
<p>
|
|
florian@4235
|
107 |
<form method="post" action="%s">
|
|
tw@14
|
108 |
<input type="hidden" name="action" value="Despam">
|
|
tw@14
|
109 |
<input type="hidden" name="editor" value="%s">
|
|
tw@14
|
110 |
<input type="submit" name="ok" value="%s">
|
|
tw@14
|
111 |
</form>
|
|
tw@14
|
112 |
</p>
|
|
florian@4235
|
113 |
''' % (request.href(pagename), wikiutil.url_quote(editor), _("Revert all!")))
|
|
tw@14
|
114 |
|
|
tw@14
|
115 |
def revert_page(request, pagename, editor):
|
|
tw@14
|
116 |
if not request.user.may.revert(pagename):
|
|
tw@949
|
117 |
return
|
|
tw@14
|
118 |
|
|
tw@14
|
119 |
log = editlog.EditLog(request, rootpagename=pagename)
|
|
tw@14
|
120 |
|
|
tw@14
|
121 |
first = True
|
|
tw@14
|
122 |
rev = u"00000000"
|
|
tw@14
|
123 |
for line in log.reverse():
|
|
tw@14
|
124 |
if first:
|
|
tw@14
|
125 |
first = False
|
|
tw@3094
|
126 |
if repr(line.getInterwikiEditorData(request)) != editor:
|
|
tw@14
|
127 |
return
|
|
tw@14
|
128 |
else:
|
|
tw@3094
|
129 |
if repr(line.getInterwikiEditorData(request)) != editor:
|
|
tw@14
|
130 |
rev = line.rev
|
|
tw@14
|
131 |
break
|
|
tw@230
|
132 |
|
|
tw@2286
|
133 |
if rev == u"00000000": # page created by spammer
|
|
tw@230
|
134 |
comment = u"Page deleted by Despam action"
|
|
tw@230
|
135 |
pg = PageEditor.PageEditor(request, pagename, do_editor_backup=0)
|
|
tw@230
|
136 |
try:
|
|
tw@230
|
137 |
savemsg = pg.deletePage(comment)
|
|
tw@230
|
138 |
except pg.SaveError, msg:
|
|
tw@230
|
139 |
savemsg = unicode(msg)
|
|
tw@230
|
140 |
else: # page edited by spammer
|
|
tw@230
|
141 |
oldpg = Page.Page(request, pagename, rev=int(rev))
|
|
tw@230
|
142 |
pg = PageEditor.PageEditor(request, pagename, do_editor_backup=0)
|
|
tw@230
|
143 |
try:
|
|
tw@230
|
144 |
savemsg = pg.saveText(oldpg.get_raw_body(), 0, extra=rev, action="SAVE/REVERT")
|
|
tw@230
|
145 |
except pg.SaveError, msg:
|
|
tw@230
|
146 |
savemsg = unicode(msg)
|
|
tw@14
|
147 |
return savemsg
|
|
tw@889
|
148 |
|
|
tw@14
|
149 |
def revert_pages(request, editor, timestamp):
|
|
tw@889
|
150 |
_ = request.getText
|
|
tw@14
|
151 |
|
|
tw@4569
|
152 |
editor = wikiutil.url_unquote(editor)
|
|
tw@14
|
153 |
timestamp = int(timestamp * 1000000)
|
|
tw@14
|
154 |
log = editlog.EditLog(request)
|
|
tw@14
|
155 |
pages = {}
|
|
tw@230
|
156 |
revertpages = []
|
|
tw@14
|
157 |
for line in log.reverse():
|
|
tw@14
|
158 |
if line.ed_time_usecs < timestamp:
|
|
tw@14
|
159 |
break
|
|
tw@14
|
160 |
|
|
tw@14
|
161 |
if not request.user.may.read(line.pagename):
|
|
tw@14
|
162 |
continue
|
|
tw@14
|
163 |
|
|
tw@551
|
164 |
if not line.pagename in pages:
|
|
tw@14
|
165 |
pages[line.pagename] = 1
|
|
tw@3094
|
166 |
if repr(line.getInterwikiEditorData(request)) == editor:
|
|
tw@230
|
167 |
revertpages.append(line.pagename)
|
|
tw@230
|
168 |
|
|
tw@3094
|
169 |
request.write("Pages to revert:<br>%s" % "<br>".join(revertpages))
|
|
tw@230
|
170 |
for pagename in revertpages:
|
|
tw@3094
|
171 |
request.write("Begin reverting %s ...<br>" % pagename)
|
|
tw@230
|
172 |
msg = revert_page(request, pagename, editor)
|
|
tw@230
|
173 |
if msg:
|
|
tw@230
|
174 |
request.write("<p>%s: %s</p>" % (
|
|
tw@230
|
175 |
Page.Page(request, pagename).link_to(request), msg))
|
|
tw@3094
|
176 |
request.write("Finished reverting %s.<br>" % pagename)
|
|
tw@14
|
177 |
|
|
tw@14
|
178 |
def execute(pagename, request):
|
|
tw@14
|
179 |
_ = request.getText
|
|
rb@3525
|
180 |
# check for superuser
|
|
rb@3525
|
181 |
if not request.user.isSuperUser():
|
|
alex@2966
|
182 |
request.theme.add_msg(_('You are not allowed to use this action.'), "error")
|
|
alex@2966
|
183 |
return Page.Page(request, pagename).send_page()
|
|
tw@14
|
184 |
|
|
florian@4201
|
185 |
editor = request.form.get('editor')
|
|
tw@3094
|
186 |
timestamp = time.time() - DAYS * 24 * 3600
|
|
florian@4201
|
187 |
ok = request.form.get('ok', 0)
|
|
tw@14
|
188 |
|
|
tw@889
|
189 |
request.theme.send_title("Despam", pagename=pagename)
|
|
tw@14
|
190 |
# Start content (important for RTL support)
|
|
tw@14
|
191 |
request.write(request.formatter.startContent("content"))
|
|
tw@889
|
192 |
|
|
tw@14
|
193 |
if ok:
|
|
tw@14
|
194 |
revert_pages(request, editor, timestamp)
|
|
tw@14
|
195 |
elif editor:
|
|
tw@14
|
196 |
show_pages(request, pagename, editor, timestamp)
|
|
tw@14
|
197 |
else:
|
|
tw@3905
|
198 |
request.write(show_editors(request, pagename, timestamp))
|
|
tw@14
|
199 |
|
|
tw@14
|
200 |
# End content and send footer
|
|
tw@14
|
201 |
request.write(request.formatter.endContent())
|
|
tw@616
|
202 |
request.theme.send_footer(pagename)
|
|
tw@617
|
203 |
request.theme.send_closing_html()
|
|
tw@14
|
204 |
|