Module:User

local getArgs = require('Module:Arguments').getArgs local loader = require('Module:Loader')

local string, table, yesno, libUtil = loader.require('String', 'Table', 'Yesno', 'LibU') local checkType = libUtil.checkType

local thisdata, staffaliases = loader.loadData('User/Data', 'Staff/Aliases') local sep = ' • '

local p = {}

-- Helper Functions local function bracket(s) return string.wrapHtml( ('(%s)'):format(s), ' ', { style = 'font-size: 10px' } ) end

- -- Export Templates - -- Template: UserRole function p.userRole(frame) local args = getArgs(frame) local name = args[1] local alt = args[2] local plural = yesno(args['plural'] or args['plur'] or args['p'], false) local shorten = yesno(args['short'] or args['shr'] or args['s'], false) local linkAlt = args['link_alt'] or args['link'] or args['linkalt'] or args['la'] or args['l'] local altText = args['alt'] or args['a'] local success, response = pcall(p._userRole, name, alt, plural, shorten, linkAlt, altText, false) return success and response or string.error(response) end function p._userRole(...) local name, alt, plural, shorten, linkAlt, altText if type(({...})[1]) ~= 'table' then name, alt, plural, shorten, linkAlt, altText = ... else local opts = ({...})[1] name, alt, plural, shorten, linkAlt, altText = opts.name, opts.alt or opts.alttext or opts.altText, opts.plural, opts.short or opts.shorten, opts.linkAlt or opts.link, opts.altText end if name ==  or name == nil then return  end checkType('_userRole', 1, name, 'string') checkType('_userRole', 2, alt, 'string', true) checkType('_userRole', 3, plural, 'boolean', true) checkType('_userRole', 4, shorten, 'boolean', true) checkType('_userRole', 5, linkAlt, 'string', true) checkType('_userRole', 6, altText, 'string', true) if name:lower:match('(\'?s)$') or plural then plural = true name = name:gsub('(\'?s)$', '') else plural = false end local titleId = staffaliases[name:gsub('_', ' '):lower] local data = thisdata.roles[titleId] if not titleId then error(string.format('Invalid staff rank name %s', name), 2) end local function hideAlways(s) return ' ' .. s .. ' '	end local text = alt or		(shorten and plural) and data.shortPlural or		(shorten) and data.short or		(plural) and data.plural or		data.title local format_string = linkAlt and ( linkAlt:match('https?%:%/%/%S*') and '%s[%s %s]' or '%s%s' ) or		'%s%s' local output_text = format_string:format(		hideAlways(data.order),		linkAlt or data.link,		string.wrapHtml(altText or text, ' ', { class = data.class })	) return output_text end

-- Template: Userlinks -- Creates a link to a user's Userpage, wall, contributions, and posts. function p.userLink(frame) local args = getArgs(frame) local value = args[1] return p._userLink(value, args['disableOther'] or args['disable']) end function p._userLink(user, disableOthers) local res = p.genLinks(user) if p.isIp(user) then return res['usercontribs'] .. (disableOthers and '' or (' ' .. bracket(res['posts']))) end local ret = { res['wall'], res['contribs'], res['posts'] } return table.concat{ string.makeLink({ 'User:', user }, user), disableOthers and '' or ' ', not disableOthers and bracket(table.concat(ret, sep)) or '', } end

-- Template: UserList -- Creates a user list with links. function p.userList(frame) return p._userList(table.unpackRaw(getArgs(frame))) end function p._userList(users, ...) local split = string.split(users, '%s*,%s*') if not users:match',' then split = { users, ... }	end return table.concat(table.map(split, function(v) return p._userLink(v) end), ', ') end

