Module:linkbar

From Wiktionary, the free dictionary
Jump to navigation Jump to search

This module needs documentation.
Please document this module by describing its purpose and usage on the documentation page.

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 = "abuse 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