Module:UserLinks/sandbox

This is an old revision of this page, as edited by Mr. Stradivarius (talk | contribs) at 14:44, 1 April 2014 (switch link code check order). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
-- Require necessary modules
local yesno = require('Module:Yesno')

-- Lazily initialise modules that we might or might not need
local mArguments
local mToolbar
local mCategoryHandler
local mTableTools
local interwikiTable -- Module:InterwikiTable, loaded with mw.loadData

-- Load shared helper functions
local mShared = require('Module:UserLinks/shared')
local raiseError = mShared.raiseError
local makeWikitextError = mShared.makeWikitextError
local makeWikilink = mShared.makeWikilink
local makeUrlLink = mShared.makeUrlLink

local p = {}

--------------------------------------------------------------------------------
-- Link functions
--------------------------------------------------------------------------------

function p.getLinkFunctions()
	local linkFunctions = {}

	-- Get extra link functions first, and allow the built-in link functions to
	-- overwrite them. Extra link functions are stored in /extra. We need to
	-- give the built-in functions priority, or a vandal could change high-risk
	-- link functions from the /extra module.
	local success, mExtra = pcall(require, 'Module:UserLinks/extra')
	if success then
		local extraLinkFunctions = type(mExtra) == 'table' and mExtra.linkFunctions
		if type(extraLinkFunctions) == 'table' then
			for code, func in pairs(extraLinkFunctions) do
				if type(code) == 'string'
					and code ~= ''
					and type(func) == 'function'
				then
					linkFunctions[code] = func
				end
			end
		end
	end

	-- Built-in link functions
	function linkFunctions.u(snippets)
		-- User page
		return makeWikilink(snippets.interwiki .. 'User:' .. snippets.username, snippets.username)
	end

	function linkFunctions.t(snippets)
		-- User talk page
		return makeWikilink(snippets.interwiki .. 'User talk:' .. snippets.username, 'talk')
	end

	function linkFunctions.c(snippets)
		-- Contributions
		return makeWikilink(snippets.interwiki .. 'Special:Contributions/' .. snippets.username, 'contribs')
	end

	function linkFunctions.ct(snippets)
		-- Edit count
		return string.format(
			'[//tools.wmflabs.org/supercount/index.php?user=%s&project=%s.%s count]',
			snippets.usernameHtml, snippets.toolLang, snippets.projectLong
		)
	end

	function linkFunctions.m(snippets)
		-- Page moves
		return makeWikilink(snippets.interwiki .. 'Special:Log/move/' .. snippets.username, 'page moves')
	end

	function linkFunctions.l(snippets)
		-- Logs
		return makeWikilink(snippets.interwiki .. 'Special:Log/' .. snippets.username, 'logs')
	end

	function linkFunctions.bl(snippets)
		-- Block log
		return makeUrlLink(snippets.interwiki .. 'Special:Log/block', {page = 'User:' .. snippets.username}, 'block log')
	end

	function linkFunctions.bls(snippets)
		-- Blocks
		return makeWikilink(snippets.interwiki .. 'Special:Log/block/' .. snippets.username, 'blocks')
	end

	function linkFunctions.bu(snippets)
		-- Block user
		return makeWikilink(snippets.interwiki .. 'Special:Block/' .. snippets.username, 'block user')
	end

	function linkFunctions.ca(snippets)
		-- Central auth
		return makeWikilink(snippets.interwiki .. 'Special:CentralAuth/' .. snippets.username, 'central auth')
	end

	function linkFunctions.dc(snippets)
		-- Deleted contribs
		return makeWikilink(snippets.interwiki .. 'Special:DeletedContributions/' .. snippets.username, 'deleted contribs')
	end

	function linkFunctions.e(snippets)
		-- Email
		return makeWikilink(snippets.interwiki .. 'Special:EmailUser/' .. snippets.username, 'email')
	end

	function linkFunctions.es(snippets)
		-- Edit summaries
		return string.format(
			'[//tools.wmflabs.org/xtools/editsummary/index.php?name=%s&lang=%s&wiki=%s edit summaries]',
			snippets.usernameHtml, snippets.toolLang, snippets.projectLong
		)
	end

	function linkFunctions.del(snippets)
		-- Deletions
		return makeWikilink(snippets.interwiki .. 'Special:Log/delete/' .. snippets.username, 'deletions')
	end

	function linkFunctions.lu(snippets)
		-- List user
		return makeUrlLink(snippets.interwiki .. 'Special:ListUsers', {limit = 1, user = snippets.username}, 'list user')
	end

	function linkFunctions.sul(snippets)
		-- SUL
		return makeWikilink('sulutil:' .. snippets.username, 'global contribs')
	end

	function linkFunctions.tl(snippets)
		-- Target logs
		return makeUrlLink(snippets.interwiki .. 'Special:Log', {page = 'User:' .. snippets.username}, 'target logs')
	end

	function linkFunctions.efl(snippets)
		-- Edit filter log
		return makeUrlLink(snippets.interwiki .. 'Special:AbuseLog', {wpSearchUser = snippets.username}, 'edit filter log')
	end

	function linkFunctions.pr(snippets)
		-- Protections
		return makeWikilink(snippets.interwiki .. 'Special:Log/protect/' .. snippets.username, 'protections')
	end

	function linkFunctions.rl(snippets)
		-- User rights
		return makeWikilink(snippets.interwiki .. 'Special:Log/rights/' .. snippets.username, 'rights')
	end

	function linkFunctions.ren(snippets)
		-- Renames
		return makeWikilink(snippets.interwiki .. 'Special:Log/renameuser/' .. snippets.username, 'renames')
	end

	function linkFunctions.rfa(snippets)
		-- Requests for adminship
		return makeWikilink('Special:PrefixIndex/Wikipedia:Requests for adminship/' .. snippets.username, 'RfA')
	end

	function linkFunctions.api(snippets)
		-- API user data
		return string.format(
			'[//%s/w/api.php?action=query&list=users&usprop=editcount&ususers=%s api]',
			snippets.fullDomain, snippets.usernameHtml
		)
	end

	function linkFunctions.up(snippets)
		-- Uploads
		return makeWikilink(snippets.interwiki .. 'Special:ListFiles/' .. snippets.username, 'uploads')
	end

	return linkFunctions
