forked from wikimedia-gadgets/twinkle
-
Notifications
You must be signed in to change notification settings - Fork 0
/
twinkledeprod.js
189 lines (167 loc) · 6.19 KB
/
twinkledeprod.js
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
// <nowiki>
(function($) {
/*
****************************************
*** twinkledeprod.js: Batch deletion of expired PRODs (sysops only)
****************************************
* Mode of invocation: Tab ("Deprod")
* Active on: Categories whose name contains "proposed_deletion"
*/
Twinkle.deprod = function() {
if (
!Morebits.userIsSysop ||
mw.config.get('wgNamespaceNumber') !== 14 ||
!(/proposed_deletion/i).test(mw.config.get('wgPageName'))
) {
return;
}
Twinkle.addPortletLink(Twinkle.deprod.callback, 'Deprod', 'tw-deprod', 'Delete prod pages found in this category');
};
const concerns = {};
Twinkle.deprod.callback = function() {
const Window = new Morebits.simpleWindow(800, 400);
Window.setTitle('PROD cleaning');
Window.setScriptName('Twinkle');
Window.addFooterLink('Proposed deletion', 'WP:PROD');
Window.addFooterLink('Twinkle help', 'WP:TW/DOC#deprod');
Window.addFooterLink('Give feedback', 'WT:TW');
const form = new Morebits.quickForm(callback_commit);
const statusdiv = document.createElement('div');
statusdiv.style.padding = '15px'; // just so it doesn't look broken
Window.setContent(statusdiv);
Morebits.status.init(statusdiv);
Window.display();
const query = {
action: 'query',
generator: 'categorymembers',
gcmtitle: mw.config.get('wgPageName'),
gcmlimit: Twinkle.getPref('batchMax'),
gcmnamespace: '0|2', // only display articles or user pages
prop: 'info|revisions',
rvprop: 'content',
inprop: 'protection',
format: 'json'
};
const statelem = new Morebits.status('Grabbing list of pages');
const wikipedia_api = new Morebits.wiki.api('loading...', query, ((apiobj) => {
const response = apiobj.getResponse();
const pages = (response.query && response.query.pages) || [];
const list = [];
const re = /\{\{Proposed deletion/;
pages.sort(Twinkle.sortByNamespace);
pages.forEach((page) => {
const metadata = [];
const content = page.revisions[0].content;
const res = re.exec(content);
const title = page.title;
if (res) {
const parsed = Morebits.wikitext.parseTemplate(content, res.index);
concerns[title] = parsed.parameters.concern || '';
metadata.push(concerns[title]);
}
const editProt = page.protection.filter((pr) => pr.type === 'edit' && pr.level === 'sysop').pop();
if (editProt) {
metadata.push('fully protected' +
(editProt.expiry === 'infinity' ? ' indefinitely' : ', expires ' + editProt.expiry));
}
list.push({
label: metadata.length ? '(' + metadata.join('; ') + ')' : '',
value: title,
checked: concerns[title] !== '',
style: editProt ? 'color:red' : ''
});
});
apiobj.params.form.append({ type: 'header', label: 'Pages to delete' });
apiobj.params.form.append({
type: 'button',
label: 'Select All',
event: function(e) {
$(Morebits.quickForm.getElements(e.target.form, 'pages')).prop('checked', true);
}
});
apiobj.params.form.append({
type: 'button',
label: 'Deselect All',
event: function(e) {
$(Morebits.quickForm.getElements(e.target.form, 'pages')).prop('checked', false);
}
});
apiobj.params.form.append({
type: 'checkbox',
name: 'pages',
list: list
});
apiobj.params.form.append({
type: 'submit'
});
const rendered = apiobj.params.form.render();
apiobj.params.Window.setContent(rendered);
Morebits.quickForm.getElements(rendered, 'pages').forEach(Twinkle.generateBatchPageLinks);
}), statelem);
wikipedia_api.params = { form: form, Window: Window };
wikipedia_api.post();
};
var callback_commit = function(event) {
const pages = Morebits.quickForm.getInputData(event.target).pages;
Morebits.status.init(event.target);
const batchOperation = new Morebits.batchOperation('Deleting pages');
batchOperation.setOption('chunkSize', Twinkle.getPref('batchChunks'));
batchOperation.setOption('preserveIndividualStatusLines', true);
batchOperation.setPageList(pages);
batchOperation.run((pageName) => {
const params = { page: pageName, reason: concerns[page] };
let query = {
action: 'query',
titles: pageName,
prop: 'redirects',
rdlimit: 'max', // 500 is max for normal users, 5000 for bots and sysops
format: 'json'
};
let wikipedia_api = new Morebits.wiki.api('Grabbing redirects', query, callback_deleteRedirects);
wikipedia_api.params = params;
wikipedia_api.post();
const pageTitle = mw.Title.newFromText(pageName);
// Don't delete user talk pages, limiting this to Talk: pages since only article and user pages appear in deprod
if (pageTitle && pageTitle.namespace % 2 === 0 && pageTitle.namespace !== 2) {
pageTitle.namespace++; // now pageTitle is the talk page title!
query = {
action: 'query',
titles: pageTitle.toText(),
format: 'json'
};
wikipedia_api = new Morebits.wiki.api('Checking whether ' + pageName + ' has a talk page', query,
callback_deleteTalk);
wikipedia_api.params = params;
wikipedia_api.post();
}
var page = new Morebits.wiki.page(pageName, 'Deleting page ' + pageName);
page.setEditSummary('Expired [[WP:PROD|PROD]], concern was: ' + concerns[pageName]);
page.setChangeTags(Twinkle.changeTags);
page.suppressProtectWarning();
page.deletePage(batchOperation.workerSuccess, batchOperation.workerFailure);
});
},
callback_deleteTalk = function(apiobj) {
// no talk page; forget about it
if (apiobj.getResponse().query.pages[0].missing) {
return;
}
const page = new Morebits.wiki.page('Talk:' + apiobj.params.page, 'Deleting talk page of page ' + apiobj.params.page);
page.setEditSummary('[[WP:CSD#G8|G8]]: [[Help:Talk page|Talk page]] of deleted page "' + apiobj.params.page + '"');
page.setChangeTags(Twinkle.changeTags);
page.deletePage();
},
callback_deleteRedirects = function(apiobj) {
const response = apiobj.getResponse();
const redirects = response.query.pages[0].redirects || [];
redirects.forEach((rd) => {
const title = rd.title;
const page = new Morebits.wiki.page(title, 'Deleting redirecting page ' + title);
page.setEditSummary('[[WP:CSD#G8|G8]]: Redirect to deleted page "' + apiobj.params.page + '"');
page.setChangeTags(Twinkle.changeTags);
page.deletePage();
});
};
Twinkle.addInitCallback(Twinkle.deprod, 'deprod');
}(jQuery));
// </nowiki>