Module:Database report/facade/sandbox

local Arguments = require('Module:Arguments')
local TableTools = require('Module:TableTools')

local p = {}

local function error(text)
	return '\n*' .. require('Module:Error').error{ text, tag = 'p' }
end 

local function str_split(inputstr, sep)
    local t = {}
    for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
		table.insert(t, str)
    end
    return t
end

local function is_integer(str) 
	if str:match("%D") then 
		return false
	end 
	return true
end

local function trim(s)
   return s:match("^%s*(.-)%s*$")
end

p.main = function(frame)
	local args = Arguments.getArgs(frame)
	local title = mw.title.getCurrentTitle()
	
	local lua_config, lua_err = invoke_lua_source(args, frame)
	local headContent = lua_config and lua_config.head_content or ''
	local tailContent = lua_config and lua_config.tail_content or ''
	
	local isSilent = args.silent ~= nil or (lua_config and lua_config.silent ~= nil)
	local isPeriodic = args.interval ~= nil or (lua_config and lua_config.interval ~= nil)
	
	return headContent .. 
		(isSilent and '' or 
			"<div style='float: right; padding-left: 15px;'>" ..
			'[https://sdzerobot.toolforge.org/database-report?page='..mw.uri.encode(title.prefixedText)..' Update the table now]' ..
			'</div>' ..
			"<div style='margin-bottom: 5px; border-bottom: 3px solid #2F74D0; padding-right: 10px;'>" ..
			"This table is generated by querying the [[wikitech:Help:Toolforge/Database|database replica]] "..(isPeriodic and 'and is periodically updated' or '').." by [[User:SDZeroBot|a bot]].<br> " ..
			'<mark>Edits made within the table area will be removed on the next update!</mark>' ..
			'</div>')
		.. '[[Category:SDZeroBot database report subscriptions]]'
		.. (lua_err or validate(args))
		.. tailContent
end

