Module:Sandbox/Aidan9382/DiscussionOverview

--[=[ 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:]+$") or string.match(user, "^~%d%d%d%d%-%d%d%d%d%d%-%d%d%d$") then --Lazy but mostly working basic IPv6 regex final = final .. ""..user..", " else final = final .. ""..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 good enough local function getUserMentions(text) --Returns a list of users, and if they were considered a "participant" or someone who was just mentioned local mentions = {} text = mw.text.decode(text,true) --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 (why?) so that it still picks up	local timestampRegex = "((%d%d:%d%d, %d%d? %w+,? %d%d%d%d) %(UTC%))"	local userRegex = "(%[%[:?[Uu]ser:([^#|%]]+))"	local userTalkRegex = "(%[%[:?[Uu]ser[ _][Tt]alk:([^#|%]]+))"	local userContribRegex = "(%[%[:?[Ss]pecial:[Cc]ontributions/([^#|%]]+))"	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 identifier = string.gsub(identifier,"_"," ") if not string.find(identifier,"/") then --Avoid subpage nonsense 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 --else: be confused as hell mw.log("Timestamp had no associated users on its line (TS "..wholeText..")") 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 _, text = xpcall(function		return Transcluder.get(page)	end, function(err)		error(debug.traceback)	end) local sections = getSectionData(text) local tableContent = '{| class="wikitable sortable"\n! style="text-align:center" colspan=6 | Conversation summary for ' .. page .. '' .. ' v ' .. '\n|-\n! Section !! Initiator !! Last Comment !! Size !! Participants !! Mentions' for _,section in next,sections do		local sanitisedName = string.gsub(string.gsub(mw.uri.anchorEncode(frame:preprocess(section.name)),"%[%[:?[^|]-|([^%]]-)]]","%1"),"%[%[:?([^%]]-)]]","%1") local displayName = string.gsub(string.gsub(frame:preprocess(section.name),"%[%[:?[^|]-|([^%]]-)]]","%1"),"%[%[:?([^%]]-)]]","%1") local wikilinkAnchor = ""..displayName.."" 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 mentionedUsers = {} for _,userData in next,membersInText do			if not userData.participated and not table.find(uniqueParticipants,userData.user) and not table.find(mentionedUsers,userData.user) then mentionedUsers[#mentionedUsers+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 local firstComment,lastComment if #orderedComments == 0 then firstComment = "N/A" lastComment = "N/A" elseif #orderedComments == 1 then firstComment = formatDateDiff(now-orderedComments[1].when) .. " ago" .. " " .. concatUsers({orderedComments[1].user}) lastComment = "N/A" else firstComment = formatDateDiff(now-orderedComments[1].when) .. " ago" .. " " .. concatUsers({orderedComments[1].user}) lastComment = formatDateDiff(now-orderedComments[#orderedComments].when) .. " ago" .. " " .. concatUsers({orderedComments[#orderedComments].user}) end local participants = #uniqueParticipants .. ": " .. concatUsers(uniqueParticipants) local mentions = #mentionedUsers .. ": " .. concatUsers(mentionedUsers) 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