Lua error at line 131: page-not-found. Lua error at line 131: page-not-found.


--[=[
A module designed to provide an overall summary and some statistics on a discussion board
Inspired by, and partially borrowed from, [[Module:Sandbox/Smalljim/DiscussionIndexTest]]
--]=]
local Transcluder = require("Module:Transcluder")
local p = {}

table.find = function(t,o) --Used to luau, so assumed this existed. Heres a quick version
	for a,b in next,t do
		if b == o then
			return true
		end
	end
	return false
end

local lang = mw.getContentLanguage()
local function getTime(timestamp)
	return tonumber(lang:formatDate("U",timestamp))
end

local function concatUsers(users)
	local final = ""
	for _,user in next,users do
		if string.match(user,"^%d+%.%d+%.%d+%.%d+$") or string.match(user,"^%x+:[%x:]+$") then --Lazy but mostly working basic IPv6 regex
			final = final .. "[[Special:Contributions/"..user.."|"..user.."]], "
		else
			final = final .. "[[:User:"..user.."|"..user.."]], "
		end
	end
	return string.sub(final,1,-3)
end

--Specialised version of Sandbox/Smalljim/ParsePageTest.formatDateDiff that just does hours (better for sorting cause im not learning wikitables)
local function formatDateDiff( date_diff )
    return tonumber( math.floor(date_diff/(6*60))/10 ) .. ' hours';
end

