User:Firefly/more-block-info.js

function mbi_logTimestampToWikiTimestamp(logTimestamp) {    const logDatetime = new Date(logTimestamp);    return (        logDatetime.toLocaleString("en-GB", {            hour: "2-digit",            minute: "2-digit",        }) +        ", " +        logDatetime.toLocaleString("en-GB", {            day: "numeric",            month: "long",            year: "numeric",        })    );}function mbi_getBlockOptionsString(blockEntry) {    let retVal = " (";    if ("nocreate" in blockEntry) {        // ACB        retVal += "account creation blocked, ";    }    if (!("allowusertalk" in blockEntry)) {        // NTP        retVal += "cannot edit own talk page, ";    }    retVal += ")";    retVal = retVal.replace(", )", ")").replace("()", "");    return retVal;}function mbi_getBlockDisplayListItem(user, logid, timestamp, blockActor, blockComment, blockExpiry, blockOptions, isPartial) {    return `<li data-mw-logaction="block/block" class="mw-logline-block" > <a href="https://www.search.com.vn/wiki/?lang=en&title=Special:Log&amp;logid=${logid}" title="Special:Log" >${timestamp}</a > <a href="https://www.search.com.vn/wiki/en/User:${blockActor}" class="mw-userlink userlink" title="User:${blockActor}" ><bdi>${blockActor}</bdi></a > <span class="mw-usertoollinks mw-changeslist-links" ><span ><a href="https://www.search.com.vn/wiki/en/User_talk:${blockActor}" class="mw-usertoollinks-talk userlink" title="User talk:${blockActor}" >talk</a ></span > <span ><a href="https://www.search.com.vn/wiki/en/Special:Contributions/${blockActor}" class="mw-usertoollinks-contribs userlink" title="Special:Contributions/${blockActor}" >contribs</a ></span ></span > ${isPartial && '<strong>partially</strong> '|| ''}blocked <a href="https://www.search.com.vn/wiki/en/Special:Contributions/${user}" class="mw-userlink mw-anonuserlink" title="Special:Contributions/${user}" ><bdi>${user}</bdi></a > <span class="mw-usertoollinks mw-changeslist-links" ><span ><a href="https://www.search.com.vn/wiki/?lang=en&title=User_talk:${user}&amp;action=edit&amp;redlink=1" class="new mw-usertoollinks-talk" title="User talk:${user}" >talk</a ></span ></span > with an expiration time of <span class="blockExpiry" title="${blockExpiry}">${blockExpiry}</span> ${blockOptions} <span class="comment">(${blockComment})</span>&nbsp;<span class="mw-logevent-actionlink sysop-show">(<a href="https://www.search.com.vn/wiki/en/Special:Unblock/${user}" title="Special:Unblock/${user}">unblock</a> | <a href="https://www.search.com.vn/wiki/en/Special:Block/${user}" title="Special:Block/${user}">change block</a>)</span> </li>`;}function mbi_getWarningboxLocked(username, logid, timestamp, lockActor, lockComment) {    return `<div class="warningbox mw-warning-with-logexcerpt mw-content-ltr more-block-info-box more-block-info-locked" dir="ltr" lang="en"> <p> This account is currently globally locked. The latest <span class="plainlinks" ><a class="external text" href="https://meta.wikimedia.org/wiki/Special:CentralAuth/${username}" >global account change log</a ></span > entry is provided below for reference: </p> <ul class="mw-logevent-loglines"> <li> <a href="https://meta.wikimedia.org/w/index.php?title=Special:Log&logid=${logid}" >${timestamp}</a > <a href="https://meta.wikimedia.org/wiki/User:${lockActor}" class="mw-userlink userlink" title="User:${lockActor}" ><bdi>${lockActor}</bdi></a > <span class="mw-usertoollinks mw-changeslist-links" ><span ><a href="https://meta.wikimedia.org/wiki/User_talk:${lockActor}" class="mw-usertoollinks-talk userlink" title="User talk:${lockActor}" >talk</a ></span > <span ><a href="https://meta.wikimedia.org/wiki/Special:Contributions/${lockActor}" class="mw-usertoollinks-contribs userlink" title="Special:Contributions/${lockActor}" >contribs</a ></span ></span > changed status for global account <a href="https://www.search.com.vn/wiki/en/User:${username}" class="mw-userlink userlink user-blocked-indef" ><bdi>${username}</bdi></a > <span class="mw-usertoollinks mw-changeslist-links" ><span ><a href="https://www.search.com.vn/wiki/en/User_talk:${username}" class="mw-usertoollinks-talk userlink user-blocked-indef" >talk</a ></span > <span ><a href="https://www.search.com.vn/wiki/en/Special:Contributions/${username}" class="mw-usertoollinks-contribs userlink user-blocked-indef" >contribs</a ></span ></span > : set locked; unset (none) <span class="comment">(${lockComment})</span> </li> </ul> <a href="https://meta.wikimedia.org/wiki/Special:CentralAuth/${username}">View full log</a> </div>`;}function mbi_HtmlEncode(rawString) {    return $("<div>").text(rawString).html();}function mbi_insertMbiBox(boxContent) {    let blockedNoticeElemList = $(".mw-contributions-blocked-notice");    // If there's an existing block box, append after it    // If not, just shove our box at the top of the content element    if (blockedNoticeElemList.length > 0) {        $($(".mw-contributions-blocked-notice")[0]).after(boxContent);    } else {        $("#mw-content-text").prepend(boxContent);    }}async function mbi_getWarningboxRangeblocks(rangeblocks) {    let liConcat = "";    rangeblocks.forEach(function (blockEntry) {        //const blockEntry = rangeblocks[cidr].blockEntries[0];        const blockOptions = mbi_getBlockOptionsString(blockEntry);        //const parsedComment = await mbi_parseWikitext(blockEntry.comment);        liConcat += mbi_getBlockDisplayListItem(            blockEntry.user.replace("User:", ""),            blockEntry.id,            mbi_logTimestampToWikiTimestamp(blockEntry.timestamp),            blockEntry.by,            mbi_HtmlEncode(blockEntry.reason), // HTML-encode the block summary as they often contain hidden notes            mbi_logTimestampToWikiTimestamp(blockEntry.expiry),            blockOptions,            "partial" in blockEntry        );    });    return `<div class="warningbox mw-warning-with-logexcerpt mw-content-ltr more-block-info-box more-block-info-rangeblocks " dir="ltr" lang="en" > <p> This IP address is currently subject to one or more rangeblocks. A list of these rangeblocks is below: </p> <ul class="mw-logevent-loglines">${liConcat}</ul> </div>`;}// Shamelessly nicked from [[User:GeneralNotability/mark-locked.js]]async function mbi_isLocked(user) {    const api = new mw.Api();    try {        const response = await api.get({            action: "query",            list: "globalallusers",            agulimit: "1",            agufrom: user,            aguto: user,            aguprop: "lockinfo",        });        if (response.query.globalallusers.length === 0) {            // If the length is 0, then we couldn't find the global user            return false;        }        // If the 'locked' field is present, then the user is locked        return "locked" in response.query.globalallusers[0];    } catch (error) {        return false;    }}async function mbi_parseWikitext(wikitext, stripParaTag = true) {    const api = new mw.Api();    const apiResponse = await api.post({        action: "parse",        format: "json",        text: wikitext,        prop: "text",        disableeditsection: 1,        formatversion: "2",    });    const parsedText = apiResponse.parse.text;    if (stripParaTag) {        let div = document.createElement("div");        div.innerHTML = parsedText;        const pHtml = div.getElementsByTagName("p")[0].innerHTML;        return pHtml.trim();    } else {        return parsedText.trim();    }}async function mbi_getRangeblocks(user) {    const retVal = {        currentlyBlocked: false,        everBlocked: false,        blockEntries: [],    };    const api = new mw.Api();    try {        const response = await api.post({            action: "query",            list: "blocks",            bkip: user,        });        let retVal = [];        response.query.blocks.forEach(function (block) {            if (block.user.includes("/")) {                retVal.push(block);            }        });        return retVal;    } catch (error) {        return undefined;    }}/*async function mbi_getBlockEntries(user) {    const now = Date.now();    function blockIsCurrent(blockLogEntry) {        return new Date(blockLogEntry.params.expiry) > now;    }    const retVal = {        currentlyBlocked: false,        everBlocked: false,        blockEntries: [],    };    const api = new mw.Api();    try {        const response = await api.post({            action: "query",            list: "logevents",            letitle: `User:${user}`,            letype: "block",        });        const blockEntries = response.query.logevents;        if (blockEntries.length > 0) {            // user/range has been blocked at least once            retVal.everBlocked = true;            retVal.currentlyBlocked = blockIsCurrent(blockEntries[0]);            retVal.blockEntries = blockEntries;        }        return retVal;    } catch (error) {        return undefined;    }}*/async function mbi_getLockLogEntry(user) {    const api = new mw.Api();    try {        const response = await $.post("https://meta.wikimedia.org/w/api.php", {            action: "query",            list: "logevents",            lelimit: "1",            letitle: `User:${user}@global`,            leaction: "globalauth/setstatus",            origin: "*",            format: "json",        });        const logEvent = response.query.logevents[0];        const wikiTimestamp = mbi_logTimestampToWikiTimestamp(logEvent.timestamp);        const rawComment = logEvent.comment.replace("[[", "[[meta:"); // Crude fix for wikilinks in lock comments intending to point to Meta-Wiki pages        const parsedComment = await mbi_parseWikitext(rawComment);        const retVal = {            logid: logEvent.logid,            lockActor: logEvent.user,            lockComment: parsedComment,            timestamp: wikiTimestamp,        };        return retVal;    } catch (error) {        console.log(error);        return undefined;    }}async function mbi_handleRegisteredUser(relevantUserName) {    const userLocked = await mbi_isLocked(relevantUserName);    if (userLocked) {        const lockLogEntry = await mbi_getLockLogEntry(relevantUserName);        const lockedBox = mbi_getWarningboxLocked(            relevantUserName,            lockLogEntry.logid,            lockLogEntry.timestamp,            lockLogEntry.lockActor,            lockLogEntry.lockComment        );        $("a[title='m:Global locks']").parent().parent().remove(); // Remove "this account is globally locked" box        mbi_insertMbiBox(lockedBox);    }}async function mbi_handleIPOrRange(relevantUserName) {    const ipRangeBlocks = await mbi_getRangeblocks(relevantUserName);    if (ipRangeBlocks.length > 0) {        // If there's only one block returned, and it matches the rangeblock already displayed        // then don't duplicate it        if (ipRangeBlocks.length == 1) {            const existingRange = $(".mw-warning-with-logexcerpt>ul>li>a.mw-anonuserlink");            if (existingRange.length > 0) {                const existingRangeIP = existingRange.attr("href").split("/").slice(3).join("/");                if (existingRangeIP === ipRangeBlocks[0].user.replace("User:", "")) {                    return;                }            }        }        const rangeblockBox = await mbi_getWarningboxRangeblocks(ipRangeBlocks);        mbi_insertMbiBox(rangeblockBox);    }}$.when($.ready, mw.loader.using("mediawiki.util")).then(async function () {    if (mw.config.get("wgPageName").includes("Special:Contributions")) {        mw.util.addCSS("div.more-block-info-box.mw-warning-with-logexcerpt.mw-warning-with-logexcerpt.mw-warning-with-logexcerpt { " + "border: 1px solid #7196bc; " + "background-color: #dbedff; " + "}");        const relevantUserName = mw.config.get("wgRelevantUserName");        if (relevantUserName !== null) {            // wgRelevantUserName is null for IP ranges (see phab T206954)            const isip = mw.util.isIPAddress(relevantUserName, true);            if (!isip) {                // No point checking for locks if IP, IPs cannot be locked                mbi_handleRegisteredUser(relevantUserName);            } else {                mbi_handleIPOrRange(relevantUserName);            }        } else {            // We're naively assuming an IP range            // Have to extract range manually from URL as wgRelevantUserName is null            const queryParamsRaw = window.location.search;            let ipRange;            if (queryParamsRaw === "") {                ipRange = mw.config.get("wgPageName").split("/").slice(1).join("/");            } else {                const queryParams = new URLSearchParams(queryString);                ipRange = queryParams.get("target");            }            mbi_handleIPOrRange(ipRange);        }    }});