Module:UserLinks/sandbox2

From Wikipedia, the free encyclopedia
local ToolbarBuilder = require('Module:Toolbar')
local interwikiTable = mw.loadData("Module:InterwikiTable")

local u = {} -- Table for user-data helper strings.
local trackingCategories = {} -- Table for storing the tracking categories.
local demo

-- Define a custom error message for this module.
local function err(msg, section)
    local help
    if section then
        help = ' ([[Template:User-multi#' .. section .. '|help]])'
    else
        help = ''
    end
    local cat
    if demo == 'yes' then
        cat = ''
    else
        cat = '[[Category:UserLinks transclusions with errors]]'
    end
    return '<span class="error">[[Template:User-multi|User-multi]] error: ' .. msg 
        .. help .. '.</span>' .. cat
end

----------------------------------------------------------------------------------------------
--      To add more link types, write a function that produces an individual link, and put  --
--      it at the bottom of the list below. Then, add a link code for your function to the  --
--      "linktypes" table. Try and make the code three letters or less. There are a number  --
--      of helper strings available for writing the functions:                       --
--                                                                                          --
--      u.username          The plain username. If the username is not present then the     --
--                          module returns an error.                                        --
--      u.usernameHtml      The username html-encoded. Spaces are encoded with plus signs.  --
--      u.project           The project name. Nil if not specified.                         --
--      u.lang              The language code. Nil if not specified.                        --
--      u.interwiki         The interwiki prefix, consisting of the project and language    --
--                          values, separated by colons, e.g. ":wikt:es:". If no project    --
--                          or language values are found, this is the blank string, "".     --
--      u.projectCode       If a valid project is specified, this is the code for that      --
--                          project in [[Module:InterwikiTable]]. Otherwise this is nil.    --
--      u.projectLong       The long project name, e.g. "wikipedia" or "wikibooks". If      --
--                          not specified the default is "wikipedia".                       --
--      u.toolLang          The language code for use with toolserver or labs tools. The    --
--                          default is "en".                                                --
--                                                                                          --
--      If you want more helper strings, you can define them in the generateUserDataStrings --
--      function below.                                                                     --
----------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------
--                                LINK FUNCTIONS START                                      --
----------------------------------------------------------------------------------------------

local function makeUserLink()
    return '[[' .. u.interwiki .. 'User:' .. u.username .. '|' .. u.username .. ']]'
end

local function makeTalkLink()
    return '[[' .. u.interwiki .. 'User talk:' .. u.username .. '|talk]]'
end

local function makeContribsLink()
    return '[[' .. u.interwiki .. 'Special:Contributions/' .. u.username .. '|contribs]]'
end

local function makeCountLink()
    return '[https://tools.wmflabs.org/supercount/index.php?user=' .. u.usernameHtml
        .. '&project=' .. u.toolLang .. '.' .. u.projectLong
        .. ' count]'
end

local function makeMovesLink()
    return '[[' .. u.interwiki .. 'Special:Log/move/' .. u.username .. '|page&nbsp;moves]]'
end

local function makeLogsLink()
    return '[[' .. u.interwiki .. 'Special:Log/' .. u.username .. '|logs]]'
end

local function makeBlockLogLink()
    local url = mw.uri.fullUrl(u.interwiki .. 'Special:Log/block', 'page=User:' .. u.usernameHtml)
    return '[' .. tostring(url) .. ' block&nbsp;log]'
end

local function makeBlocksLink()
    return '[[' .. u.interwiki .. 'Special:Log/block/' .. u.username .. '|blocks]]'
end

local function makeBlockUserLink()
    return '[[' .. u.interwiki .. 'Special:Block/' .. u.username .. '|block&nbsp;user]]'
end

local function makeCentralAuthLink()
    return '[[' .. u.interwiki .. 'Special:CentralAuth/' .. u.username .. '|central&nbsp;auth]]'
end

local function makeDeletedContribsLink()
    return '[[' .. u.interwiki .. 'Special:DeletedContributions/' .. u.username .. '|deleted&nbsp;contribs]]'
end

local function makeEmailLink()
    return '[[' .. u.interwiki .. 'Special:Emailuser/' .. u.username .. '|email]]'
end

