Module:Report

local getArgs = require('Module:Arguments').getArgs local loader = require('Module:Loader')

local string, table, yesno, lu = loader.require('String', 'Table', 'Yesno', 'LibraryUtil')

local checkType = lu.checkType

local sep = ' • '

--Begin Exports local p = {}

--Helper Functions local function trimWhitespace(s) checkType('trimWhitespace', 1, s, 'string') return s:match( '^%s*(.-)%s*$' ) end

function p._trimUser(frame) local args = getArgs(frame) return p.trimUser(args[1], yesno(args[2], false)) end

function p.trimUser(s, link) checkType(1, s, 'string') local s = trimWhitespace(s) local matches = { {			['^.-%[%[.-%:([^%|]-)%|.*%]%].*$'] = '%1',			['^.-%[%[.-%:(.-)%]%].*$'] = '%1',		},		{			['^.-%{%{.+%:(.-)%/.+%|?.*%}%}.*$'] = '%1',		},		{			['^.-%[?https?%:/%/%S-%/wiki%/.-%:(.+) ?.-%]?.*$'] = '%1', ['^AbuseLog%?wpSearchUser=(.+)$'] = '%1', ['Contribu?t?i?o?n?s%/ ' ]='', ['^(.-)%?.+$'] = '%1',			[' .-%]$'] = '',		},	}	if s:match('^.-(%[%[.-%]%]).*$') then s = string.gsubMulti(s, matches[1]) elseif s:match('^.-%{%{.+%:(.-)%/.+%|?.*%}%}.*$') then s = string.gsubMulti(s, matches[2]) elseif s:match('^.-%[?https?%:/%/%S-%/wiki%/.-%:(.+) ?.-%]?.*$') then s = string.gsubMulti(s, matches[3]) end return link and table.concat{ , s,  } or s end