function validate(args)
	
	-- sql param is required, except if the config is lua-generated
	if not args.sql and not args.lua_source then
		return error('Invalid config: required parameter "sql" is missing')
	end
	
	local deprecated_params = {
		['frequency'] = 'interval'
	}
	
	-- check for invalid parameters
	for param, _ in pairs(args) do
		if deprecated_params[param] ~= nil then
			return error(param .. ' is deprecated, please use ' .. deprecated_params[param] .. ' instead')
		end
		if not TableTools.inArray({
			'sql', 'wikilinks', 'excerpts', 'comments', 'widths', 'hide', 'silent',
			'table_style', 'table_class', 'remove_underscores', 'pagination', 'output_page',
			'max_pages', 'interval', 'row_template', 'skip_table', 'header_template',
			'footer_template', 'row_template_named_params', 'postprocess_js',
			'lua_source', 'lua_function'
		}, param) and not param:find('^lua_arg_') == nil then
			return error('Unknown parameter "' .. param .. '" used, ignoring')
		end
	end
	
	-- check incompatible param combinations
	if not args.row_template then
		if args.skip_table then 
			return error('Invalid config: skip_table can only be used with row_template')
		end 
	end
	
	if args.output_page then
		if args.pagination then 
			return error('pagination and output_page cannot be used together; output_page will be ignored')
		end
		local t1 = mw.title.getCurrentTitle()
		local t2 = mw.title.new(args.output_page)
		if t1.namespace ~= t2.namespace or t2.text:find(t1.text..'/', 1, true) ~= 1 then
			return error('output_page must be a subpage of the current page')
		end
	end

	-- check wikilinks config
	if args.wikilinks then
		local configs = str_split(args.wikilinks, ',')
		for _, config in ipairs(configs) do
			local parts = str_split(trim(config), ':')
			local srcColNum = parts[1]
			if not is_integer(srcColNum) then
				return error('Invalid wikilink config: Non-numeral source column number: '..parts[1]..'. Will be ignored.')
			end
			local ns = parts[2]
			if ns and ns:match("^c?%d+$") == nil then 
				return error('Invalid namespace number "'.. ns..'" in wikilinks parameter: refer to [[WP:NS]] for namespace numbers, or use "cN" to take namespace number from column number N')
			end 
		end 
	end
	
	-- check excerpts config
	if args.excerpts then
		local configs = str_split(args.excerpts, ',')
		for _, config in ipairs(configs) do
			local parts = str_split(trim(config), ':')
			local srcColNum = parts[1]
			if not is_integer(srcColNum) then
				return error('Invalid excerpts config: Non-numeral source column number: '..parts[1]..'. Will be ignored.')
			end
			local dstColNum = parts[2]
			if dstColNum and not is_integer(dstColNum) then
				return error('Invalid excerpts config: Non-numeral destination column number: '..parts[2]..'. Will be ignored.')
			end
			local ns = parts[3]
			if ns and ns:match("^c?%d+$") == nil then 
				return error('Invalid namespace number "'.. ns..'" in excerpts parameter: refer to [[WP:NS]] for namespace numbers, or use "cN" to take namespace number from column number N')
			end 
			local charLimit = parts[4]
			if charLimit and not is_integer(charLimit) then 
				return error('Invalid excerpts config: Non-numeral in charLimit: '..parts[4]..'. Will be ignored.')
			end 
			local hardCharLimit = parts[5]
			if hardCharLimit and not is_integer(hardCharLimit) then 
				return error('Invalid excerpts config: Non-numeral in hardCharLimit: '..parts[5]..'. Will be ignored.')
			end 
		end 
	end
	
	-- check column numbers in widths param
	if args.widths then
		local configs = str_split(args.widths, ',')
		for _, config in ipairs(configs) do 
			local parts = str_split(trim(config), ':')
			local column = parts[1]
			if not is_integer(column) then
				return error('Invalid widths config: Non-numeral column number: '..parts[1]..'. Will be ignored.')
			end
		end 
	end
	
	-- check numeric configs
	if args.comments then
		local columns = str_split(args.comments, ',')
		for _, column in ipairs(columns) do
			if not is_integer(trim(column)) then
				return error('Invalid comments parameter: Non-numeral column number: '..column..'. Will be ignored.')
			end
		end
	end
	if args.remove_underscores then
		local columns = str_split(args.remove_underscores, ',')
		for _, column in ipairs(columns) do
			if not is_integer(trim(column)) then
				return error('Invalid remove_underscores parameter: Non-numeral column number: '..column..'. Will be ignored.')
			end
		end
	end
	if args.hide then
		local columns = str_split(args.hide, ',')
		for _, column in ipairs(columns) do
			if not is_integer(trim(column)) then
				return error('Invalid hide parameter: Non-numeral column number: '..column..'. Will be ignored.')
			end
		end
	end
	if args.pagination and not is_integer(args.pagination) then 
		return error('pagination should be an integer. Will be ignored.')
	end 
	if args.max_pages and not is_integer(args.max_pages) then
		return error('max_pages should be an integer. Will be ignored.')
	end 
	if args.interval and not is_integer(args.interval) then
		return error('interval should be an integer. Will be ignored.')
	end 
	if args.row_template_named_params and not args.row_template then
		return error('row_template_named_params is only applicable when row_template is used')
	end

	return ''
end

function invoke_lua_source(args, frame)
	if not args.lua_source then
		return nil, nil
	end 
	local module_title = mw.title.new(args.lua_source, 828)
	if module_title == nil or module_title.namespace ~= 828 then
		return nil, error('lua_source should be a valid Module title')
	end
	local module_name = module_title.text
	local lua_params = ''
	for key, val in pairs(args) do
		if key:find('^lua_arg_') then
			local argName = string.sub(key, string.len('lua_arg_') + 1)
			local argValue = val
			lua_params = lua_params .. '|'..argName..'='..argValue
		end
	end
	local invoke = '{{#invoke:'..module_name..'|'..(args.lua_function or 'main')..lua_params..'}}'
	
	local moduleOutput = frame:preprocess(invoke)
	
	-- FIXME: more robust error detection
	if moduleOutput:find('error') ~= nil then
		return nil, moduleOutput
	end
	
	if not moduleOutput:match('^{{') or not moduleOutput:match('}}$') then
		-- XXX: Module is returning something other than report:generate(), error out? 
		return {}, nil
	end
	local config = {}
	-- Parse the configuration text to extract parameter values
	for line in moduleOutput:gmatch("[^\n]+") do
		local param, value = line:match("^|([^=]+) = (.*)$")
		if param and value then
			value = trim(value)
			if value ~= "" and value ~= "nil" then
				config[param] = value
			end
		end
	end
	return config, nil
end

return p

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.