local function makeEditSummariesLink()
    return '[https://tools.wmflabs.org/xtools/editsummary/index.php?name=' .. u.usernameHtml
        .. '&lang=' .. u.toolLang
        .. '&wiki=' .. u.projectLong
        .. ' edit&nbsp;summaries]'
end

local function makeDeletionsLink()
    return '[[' .. u.interwiki .. 'Special:Log/delete/' .. u.username .. '|deletions]]'
end

local function makeListUserLink()
    local url = mw.uri.fullUrl(u.interwiki .. 'Special:ListUsers', 'limit=1&username=' .. u.usernameHtml)
    return '[' .. tostring(url) .. ' list&nbsp;user]'
end

local function makeSulLink()
    return '[[sulutil:' .. u.username .. '|global&nbsp;contribs]]'
end

local function makeTargetLogsLink()
    local url = mw.uri.fullUrl(u.interwiki .. 'Special:Log', 'page=User:' .. u.usernameHtml)
    return '[' .. tostring(url) .. ' target&nbsp;logs]'
end

local function makeEditFilterLogLink()
    local url = mw.uri.fullUrl(u.interwiki .. 'Special:AbuseLog', 'wpSearchUser=' .. u.usernameHtml)
    return '[' .. tostring(url) .. ' edit&nbsp;filter&nbsp;log]'
end

local function makeProtectionsLink()
    return '[[' .. u.interwiki .. 'Special:Log/protect/' .. u.username .. '|protections]]'
end

local function makeRightsLink()
    return '[[' .. u.interwiki .. 'Special:Log/rights/' .. u.username .. '|rights]]'
end

local function makeRenamesLink()
    return '[[' .. u.interwiki .. 'Special:Log/renameuser/' .. u.username .. '|renames]]'
end

local function makeRfaLink()
    if u.project or u.lang then
        table.insert( trackingCategories, '[[Category:UserLinks transclusions with unresolvable interwiki links]]' )
    end
    return '[[Special:PrefixIndex/Wikipedia:Requests for adminship/' .. u.username .. '|RfA]]'
end

local function makeApiLink()
    -- Find the full domain, as the API can't be accessed through the interwiki system.
    local fulldomain
    local lang = u.lang or 'en'
    if u.projectCode then
        local domain = interwikiTable[u.projectCode].domain
        local takesLangPrefix = interwikiTable[u.projectCode].takes_lang_prefix
        if not takesLangPrefix then
            fulldomain = domain
        else
            fulldomain = lang .. '.' .. domain
        end
    else
        fulldomain = lang .. '.wikipedia.org'
    end
    
    -- Return the API link
    return '[https://' .. fulldomain .. '/w/api.php?action=query&list=users&usprop=editcount&ususers=' .. u.usernameHtml .. ' api]'
end

local function makeUploadsLink()
    return '[[' .. u.interwiki .. 'Special:ListFiles/' .. u.username .. '|uploads]]'
end

----------------------------------------------------------------------------------------------
--                                   LINK FUNCTIONS END                                     --
--      To enable new link functions, add the code to the "linktypes" table directly below. --
----------------------------------------------------------------------------------------------

local linktypes = {
    {'t'   , makeTalkLink},
    {'c'   , makeContribsLink},
    {'ct'  , makeCountLink},
    {'m'   , makeMovesLink},
    {'l'   , makeLogsLink},
    {'bl'  , makeBlockLogLink},
    {'bls' , makeBlocksLink},
    {'bu'  , makeBlockUserLink},
    {'ca'  , makeCentralAuthLink},
    {'dc'  , makeDeletedContribsLink},
    {'e'   , makeEmailLink},
    {'es'  , makeEditSummariesLink},
    {'del' , makeDeletionsLink},
    {'lu'  , makeListUserLink},
    {'sul' , makeSulLink},
    {'tl'  , makeTargetLogsLink},
    {'efl' , makeEditFilterLogLink},
    {'pr'  , makeProtectionsLink},
    {'rl'  , makeRightsLink},
    {'ren' , makeRenamesLink},
    {'rfa' , makeRfaLink},
    {'api' , makeApiLink},
    {'up'  , makeUploadsLink}
}

