Jump to content

Module:Person

From HopperWiki

Documentation for this module may be created at Module:Person/doc

-- ================================================================================
-- Module dependencies
-- ================================================================================
local cargo = mw.ext.cargo
local getArgs = require('Module:Arguments').getArgs -- for processing arguments

-- Utilities
local str = require("Module:String utilities")

-- Galleries
local gallery = require("Module:Gallery")




-- ================================================================================
-- Main table
-- ================================================================================
local p = {}


-- Builds a Cargo "OR" WHERE clause matching Full_name against each name in names.
local function build_or_conditions(names)
    local conditions = {}
    for _, name in ipairs(names) do
        local sanitized = str.escape_string_for_sql(name)
        table.insert(conditions, string.format("Full_name = '%s'", sanitized))
    end
    return table.concat(conditions, ' OR ')
end


-- Queries the Person table for the given names, falling back to Person_extra
-- for any names not found there. Person_extra holds people who are recorded
-- as data without getting their own full wiki page.
-- Returns a table keyed by Full_name -> row, containing only names that were found.
local function query_person_rows(name_array, fields)
    local found_names = {}
    local primary_results = cargo.query("Person", fields, { where = build_or_conditions(name_array) })
    for _, entry in ipairs(primary_results) do
        found_names[entry.Full_name] = entry
    end

    local missing_names = {}
    for _, name in ipairs(name_array) do
        if not found_names[name] then
            table.insert(missing_names, name)
        end
    end

    if #missing_names > 0 then
        local backup_results = cargo.query("Person_extra", fields, {
            where = build_or_conditions(missing_names)
        })
        for _, entry in ipairs(backup_results) do
            found_names[entry.Full_name] = entry
        end
    end

    return found_names
end













function p.get_person_gallery_modern(frame)
    
    -- ========================================
    -- Parse arguments
    -- ========================================
    local args = getArgs(frame)
    local name_string = args.names or ""
    local perrow = args.perrow or 6
    
    -- Convert comma-delimited names to array
    local name_array = {}
    for value in string.gmatch(name_string, '([^,]+)') do
        table.insert(name_array, mw.text.trim(value))
    end
    
    if #name_array == 0 then
        return '<span class="gallery-error">No names provided!</span>'
    end
    
    -- ========================================
    -- Query Person table (falling back to Person_extra)
    -- ========================================
    local fields = "Full_name, Image, Organizations, Position_titles"
    local found_names = query_person_rows(name_array, fields)

    -- ========================================
    -- Build gallery items
    -- ========================================
    local placeholder = 'Face silhouette for no photo profiles.png'
    local gallery_items = {}
    
	for _, name in ipairs(name_array) do
	    local person = found_names[name]
	    
	    -- Determine image
	    local image = placeholder
	    if person and person.Image and person.Image ~= '' then
	        image = str.file_title(person.Image)
	    end
	    
	    -- Simple caption: just the name as a link
	    local caption = string.format("[[%s|%s]]", name, name)
	    
	    table.insert(gallery_items, {
	        image = image,
	        link = name,
	        caption = caption
	    })
	end

	local gallery_output = gallery.build_modern_gallery(gallery_items, {
	    widths = "175px",   
	    perrow = perrow,
	    show_captions = "always"
	})
    
    return frame:preprocess(gallery_output)
end











-- ================================================================================
-- Get person gallery
-- ================================================================================
function p.get_person_gallery(frame)

    -- ========================================
    -- Parse arguments
    -- ========================================
    local args = getArgs(frame)
    local gallery_mode = args.gallery_mode or "packed"
    local name_string = args.names or ""

    local name_array = {}
    for value in string.gmatch(name_string, '([^,]+)') do
        table.insert(name_array, mw.text.trim(value))
    end

    if #name_array == 0 then
        return '<span class="gallery-error">No names provided!</span>'
    end

    -- ========================================
    -- Query Person table (falling back to Person_extra)
    -- ========================================
    local placeholder_image = 'Face silhouette for no photo profiles.png'
    local fields = "Full_name, Image, Organizations, Position_titles"
    local found_names = query_person_rows(name_array, fields)

    -- ========================================
    -- Build gallery items
    -- ========================================
    local gallery_items = {}
    for _, name in ipairs(name_array) do
        local person = found_names[name]

        local image = placeholder_image
        if person and person.Image and person.Image ~= '' then
            image = str.file_title(person.Image)
        end

        local organizations = (person and person.Organizations) or "Unknown organization"
        local position_titles = (person and person.Position_titles) or "Unknown position"
        local caption = string.format("%s<br>%s<br>%s", name, organizations, position_titles)

        table.insert(gallery_items, { image = image, caption = caption })
    end

    -- ========================================
    -- Render through Module:Gallery instead of hand-built wikitext
    -- ========================================
    local gallery_wikitext = gallery.build_gallery(gallery_items, { mode = gallery_mode, heights = "200" })

    return frame:preprocess(gallery_wikitext)

