Module:Proposal check
From the Super Mario Wiki, the Mario encyclopedia
Jump to navigationJump to search
This module powers the {{proposal check}} template.
local p = {}
local function fmtVotes(votes)
if votes == 1 then
return "'''1''' vote"
else
return "'''" .. votes .. "''' votes"
end
end
local function fmtProposalCheckOutput(args)
local bq = mw.html.create("blockquote")
if args.desc then
bq
:tag("span")
:wikitext(args.desc .. " ")
end
if args.verdict then
bq
:tag("b")
:wikitext(args.verdict)
:css("color", args.verdictColor)
end
return bq
end
local function normalizeArgs(rawArgs)
local args = {}
for k, v in pairs(rawArgs) do
v = mw.text.trim(v)
if v ~= "" then
args[k] = v
end
end
return args
end
function p.proposalCheck(args)
local voteTally = nil
local totalUsers = nil
local isEarly = args.early ~= nil
local firstPlaceOptionVotes = -1
local firstPlaceOptionIndex = nil
local secondPlaceOptionVotes = -1
local voteMargin = nil
local approvalRate = nil
if args[1] == nil then
return fmtProposalCheckOutput {
verdictColor = "red",
verdict = "MISSING PARAMETERS; SEE [[Template:Proposal check|DOCUMENTATION]]",
}
elseif args[1]:match("^%d+$") then
-- legacy call: 5 | 3 | 7 | early=y
firstPlaceOptionVotes = tonumber(args[1])
secondPlaceOptionVotes = tonumber(args[2])
if (firstPlaceOptionVotes == nil or secondPlaceOptionVotes == nil) then
return fmtProposalCheckOutput {
verdictColor = "red",
verdict = "INVALID PARAMETERS; SEE [[Template:Proposal check|DOCUMENTATION]]",
}
elseif secondPlaceOptionVotes > firstPlaceOptionVotes then
return fmtProposalCheckOutput {
verdictColor = "red",
verdict = "SECOND PLACE OPTION CANNOT HAVE MORE VOTES THAN FIRST PLACE",
}
end
if args[3] == nil then
totalUsers = firstPlaceOptionVotes + secondPlaceOptionVotes
else
totalUsers = tonumber(args[3])
if totalUsers == nil then
return fmtProposalCheckOutput {
verdictColor = "red",
verdict = '"' .. args[3] .. '" IS NOT A VALID NUMBER',
}
end
end
else
-- 5-3-2 | 7 | early=y
voteTally = mw.text.split(args[1], "-", true)
totalUsers = tonumber(args[2])
local totalVoteCount = 0
for index, votesStr in ipairs(voteTally) do
local votes = tonumber(votesStr)
if votes == nil then
return fmtProposalCheckOutput {
verdictColor = "red",
verdict = '"' .. votesStr .. '" IS NOT A VALID NUMBER',
}
end
totalVoteCount = totalVoteCount + votes
if votes >= firstPlaceOptionVotes then
secondPlaceOptionVotes = firstPlaceOptionVotes
firstPlaceOptionVotes = votes
firstPlaceOptionIndex = index
elseif votes >= secondPlaceOptionVotes then
secondPlaceOptionVotes = votes
end
end
if totalUsers == nil and #voteTally == 2 then
totalUsers = firstPlaceOptionVotes + secondPlaceOptionVotes
elseif totalUsers == nil then
return fmtProposalCheckOutput {
verdictColor = "red",
verdict = "MISSING UNIQUE USER COUNT FOR MULTI-OPTION PROPOSAL",
}
elseif totalUsers > totalVoteCount then
return fmtProposalCheckOutput {
verdictColor = "red",
verdict = "PROPOSAL CANNOT HAVE MORE UNIQUE USERS THAN VOTES",
}
end
end
if firstPlaceOptionVotes > totalUsers then
return fmtProposalCheckOutput {
verdictColor = "red",
verdict = "FIRST PLACE OPTION CANNOT HAVE MORE VOTES THAN UNIQUE USERS",
}
end
voteMargin = firstPlaceOptionVotes - secondPlaceOptionVotes
approvalRate = firstPlaceOptionVotes / totalUsers
if firstPlaceOptionVotes < 4 then
return fmtProposalCheckOutput {
desc = "The first place option must have at least 4 votes, "
.. "but it has only " .. fmtVotes(firstPlaceOptionVotes) .. ".",
verdictColor = "gray",
verdict = "NO QUORUM",
}
elseif voteMargin == 0 then
return fmtProposalCheckOutput {
desc = "The top two options have an equal number of votes.",
verdictColor = "red",
verdict = "CONSENSUS NOT REACHED",
}
end
local prefix = "With a margin of " .. fmtVotes(voteMargin) .. ", "
local suffix = "'''" .. (math.floor(1000 * approvalRate + 0.5) / 10) .. "%''' approve "
.. (
firstPlaceOptionIndex and "option #" .. firstPlaceOptionIndex .. "."
or "the first place option."
)
if isEarly then
if voteMargin < 8 then
return fmtProposalCheckOutput {
desc = prefix .. "the proposal is not eligible to close one week early.",
verdictColor = "red",
verdict = "DO NOT CLOSE EARLY",
}
end
local canCloseEarly = approvalRate >= 0.8
return fmtProposalCheckOutput {
desc = prefix .. "at least 80% approval is required to close one week early. "
.. suffix,
verdictColor = canCloseEarly and "green" or "red",
verdict = canCloseEarly and "CLOSE EARLY" or "DO NOT CLOSE EARLY",
}
elseif voteMargin >= 3 then
local hasConsensus = approvalRate > 0.5
return fmtProposalCheckOutput {
desc = prefix .. "more than 50% approval is required. " .. suffix,
verdictColor = hasConsensus and "green" or "red",
verdict = hasConsensus and "CONSENSUS REACHED" or "CONSENSUS NOT REACHED",
}
else
local hasConsensus = approvalRate >= 0.6
return fmtProposalCheckOutput {
desc = prefix .. "at least 60% approval is required. " .. suffix,
verdictColor = hasConsensus and "green" or "red",
verdict = hasConsensus and "CONSENSUS REACHED" or "CONSENSUS NOT REACHED",
}
end
end
function p.main(frame)
local parentArgs = frame:getParent() and frame:getParent().args or {}
local args = normalizeArgs(parentArgs)
if next(args) == nil then
args = normalizeArgs(frame.args)
end
return p.proposalCheck(args)
end
return p