local function getLink(linktype)
    local linkNumber
    for i, value in ipairs(linktypes) do
        if value[1] == linktype then
            linkNumber = i
            break
        end
    end
    if not linkNumber then
        return err('"' .. linktype .. '" is not a valid link code', 'Not a valid link code')
    end
    local result = linktypes[linkNumber][2]()
    if type(result) ~= 'string' then
        return err(
            'the function for code "' .. linktype .. '" did not return a string value',
            'Function did not return a string value'
        )
    end
    return result
end

local function makeToolbar(args)
    local targs = {}
    local numArgsExist = false
    for k, v in pairs(args) do
        if type(k) == 'number' then
            numArgsExist = true
            targs[k] = getLink(v)
        end
    end
    targs.style = args.small and 'font-size: 90%;'
    targs.separator = args.separator or 'dot'
    
    if numArgsExist == false then
        return nil -- Don't return a toolbar if no numeric arguments exist.
    else
        return ToolbarBuilder.main(targs)
    end
end

-- This function finds whether a string is a valid interwiki project prefix.
-- If the string is valid, the function outputs two values: true, and the site code
-- used in [[Module:InterwikiTable]]. If the string is valid, the function outputs
-- false and nil.
local function isKnownProject(prefix)
    for projectCode, projectVal in pairs(interwikiTable) do
        for _, iwCode in ipairs(projectVal.iw_prefix) do
            if iwCode == prefix then
                return true, projectCode
            end
        end
    end
    return false, nil
end

local function generateUserDataStrings(args)
    -- If the username is absent or blank, return an error and a tracking category.
    if args.user == '' or (not args.user and (not args.User or args.User == '')) then
        return err('no username detected', 'No username detected')
    else
        u.username = args.user or args.User
    end
    
    -- Get other basic user data strings.
    u.project = args.Project or args.project
    u.lang = args.lang or args.Lang
    if u.lang then
        if mw.language.isKnownLanguageTag(u.lang) then
            table.insert(trackingCategories, '[[Category:UserLinks transclusions with language parameters]]')
        else
            return err('"' .. u.lang .. '" is not a valid language code', 'Not a valid language code')
        end
    end
    
    -- Process the project value if it is present.
    if u.project then
        table.insert( trackingCategories, '[[Category:UserLinks transclusions with project parameters]]' )
        
        -- If u.project is a known project, we only need to get the project code. If the project 
        -- isn't known, first check whether it is a valid language code, and if not then see if it's
        -- an interwiki code separated by colons, e.g. "wikt:es".
        local uprojectIsKnownProject, uprojectProjectCode = isKnownProject(u.project)
        if uprojectIsKnownProject then
            u.projectCode = uprojectProjectCode
        else
            if mw.language.isKnownLanguageTag(u.project) then
                u.lang = u.project
                u.project = nil
            else
                local pref1, pref2 = mw.ustring.match( u.project, '^(%w+):(%w+)$' )
                if pref1 and pref2 then
                    local pref1IsKnownProject, pref1ProjectCode = isKnownProject(pref1)
                    local pref2IsKnownProject, pref2ProjectCode = isKnownProject(pref2)
                    if pref1IsKnownProject
                        and mw.language.isKnownLanguageTag(pref2)
                        and interwikiTable[pref1ProjectCode].takes_lang_prefix then
                        u.project = pref1
                        u.lang = pref2
                        u.projectCode = pref1ProjectCode
                        table.insert(
                            trackingCategories,
                            '[[Category:UserLinks transclusions with project parameters containing language codes]]'
                        )
                    elseif pref2IsKnownProject
                        and mw.language.isKnownLanguageTag(pref1)
                        and interwikiTable[pref2ProjectCode].takes_lang_prefix then
                        u.project = pref2
                        u.lang = pref1
                        u.projectCode = pref2ProjectCode
                        table.insert(
                            trackingCategories,
                            '[[Category:UserLinks transclusions with project parameters containing language codes]]'
                        )
                    else
                        return err(
                            '"' .. u.project .. '" is not a valid interwiki prefix',
                            'Not a valid interwiki prefix'
                        )
                    end
                else
                    return err(
                        '"' .. u.project .. '" is not a valid interwiki prefix',
                        'Not a valid interwiki prefix'
                    )
                end
            end
        end
    end
    
    -- Generate the interwiki prefix. This includes colons.
    if u.project or u.lang then
        u.interwiki = ''
        if u.project then
            u.interwiki = u.interwiki .. ':' .. u.project
        end
        if u.lang then
            u.interwiki = u.interwiki .. ':' .. u.lang
        end
        u.interwiki = u.interwiki .. ':'
    else
        u.interwiki = ''
    end

    -- Generate the other helper strings.
    u.usernameHtml = mw.uri.encode(u.username) -- Html-encoded username. Spaces are encoded as pluses.
    if u.project then
        local prefixes = interwikiTable[u.projectCode].iw_prefix
        u.projectLong = prefixes[2] or prefixes[1] -- A bit of a hack, but should find the long prefix name most of the time.
    else
        u.projectLong = 'wikipedia'
    end
    u.toolLang = u.lang or 'en' -- set the default language for tools on the toolserver or labs.