end






-- ================================================================================
-- Create a person bio box (with robust checks and meaningful errors)
-- ================================================================================
function p.get_person_bio_box(frame)

    -- --------------------------------------------------------------------------
    -- 1. Validate frame and arguments
    -- --------------------------------------------------------------------------
    if frame == nil then
        return '<span style="color: red;">Error: No frame passed to get_person_bio_box.</span>'
    end

    local ok, args = pcall(getArgs, frame)
    if not ok then
        return string.format('<span style="color: red;">Error retrieving template arguments: %s</span>', args or "unknown error")
    end

    local title = mw.title.getCurrentTitle() and mw.title.getCurrentTitle().text or "(no title)"
    local name = args.name or title or ""
    if name == "" then
        return '<span style="color: red;">Error: No name provided and current page title is empty.</span>'
    end

    -- --------------------------------------------------------------------------
    -- 2. Run Cargo query
    -- --------------------------------------------------------------------------
    local tables = "Person"
    local fields = "Full_name, Image, Position_titles, Bio"
    local where = string.format('Full_name = "%s"', mw.text.trim(name))

    local cargo_results
    local success, err = pcall(function()
        cargo_results = mw.ext.cargo.query(tables, fields, { where = where })
    end)

    if not success then
        return string.format('<span style="color: red;">Error querying Cargo: %s</span>', err or "unknown")
    end

    if not cargo_results or #cargo_results < 1 then
        return string.format('<span style="color: red;">No Cargo record found for "%s".</span>', name)
    end

    local row = cargo_results[1]

    -- --------------------------------------------------------------------------
    -- 3. Prepare values safely
    -- --------------------------------------------------------------------------
    local image = row.Image
    if not image or image == "" then
        image = "Face silhouette for no photo profiles.png"
    end

    if str and str.add_file_prefix_gentle then
        local ok2, prefixed = pcall(str.add_file_prefix_gentle, image)
        if ok2 and prefixed then image = prefixed end
    end

    local position_titles = args.position_title or row.Position_titles or ""
    local bio_text = row.Bio or ""

    -- --------------------------------------------------------------------------
    -- 4. Build HTML structure
    -- --------------------------------------------------------------------------
    local container = mw.html.create('div'):addClass('person-photo-box')

    -- Header
    local header_text
    if position_titles ~= "" then
        header_text = string.format('[[%s|%s - %s]]', name, name, position_titles)
    else
        header_text = string.format('[[%s|%s]]', name, name)
    end

    container:tag('div')
        :addClass('person-photo-header')
        :wikitext(header_text)

    -- Content wrapper
    local contentWrapper = mw.html.create('div'):addClass('content-wrapper')

    local imageDiv = mw.html.create('div')
        :addClass('person-photo-content')
        :wikitext(string.format('[[%s|link=%s]]', image, name))

    local textDiv = mw.html.create('div')
        :addClass('person-photo-text')
        :wikitext(bio_text)

    contentWrapper:node(imageDiv):node(textDiv)
    container:node(contentWrapper)

    -- --------------------------------------------------------------------------
    -- 5. Return safely
    -- --------------------------------------------------------------------------
    return tostring(container)
end






-- ================================================================================
-- Get person photo
-- ================================================================================
local function get_person_photo(frame)
	
	local args = getArgs(frame)
	local title = mw.title.getCurrentTitle().text
	local name = args.name or title

	-- cargo query to retrieve user image
    local tables = "Person"
	local fields = "Full_name, Image"
    local cargo_args = {
    	where = string.format('Full_name = "%s"', name)
	}
	
	local cargo_results = cargo.query(tables, fields, cargo_args)
	
	-- extract image name
	local image = cargo_results[1].Image
	-- add file prefix if needed
	image = str.add_file_prefix_gentle(image)
	
	if cargo_results and #cargo_results > 0 then
		 -- return user bio
    	return "[[" .. image .. "]]"
    else
    	 -- return error message in red
        return string.format('<span style="color: red;">%s</span>', "Can't find this name in the Cargo database!")
	end

end
p.get_person_photo = get_person_photo





























-- ================================================================================
-- Retrieve a Person biography
-- ================================================================================
local function biography(frame)
	
	local args = getArgs(frame)
	local title = mw.title.getCurrentTitle().text
	
	local name = args.name or title

	-- cargo query to retrieve user bio
    local tables = "Person"
	local fields = "Full_name, Bio"
    local cargo_args = {
    	where = string.format('Full_name = "%s"', name)
	}
	
	local cargo_results = cargo.query(tables, fields, cargo_args)
	
	if cargo_results and #cargo_results > 0 then
		 -- return user bio
    	return cargo_results[1]["Bio"]
    else
    	 -- return error message in red
        return string.format('<span style="color: red;">%s</span>', "Can't find this name in the Cargo database!")
	end

end
p.biography = biography








return p
Cookies help us deliver our services. By using our services, you agree to our use of cookies.