Module:Requested move: Difference between revisions

Content deleted Content added
add additional error checks – see Module talk:Requested move and the Module:Requested move/sandbox revision history
m simplify some code (should be a no-op; if there are any errors no discussion is needed before reverting (WP:TPEDISPUTE))
 
(37 intermediate revisions by 10 users not shown)
Line 1:
-- This module implements {{requested move}} and {{move-multi}}.
 
-- Load necessary modules
Line 5:
local tableTools = require('Module:TableTools')
local yesno = require('Module:Yesno')
local mRedirect = require('Module:Redirect')
 
-- Set static values
Line 14 ⟶ 15:
-- Helper functions
--------------------------------------------------------------------------------
 
local function err(msg, numargs, reason, count)
-- Generates a wikitext error message
local commented = '<!-- {{subst:requested move|'
return string.format('{{error|%s}}', msg)
if count ~= 1 then
commented = commented .. 'new1='
end
commented = commented .. numargs[1]['new']
for i = 2,count do
commented = commented .. string.format('|current%i=%s', i, (numargs[i]['current'] or ''))
commented = commented .. string.format('|new%i=%s', i, (numargs[i]['new'] or ''))
end
if reason then
commented = commented .. '|reason=' .. reason
end
commented = commented .. '}} -->'
return string.format('{{error|%s}}', msg) .. commented
end
 
Line 67 ⟶ 81:
 
return true, titleObj
end
 
--------------------------------------------------------------------------------
-- Validate title entry point (used at [[Template:RMassist/core]])
--------------------------------------------------------------------------------
function p.validateTitle(frame)
local value = frame.args[1]
local validTitle, currentTitle = validateTitle(value or '', '1', '')
if not validTitle then
-- If invalid, the second parameter is the error message.
return currentTitle
end
return 'yes'
end
 
--------------------------------------------------------------------------------
-- Confirm protection levels (used at [[Template:Requested move/dated]])
--------------------------------------------------------------------------------
 
function p.protected(frame)
local args = getArgs(frame, {parentOnly = true})
if args.protected then
local levels = mw.title.new(args.protected).protectionLevels
local levelMove = levels['move'] and levels['move'][1]
local levelEdit = levels['edit'] and levels['edit'][1]
local levelCreate = levels['create'] and levels['create'][1]
if levelMove == 'sysop'
or levelEdit == 'sysop'
or levelEdit == 'editprotected'
or levelCreate == 'sysop' then
return 'sysop'
elseif levelMove == 'templateeditor'
or levelEdit == 'templateeditor'
or levelCreate == 'templateeditor' then
return 'templateeditor'
end
end
end
 
Line 95 ⟶ 146:
-- The current1 parameter is a special case, as it does not need to be
-- specified. To avoid clashes with later current parameters, we need to
-- add it to the args table manually. Although it does not need to be
-- specified, we don't want the module's behaviour to change if a user
-- specifies it anyway.
--
-- Also, we allow the first positional parameter to be an alias for the
Line 108 ⟶ 157:
-- true.
--]]
if not args.current1 then
args.current1 = title.subjectPageTitle.prefixedText
end
 
-- Find the first new page title, if specified, and keep a record of the
Line 141 ⟶ 192:
-- multiple nomination.
local argsByNumCount = #argsByNum
local multi = (argsByNumCount >= 2)
 
