local export = {}
local X16 = "[0-9A-Fa-f][0-9A-Fa-f]?[0-9A-Fa-f]?[0-9A-Fa-f]?"
local IPv6_FULL = "^" .. X16 .. ":" .. X16 .. ":" .. X16 .. ":" .. X16 .. ":" .. X16 .. ":" .. X16 .. ":" .. X16 .. ":" .. X16 .. "$"
local function is_unregistered(username)
-- IPv4
if username:match("^[0-9][0-9]?[0-9]?%.[0-9][0-9]?[0-9]?%.[0-9][0-9]?[0-9]?%.[0-9][0-9]?[0-9]?$") then
-- this is the same algorithm MediaWiki uses, so we use it here too.
-- seriously, 359.33.9.234 passes off as valid.
return true
end
-- IPv6
local lhs, rhs = username:match("^([0-9A-Fa-f:]*)::([0-9A-Fa-f:]*)$")
if lhs then
-- abbreviated address
local counter = 0
local function check(side)
if side == "" then
return true
end
for word in mw.text.gsplit(side, ":") do
if not word:match(X16) then
return false
end
counter = counter + 1
if counter >= 8 then
return false
end
end
return true
end
if check(lhs) and check(rhs) then
return true
end
else
-- full address
if username:match(IPv6_FULL) then
return true
end
end
return false
end
local user_linkbar_items = {
userpage = {
label = "user page";
page = "User:%s";
only_registered = true;
no_ping = true;
};
talk = {
label = "talk";
page = "User talk:%s";
};
contribs = {
label = "contribs";
page = "Special:Contributions/%s";
};
deleted = {
label = "deleted contribs";
page = "Special:DeletedContributions/%s";
};
block = {
label = "block";
page = "Special:Block/%s";
};
-- this is just to have a different label
reblock = {
label = "change block settings";
page = "Special:Block/%s";
};
unblock = {
label = "unblock";
page = "Special:Unblock/%s";
};
blocklog = {
label = "block log";
page = "Special:Log";
query = "type=block&page=User:%s";
};
actions = {
label = "actions";
page = "Special:Log//%s";
};
moves = {
label = "page moves";
page = "Special:Log/move/%s";
only_registered = true;
};
newusers = {
label = "user creation log";
page = "Special:Log/newusers/%s";
only_registered = true;
};
blocklist = {
label = "active blocks";
page = "Special:BlockList/%s"
};
global_blocklist = {
label = "global blocks";
page = "Special:GlobalBlockList/%s";
only_ip = true;
};
rights = {
label = "rights";
page = "Special:UserRights/%s";
only_registered = true;
};
nuke = {
label = "nuke";
page = "Special:Nuke/%s";
};
abuselog = {
label = "edit filter log";
page = "Special:AbuseLog";
query = "wpSearchUser=%s";
};
userspace = {
label = "userspace";
page = "Special:PrefixIndex/User:%s/";
only_registered = true;
};
email = {
label = "email";
page = "Special:EmailUser/%s";
only_registered = true;
};
centralauth = {
label = "global account info";
page = "m:Special:CentralAuth/%s";
only_registered = true;
};
whois = {
label = "whois";
external = "//whois.toolforge.org/w/%s/lookup";
only_ip = true;
};
}
function export.make_user_linkbar(frame)
local po, pc = '', ''
local user_name = frame.args.user or "Example"
local user_enc = mw.uri.encode(user_name, "WIKI")
-- https://git.wikimedia.org/blob/mediawiki%2Fextensions%2FEcho.git/HEAD/includes%2FDiscussionParser.php#L223
-- shows that Echo parses discussions without passing the revision id (or user) to the parser.
-- therefore we can use this trick to conceal a link from Echo, but render it normally on ordinary page view.
-- the "obfuscated" link will also show up in page preview and pre-save transform (substitution), though.
local is_echo = frame.preprocess and frame:preprocess "{{REVISIONUSER}}" == ""
local function make_link(linkinfo, label)
if linkinfo.external then
po, pc = '<span class="plainlinks">', '</span>'
return "[" .. linkinfo.external:format(user_enc) .. " " .. (label or linkinfo.label) .. "]"
elseif linkinfo.query or (linkinfo.no_ping and frame.args.noping and is_echo) then
po, pc = '<span class="plainlinks">', '</span>'
return "[" .. tostring(mw.uri.fullUrl(
linkinfo.page:format(user_enc),
(linkinfo.query or ""):format(user_enc)
)) .. " " .. (label or linkinfo.label) .. "]"
else
return "[[" .. linkinfo.page:format(user_name) .. "|" .. (label or linkinfo.label) .. "]]"
end
end
local is_anon = is_unregistered(user_name)
local items = {}
local user_link
if is_anon then
if frame.args.ip then
user_link = make_link(user_linkbar_items[frame.args.ip], user_name)
else
user_link = user_name
end
else
user_link = make_link(user_linkbar_items.userpage, user_name)
end
for _, item in ipairs(frame.args) do
local linkinfo = user_linkbar_items[item]
if not linkinfo then
error("Unrecognised link id: \"" .. item .. "\"")
end
if is_anon then
if not (linkinfo.only_registered or (item == frame.args.ip)) then
items[#items + 1] = make_link(linkinfo)
end
else
if not linkinfo.only_ip then
items[#items + 1] = make_link(linkinfo)
end
end
end
return po .. user_link .. ((#items > 0) and (" (" .. table.concat(items, " • ") .. ")") or "") .. pc
end
return export