--Specialised version of Transcluder.getSections, using a similar design
local function getSectionData(text)
	local sections = {}
	text = "\n"..text.."\n== "
	while true do
		local section,content = string.match(text,"\n==%s*([^=]-)%s*==\n(.-)\n==[^=]")
		if not section then
			break
		end
		text = string.sub(text,string.find(text,content,1,true)+#content,-1)
		sections[#sections+1] = {name=section,content=content}
	end
	return sections
end

--This is a bloody mess of a mix of ideas, but it mostly works, so im dealing with it
local function getUserMentions(text)
	--Returns a list of users, and if they were considered a "participant" or someone who was just mentioned
	local mentions = {}
	--Timestamp is %d%d:%d%d, %d%d? %w+ %d%d%d%d %(UTC%)) but we allow some (minor) leniancy for those who just slightly edit their dates so that it still picks up
	local timestampRegex = "((%d%d:%d%d, %d%d? %w+,? %d%d%d%d) %(UTC%))"
	local userRegex = "(%[%[:?User:([^|%]]+))"
	local userTalkRegex = "(%[%[:?User:([^|%]]+))"
	local userContribRegex = "(%[%[:?Special:Contributions/([^|%]]+))"
	for line in string.gmatch(text,"[^\n]+") do
		--Split by line and check all content on said line. This assumes all signatures never use newlines, which they should not be doing anyways.
		--Bar of entry for being labelled a "participant" is a valid timestamp along with their user/usertalk/contribs
		--Users can be noted as being both a participant and a mention during the data, so be smart in using this data
		local usersOnThisLine = {}
		for _,reg in next,{userRegex,userTalkRegex,userContribRegex} do
			local index = 1
			while true do
				local targetText = string.sub(line,index,-1)
				local wholeText,identifier = string.match(targetText,reg)
				if not wholeText then
					break
				end
				if not string.find(identifier,"/") then --Avoid subpage nonsense
					mw.log("Found user on reg",reg,"name is",identifier)
					usersOnThisLine[string.find(targetText,reg)] = identifier
				end
				index = index + string.find(targetText,reg) + #wholeText
			end
		end
		--Start associating timestamps with users
		local index = 1
		local pindex = {} --Lazy coding
		local participants = {}
		while true do
			local targetText = string.sub(line,index,-1)
			local wholeText,identifier = string.match(targetText,timestampRegex)
			if not wholeText then
				break
			end
			--Backtrack through the text for a mention
			local timestampLocation = string.find(targetText,identifier)
			local user,where
			for i = timestampLocation,1,-1 do
				user,where = usersOnThisLine[i],i
				if user then
					break
				end
			end
			if user then
				participants[#participants+1] = {user=user,when=identifier,participated=true}
				pindex[user] = true
			--else: be confused as hell
			end
			index = index + timestampLocation + #wholeText
		end
		local pings = {}
		for _,user in next,usersOnThisLine do
			if not pings[user] and not pindex[user] then --If they participated on a line, just ignore all pings
				pings[user] = true
			end
		end
		--Integrate the new data
		for user,_ in next,pings do
			mentions[#mentions+1] = {user=user,participated=false}
		end
		for _,userData in next,participants do
			mentions[#mentions+1] = userData
		end
	end
	return mentions
end

function p.main(frame)
	local page = frame.args[1] or frame.args.page
	assert(type(page)=="string","Invalid or no page provided")
	
	local success,text = pcall(Transcluder.get,page)
	assert(success,text)
	
	local sections = getSectionData(text)
	local tableContent = '{| class="wikitable sortable"\n! Section !! Initiator !! Last Comment !! Size !! Participants !! Mentions'
	for _,section in next,sections do
		local sanitisedName = string.gsub(string.gsub(section.name,"%[%[:?[^|]-|([^%]]-)]]","%1"),"%[%[:?([^%]]-)]]","%1")
		local wikilinkAnchor = "[[:"..page.."#"..sanitisedName.."|"..sanitisedName.."]]"
		local membersInText = getUserMentions(section.content)
		local uniqueParticipants = {}
		for _,userData in next,membersInText do
			if userData.participated and not table.find(uniqueParticipants,userData.user) then
				uniqueParticipants[#uniqueParticipants+1] = userData.user
			end
		end
		local now = getTime()
		local orderedComments = {}
		for _,userData in next,membersInText do
			if userData.participated then
				local when = getTime(userData.when)
				if now > when then --Ensure comment is from the past
					if #orderedComments == 0 then
						orderedComments[#orderedComments+1] = {user=userData.user,when=when}
					else
						for i = 1,#orderedComments do
							local comment = orderedComments[i]
							if when < comment.when then
								for i2 = #orderedComments+1,i,-1 do
									orderedComments[i2] = orderedComments[i2-1]
								end
								orderedComments[i] = {user=userData.user,when=when}
								break
							end
							if i == #orderedComments then
								orderedComments[#orderedComments+1] = {user=userData.user,when=when} --Reached the end, latest comment
								break
							end
						end
					end
				end
			end
		end
		mw.logObject(orderedComments)
		
		local firstComment,lastComment
		if #orderedComments == 0 then
			firstComment = "N/A"
			lastComment = "N/A"
		elseif #orderedComments == 1 then
			firstComment = formatDateDiff(now-orderedComments[1].when) .. " ago" .. "<br>" .. concatUsers({orderedComments[1].user})
			lastComment = "N/A"
		else
			firstComment = formatDateDiff(now-orderedComments[1].when) .. " ago" .. "<br>" .. concatUsers({orderedComments[1].user})
			lastComment = formatDateDiff(now-orderedComments[#orderedComments].when) .. " ago" .. "<br>" .. concatUsers({orderedComments[#orderedComments].user})
		end
		local participants = #uniqueParticipants .. ": " .. concatUsers(uniqueParticipants)
		local mentions = "Could be calculated but I'm lazy"
		local sectionContent = "\n|-\n| "..wikilinkAnchor.." || "..firstComment.." || "..lastComment.." || "..#section.content.." || "..participants.." || "..mentions
		tableContent = tableContent .. sectionContent
	end
	return tableContent .. "\n|}"
end

function p.maindev(frame)
	local content = p.main(frame)
	return content .. "\n\n" .. frame:extensionTag("syntaxhighlight",content,{lang="html5"})
end

p.getSectionData = getSectionData
p.getUserMentions = getUserMentions

return p