User:Hamish/userRightsManager.js
外观
注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google Chrome、Firefox、Microsoft Edge及Safari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。
/* global Morebits */
/* eslint-disable no-extra-boolean-cast */
// <nowiki>
// Some UI code adapted from [[User:Mr. Stradivarius/gadgets/Draftify.js]]
// Adapted from https://en.wikipedia.org/wiki/User:MusikAnimal/userRightsManager.js
// https://zh.wikipedia.org/wiki/User:Xiplus/js/userRightsManager.js
(function() {
var pagePermissions = {
'Wikipedia:權限申請/申請IP封禁豁免權': 'ipblock-exempt',
'Wikipedia:權限申請/申請巡查權': 'patroller',
'Wikipedia:權限申請/申請回退權': 'rollbacker',
'Wikipedia:權限申請/申請巡查豁免權': 'autoreviewer',
'Wikipedia:權限申請/申請確認用戶權': 'confirmed',
'Wikipedia:權限申請/申請大量訊息發送權': 'massmessage-sender',
'Wikipedia:權限申請/申請大量帳號建立權': 'accountcreator',
'Wikipedia:權限申請/申請檔案移動權': 'filemover',
'Wikipedia:權限申請/申請跨維基導入權': 'transwiki',
'Wikipedia:權限申請/申請模板編輯權': 'templateeditor',
'Wikipedia:權限申請/申請過濾器助理權限': 'abusefilter-helper',
'Wikipedia:權限申請/申請活動組織權': 'event-organizer',
'Wikipedia:權限申請/申請IP封鎖豁免授予權': 'ipblock-exempt-grantor'
}
var pageName = mw.config.get('wgPageName');
var permission = pagePermissions[pageName];
if (!permission) {
return;
}
if (permission === 'accountcreator' && mw.config.get('wgUserGroups').indexOf('bureaucrat') === -1) {
return;
}
var templates = {
'ipblock-exempt': 'Ipexemptgranted',
'patroller': 'Patrolgranted',
'rollbacker': 'Rollbackgranted',
'autoreviewer': 'Autopatrolgranted',
'massmessage-sender': 'MMSgranted',
'templateeditor': 'Template editor granted',
'transwiki': 'Importer granted',
'filemover': 'Filemovergranted',
'abusefilter-helper': 'Edit filter helper granted',
};
var api,
tagLine = '(使用[[User:Hamish/userRightsManager.js|userRightsManager]])',
permaLink, userName, dialog, permissionNames;
mw.loader.using(['oojs-ui', 'mediawiki.api', 'mediawiki.widgets.SelectWithInputWidget', 'mediawiki.widgets.expiry', 'ext.gadget.morebits', 'ext.gadget.HanAssist'], function() {
var conv = require('ext.gadget.HanAssist').conv;
permissionNames = {
'ipblock-exempt': conv({ hans: 'IP封禁豁免', hant: 'IP封鎖例外' }),
'patroller': conv({ hans: '巡查员', hant: '巡查員' }),
'rollbacker': conv({ hans: '回退员', hant: '回退員' }),
'confirmed': conv({ hans: '已确认的用户', hant: '已確認的使用者' }),
'massmessage-sender': conv({ hans: '大量消息发送者', hant: '大量訊息傳送者' }),
'accountcreator': conv({ hans: '大量账户创建者', hant: '大量帳號建立者' }),
'filemover': conv({ hans: '文件移动员', hant: '檔案移動員' }),
'transwiki': conv({ hans: '跨维基导入者', hant: '跨維基匯入者' }),
'templateeditor': conv({ hans: '模板编辑员', hant: '模板編輯員' }),
'autoreviewer': '巡查豁免者',
'abusefilter-helper': conv({ hans: '过滤器助理', hant: '過濾器助理' }),
'event-organizer': conv({ hans: '活动组织者', hant: '活動組織者' }),
'ipblock-exempt-grantor': conv({ hans: 'IP封禁豁免授予者', hant: 'IP封鎖例外授予者' })
};
api = new mw.Api();
$('.perm-assign-permissions a').on('click', function(e) {
if (permission === 'AutoWikiBrowser') return true;
e.preventDefault();
userName = mw.util.getParamValue('user', $(this).attr('href'));
showDialog();
});
});
function showDialog() {
var Dialog = function(config) {
Dialog.super.call(this, config);
};
OO.inheritClass(Dialog, OO.ui.ProcessDialog);
Dialog.static.name = 'user-rights-manager';
Dialog.static.title = '授予' + permissionNames[permission] + conv({ hans: '给', hant: '給' }) + userName;
Dialog.static.actions = [
{ action: 'submit', label: conv({ hans: '授权', hant: '授權' }), flags: ['primary', 'progressive'] },
{ label: '取消', flags: 'safe' },
];
Dialog.prototype.getApiManager = function() {
return this.apiManager;
};
Dialog.prototype.getBodyHeight = function() {
return 255;
};
Dialog.prototype.initialize = function() {
Dialog.super.prototype.initialize.call(this);
this.editPanel = new OO.ui.PanelLayout({
expanded: false,
});
var rightLogWapper = $('<span>');
var url = mw.util.getUrl('Special:Log/rights', { type: 'rights', page: 'User:' + userName });
$('<a>').text(conv({ hans: '最近权限日志', hant: '最近權限日誌' })).attr({ 'href': url, 'target': '_blank' }).appendTo(rightLogWapper);
rightLogWapper.append(':');
var rightLogText = $('<span>').text(conv({ hans: '获取中', hant: '取得中' })).appendTo(rightLogWapper);
this.rightLog = new OO.ui.LabelWidget({
label: rightLogWapper,
});
this.editPanel.$element.append(this.rightLog.$element);
api.get({
action: 'query',
format: 'json',
list: 'logevents',
leaction: 'rights/rights',
letitle: 'User:' + userName,
lelimit: '1',
}).done(function(data) {
var logs = data.query.logevents;
if (logs.length === 0) {
rightLogText.text(conv({ hans: '没有任何日志', hant: '沒有任何日誌' }));
} else {
var timestamp = new Morebits.date(logs[0].timestamp).calendar();
var rights = logs[0].params.newgroups.join('、') || conv({ hans: '(无)', hant: '(無)' });
rightLogText.text(timestamp + ' ' + logs[0].user + conv({ hans: '将用户组改为', hant: '將使用者群組改為' }) + rights);
}
});
this.editFieldset = new OO.ui.FieldsetLayout({
classes: ['container'],
});
this.editPanel.$element.append(this.editFieldset.$element);
this.rightsChangeSummaryInput = new OO.ui.TextInputWidget({
value: '',
placeholder: '可留空',
});
this.expiryInput = new mw.widgets.ExpiryWidget({
$overlay: $('.oo-ui-window'),
RelativeInputClass: mw.widgets.SelectWithInputWidget,
relativeInput: {
or: true,
dropdowninput: {
options: [
{ data: '1 day', label: '1天' },
{ data: '1 week', label: conv({ hans: '1周', hant: '1週' })},
{ data: '1 month', label: conv({ hans: '1个月', hant: '1個月' })},
{ data: '3 months', label: conv({ hans: '3个月', hant: '3個月' })},
{ data: '6 months', label: conv({ hans: '6个月', hant: '6個月' })},
{ data: '1 year', label: '1年' },
{ data: 'infinite', label: conv({ hans: '没有期限', hant: '沒有期限' })},
{ data: 'other', label: conv({ hans: '其他时间', hant: '其他時間' })},
],
value: 'infinite',
},
textinput: {
required: true,
},
},
});
this.closingRemarksInput = new OO.ui.TextInputWidget({
value: '{{done}}--~~~~',
});
this.watchTalkPageCheckbox = new OO.ui.CheckboxInputWidget({
selected: false,
});
var formElements = [
new OO.ui.FieldLayout(this.rightsChangeSummaryInput, {
label: conv({ hans: '授权原因', hant: '授權原因' }),
}),
new OO.ui.FieldLayout(this.expiryInput, {
label: conv({ hans: '结束时间', hant: '結束時間' }),
}),
new OO.ui.FieldLayout(this.closingRemarksInput, {
label: conv({ hans: '关闭请求留言', hant: '關閉請求留言' }),
}),
];
if (!!templates[permission]) {
formElements.push(
new OO.ui.FieldLayout(this.watchTalkPageCheckbox, {
label: conv({ hans: '监视用户讨论页', hant: '監視使用者討論頁' }),
})
);
}
this.editFieldset.addItems(formElements);
this.submitPanel = new OO.ui.PanelLayout({
$: this.$,
expanded: false,
});
this.submitFieldset = new OO.ui.FieldsetLayout({
classes: ['container'],
});
this.submitPanel.$element.append(this.submitFieldset.$element);
this.changeRightsProgressLabel = new OO.ui.LabelWidget();
this.changeRightsProgressField = new OO.ui.FieldLayout(this.changeRightsProgressLabel);
this.markAsDoneProgressLabel = new OO.ui.LabelWidget();
this.markAsDoneProgressField = new OO.ui.FieldLayout(this.markAsDoneProgressLabel);
this.issueTemplateProgressLabel = new OO.ui.LabelWidget();
this.issueTemplateProgressField = new OO.ui.FieldLayout(this.issueTemplateProgressLabel);
this.stackLayout = new OO.ui.StackLayout({
items: [this.editPanel, this.submitPanel],
padded: true,
});
this.$body.append(this.stackLayout.$element);
};
Dialog.prototype.onSubmit = function() {
var self = this, promiseCount = !!templates[permission] ? 3 : 2;
self.actions.setAbilities({ submit: false });
var addPromise = function(field, promise) {
self.pushPending();
promise.done(function() {
field.$field.append($('<span>')
.text('完成!')
.prop('style', 'position:relative; top:0.5em; color: #009000; font-weight: bold')
);
}).fail(function(obj) {
if (obj && obj.error && obj.error.info) {
field.$field.append($('<span>')
.text(conv({ hans: '错误:', hant: '錯誤:' }) + obj.error.info)
.prop('style', 'position:relative; top:0.5em; color: #cc0000; font-weight: bold')
);
} else {
field.$field.append($('<span>')
.text(conv({ hans: '发生未知错误。', hant: '發生未知錯誤。' }))
.prop('style', 'position:relative; top:0.5em; color: #cc0000; font-weight: bold')
);
}
}).always(function() {
promiseCount--; // FIXME: maybe we could use a self.isPending() or something
self.popPending();
if (promiseCount === 0) {
setTimeout(function() {
location.reload(true);
}, 1000);
}
});
return promise;
};
self.markAsDoneProgressField.setLabel(conv({ hans: '标记请求为已完成...', hant: '標記請求為已完成...' }));
self.submitFieldset.addItems([self.markAsDoneProgressField]);
self.changeRightsProgressField.setLabel(conv({ hans: '授予权限...', hant: '授予權限...' }));
self.submitFieldset.addItems([self.changeRightsProgressField]);
if (!!templates[permission]) {
self.issueTemplateProgressField.setLabel(conv({ hans: '发送通知...', hant: '發送通知...' }));
self.submitFieldset.addItems([self.issueTemplateProgressField]);
}
addPromise(
self.markAsDoneProgressField,
markAsDone('\n:' + this.closingRemarksInput.getValue())
).then(function(data) {
addPromise(
self.changeRightsProgressField,
assignPermission(
this.rightsChangeSummaryInput.getValue(),
data.edit.newrevid,
this.expiryInput.getValue()
)
).then(function() {
if (!!templates[permission]) {
addPromise(
self.issueTemplateProgressField,
issueTemplate(this.watchTalkPageCheckbox.isSelected())
);
}
}.bind(this));
}.bind(this));
self.stackLayout.setItem(self.submitPanel);
};
Dialog.prototype.getActionProcess = function(action) {
return Dialog.super.prototype.getActionProcess.call(this, action).next(function() {
if (action === 'submit') {
return this.onSubmit();
} else {
return Dialog.super.prototype.getActionProcess.call(this, action);
}
}, this);
};
dialog = new Dialog({
size: 'medium',
});
var windowManager = new OO.ui.WindowManager();
$('body').append(windowManager.$element);
windowManager.addWindows([dialog]);
windowManager.openWindow(dialog);
}
function assignPermission(summary, revId, expiry) {
if (expiry === '') {
expiry = 'infinite';
}
var removePermission = '';
if (permission === 'patroller' && expiry === 'infinite') {
removePermission = 'autoreviewer';
}
permaLink = '[[Special:PermaLink/' + revId + '#User:' + userName + '|' + conv({ hans: '权限申请', hant: '權限申請' }) + ']]';
var fullSummary = '+' + permissionNames[permission] + ';' + permaLink;
if (summary !== '') {
fullSummary += ';' + summary;
}
fullSummary += tagLine;
return api.postWithToken('userrights', {
action: 'userrights',
format: 'json',
user: userName.replace(/ /g, '_'),
add: permission,
remove: removePermission,
reason: fullSummary,
expiry: expiry,
});
}
function markAsDone(closingRemarks) {
var sectionNode = document.getElementById('User:' + userName.replace(/"/g, '.22').replace(/ /g, '_')),
sectionNumber = $(sectionNode).siblings('.mw-editsection').find("a:not('.mw-editsection-visualeditor')").prop('href').match(/section=(\d+)/)[1];
var basetimestamp, curtimestamp, page, revision, content;
return api.get({
action: 'query',
prop: 'revisions',
rvprop: ['content', 'timestamp'],
titles: [pageName],
rvsection: sectionNumber,
formatversion: '2',
curtimestamp: true,
})
.then(function(data) {
if (!data.query || !data.query.pages) {
return $.Deferred().reject('unknown');
}
page = data.query.pages[0];
if (!page || page.invalid) {
return $.Deferred().reject('invalidtitle');
}
if (page.missing) {
return $.Deferred().reject('nocreate-missing');
}
revision = page.revisions[0];
basetimestamp = revision.timestamp;
curtimestamp = data.curtimestamp;
content = revision.content;
})
.then(function() {
content = content.trim();
content = content.replace(/(:\s*{{Status)(\|.*?)?}}/i, '$1|+}}');
content += closingRemarks;
return api.postWithEditToken({
action: 'edit',
title: pageName,
section: sectionNumber,
text: content,
summary: '/* User:' + userName + ' */ 完成' + tagLine,
formatversion: '2',
assert: mw.config.get('wgUserName') ? 'user' : undefined,
basetimestamp: basetimestamp,
starttimestamp: curtimestamp,
nocreate: true,
});
});
}
function issueTemplate(watch) {
var talkPage = 'User talk:' + userName.replace(/ /g, '_');
var message = '{{subst:' + templates[permission] + '}}';
return api.get({
action: 'query',
prop: 'info',
titles: talkPage,
}).then(function(data) {
var page = Object.values(data.query.pages)[0];
if (page.missing !== undefined) {
return api.create(
talkPage,
{
summary: conv({ hans: '根据', hant: '根據' }) + permaLink + '授予' + permissionNames[permission] + tagLine,
watchlist: watch ? 'watch' : 'unwatch',
},
message
);
} else if (page.contentmodel == 'flow-board') {
return api.postWithEditToken({
action: 'flow',
page: talkPage,
submodule: 'new-topic',
nttopic: conv({ hans: '根据', hant: '根據' }) + permaLink + '授予' + permissionNames[permission],
ntcontent: message,
ntformat: 'wikitext',
});
} else {
return api.edit(talkPage, function(revision) {
return {
text: (revision.content + '\n\n' + message).trim(),
summary: conv({ hans: '根据', hant: '根據' }) + permaLink + '授予' + permissionNames[permission] + tagLine,
watchlist: watch ? 'watch' : 'unwatch',
};
});
}
});
}
})();
// </nowiki>