Jump to content

Module:CapacityExchange

From Meta, a Wikimedia project coordination wiki
Module documentation

This Lua module is part of the Capacity Exchange platform. It is designed to display user capacities on their user pages. The module retrieves user data and capacity information from toolforge:capx, process and generates the HTML content to present the user's known and wanted capacities.

Usage

[edit]

{{CapacityExchange}}


local users = mw.ext.data.get("CapacityExchange/users.tab").data
local lang = mw.getCurrentFrame():preprocess("{{Int:Lang}}")
local capacities = mw.ext.data.get("CapacityExchange/capacities.tab", lang).data
local badgesData = mw.ext.data.get("CapacityExchange/badges.tab").data
local tmb = require 'mw.ext.translate.messageBundle'
local mb = tmb.new( "Module:CapacityExchange/locale.json", lang )
local is_rtl = require( 'Module:Is rtl' )
local p = {}

-- Get the text direction
function get_dir()
    if is_rtl[lang] then
        return "rtl"
    else
        return "ltr"
    end
end

-- Create a mapping of capacity IDs to their names and descriptions.
-- Export rows: [id:number, name:string, description:string, wikidata_item:string]
local capacityMap = {}
for _, capacity in ipairs(capacities) do
    local id = tostring(capacity[1])
    local nameVal = capacity[2] or ''
    local descVal = capacity[3] or ''
    local key = capacity[4] -- wikidata_item / QID
    capacityMap[id] = { key = key, label = nameVal, description = descVal }
end

-- Create a mapping of badge IDs to their names and images
local badgeMap = {}
for _, badge in ipairs(badgesData) do
    -- badge schema: [id:number, name:string, image:string, base_url:string]
    local id = tostring(badge[1])
    badgeMap[id] = { name = badge[2], image = badge[3], base_url = badge[4] }
end

-- Function to get user data by username
local function getUserData(username)
    for _, userData in ipairs(users) do
        if userData[1] == username then
            return {
                username = userData[1],
                skills_known = userData[2],
                skills_available = userData[3],
                badges = userData[4]
            }
        end
    end
    return nil
end

-- Helper function to replace capacity IDs with names and descriptions
local function replaceCapacities(capacityList, sectionPrefix)
    local result = {}
    -- Remove [] and split by comma
    capacityList = mw.ustring.gsub(capacityList, "%[", "")
    capacityList = mw.ustring.gsub(capacityList, "%]", "")
    for _, capacityId in ipairs(mw.text.split(capacityList, ",")) do
        local trimmedId = mw.text.trim(capacityId)
        if trimmedId ~= "" then
            local meta = capacityMap[trimmedId]
            if meta then
                local toggleId = sectionPrefix .. "-" .. meta.key
                table.insert(result,
                    "<div class='capx-capacity'>" ..
                        "<div class='capx-name mw-customtoggle-" .. toggleId .. "'>" .. meta.label .. "</div>" ..
                        "<div class='capx-desc mw-collapsible mw-collapsed' id='mw-customcollapsible-" .. toggleId .. "'>" .. meta.description .. "</div>" ..
                    "</div>"
                )
            else
                table.insert(result, "<div class='capx-unknown'>" .. trimmedId .. "</div>")
            end
        end
    end
    return result
end

-- Helper function to load badges
local function loadBadges(badgeList)
    local result = {}
    -- Remove [] and split by comma
    badgeList = mw.ustring.gsub(badgeList, "%[", "")
    badgeList = mw.ustring.gsub(badgeList, "%]", "")
    for _, badge in ipairs(mw.text.split(badgeList, ",")) do
        local parts = mw.text.split(mw.text.trim(badge), "§")
        local id = mw.text.trim(parts[1] or "")
        if id ~= "" then
            local meta = badgeMap[id]
            if meta then
                local hashCode = parts[2]
                local badgeUrl = nil
                if hashCode and hashCode ~= "" and meta.base_url and meta.base_url ~= "" then
                    badgeUrl = meta.base_url .. hashCode
                end
                if not badgeUrl or badgeUrl == "" then
                    badgeUrl = "https://meta.wikimedia.org/wiki/Capacity_Exchange/User_Guide#Badges"
                end
                table.insert(result, "<div class='capx-badge'>")
                table.insert(result, "<table role='presentation'>")
                table.insert(result, "<tr>")
                table.insert(result, "<td>[[File:" .. meta.image .. "|45px]]</td>")
                table.insert(result, "<td>" .. mw.getCurrentFrame():preprocess(mb:t( "badge" ):params( badgeUrl, meta.name, '{{PAGENAME}}' ):plain()) .. "</td>")
                table.insert(result, "</tr>")
                table.insert(result, "</table>")
                table.insert(result, "</div>")
            else
                -- Unknown badge id
                table.insert(result, "<div class='capx-badge capx-unknown'>" .. mb:t( "unknown-badge" ):params( id ):plain() .. "</div>")
            end
        end
    end
    return result
