Jump to content

Module:workgroup ping

From Wiktionary, the free dictionary

This module is in beta stage.
Its interface has been stabilised, but the module may still contain errors. Do not deploy widely until the module has been tested.

This module implements {{wgping}}, which enables one to quickly and conveniently notify users interested in a particular topic of a discussion. See documentation for {{wgping}} for details.

For workgroup membership data, see Module:workgroup ping/data.


local concat = table.concat
local get_template_invocation_name = require("Module:template parser").getTemplateInvocationName
local insert = table.insert

local export = {}

local m_data = mw.loadData('Module:workgroup ping/data')

function export.ping(frame)
	local parent_frame = frame:getParent()
	local args = parent_frame.args
	local users, errors = {}, {}
	local had_ind = false
	
	local function gather_users(myself)
		local had_user = { }
		if myself and not args.fix then
			had_user[myself] = true
		end

		local empty = true		
		for _, wgid in ipairs(args) do
			local _, user = wgid:match("^User:(.*)")
			if user then
				insert(users, user)
				had_user[user] = true
				had_ind = true
			else
				local data = m_data[wgid]
				if data then
					if data[1] then
						for i, user in ipairs(data) do
							if not had_user[user] then
								insert(users, user)
							end
						end
					else
						insert(errors, ('%s=empty'):format(wgid))
					end
				else
					insert(errors, ('%s=404'):format(wgid))
				end
			end
			empty = false
		end
		
		if empty then
			insert(errors, "nogroups")
		end
	end
	
	local title = mw.title.getCurrentTitle()
	local invocation = get_template_invocation_name(mw.title.new(parent_frame:getTitle()))
	if mw.isSubsting() then
		local output = { '{{', invocation }
		
		local my_username = frame:callParserFunction("REVISIONUSER", title.fullText)
		gather_users(my_username)
		
		for _, wgid in ipairs(args) do
			insert(output, '|' .. wgid)
		end

		for i, user in ipairs(users) do
			insert(output, ('|u%u=%s'):format(i, user))
		end
		
		-- [[gerrit:159800]]
		if #users > 50 then
			insert(errors, "limit")
		end

		for i, err in ipairs(errors) do
			insert(output, ('|e%u=%s'):format(i, err))
		end
		
		insert(output, '}}')
		return concat(output)
	else
		if parent_frame:getTitle() == title.fullText then
			return '<small>(Notifying [[User:Example|Example]]): </small>'	
		end

		local output = { '<small>(Notifying ' }
		local i

		-- the |u#= and |e#= parameters are for internal use only.
		i = 1
		while args['e' .. i] do
			insert(errors, args['e' .. i])
			i = i + 1	
		end

		i = 1
		while args['u' .. i] do
			insert(users, args['u' .. i])
			i = i + 1	
		end

		local is_preview = frame:preprocess("{{REVISIONID}}") == ""

		if (#users + #errors) == 0 then
			if is_preview then
				local unfmted = {}
				for _, item in ipairs(args) do
					insert(unfmted, '|' .. item)
					-- XXX: more detailed?
				end

				return '<strong class="error">Error: <code>{{' .. invocation .. '}}</code> must be [[mw:Manual:Substitution|substituted]]! ' ..
					'Use <code>{{subst:' .. invocation .. concat(unfmted) .. '}}</code> instead</strong>'
			else
				insert(output, "[[Category:unsubstituted " .. invocation .. "]]")
				insert(errors, "subst")
				gather_users()
			end
		end

		for i, user in ipairs(users) do
			insert(output, ('%s[[User:%s|%s]]'):format(
				(i == 1) and "" or ", ",
				user, user
			))
		end

		local function explain_error(e)
			if e == "subst" then
				return "template was not substituted; please substitute passing |fix=1"
			elseif e == "nogroups" then
				return "no workgroups specified"
			else
				local g, e = e:match("(.-)=(.*)")
				if e == "404" then
					return "group '" .. g .. "' does not exist"
				elseif e == "empty" then
					return "group '" .. g .. "' is empty"
				elseif e == "limit" then
					return "more than 50 users to notify: notification will not work"
				end
			end
			return "unknown error '" .. e .. "'"
		end
	
		if #errors > 0 then
			if is_preview then
				insert(output, '; <strong class="error">errors: ')
				for i, e in ipairs(errors) do
					insert(output, ((i == 1) and "" or ", ") .. explain_error(e))
				end
				insert(output, '</strong>')
			else
				insert(output, '; <span style="border-bottom: 1px dotted red; color: red; font-weight: bold;" title="')
				for i, e in ipairs(errors) do
					insert(output, ((i == 1) and "" or ", ") .. explain_error(e))
				end
				insert(output, '">errors</span>')
			end
		end

		insert(output, '): </small>')
		return concat(output)
	end
end

function export.show_list(frame)
	local categories_list = {}
	local categories_map = {}
	local wg_codes, wg_aliases = {}, {}
	
	for key, data in pairs(m_data) do
		if type(data) == 'string' then
			if not wg_aliases[data] then
				wg_aliases[data] = {}	
			end
			insert(wg_aliases[data], ("<code>%s</code>"):format(key))
		else
			local categ = data.category or ""
			if not categories_map[categ] then
				local newcat = { desc = categ, groups = {} }
				insert(categories_list, newcat)
				categories_map[categ] = newcat
			end
			categ = categories_map[categ]
			wg_codes[data] = key
			
			insert(categ.groups, data)
		end
	end

	table.sort(categories_list, function (apple, orange)
		return apple.desc < orange.desc
	end)
	
	local output = {
		'{| class="wikitable" style="width: 90%;" \n|-\n! style="width: 8em;" | Shortcut(s) \n! Group name \n! Members'
	}
	for _, categ in pairs(categories_list) do
		table.sort(categ.groups, function (apple, orange)
			return apple.desc < orange.desc
		end)

		if categ.desc ~= "" then
			insert(output, '|-\n! colspan="3" style="font-size: smaller; text-align: left;" | ' .. categ.desc)
		end
		for _, wgdata in pairs(categ.groups) do
			local members = {}
			local had_users, had_tfs = {}, {}
			
			if type(wgdata) ~= 'table' then
				return	
			end
			
			for _, user in ipairs(wgdata) do
				if not had_users[user] then
					insert(members, ("[[User:%s|%s]]"):format(user, user))
					had_users[user] = true
				end
			end

			local wg_code = ("<code>%s</code>"):format(wg_codes[wgdata])
			if wg_aliases[wg_codes[wgdata]] then
				wg_code = ('%s<br/><small>(%s)</small>'):format(wg_code, concat(wg_aliases[wg_codes[wgdata]], ", "))
			end
			insert(output, ('|- id="%s" style="vertical-align: top;" \n|%s\n|%s\n|%s <small>(%u %s)</small>'):format(
				wg_codes[wgdata], wg_code, wgdata.desc, concat(members, ", "), #members, ((#members == 1) and 'user' or 'users')
			))
		end
	end
	insert(output, "|}")
	return concat(output, "\n")
end

return export