Permanently protected module

Module:Monthly Challenge statistics

From Wikisource
Jump to navigation Jump to search
Module documentation[view] [edit] [history] [purge]

Logic for {{Monthly Challenge statistics}}

--[=[
Statistics for data using the Monthly Challenge format.

There are two data sources:
 * category data, which provides a _current_ per-index and total count
 * daily data, which provides _day-by-day_ total counts
]=]

local p = {} --p stands for package
local getArgs = require('Module:Arguments').getArgs

-- Default data prefixes
local cDataPrefix = "Module:Monthly Challenge category stats/data/"
local dDataPrefix = "Module:Monthly Challenge daily stats/data/"
local workDataPrefix = "Module:Monthly Challenge/data/"

function length(arr)
	if arr == nil then
		return 0
	end
	local count = 0
	for k, v in pairs(arr) do
		count = count + 1
	end
	return count
end

--[=[
Calculate "processed" pages for a given stats dump
 * validated is double because it includes a prior proofread step (otherwise
   validating is a zero sum, as q3 loses one, and q4 gains one)
]=]
function getProcessed(t)
	return t.q0 + t.q3 + (t.q4 * 2)
end

function getProofread(t)
	return t.q3	
end

function getComplete(t)
	return t.q0 + t.q4
end

function getIncomplete(t)
	return t.count - (t.q0 + t.q4)
end

--[=[
Get the number of works in the MC cat stats
]=]
function getNumberOfCatWorks(cData)
	return length(cData.indexes)
end

function getDailyUplifts(dData)
	local uplifts = {
		total = {
			processed = 0,
			proofread = 0,
			complete = 0
		},
		days = {}
	}
	
	-- guard against totally bogus/missing input data
	if dData == nil or dData.days == nil then
		return uplifts
	end
	
	local untilDay
	if not untilDay then
		untilDay = length(dData.days) - 1
	end
	
	local last = {
		processed = getProcessed(dData.days[0]),
		proofread = getProofread(dData.days[0]),
		complete = getComplete(dData.days[0])
	}
	
	for day = 1, untilDay do
		day_data = data.days[day]

		local processed = 0
		local diff_proc = 0
		local diff_pr = 0
		local diff_complete = 0
		
		local day_stats = {
			processed = 0,
			proofread = 0,
			complete = 0
		}
		
		if day_data then
			day_stats.processed = getProcessed(day_data) - last.processed
			day_stats.proofread = getProofread(day_data) - last.proofread
			day_stats.complete = getComplete(day_data) - last.complete
		end
		
		last.processed = last.processed + day_stats.processed
		last.proofread = last.proofread + day_stats.proofread
		last.complete = last.complete + day_stats.complete

		table.insert(uplifts.days, day_stats)

		uplifts.total.processed = uplifts.total.processed + day_stats.processed
		uplifts.total.proofread = uplifts.total.proofread + day_stats.proofread
		uplifts.total.complete = uplifts.total.complete + 	day_stats.complete
	end
	
	return uplifts
end

function getMeans(uplifts)
	
	local n = length(uplifts.days)
	
	if n == 0 then
		return {
			processed = 0,
			proofread = 0,
			complete = 0,
		}
	end
	
	return {
		processed = uplifts.total.processed / n,
		proofread = uplifts.total.proofread / n,
		complete = uplifts.total.complete / n,
	}
end

function getYMData(prefix, year, month)
	local statsPage = prefix .. string.format('%d-%02d', year, month)
	ok, data = pcall(mw.loadData, statsPage)
	return data
end

function getWorkData(prefix, year, month)
	local ok, data = pcall(mw.loadData, workDataPrefix .. string.format('%d-%02d', year, month))
	return data
end

--[=[
Function docs
]=]
function p.statistics(frame)
	local args = getArgs(frame)
	
	local year = tonumber(args.year)
	local month = tonumber(args.month)

	local cData = getYMData(cDataPrefix, year, month)
	local dData = getYMData(dDataPrefix, year, month)
	local workData = getWorkData(workDataPrefix, year, month)

	local txt = args.format
	
	txt = txt:gsub('@num_works@', function()
		return getNumberOfCatWorks(cData)
	end)
	
	txt = txt:gsub('@count_all_pages@', function()
		return cData.total.count
	end)

	txt = txt:gsub('@mean_processed_to_date@', function()
		local uplifts = getDailyUplifts(dData)
		local monthlyMeans = getMeans(uplifts)
		return math.floor(monthlyMeans.processed + 0.5)
	end)
	
	txt = txt:gsub('@processed_this_month@', function()
		local uplifts = getDailyUplifts(dData)
		return uplifts.total.processed
	end)
	
	txt = txt:gsub('@processed_yesterday@', function()
		
		local timeNow = os.date("*t")
		timeNow.day = timeNow.day - 1
		local timeYesterday = os.date("*t", os.time(timeNow))
		
		local yestData = dData
		if not (timeYesterday.month == month and timeYesterday.year == year) then
			yestData = getYMData(dDataPrefix, timeYesterday.year, timeYesterday.month)
		end
		
		local uplifts = getDailyUplifts(yestData)
		if uplifts.days[timeYesterday.day] then
			return uplifts.days[timeYesterday.day].processed
		end
		return 0
	end)
	
	txt = txt:gsub('@target_pages@', function()
		return workData.target
	end)
	
	txt = txt:gsub('@processed_percent@', function()
		local uplifts = getDailyUplifts(dData)
		if workData.target == nil or workData.target <= 0 then
			return '0'
		end
		return string.format("%.1f", 100 * uplifts.total.processed / workData.target)
	end)
	
	return txt
end

return p