if argsByNumCount >= 2 then
multi = true
else
multi = false
end
--[[
-- Validate new params.
Line 167 ⟶ 213:
end
end
 
----------------------------------------------------------------------------
-- Error checks
Line 188 ⟶ 234:
local msg = '[[Template:Requested move]] must be used in a TALKSPACE, e.g., [[%s:%s]]'
msg = string.format(msg, mw.site.namespaces[title.namespace].talk.name, title.text)
return err(msg, argsByNum, args.reason, argsByNumCount)
end
Line 208 ⟶ 254:
.. ' please add it or remove the "new%d" parameter'
msg = string.format(msg, num, num)
return err(msg, argsByNum, args.reason, argsByNumCount)
end
 
Line 218 ⟶ 264:
-- If invalid, the second parameter is the error message.
local msg = currentTitle
return err(msg, argsByNum, args.reason, argsByNumCount)
end
 
Line 226 ⟶ 272:
local msg = '[[Template:Requested move]] is not for categories,'
.. ' see [[Wikipedia:Categories for discussion]]'
return err(msg, argsByNum, args.reason, argsByNumCount)
-- File namespace check
Line 233 ⟶ 279:
.. ' see [[Wikipedia:Moving a page#Moving a file page]]'
.. ' (use [[Template:Rename media]] instead)'
return err(msg, argsByNum, args.reason, argsByNumCount)
 
-- Draft and User namespace check
elseif subjectSpace == 2 or subjectSpace == 118 then
local msg = '[[Template:Requested move]] is not for moves from draft or user space;.'
.. '<br>If you would like to submit your draft for review, add <code>{{tlf|subst:submit}}</code>'
.. ' see [[Wikipedia:Articles for creation]]'
.. 'to (usethe top of the page.'
.. '<br>Otherwise, see [[Help:How to move a page]] for instructions.'
.. mw.text.nowiki('{{')
.. '<br>If you cannot move it yourself, see [[Wikipedia:Requested moves#Requesting technical moves|Requesting technical moves]].'
.. '[[Wikipedia:Substitution|subst]]:[[Template:Submit|submit]]'
return err(msg, argsByNum, args.reason, argsByNumCount)
.. mw.text.nowiki('}}')
end
.. ' instead),'
 
.. ' or [[Help:How to move a page|move it yourself]]'
-- Request to move a single page must be placed on that page's talk, or the page it redirects to
return err(msg)
if not multi and args.current1 ~= title.subjectPageTitle.prefixedText then
local idealpage = mw.title.new(args.current1).talkPageTitle
local rtarget = mRedirect.getTarget(idealpage)
if rtarget == title.prefixedText then
multi = true
else
local msg = 'Request to move a single page must be placed on that page\'s talk or the page its talk redirects to'
return err(msg, argsByNum, args.reason, argsByNumCount)
end
end
 
Line 252 ⟶ 307:
local msg = 'Must create [[:%s]] before requesting that it be moved'
msg = string.format(msg, current)
return err(msg, argsByNum, args.reason, argsByNumCount)
end
 
Line 263 ⟶ 318:
.. currentTitle.prefixedText
.. '"); cannot move the same page to two different places'
return err(msg, argsByNum, args.reason, argsByNumCount)
else
currentDupes[currentId] = true
Line 279 ⟶ 334:
-- If invalid, the second parameter is the error message.
local msg = newTitle
return err(msg, argsByNum, args.reason, argsByNumCount)
end
 
Line 294 ⟶ 349:
.. newTitle.prefixedText
.. '"); cannot move two different pages to the same place'
return err(msg, argsByNum, args.reason, argsByNumCount)
else
newDupes[newPrefixedText] = true
end
end
end
----------------------------------------------------------------------------
-- Check for page protection
----------------------------------------------------------------------------
local highestProtection = ''
local protectedTitle = ''
-- Checking page protection requires use of .protectionLevels(), one of the
-- "expensive" parser functions, which stop working after 500 uses total.
-- Without some limit set, this starts breaking near 250 distinct titles.
local titleLimit = 80
local titlesChecked = 0
local titles = {}
-- Consolidate duplicate titles (i.e., when moving A to B and B to C)
for i = 1,argsByNumCount do
titles[mw.title.new(argsByNum[i]['current'])] = true
titles[mw.title.new(argsByNum[i]['new'])] = true
end
-- Check each title t, while ignoring the "true" value
for t, _ in pairs(titles) do
if titlesChecked < titleLimit then
local levels = t.protectionLevels
titlesChecked = titlesChecked + 1
local levelMove = levels['move'] and levels['move'][1]
local levelEdit = levels['edit'] and levels['edit'][1]
local levelCreate = levels['create'] and levels['create'][1]
if levelMove == 'sysop'
or levelEdit == 'sysop'
or levelEdit == 'editprotected'
or levelCreate == 'sysop' then
highestProtection = 'sysop'
protectedTitle = tostring(t)
break
elseif levelMove == 'templateeditor'
or levelEdit == 'templateeditor'
or levelCreate == 'templateeditor' then
highestProtection = 'templateeditor'
protectedTitle = tostring(t)
end
else
-- End the "for" loop if the titleLimit is reached
break
end
end
Line 306 ⟶ 406:
 
-- For custom values of |heading=, use those.
-- For |heading=yesno, |heading=yn, etc., usedon't the current date asinclude a heading.
-- Otherwise don'tuse includethe current date as a heading.
local heading = args.heading or args.header
local useHeading = yesno(heading, heading)
if heading and useHeading == heading then
heading = '== ' .. heading .. ' ==\n\n'
elseif useHeading == false then
heading = ''
else
local lang = mw.language.getContentLanguage()
local headingDate = lang:formatDate('dj F Y')
heading = '== Requested move ' .. headingDate .. ' ==\n\n'
else
heading = ''
end
Line 340 ⟶ 440:
rmd[#rmd + 1] = '|' .. new1param .. argsByNum[1].new
 
-- Add the rest of themore arguments for multi.
if multi then
for i = 2, argsByNumCount do
Line 350 ⟶ 450:
rmd[#rmd + 1] = '|new' .. numString .. '=' .. new
end
end
-- The old multi template always has a bar before the closing curly
-- braces, so we will do that too.
-- Highest page protection (if admin or template-editor)
if highestProtection == 'sysop' or highestProtection == 'templateeditor' then
rmd[#rmd + 1] = '|protected=' .. protectedTitle
end
-- Pass through demo=yes to the
if args.demo ~= nil then
rmd[#rmd + 1] = '|demo='
rmd[#rmd + 1] = args.demo
end
-- The old multi template always has a bar before the closing curly
-- braces, so we will do that too.
if multi then
rmd[#rmd + 1] = '|'
end
Line 366 ⟶ 480:
local current = t.current
local new = t.new
local msg = '\n%s[[:%s]] → '
if new ~= defaultNewPagename then
msg = msg .. '{{no redirect|%s}}'
else
msg = msg .. '%s'
end
local item = string.format(
msg,
'\n%s[[:%s]] → {{no redirect|%s}}',
multi and '* ' or '', -- Don't make a list for single page moves.
current,
Line 382 ⟶ 502:
-- Reason
local reason = args.reason or args[2] or 'Please place your rationale for the proposed move here.'
reason = '– ' .. reason .. ' ~~~~'
if yesno(args.sign or args.sig or args.signature or 'unspecified', not reason:match("~~~$")) then
reason = reason .. ' ~~~~'
end
 
-- Talk blurb
local talk = ''
if yesno(args.talk, true) then
talk = frame:expandTemplate{title = 'Requested move/talk'}
else
talk = ''
end