User:MonkeysHK/common.js

/** Staff Tagger * * Code to automate some part of administrator's actions for staff promotion/demotion * * Staff "tag" option appears on Template:User_rights_request * It is commonly used on HSW:STFREQS */

/* jshint esversion: 5, forin: true, immed: true, indent: 4, latedef: true, newcap: true, noarg: true, undef: true, undef: true, unused: true, browser: true, jquery: true, onevar: true, eqeqeq: true, multistr: true, maxerr: 999999, sub: true, forin: false, -W082, -W084

/* global mw, BannerNotification */ "use strict"; (function {    if (window.StaffTagger && window.StaffTagger.Loaded)        return;

window.StaffTagger = window.StaffTagger || {}; window.StaffTagger.Loaded = true;

console.log("[User:MonkeysHK/common.js] Test script loading."); $.when(       mw.loader.using([ "mediawiki.util", "mediawiki.api", mw.loader.getModuleNames.find(function (module) {               return module.startsWith("BannerNotification");            }), ]),       $.Deferred(function (def) { mw.hook("dev.modal").add(function {                def.resolve;            }); }),       $.Deferred(function (def) { if (mw.util.StaffUtil) { def.resolve(mw.util.StaffUtil); } else { $.ajax({                   cache: true,                    dataType: "script",                    url: "https://hypixel-skyblock.fandom.com/wiki/MediaWiki:Gadget-StaffColorsUpdater.js"                }).done(function  {                    def.resolve(mw.util.StaffUtil);                }); }       })    ).then(function  {        if (!/codeeditor|sysop|bureaucrat|soap|staff|helper|wiki-manager|content-team-member|util/.test(mw.config.get("wgUserGroups").join("\n")))            return;

window.StaffTagger = window.StaffTagger || {};

var StaffTagger, that, cachedStaffData; StaffTagger = that = window.StaffTagger = Object.assign(this, {           Loaded: true,            api: new mw.Api,            staffDataPage: "Module:Staff/Members",            ranksAvailable: [                "bureaucrat",                "sysop",                "codeeditor",                "content-moderator",                "threadmoderator",                "rollback",            ],            rankShorts: {                bureaucrat: "BU",                sysop: "AD",                codeeditor: "CE",                "content-moderator": "CM",                threadmoderator: "DM",                rollback: "RB",            },

// Begin (Taken from HypixelItemDataFetcher (by Fewfre) and modified) luaTableDataModuleToJson: function (moduleName) { return that.api.post({                       action: "scribunto-console",                        title: mw.config.get("wgPageName"),                        question: "=mw.text.jsonEncode(require('" + moduleName + "'))"                    }) .then(function (response) {                       return response.return;                    }) .then(function (data) {                       return JSON.parse(data);                    }); },           toSafeStr: function (s) { return s.replaceAll("\'", "\\\'").replaceAll("\"", "\\\""); },           toLuaKey: function (k) { k = that.toSafeStr(k); return (/^\w+$/.test(k) && /^[^\d]/.test(k)) ? k : ("[\"" + k + "\"]"); },           jsonToLuaTable: function (json, depth) { depth = typeof depth === "undefined" ? -1 : depth; depth++; if (Array.isArray(json)) { return "{ " + json.map(function (o) {                       return that.jsonToLuaTable(o, depth);                    }).join(", ") + " }"; } else if (typeof json === "object") { var space = depth ? "" : "\t", br = depth ? "" : "\n", ex = depth ? " " : "";                   return "{ " + br + Object.entries(json).sort(function (a, b) {                           return a[0] > b[0];                        }).map(function (data) {                            return space + that.toLuaKey(data[0]) + " = " + that.jsonToLuaTable(data[1], depth);                        }).join(", " + br) + br + ex + "}"; }               // Otherwise seems to be normal value; done on this branch! else { return typeof json === "string" ? "\"" + that.toSafeStr(json) + "\"" : json; }           },            saveToWiki: function (json, summary, page) { var lua = "-- \nreturn " + that.jsonToLuaTable(json);

return that.api.postWithEditToken({                   action: "edit",                    text: lua,                    title: page,                    summary: summary,                    minor: true,                }).catch(console.warn); },           // End (Taken from HypixelItemDataFetcher (by Fewfre) and modified)

fetchStaffData: function { return that.luaTableDataModuleToJson(that.staffDataPage).then(function (data) {                   cachedStaffData = data;                }); },           fetchUserRights: function (user) { return that.api.get({                   action: "query",                    list: "users",                    ususers: user,                    usprop: "groupmemberships",                    aulimit: 500,                }).then(function (dt) {                    var result = dt.query.users[0].groupmemberships.map(function(v) { return v.expiry === "infinity" ? v.group : ""; });                   that.existingGroups = [];                    for (var i in that.ranksAvailable)                        if (result.includes(that.ranksAvailable[i]))                            that.existingGroups.push(that.ranksAvailable[i]);                }).catch(console.warn); },

putToday: function (e) { e.preventDefault; var date = new Date; $("#StaffTagger-date-input").val(date.getUTCFullYear + "-" + (date.getUTCMonth + 1) + "-" + date.getUTCDate); },           getDefaultDate: function (user) { return (!cachedStaffData[user] || !cachedStaffData[user]["join"]) ? "" : cachedStaffData[user]["join"]; },

// #1: Granting rights (if applicable) grantUserRights: function (user, ranks_to_add, ranks_to_remove, reason) { return that.api.get({                   action: "query",                    list: "users",                    ususers: user,                    ustoken: "userrights",                }).always(function (data) {                    var usToken = data.query.users[0].userrightstoken;                    if (data.query) {                        new mw.Api.post({ "action": "userrights", "format": "json", "user": user, "add": ranks_to_add, "remove": ranks_to_remove, "expiry": "infinite", "reason": reason, "token": usToken, }).always(function (data) { if (data.userrights) { console.log("[StaffTagger #1]: Finished modified ranks (when applicable)!"); console.log("Ranks added (" + data.userrights.added.length + "): ", data.userrights.added); console.log("Ranks removed (" + data.userrights.removed.length + "): ", data.userrights.removed); } else console.warn("[StaffTagger #1]: Failed to modify ranks:" + data); });                   } else                        console.warn("[StaffTagger #1]: API error in getting user rights token:" + data, "(API Error code \"" + data + "\")");                }); },

// #2: Change Staff Data on Staff Page // Now should update Module:Staff/Members instead changeStaffData: function (user, ranklist, joindate, reason) { var shorts = []; for (var i in that.ranksAvailable) if (ranklist.includes(that.ranksAvailable[i])) shorts.push(that.rankShorts[that.ranksAvailable[i]]);

cachedStaffData[user] = cachedStaffData[user] || {}; Object.assign(cachedStaffData[user], {                   rank: shorts.join("|"),                    join: joindate,                });

return that.saveToWiki(cachedStaffData, reason, that.staffDataPage).always(function (data) {                   if (data.edit)                        console.log("[StaffTagger #2]: Successfully added" + user + " to staff member list");                    else                        console.warn("[StaffTagger #2]: API Error in editing staff member list", user + ":", data);                }); },

// #3: Add staff message box to userpage addMsgBox: function (user, reason) { var userpage = "User:" + user, newtext = "\n"; return that.api.get({                   action: "query",                    format: "json",                    prop: "revisions",                    titles: userpage,                    formatversion: 2,                    rvprop: "content",                    rvslots: "*",                }).then(function (d) {                    var content = d.query.pages[0].revisions[0].slots.main.content;                    var regex = new RegExp("\\{\\{StaffM?s?g?b?o?x?\\|.*?\\}\\}\\s*", "ig");                    var options = {                        action: "edit",                        watchlist: "nochange",                        summary: reason,                        title: userpage,                        minor: true,                        prependtext: newtext,                        token: mw.user.tokens.values.editToken,                    };                    if (content.match(regex)) { delete options.prependtext; options.text = newtext + content.replace(regex, ""); console.log("[StaffTagger #3]: Replaced existing StaffMsgbox"); }                   return that.api.post(options); }).always(function (data) { if (data.edit) console.log("[StaffTagger #3]: Successfully added StaffMsgbox to", user); else console.warn("[StaffTagger #3]: API Error in adding StaffMsgbox for", user + ":", data); });           },

// #4: Protect staff userpage protectStaffPage: function (user, ranks) { var userpage = "User:" + user; return that.api.post({                   action: "protect",                    bot: true,                    watchlist: "nochange",                    title: userpage,                    protections: (/content-moderator|codeeditor|sysop|bureaucrat/.test(ranks)) ?                        "edit=sysop|move=sysop" : "edit=autoconfirmed|move=autoconfirmed",                    expiry: "infinite",                    reason: "Protecting wiki staff userpage",                    token: mw.user.tokens.values.editToken,                }).always(function (data) {                    if (data.protect)                        console.log("[StaffTagger #4]: Successfully protected", user + "\'s userpage");                    else                        console.warn("[StaffTagger #4]: API error in protecting", user + "\'s userpage:", data);                }); },

// #5: Update staff-colors.less updateStaffColors: function { return mw.util.StaffUtil.updateStaffColors(function {                    console.log("[StaffTagger #5]: Successfully updated staff-colors.less");                }); },

processInformation: function { var ranklist = $("#StaffTagger-ranks-wrapper *:checked").get.map(function (el) {                       return $(el).attr("data-rank");                    }), ranks = ranklist.join("|"), user = $("#StaffTagger-user-input").val, date = $("#StaffTagger-date-input").val, reason = $("#StaffTagger-reason-input").val;

Promise.all([                   that.grantUserRights(user, ranks, "", reason), // #1                    that.changeStaffData(user, ranklist, date, reason), // #2                    that.addMsgBox(user), // #3                    that.protectStaffPage(user, ranks), // #4                    that.updateStaffColors, // #5                ]).then(that.onResolve);

that.modal.hide; new BannerNotification($(" ", { html: " Processing Another pop-up should indicate completion. ", }).prop("outerHTML"), "confirm").show; },

onResolve: function { new BannerNotification($(" ", { html: " All subprocesses completed See Console for detailed results You may now Update CSS. ", }).prop("outerHTML"), "confirm").show; },

editorCloseHandler: function { that.modal.hide; },

createIntroSection: function { return "Select the ranks for this user. Then, the Staff Tagger will perform the following:\	\	Grant selected rights to the user on wiki (if applicable)\	Change staff data on Module:Staff/Members\	Add StaffMsgBox to the user page\	Protect the user page\	Update staff-color.less</li>\	Null Edit  and   for the user</li>\	</ol>\	"; },

createRanksSelection: function { return that.ranksAvailable.map(function (rank) {                   var idname = "StaffTagger-rank-" + rank;                    return {                        type: "div",                        attr: {                            id: "StaffTagger-ranks-wrapper"                        },                        children: [{                            type: "input",                            attr: {                                type: "checkbox",                                id: idname,                                "data-rank": rank                            },                        }, {                            type: "label",                            attr: {                                for: idname                            },                            text: " " + rank,                        }],                    };                }); },

showModal: function { var user = that.user || ""; Promise.all([                   that.fetchStaffData,                    that.fetchUserRights(user),                ]).then(function  {                    var defaultDate = that.getDefaultDate(user),                        defaultReason = "Per request to be staff: HSW:STFREQS";                    that.modal.setContent({ children: [{ type: "form", attr: { id: "StaffTagger-form", style: "margin: 0 1em;", },                           children: [{ type: "span", attr: { class: "page-content" },                               html: that.createIntroSection, }, {                               type: "div", id: "StaffTagger-input", children: [{ type: "div", attr: { id: "StaffTagger-user-wrapper" },                                   children: [{ type: "label", id: "StaffTagger-user-label", text: "User: ", }, {                                       type: "input", attr: { id: "StaffTagger-user-input", type: "text", value: user, },                                   }],                                }, {                                    type: "div", attr: { id: "StaffTagger-ranks-wrapper" },                                   children: [{ type: "div", id: "StaffTagger-ranks-label", text: "Select the ranks to add (Deselect the ranks to remove):", }].concat(that.createRanksSelection), }, {                                   type: "div", attr: { id: "StaffTagger-date-wrapper" },                                   children: [{ type: "label", id: "StaffTagger-date-label", text: "Join/Resign Date: ", }, {                                       type: "input", attr: { id: "StaffTagger-date-input", type: "text", value: defaultDate },                                   }, {                                        type: "a", attr: { id: "StaffTagger-date-today", type: "text", href: "#", },                                       html: "[Today]", }],                               }, {                                    type: "div", attr: { id: "StaffTagger-reason-wrapper" },                                   children: [{ type: "label", id: "StaffTagger-reason-label", text: "Reason: ", }, {                                       type: "input", attr: { id: "StaffTagger-reason-input", type: "text", value: defaultReason },                                   }],                                }],                            }],                        }]                    });                    that.modal.show;                    for (var i in that.existingGroups)                        $("#StaffTagger-rank-" + that.existingGroups[i]).prop("checked", true);                    $("#StaffTagger-date-today").click(that.putToday);                }); },           onclick: function (e) { e.preventDefault; that.user = (mw.config.get("wgNamespaceNumber") !== 2) ? $(this).parent.attr("data-user") : mw.config.get("wgPageName").match(mw.config.get("wgFormattedNamespaces")[2] + ":([^/]*)")[1]; that.showModal; },           init: function  { $("span#tag-user > a[href*=\"prepend=\"].text").click(that.onclick); if (mw.config.get("wgNamespaceNumber") === 2) { $(".page-header__contribution-buttons .wds-list, .page-header__actions .wds-list").first.append(                       $("").append( $("", {                               text: "Staff Tagger",                                href: "#",                                click: that.onclick,                            }) )                   );                }            },        });

Object.assign(this, {           modal: new window.dev.modal.Modal({ id: "StaffTagger-modal", title: "Staff Tagger", content: "", buttons: [{ event: "onSubmit", id: "StaffTagger-submit", primary: true, text: "Submit", }],               events: { onSubmit: this.processInformation, },               size: "large", }),       });        that.modal.create;

that.init; }); });