end

--------------------------------------------------------------------------------
-- User data snippets
--------------------------------------------------------------------------------

function p.getSnippets(args)
	local snippets, snippetFunctions = {}, {}
	setmetatable(snippets, {
		__index = function (t, key)
			local snippetFunction = snippetFunctions[key]
			if snippetFunction then
				snippets[key] = snippetFunction() or ''
				return snippets[key]
			else
				raiseError('no snippet exists for the key "' .. key .. '"', 'No snippet exists')
			end
		end
	})

	local function snippetExists(key)
		-- We have set the metatable up to make snippets default to '', so we
		-- don't have to test for false or nil.
		return snippets[key] ~= ''
	end

	local function getSnippet(key)
		local ret = snippets[key]
		if ret == '' then
			return nil
		else
			return ret
		end
	end

	function snippetFunctions.username()
		-- The username.
		local username = args.user or args.User
		return username or raiseError('no username detected', 'No username detected')
	end

	function snippetFunctions.usernameHtml()
		-- The username html-encoded. Spaces are encoded as pluses.
		return mw.uri.encode(snippets.username)
	end

	function snippetFunctions.project()
		-- The project name.
		-- Also does the work for snippetFunctions.interwikiTableKey.
		local project = args.Project or args.project
		if not project then
			return nil
		end
		local projectValidated, interwikiTableKey = p.validateProjectCode(project)
		if not projectValidated then
			raiseError('"' .. project .. '" is not a valid interwiki prefix', 'Not a valid interwiki prefix')
		end
		snippets.interwikiTableKey = interwikiTableKey
		return project
	end

	function snippetFunctions.interwikiTableKey()
		-- The key for the project in Module:InterwikiTable.
		-- Relies on snippetFunctions.project to do the real work.
		local temp = snippets.project -- required, as it puts the key in the snippets table
		return rawget(snippets, 'interwikiTableKey')
	end

	function snippetFunctions.projectLong()
		-- The long form of the project name, e.g. "wikipedia" or "wikibooks".
		local key = getSnippet('interwikiTableKey')
		if not key then
			return nil
		end
		interwikiTable = interwikiTable or mw.loadData('Module:InterwikiTable')
		local prefixes = interwikiTable[key].iw_prefix
		return prefixes[2] or prefixes[1] -- A bit of a hack, but should find the long name most of the time
	end

	function snippetFunctions.lang()
		-- The language code.
		local lang = args.lang or args.Lang
		if not lang then
			return nil
		end
		if mw.language.isKnownLanguageTag(lang) then
			return lang
		else
			raiseError('"' .. lang .. '" is not a valid language code', 'Not a valid language code')
		end
	end

	function snippetFunctions.toolLang()
		-- The language code for use with toolserver or labs tools. It is always
		-- present, even if the "lang" argument is absent. The default value is "en". 
		return getSnippet('lang') or 'en'
	end

	function snippetFunctions.interwiki()
		-- The interwiki prefix, consisting of the project and language values,
		-- separated by colons, e.g. ":wikt:es:".
		local project = getSnippet('project')
		local lang = getSnippet('lang')
		if not project and not lang then
			return nil
		end
		local ret = {}
		ret[#ret + 1] = project
		ret[#ret + 1] = lang
		return ':' .. table.concat(ret, ':') .. ':'
	end

	function snippetFunctions.fullDomain()
		-- The full ___domain name of the site, e.g. www.mediawiki.org,
		-- en.wikpedia.org, or ja.wikibooks.org.
		local fullDomain
		local lang = getSnippet('toolLang')
		local key = getSnippet('interwikiTableKey')
		if key then
			interwikiTable = interwikiTable or mw.loadData('Module:InterwikiTable')
			local ___domain = interwikiTable[key].___domain
			local takesLangPrefix = interwikiTable[key].takes_lang_prefix
			if takesLangPrefix then
				fullDomain = lang .. '.' .. ___domain
			else
				fullDomain = ___domain
			end
		else
			fullDomain = lang .. '.wikipedia.org'
		end
		return fullDomain
	end

	return snippets
end	

function p.validateProjectCode(s)
	-- Validates a project code, by seeing whether it is present in
	-- [[Module:InterwikiTable]]. If it is present, returns the code and the
	-- InterwikiTable key for the corresponding site. If not present,
	-- returns nil for both.
	interwikiTable = interwikiTable or mw.loadData('Module:InterwikiTable')
    for key, t in pairs(interwikiTable) do
        for i, prefix in ipairs(t.iw_prefix) do
            if s == prefix then
                return s, key
            end
        end
    end
    return nil, nil
end

--------------------------------------------------------------------------------
-- Main functions
--------------------------------------------------------------------------------

local function makeInvokeFunction(funcName)
	return function (frame)
		mArguments = require('Module:Arguments')
		local args = mArguments.getArgs(frame)
		return p[funcName](args)
	end
end

p.main = makeInvokeFunction('_main')

function p._main(args)
	local options = p.getOptions(args)
	local snippets = p.getSnippets(args)
	local codes = p.getCodes(args)
	local linkFunctions = p.getLinkFunctions()
	local success, result = pcall(p.export, codes, snippets, linkFunctions, options)
	if success then
		return result
	else
		return makeWikitextError(result, options.isDemo)
	end
end

function p.getOptions(args)
	local options = {}
	options.isDemo = yesno(args.demo) or false
	options.toolbarStyle = yesno(args.small) and 'font-size: 90%;' or nil
	options.sup = yesno(args.sup, true)
	options.separator = args.separator
	options.span = args.span
	return options
end

function p.getCodes(args)
	mTableTools = require('Module:TableTools')
	local codes = mTableTools.compressSparseArray(args)
	return codes
end

function p.export(codes, snippets, linkFunctions, options)
	-- Make the user link.
	local userLink = linkFunctions.u(snippets)

	-- Check to see that we were passed at least one code, and return the
	-- blank string otherwise.
	if #codes < 1 then
		return ''
	end

	-- Make the toolbar.
	mToolbar = require('Module:Toolbar')
	local toolbarArgs = {}
	for i, code in ipairs(codes) do
		local linkFunction = linkFunctions[code]
		if not linkFunction then
			raiseError('"' .. code .. '" is not a valid link code', 'Not a valid link code')
		end
		local link = linkFunction(snippets)
		toolbarArgs[#toolbarArgs + 1] = link
	end
	toolbarArgs.style = options.toolbarStyle
	toolbarArgs.separator = options.separator or 'dot'
	toolbarArgs.span = options.span
	local toolbar = mToolbar.main(toolbarArgs)

	-- Apply the sup option and return the result.
	if options.sup then
		toolbar = '<sup>' .. toolbar .. '</sup>'
	end
	return userLink .. '&nbsp;' .. toolbar
end

--------------------------------------------------------------------------------
-- Single link function
--------------------------------------------------------------------------------

p.single = makeInvokeFunction('_single')

function p._single(args)
	local options = p.getOptions(args)
	local code = args[1]
	if not code then
		return makeWikitextError(
			'no link type specified|No link type specified',
			options.isDemo
		) 
	end
	local snippets = p.getSnippets(args)
	local linkFunctions = p.getLinkFunctions()
	local linkFunction = linkFunctions[code]
	local success, result = pcall(linkFunction, snippets)
	if success then
		return result
	else
		return makeWikitextError(result, options.isDemo)
	end
end

--------------------------------------------------------------------------------
-- Link table
--------------------------------------------------------------------------------

function p.linktable()
	local args = {user = 'Example'}
	local snippets = p.getSnippets(args)
	local linkFunctions = p.getLinkFunctions()

	-- Assemble the codes and links in order
	local firstCodes = {'u', 't', 'c'}
	local firstLinks, firstCodesKeys = {}, {}
	for i, code in ipairs(firstCodes) do
		firstCodesKeys[code] = true
		local success, link = pcall(linkFunctions[code], snippets)
		if success then
			firstLinks[#firstLinks + 1] = {code, link}
		else
			return makeWikitextError(result, true)
		end
	end
	local secondLinks = {}
	for code, linkFunction in pairs(linkFunctions) do
		if not firstCodesKeys[code] then
			local success, link = pcall(linkFunction, snippets)
			if success then
				secondLinks[#secondLinks + 1] = {code, link}
			else
				return makeWikitextError(result, true)
			end
		end
	end
	table.sort(secondLinks, function(t1, t2)
		return t1[1] < t2[1]
	end)
	local links = {}
	for i, t in ipairs(firstLinks) do
		links[#links + 1] = t
	end
	for i, t in ipairs(secondLinks) do
		links[#links + 1] = t
	end

	-- Output the code table in table format
	local ret = {}
	ret[#ret + 1] = '{| class="wikitable plainlinks sortable"'
	ret[#ret + 1] = '|-'
	ret[#ret + 1] = '! Code'
	ret[#ret + 1] = '! Preview'
	for i, t in ipairs(links) do
		local code = t[1]
		local link = t[2]
		ret[#ret + 1] = '|-'
		ret[#ret + 1] = "| '''" .. code .. "'''" 
		ret[#ret + 1] = '| ' .. link
	end
	ret[#ret + 1] = '|}'
	return table.concat(ret, '\n')
end	

return p