Jump to content

Module:Sensitive IP addresses/list/validate

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Mr. Stradivarius (talk | contribs) at 11:11, 24 July 2016 (validate structure of Module:Sensitive IP addresses/list). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
(diff) ← Previous revision | Latest revision (diff) | Newer revision → (diff)

-- This module validates the data in [[Module:Sensitive IP addresses/list]].

-- Load modules
local mSensitiveIPs = require('Module:Sensitive IP addresses')
local Subnet = require('Module:IP').Subnet

-- Constants
local DATA_MODULE = 'Module:Sensitive IP addresses/list'

local p = {}

local function makeErrorLogger()
	-- Return an object for formatting errors.
	return {
		errors = {},
		addError = function (self, msg, ...)
			table.insert(self.errors, string.format(msg, ...))
		end,
		addEntryTypeError = function (self, entryIdx, field, actual, expected)
			self:addError(
				'The %s field in data entry #%d was type %s (should be string or nil)',
				field, entryIdx, actual, expected
			)
		end,
		hasErrors = function (self)
			return #self.errors > 0
		end,
		makeReport = function (self)
			if #self.errors < 1 then
				return 'No errors found'
			else
				local ret = {'Found the following errors:'}
				for i, msg in ipairs(self.errors) do
					ret[#ret + 1] = string.format('* <strong class="error">%s</strong>', msg)
				end
				return table.concat(ret, '\n')
			end
		end,
	}
end

local function loadData(logger)
	-- Load the data table, logging any errors in the process.

	-- Check whether the data module can be successfully loaded.
	local success, data = pcall(mw.loadData, DATA_MODULE)
	if not success then
		logger:addError('%s could not be parsed by mw.loadData; check for [[mw:LUAREF#mw.loadData|invalid data]]', DATA_MODULE)
		return nil
	end

	-- Check that the data table is a table.
	if type(data) ~= 'table' then
		logger:addError('%s returned a %s; table expected', DATA_MODULE, type(data))
	end

	return data
end

local function checkDataStructure(logger, data)
	-- Checks the structure of individual entries.
	for dataIndex, subtable in ipairs(data) do
		-- Check that subtables are tables.
		if type(subtable) ~= 'table' then
			logger:addError('Data entry #%d is not a table', dataIndex)
		end

		-- Check that we have a name for the entry.
		if type(subtable.name) ~= 'string' then
			logger:addError('Data entry #%d does not have a name field', dataIndex)
		elseif subtable.name == '' then
			logger:addError('Data entry #%d has a blank name field', dataIndex)
		end

		-- Check that optional string fields are strings if they are present.
		for _, field in ipairs{'description', 'notes'} do
			local val = subtable[field]
			if val ~= nil and type(val) ~= 'string' then
				logger:addEntryTypeError(dataIndex, field, type(val), 'string or nil')
			end
		end

		-- Check that the reason is valid if it is present.
		if subtable.reason ~= nil then
			if type(subtable.reason) ~= 'string' then
				logger:addEntryTypeError(
					dataIndex,
					'reason',
					type(subtable.reason),
					'string or nil'
				)
			elseif not mSensitiveIPs.isValidSensitivityReason(subtable.reason) then
				logger:addError(
					"The reason field in data entry #%d was invalid (should be '%s')",
					dataIndex,
					mw.text.listToText(
						mSensitiveIPs.getSensitivityReasons,
						"', '",
						"', or '"
					)
				)
			end
		end

		-- Check IP range tables.
		for i, field in ipairs{'ipv4Ranges', 'ipv6Ranges'} do
			local ranges = subtable[field]
			if ranges ~= nil then
				if type(ranges) ~= 'table' then
				logger:addEntryTypeError(dataIndex, field, type(ranges), 'table or nil')
				else
					for j, range in ipairs(ranges) do
						if type(range) ~= 'string' then
							logger:addError(
								'Range #%d in the %s field of entry #%d was type %s (expected string)',
								j, field, type(range)
							)
						elseif range == '' then
							logger:addError(
								'Range #%d in the %s field of entry #%d was a blank string',
								j, field
							)
						end
					end
				end
			end
		end
	end
end

function p.main()
	local logger = makeErrorLogger()
	local data = loadData(logger)
	if logger:hasErrors() then
		return logger:makeReport()
	end
	checkDataStructure(logger, data)
	return logger:makeReport()
end

return p