local function isIp(ip) if ip == nil or type(ip) ~= 'string' then return false end -- Check IPv4 local chunks = {ip:match('(%d+)%.(%d+)%.(%d+)%.(%d+)')} if (#chunks == 4) then for _,v in pairs(chunks) do			if (tonumber(v) < 0 or tonumber(v) > 255) then return false end end return true end -- Check IPv6 local _, chunks = ip:gsub('%:', '') if chunks == 7 then return true end return false end local function buildLinks(user, isIp) checkType(1, user, 'string') checkType(2, isIp, { 'boolean', 'nil' }) local ret = {} if not isIp then table.push(ret, string.fullUrl({ 'Message_wall:', user }, nil, 'wall')) -- this uses 'fullUrl' since message wall links show up as wanted pages, so full url is used instead [Oct 2021] table.push(ret, string.wrapLink({ 'Special:Contributions/', user }, 'contribs')) end table.push( ret, string.wrapLink({ 'Special:UserProfileActivity/', user }, 'posts'),		string.wrapLink({ 'Special:DeletedContributions/', user }, 'DelContribs'),		string.wrapLink({ 'Special:Log/', user }, 'logs'),		string.fullUrl( 'Special:Log/block', { ['page']=user }, 'block log'),		string.fullUrl('Special:AbuseLog', { ['wpSearchUser']=user }, 'abuse log'),		string.wrapLink({ 'Special:Block/', user }, 'Block'),		string.fullUrl('Special:BlankPage', { ['blankspecial']='nuke', ['nukeuser']=user }, 'Nuke')	) if isIp then table.push( ret,			string.externalUrl({ 'https://cleantalk.org/whois/', user }, nil, 'WHOIS'),			string.externalUrl({ 'https://www.ipqualityscore.com/free-ip-lookup-proxy-vpn-test/lookup/', user }, nil, 'Proxy check'),			string.externalUrl({ 'https://cleantalk.org/blacklists/', user }, nil, 'Spam BL check')		) end return table.concat{ string.wrapLink({ isIp and 'Special:Contributions/' or 'User:', user }, user), ' ',		string.wrapHtml(('(%s)'):format(table.concat(ret, sep)), ' ', { style = 'font-size: 10px' }) } end p.buildLinks = buildLinks

local function userLink(user, disableOthers) local ret = { string.fullUrl({ 'Message wall:', user }, nil, 'wall'), -- this uses 'fullUrl' since message wall links show up as wanted pages, so full url is used instead [Oct 2021] string.makeLink({ 'Special:Contribs/', user }, 'contribs'), string.makeLink({ 'Special:UserProfileActivity/', user }, 'posts'), }	return table.concat{ string.makeLink({ 'User:', user }, user), disableOthers and '' or ' ', not disableOthers and string.wrapHtml( ('(%s)'):format(table.concat(ret, sep)), ' ' ) or '', } end p.userLink = userLink

- -- Template: Userlinks -- -- Creates a link to a user's Userpage, wall, contributions, and posts. - function p._userLink(frame) local args = getArgs(frame) local value = args[1] return p.userLink(value, args['disableOther'] or args['disable']) end

local function buildPageLinks(page) checkType(1, page, 'string', true) page = page or mw.title.getCurrentTitle.fullText local ret = { string.fullUrl(page, { action='edit' }, 'edit'), string.fullUrl(page, { action='history' }, 'history'), string.fullUrl(page, { diff='cur' }, 'latest edit'), string.makeLink({ 'Special:WhatLinksHere/', page }, 'whl'), string.makeLink({ 'Special:PrefixIndex/', page, '/' }, 'subpages'), string.fullUrl('Special:Log', { page=page }, 'logs'), string.fullUrl('Special:AbuseLog', { wpSearchTitle=page }, 'abuse log'), string.makeLink({ 'Special:Undelete/', page }, 'del. revisions'), string.fullUrl(page, { action='protect' }, 'protect'), string.fullUrl(page, { action='delete' }, 'delete'), string.makeLink({ 'Special:MovePage/', page }, 'move'), }	return string.wrapLink(page) .. string.wrapHtml(('(%s)'):format(table.concat(ret, sep)), ' ') end

- -- Template: Report -- -- Generates a Report about a user - function p.main(frame) local args = getArgs(frame) local user = args['reported_user'] or args['ru'] or args['user'] or args['u'] or args[1] local reporter = args['reporter'] or args['r'] or args[2] local timestamp = args['timestamp'] or args['ts'] or args[3] local reason = args['reason'] or args['res'] or args[4] if not user then return string.error('Please provide a username to report!') elseif not reporter then return string.error('Please provide your signature!') elseif not reason then return string.error('Please provide a reason why you are reporting %s!', p.trimUser(user)) end return string.pcall(p._main, user, reporter, timestamp, reason) end

local function reportLink(user) return buildLinks(p.trimUser(user), isIp(user)) end

- -- Template: Report Module access point - function p._main(user, reporter, timestamp, reason) checkType(1, user, 'string') checkType(2, reporter, 'string') checkType(3, timestamp, 'string') checkType(4, reason, 'string') local links = reportLink(user) local reporter = p.trimUser(reporter) local split = mw.text.split(user, '%s*,%s*') if #split > 1 and type(split) == 'table' then local tmp = {} for i, v in ipairs(split) do			table.push(tmp, v)		end links = pipeline(table.map(split, function(v) return string.wrapTag(reportLink(v), 'li') end), 'ul', string.wrapTag) end local userinfo = table.concat({		string.fullUrl({ 'Message wall:', reporter }, nil, 'wall'), -- this uses 'fullUrl' since message wall links show up as wanted pages, so full url is used instead [Oct 2021]		string.wrapLink({ 'Special:Contributions/', reporter }, 'contribs'),	}, sep) local listitems = table.map({		'Reported User' .. (#split > 1 and type(split) == 'table') and 's' or '' .. ': ' .. links,		('Signature: %s %s'):format( string.wrapLink({ 'User:', reporter }, reporter), string.wrapHtml(('(%s)'):format(userinfo), ' ', { style='font-size: 10px' }) ),		'Timestamp: ' .. timestamp,		'Reason: ' .. reason,	}, function(v)		return string.wrapHtml(v, 'li')	end) return string.wrapHtml(listitems, 'ul') end

- -- Template: UserList -- -- Creates a user list with links. - function p._userList(frame) return p.userList(table.unpackRaw(getArgs(frame))) end

- -- function: userList(users) -- -- Invoked by. - function p.userList(users, ...) local split = string.split(users, '%s*,%s*') if not users:match',' then split = { users, ... }	end return table.concat(table.map(split, function(v) return userLink(v) end), ', ') end

- -- Template: Deletion request -- -- Generates a deletion request for a page - function p.delete(frame) local args = getArgs(frame) return p._delete(table.unpack(table.deepCopy(args))) end

- -- Template: Deletion request Module access point - function p._delete(...) local page, reporter, timestamp, reason, comments = ... checkTypeArgs({		'string',		'string',		'string',		'string',		'string',	}, ...) local page = trimWhitespace(page) local reason = trimWhitespace(reason) local links = buildPageLinks(page) local reporter = p.trimUser(reporter) local comments = trimWhitespace(comments) local timestamp = trimWhitespace(timestamp) local listitems = table.map({		'Page: ' .. links,		'Timestamp: ' .. timestamp,		'Reporter: ' .. reporter,		'Reason for report: ' .. reason,		'Addtional comments: ' .. reason,	}, function(v)		return string.wrapHtml(v, 'li')	end) return string.wrapHtml(listitems, 'ul') end

--Finish Module/Exports return p