mic_none

Module:Unsigned Source: en.wikipedia.org/wiki/Module:Unsigned

local p = {}
local yesno = require('Module:Yesno')

local function trim(s)
	return s:gsub("^%s+", ""):gsub("%s+$", ""):gsub("\226\128\142", "")
end

function p.getTimestamp(s)
	--gets the timestamp in the input
	--if nothing is found, returns the empty string
	--we search for time and date seperately to allow for a time-less addition of date
	
	-- helper to search the input string
	-- note that match on nil is a bad thing, so we include: or ''
	local function findFromInput(target)
		return mw.ustring.match( s or '', target, 0)
	end
	
	-- find the date
	local theDate =
		findFromInput('%d%d? %u%l+ %d%d%d%d') -- DMY
		or findFromInput('%u%l+ %d%d?, %d%d%d%d') -- MDY
		or findFromInput('%d%d%d%d %u%l+ %d%d?') -- YMD
		or findFromInput('%d%d%d%d-%d%d-%d%dT%d%d:%d%d:%d%d') -- 2025-06-28T19:49:51 style
		
	if theDate then
		-- we have a date, so process and return accordingly
		-- first sanitize the date
		theDate = require('Module:Format time')._main{theDate}
		-- then check if there is a timestamp
		local theTime = findFromInput('%d%d:%d%d')
		return theTime and (theTime .. ', ' .. theDate .. ' (UTC)') or theDate
	else
		return ''
	end
end

function p.getUsername(s)
	--gets the username in the input
	--------WARNING--------
	--this method assumes that *everything* besides the timestamp is, in fact, part of the username
	--it does no further username validation
	--if you try putting random garbage in, you **will** get garbage out
	--------YOU HAVE BEEN WARNED--------
	
	-- if nil, then return the empty string
	if not s then return '' end
	local toReturn = s
	
	-- Patterns matching various timestamp formats
	local patterns = {
		'%d%d%d%d-%d%d-%d%dT%d%d:%d%d:%d%d', -- Timestamp: e.g., 2025-06-28T19:49:51
		'%d%d? %u%l+ %d%d%d%d',              -- DMY: e.g., 25 June 2025
		'%u%l+ %d%d?, %d%d%d%d',             -- MDY: e.g., June 25, 2025
		'%d%d%d%d %u%l+ %d%d?',              -- YMD: e.g., 2025 June 25
		'%d%d:%d%d,?',                       -- Time: e.g., 19:32,
		'%(UTC%)',                           -- UTC marker
	}

	for _, pattern in ipairs(patterns) do
		toReturn = mw.ustring.gsub(toReturn, pattern, '', 1)
	end
	
	--concat the empty string to ensure we only return the string and not the number of matches
	return trim(toReturn) .. ''
end

local function makeUnsigned(args)
	local username
	local timestamp

	if args[2] then
		-- we have multiple parameters
		-- so we can be less janky
		timestamp = p.getTimestamp(args[2])
		if timestamp ~= '' then
			username = trim(args[1] or '')
		else
			username = trim(args[2] or '')
			timestamp = p.getTimestamp(args[1]) -- necessary to append (UTC) if needed
		end
	else
		-- be very janky; this has a high probability of GIGO-ing
		-- due to the way getUsername is implemented
		username = p.getUsername(args[1])
		timestamp = p.getTimestamp(args[1])
	end
	
	-- error if we cannot find a username
	if username == '' then
		return '<em class="error">Unable to detect username</em>'
	end
	
	return mw.getCurrentFrame():expandTemplate{ 
		title = require('Module:IPAddress')._isIp(username) and 'unsigned/unregistered' or 'unsigned/registered', 
		args = {
			username,
			timestamp,
			fix = yesno(args.fix) and 'yes' or ''
		}
	}
end

function p.main(frame)
	local args
	if type(frame.args) == 'table' then
		-- We're being called via #invoke. The args are passed through to the module
		-- from the template page, so use the args that were passed into the template.
		args = require('Module:Arguments').getArgs(frame)
	else
		-- We're being called from another module or from the debug console, so assume
		-- the args are passed in directly.
		args = frame
	end
	return makeUnsigned(args)
end

return p