-- Template:TrimUser function p.trimUser(frame) local args = getArgs(frame) return p._trimUser(args[1], yesno(args[2], false)) end function p._trimUser(s, link) checkType(1, s, 'string') local s = string.trim(s) local replacements = { {			['^.-%[%[.-%:([^%|]-)%|.*%]%].*$'] = '%1',			['^.-%[%[.-%:(.-)%]%].*$'] = '%1',		},		{			['^.-%{%{.+%:(.-)%/.+%|?.*%}%}.*$'] = '%1',		},		{			['^.-%[?https?%:/%/%S-%/wiki%/.-%:(.+) ?.-%]?.*$'] = '%1', ['^AbuseLog%?wpSearchUser=(.+)$'] = '%1', ['Contribu?t?i?o?n?s%/ ' ]='', ['^(.-)%?.+$'] = '%1',			[' .-%]$'] = '',		},	}	if s:match('^.-(%[%[.-%]%]).*$') then s = string.gsubMulti(s, replacements[1]) elseif s:match('^.-%{%{.+%:(.-)%/.+%|?.*%}%}.*$') then s = string.gsubMulti(s, replacements[2]) elseif s:match('^.-%[?https?%:/%/%S-%/wiki%/.-%:(.+) ?.-%]?.*$') then s = string.gsubMulti(s, replacements[3]) end return link and table.concat{ , s,  } or s end

- -- Export Helpers - -- Generate a comprehensive list of links for a user function p.genLinks(s) return { -- this uses 'fullUrl' since message wall links show up as wanted pages, so full url is used instead [Oct 2021] wall = string.fullUrl({ 'Message_wall:', s }, nil, 'wall'), contribs = string.wrapLink({ 'Special:Contributions/', s }, 'contribs'), posts = string.wrapLink({ 'Special:UserProfileActivity/', s }, 'posts'), delcontribs = string.wrapLink({ 'Special:DeletedContributions/', s }, 'del. contribs'), logs = string.wrapLink({ 'Special:Log/', s }, 'logs'), blocklog = string.fullUrl( 'Special:Log/block', { page = s }, 'block log'), abuse = string.fullUrl('Special:AbuseLog', { wpSearchUser = s }, 'abuse log'), block = string.wrapLink({ 'Special:Block/', s }, 'block'), nuke = string.fullUrl('Special:BlankPage', { blankspecial = 'nuke', nukeuser = s }, 'nuke'), whois = string.externalUrl({ 'https://cleantalk.org/whois/', s }, nil, 'whois'), proxy = string.externalUrl({ 'https://www.ipqualityscore.com/free-ip-lookup-proxy-vpn-test/lookup/', s }, nil, 'proxy check'), spam = string.externalUrl({ 'https://cleantalk.org/blacklists/', s }, nil, 'spam blacklist check'), edit = string.fullUrl(s, { action = 'edit' }, 'edit'), history = string.fullUrl(s, { action = 'history' }, 'history'), latest = string.fullUrl(s, { diff = 'cur' }, 'latest edit'), links = string.makeLink({ 'Special:WhatLinksHere/', s }, 'links'), subpages = string.makeLink({ 'Special:PrefixIndex/', s, '/' }, 'subpages'), logs = string.fullUrl('Special:Log', { page = s }, 'logs'), abuselog = string.fullUrl('Special:AbuseLog', { wpSearchTitle = s }, 'abuse log'), undelete = string.makeLink({ 'Special:Undelete/', s }, 'del. revisions'), protect = string.fullUrl(s, { action='protect' }, 'protect'), delete = string.fullUrl(s, { action='delete' }, 'delete'), move = string.makeLink({ 'Special:MovePage/', s }, 'move'), user = string.wrapLink({ 'User:', s }, s), usercontribs = string.wrapLink({ 'Special:Contributions/', s }, s), } end

-- Returns if a name is an IP address function p.isIp(ip) if ip == nil or type(ip) ~= 'string' then return false end -- Check IPv4 local chunks = {ip:match('(%d+)%.(%d+)%.(%d+)%.(%d+)')} if (#chunks == 4) then for _,v in pairs(chunks) do			if (tonumber(v) < 0 or tonumber(v) > 255) then return false end end return true end -- Check IPv6 local _, chunks = ip:gsub('%:', '') if chunks == 7 then return true end return false end

return p