end

local function generateTrackingCategories()
    if demo == 'yes' then
        return ''
    else
        return table.concat(trackingCategories)
    end
end

-- This function generates a table of all available link types, with their previews.
-- It is used in the module documentation.
local function getLinkTable(args)
    demo = args.demo -- Set the demo variable.
    -- Generate the user data strings and return any errors.
    local dataStringError = generateUserDataStrings(args)
    if dataStringError then
        return dataStringError
    end
    
    -- Build a table of all of the links.
    local result = '<table class="wikitable plainlinks sortable">'
        .. '\n<tr><th>Code</th><th>Preview</th></tr>'
    for i, value in ipairs(linktypes) do
        local code = value[1]
        result = result .. "\n<tr><td>'''" .. code .. "'''</td><td>" .. getLink(code) .. '</td></tr>'
    end
    result = result .. '\n</table>'
    
    return result
end

local function getSingleLink(args)
    demo = args.demo -- Set the demo variable.
    -- Generate the user data strings and return any errors.
    local dataStringError = generateUserDataStrings(args)
    if dataStringError then
        return dataStringError
    end
    
    local linktype = args[1]
    if not linktype then 
        return err('no link type specified')
    end
    local result = getLink(linktype)
    result = result .. generateTrackingCategories()
    return result
end

local function getLinks(args)
    demo = args.demo -- Set the demo variable.
    -- Generate the user data strings and return any errors.
    local dataStringError = generateUserDataStrings(args)
    if dataStringError then
        return dataStringError
    end    
    
    -- Build the template output.
    local result = makeToolbar(args) -- Get the toolbar contents.
    if result then
        if args.sup then
            result = '<sup>' .. result .. '</sup>'
        end
        result = '&nbsp;' .. result
    else
        result = '' -- If there are no links specified, don't return the toolbar at all.
    end
    result = '<span>' .. makeUserLink() .. result .. '</span>'
    result = result .. generateTrackingCategories()
    
    return result
end

local function getExampleLinks(args)
    -- This function enables example output without having to specify any
    -- parameters to #invoke.
    args.demo = 'yes'
    args.user = 'Example'
    args.User = nil
    return getLinks(args)
end

local function makeWrapper(func)
    return function (frame)
        -- If called via #invoke, use the args passed into the invoking template.
        -- Otherwise, for testing purposes, assume args are being passed directly in.
        local origArgs
        if frame == mw.getCurrentFrame() then
            origArgs = frame:getParent().args
            for k, v in pairs(frame.args) do
                origArgs = frame.args
                break
            end
        else
            origArgs = frame
        end
 
        -- Strip whitespace, and treat blank arguments as nil.
        -- 'user', 'User', and 'separator' have different behaviour depending on
        -- whether they are blank or nil, so keep them as they are.
        local args = {}
        for k, v in pairs(origArgs) do
            v = mw.text.trim(v)
            if v ~= '' or k == 'user' or k == 'User' or k == 'separator' then
                args[k] = v
            end
        end
    
        return func(args)
    end
end

return {
    main = makeWrapper(getLinks),
    single = makeWrapper(getSingleLink),
    linktable = makeWrapper(getLinkTable),
    example = makeWrapper(getExampleLinks)
}