end

-- Return the constructed table
local function constructCapacitiesTable(knownCapacities, availableCapacities, badges)
    local capacitiesTable = {}
    local localeLink = 'https://meta.wikimedia.org/w/index.php?title=Special%3ATranslate&group=messagebundle-Module%3ACapacityExchange%2Flocale.json'
    local capacitiesLink = 'https://meta.wikimedia.org/w/index.php?title=Special%3ATranslate&group=messagebundle-Module%3ACapacityExchange%2Fcapacities.json'
    table.insert(capacitiesTable, "<div class='capx-main' style='direction: " .. get_dir() .. ";'>")
    table.insert(capacitiesTable, "<div class='capx-logo'>")
    table.insert(capacitiesTable, mb:t( "help-translate-plus" ):params( localeLink, capacitiesLink ):plain())
    table.insert(capacitiesTable, "</div>")
    if #availableCapacities > 0 then
        table.insert(capacitiesTable, "<div class='capx-available'>")
	    table.insert(capacitiesTable, "<div class='capx-title-" .. get_dir() .. "'>" .. mb:t( "available" ):plain() .. "</div>")
        for _, capacity in ipairs(availableCapacities) do
            table.insert(capacitiesTable, capacity)
        end
        table.insert(capacitiesTable, "<div class='capx-message'>" .. mw.getCurrentFrame():preprocess(mb:t( "you-available" ):params( '{{PAGENAME}}' ):plain()) .. "</div>")
	    table.insert(capacitiesTable, "</div>")
    end
    if #knownCapacities > 0 then
	    table.insert(capacitiesTable, "<div class='capx-known'>")
	    table.insert(capacitiesTable, "<div class='capx-title-" .. get_dir() .. "'>" .. mb:t( "known" ):plain() .. "</div>")
	    for _, capacity in ipairs(knownCapacities) do
	        table.insert(capacitiesTable, capacity)
	    end
	    table.insert(capacitiesTable, "<div class='capx-message'>" .. mw.getCurrentFrame():preprocess(mb:t( "you-have" ):params( '{{PAGENAME}}' ):plain()) .. "</div>")
	    table.insert(capacitiesTable, "</div>")
    end
	table.insert(capacitiesTable, "<div class='capx-button'>[[:toolforge:capx|" .. mb:t( "access-capx" ):plain() .. "]]</div>")
    table.insert(capacitiesTable, "<div class='capx-badges'>")
	    table.insert(capacitiesTable, "<div class='capx-title-" .. get_dir() .. "'>" .. mb:t( "recognition" ):plain() .. "</div>")
    for _, badge in ipairs(badges) do
        table.insert(capacitiesTable, badge)
    end
    table.insert(capacitiesTable, "</div>")
    table.insert(capacitiesTable, "</div>")
    return table.concat(capacitiesTable, "\n")
end

function p.main(frame)
    -- Check if namespace is 2, else return a message
    if mw.title.getCurrentTitle().namespace ~= 2 then
        return "<div class='capx-error'>" .. mb:t( "wrong-namespace" ):plain() .. "</div>"
    end

    -- Get the title of the page and remove the namespace
    local user = mw.ustring.gsub(mw.title.getCurrentTitle().text, "User:", "")

    -- Get the specific user data
    local userData = getUserData(user)
    if not userData then
        return "<div class='capx-error'>" .. mb:t( "not-found" ):plain() .. "</div>"
    end

    -- Replace capacity IDs with names and descriptions (use unique section prefixes)
    local knownCapacities = replaceCapacities(userData.skills_known, "known")
    local availableCapacities = replaceCapacities(userData.skills_available, "available")
    local badges = loadBadges(userData.badges)

    return constructCapacitiesTable(knownCapacities, availableCapacities, badges)
end

return p