Module:Protection banner and Module:Protection banner/config: Difference between pages

From Mor Afgin Website
(Difference between pages)
m (1 revision imported)
 
m (1 revision imported)
 
Line 1: Line 1:
-- This module implements {{pp-meta}} and its daughter templates such as
-- This module provides configuration data for [[Module:Protection banner]].
-- {{pp-dispute}}, {{pp-vandalism}} and {{pp-sock}}.


-- Initialise necessary modules.
return {
require('strict')
local makeFileLink = require('Module:File link')._main
local effectiveProtectionLevel = require('Module:Effective protection level')._main
local effectiveProtectionExpiry = require('Module:Effective protection expiry')._main
local yesno = require('Module:Yesno')
 
-- Lazily initialise modules and objects we don't always need.
local getArgs, makeMessageBox, lang
 
-- Set constants.
local CONFIG_MODULE = 'Module:Protection banner/config'


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Helper functions
--
--                                BANNER DATA
--
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


local function makeCategoryLink(cat, sort)
--[[
if cat then
-- Banner data consists of six fields:
return string.format(
-- * text - the main protection text that appears at the top of protection
'[[%s:%s|%s]]',
--  banners.
mw.site.namespaces[14].name,
-- * explanation - the text that appears below the main protection text, used
cat,
--  to explain the details of the protection.
sort
-- * tooltip - the tooltip text you see when you move the mouse over a small
)
--  padlock icon.
end
-- * link - the page that the small padlock icon links to.
end
-- * alt - the alt text for the small padlock icon. This is also used as tooltip
--  text for the large protection banners.
-- * image - the padlock image used in both protection banners and small padlock
--  icons.
--
-- The module checks in three separate tables to find a value for each field.
-- First it checks the banners table, which has values specific to the reason
-- for the page being protected. Then the module checks the defaultBanners
-- table, which has values specific to each protection level. Finally, the
-- module checks the masterBanner table, which holds data for protection
-- templates to use if no data has been found in the previous two tables.
--
-- The values in the banner data can take parameters. These are specified
-- using ${TEXTLIKETHIS} (a dollar sign preceding a parameter name
-- enclosed in curly braces).
--
--                          Available parameters:
--
-- ${CURRENTVERSION} - a link to the page history or the move log, with the
-- display message "current-version-edit-display" or
-- "current-version-move-display".
--
-- ${EDITREQUEST} - a link to create an edit request for the current page.
--
-- ${EXPLANATIONBLURB} - an explanation blurb, e.g. "Please discuss any changes
-- on the talk page; you may submit a request to ask an administrator to make
-- an edit if it is minor or supported by consensus."
--
-- ${IMAGELINK} - a link to set the image to, depending on the protection
-- action and protection level.
--
-- ${INTROBLURB} - the PROTECTIONBLURB parameter, plus the expiry if an expiry
-- is set. E.g. "Editing of this page by new or unregistered users is currently
-- disabled until dd Month YYYY."
--
-- ${INTROFRAGMENT} - the same as ${INTROBLURB}, but without final punctuation
-- so that it can be used in run-on sentences.
--
-- ${PAGETYPE} - the type of the page, e.g. "article" or "template".
-- Defined in the cfg.pagetypes table.
--
-- ${PROTECTIONBLURB} - a blurb explaining the protection level of the page, e.g.
-- "Editing of this page by new or unregistered users is currently disabled"
--
-- ${PROTECTIONDATE} - the protection date, if it has been supplied to the
-- template.
--
-- ${PROTECTIONLEVEL} - the protection level, e.g. "fully protected" or
-- "semi-protected".
--
-- ${PROTECTIONLOG} - a link to the protection log or the pending changes log,
-- depending on the protection action.
--
-- ${TALKPAGE} - a link to the talk page. If a section is specified, links
-- straight to that talk page section.
--
-- ${TOOLTIPBLURB} - uses the PAGETYPE, PROTECTIONTYPE and EXPIRY parameters to
-- create a blurb like "This template is semi-protected", or "This article is
-- move-protected until DD Month YYYY".
--
-- ${VANDAL} - links for the specified username (or the root page name)
-- using Module:Vandal-m.
--
--                                Functions
--
-- For advanced users, it is possible to use Lua functions instead of strings
-- in the banner config tables. Using functions gives flexibility that is not
-- possible just by using parameters. Functions take two arguments, the
-- protection object and the template arguments, and they must output a string.
--
-- For example:
--
-- text = function (protectionObj, args)
--    if protectionObj.level == 'autoconfirmed' then
--        return 'foo'
--    else
--        return 'bar'
--    end
-- end
--
-- Some protection object properties and methods that may be useful:
-- protectionObj.action - the protection action
-- protectionObj.level - the protection level
-- protectionObj.reason - the protection reason
-- protectionObj.expiry - the expiry. Nil if unset, the string "indef" if set
--    to indefinite, and the protection time in unix time if temporary.
-- protectionObj.protectionDate - the protection date in unix time, or nil if
--    unspecified.
-- protectionObj.bannerConfig - the banner config found by the module. Beware
--    of editing the config field used by the function, as it could create an
--    infinite loop.
-- protectionObj:isProtected - returns a boolean showing whether the page is
--    protected.
-- protectionObj:isTemporary - returns a boolean showing whether the expiry is
--    temporary.
-- protectionObj:isIncorrect - returns a boolean showing whether the protection
--    template is incorrect.
--]]


-- Validation function for the expiry and the protection date
-- The master banner data, used if no values have been found in banners or
local function validateDate(dateString, dateType)
-- defaultBanners.
if not lang then
masterBanner = {
lang = mw.language.getContentLanguage()
text = '${INTROBLURB}',
end
explanation = '${EXPLANATIONBLURB}',
local success, result = pcall(lang.formatDate, lang, 'U', dateString)
tooltip = '${TOOLTIPBLURB}',
if success then
link = '${IMAGELINK}',
result = tonumber(result)
alt = 'Page ${PROTECTIONLEVEL}'
if result then
},
return result
end
end
error(string.format(
'invalid %s: %s',
dateType,
tostring(dateString)
), 4)
end


local function makeFullUrl(page, query, display)
-- The default banner data. This holds banner data for different protection
return string.format(
-- levels.
'[%s %s]',
-- *required* - this table needs edit, move, autoreview and upload subtables.
tostring(mw.uri.fullUrl(page, query)),
defaultBanners = {
display
edit = {},
)
move = {},
end
autoreview = {
default = {
alt = 'Page protected with pending changes',
tooltip = 'All edits by unregistered and new users are subject to review prior to becoming visible to unregistered users',
image = 'Pending-protection-shackle.svg'
}
},
upload = {}
},


-- Given a directed graph formatted as node -> table of direct successors,
-- The banner data. This holds banner data for different protection reasons.
-- get a table of all nodes reachable from a given node (though always
-- In fact, the reasons specified in this table control which reasons are
-- including the given node).
-- valid inputs to the first positional parameter.
local function getReachableNodes(graph, start)
--
local toWalk, retval = {[start] = true}, {}
-- There is also a non-standard "description" field that can be used for items
while true do
-- in this table. This is a description of the protection reason for use in the
-- Can't use pairs() since we're adding and removing things as we're iterating
-- module documentation.
local k = next(toWalk) -- This always gets the "first" key
--
if k == nil then
-- *required* - this table needs edit, move, autoreview and upload subtables.
return retval
banners = {
end
edit = {
toWalk[k] = nil
blp = {
retval[k] = true
description = 'For pages protected to promote compliance with the'
for _,v in ipairs(graph[k]) do
.. ' [[Wikipedia:Biographies of living persons'
if not retval[v] then
.. '|biographies of living persons]] policy',
toWalk[v] = true
text = '${INTROFRAGMENT} to promote compliance with'
end
.. ' [[Wikipedia:Biographies of living persons'
end
.. "|Wikipedia's policy on the biographies"
end
.. ' of living people]].',
end
tooltip = '${TOOLTIPFRAGMENT} to promote compliance with the policy on'
.. ' biographies of living persons',
},
dmca = {
description = 'For pages protected by the Wikimedia Foundation'
.. ' due to [[Digital Millennium Copyright Act]] takedown requests',
explanation = function (protectionObj, args)
local ret = 'Pursuant to a rights owner notice under the Digital'
.. ' Millennium Copyright Act (DMCA) regarding some content'
.. ' in this article, the Wikimedia Foundation acted under'
.. ' applicable law and took down and restricted the content'
.. ' in question.'
if args.notice then
ret = ret .. ' A copy of the received notice can be found here: '
.. args.notice .. '.'
end
ret = ret .. ' For more information, including websites discussing'
.. ' how to file a counter-notice, please see'
.. " [[Wikipedia:Office actions]] and the article's ${TALKPAGE}."
.. "'''Do not remove this template from the article until the"
.. " restrictions are withdrawn'''."
return ret
end,
image = 'Office-protection-shackle.svg',
},
dispute = {
description = 'For pages protected due to editing disputes',
text = function (protectionObj, args)
-- Find the value of "disputes".
local display = 'disputes'
local disputes
if args.section then
disputes = string.format(
'[[%s:%s#%s|%s]]',
mw.site.namespaces[protectionObj.title.namespace].talk.name,
protectionObj.title.text,
args.section,
display
)
else
disputes = display
end


--------------------------------------------------------------------------------
-- Make the blurb, depending on the expiry.
-- Protection class
local msg
--------------------------------------------------------------------------------
if type(protectionObj.expiry) == 'number' then
 
msg = '${INTROFRAGMENT} or until editing %s have been resolved.'
local Protection = {}
else
Protection.__index = Protection
msg = '${INTROFRAGMENT} until editing %s have been resolved.'
 
end
Protection.supportedActions = {
return string.format(msg, disputes)
edit = true,
end,
move = true,
explanation = "This protection is '''not''' an endorsement of the"
autoreview = true,
.. ' ${CURRENTVERSION}. ${EXPLANATIONBLURB}',
upload = true
tooltip = '${TOOLTIPFRAGMENT} due to editing disputes',
}
},
 
ecp = {
Protection.bannerConfigFields = {
description = 'For articles in topic areas authorized by'
'text',
.. ' [[Wikipedia:Arbitration Committee|ArbCom]] or'
'explanation',
.. ' meets the criteria for community use',
'tooltip',
tooltip = 'This ${PAGETYPE} is ${PROTECTIONLEVEL}',
'alt',
alt = 'Extended-protected ${PAGETYPE}',
'link',
},
'image'
mainpage = {
}
description = 'For pages protected for being displayed on the [[Main Page]]',
 
text = 'This file is currently'
function Protection.new(args, cfg, title)
.. ' [[Wikipedia:This page is protected|protected]] from'
local obj = {}
.. ' editing because it is currently or will soon be displayed'
obj._cfg = cfg
.. ' on the [[Main Page]].',
obj.title = title or mw.title.getCurrentTitle()
explanation = 'Images on the Main Page are protected due to their high'
 
.. ' visibility. Please discuss any necessary changes on the ${TALKPAGE}.'
-- Set action
.. '<br /><span style="font-size:90%;">'
if not args.action then
.. "'''Administrators:''' Once this image is definitely off the Main Page,"
obj.action = 'edit'
.. ' please unprotect this file, or reduce to semi-protection,'
elseif Protection.supportedActions[args.action] then
.. ' as appropriate.</span>',
obj.action = args.action
},
else
office = {
error(string.format(
description = 'For pages protected by the Wikimedia Foundation',
'invalid action: %s',
text = function (protectionObj, args)
tostring(args.action)
local ret = 'This ${PAGETYPE} is currently under the'
), 3)
.. ' scrutiny of the'
end
.. ' [[Wikipedia:Office actions|Wikimedia Foundation Office]]'
 
.. ' and is protected.'
-- Set level
if protectionObj.protectionDate then
obj.level = args.demolevel or effectiveProtectionLevel(obj.action, obj.title)
ret = ret .. ' It has been protected since ${PROTECTIONDATE}.'
if not obj.level or (obj.action == 'move' and obj.level == 'autoconfirmed') then
-- Users need to be autoconfirmed to move pages anyway, so treat
-- semi-move-protected pages as unprotected.
obj.level = '*'
end
 
-- Set expiry
local effectiveExpiry = effectiveProtectionExpiry(obj.action, obj.title)
if effectiveExpiry == 'infinity' then
obj.expiry = 'indef'
elseif effectiveExpiry ~= 'unknown' then
obj.expiry = validateDate(effectiveExpiry, 'expiry date')
end
 
-- Set reason
if args[1] then
obj.reason = mw.ustring.lower(args[1])
if obj.reason:find('|') then
error('reasons cannot contain the pipe character ("|")', 3)
end
end
 
-- Set protection date
if args.date then
obj.protectionDate = validateDate(args.date, 'protection date')
end
-- Set banner config
do
obj.bannerConfig = {}
local configTables = {}
if cfg.banners[obj.action] then
configTables[#configTables + 1] = cfg.banners[obj.action][obj.reason]
end
if cfg.defaultBanners[obj.action] then
configTables[#configTables + 1] = cfg.defaultBanners[obj.action][obj.level]
configTables[#configTables + 1] = cfg.defaultBanners[obj.action].default
end
configTables[#configTables + 1] = cfg.masterBanner
for i, field in ipairs(Protection.bannerConfigFields) do
for j, t in ipairs(configTables) do
if t[field] then
obj.bannerConfig[field] = t[field]
break
end
end
end
return ret
end
end,
end
explanation = "If you can edit this page, please discuss all changes and"
return setmetatable(obj, Protection)
.. " additions on the ${TALKPAGE} first. '''Do not remove protection from this"
end
.. " page unless you are authorized by the Wikimedia Foundation to do"
 
.. " so.'''",
function Protection:isUserScript()
image = 'Office-protection-shackle.svg',
-- Whether the page is a user JavaScript or CSS page.
},
local title = self.title
reset = {
return title.namespace == 2 and (
description = 'For pages protected by the Wikimedia Foundation and'
title.contentModel == 'javascript' or title.contentModel == 'css'
.. ' "reset" to a bare-bones version',
)
text = 'This ${PAGETYPE} is currently under the'
end
.. ' scrutiny of the'
 
.. ' [[Wikipedia:Office actions|Wikimedia Foundation Office]]'
function Protection:isProtected()
.. ' and is protected.',
return self.level ~= '*'
explanation = function (protectionObj, args)
end
local ret = ''
 
if protectionObj.protectionDate then
function Protection:shouldShowLock()
ret = ret .. 'On ${PROTECTIONDATE} this ${PAGETYPE} was'
-- Whether we should output a banner/padlock
return self:isProtected() and not self:isUserScript()
end
 
-- Whether this page needs a protection category.
Protection.shouldHaveProtectionCategory = Protection.shouldShowLock
 
function Protection:isTemporary()
return type(self.expiry) == 'number'
end
 
function Protection:makeProtectionCategory()
if not self:shouldHaveProtectionCategory() then
return ''
end
 
local cfg = self._cfg
local title = self.title
-- Get the expiry key fragment.
local expiryFragment
if self.expiry == 'indef' then
expiryFragment = self.expiry
elseif type(self.expiry) == 'number' then
expiryFragment = 'temp'
end
 
-- Get the namespace key fragment.
local namespaceFragment = cfg.categoryNamespaceKeys[title.namespace]
if not namespaceFragment and title.namespace % 2 == 1 then
namespaceFragment = 'talk'
end
 
-- Define the order that key fragments are tested in. This is done with an
-- array of tables containing the value to be tested, along with its
-- position in the cfg.protectionCategories table.
local order = {
{val = expiryFragment,    keypos = 1},
{val = namespaceFragment, keypos = 2},
{val = self.reason,      keypos = 3},
{val = self.level,        keypos = 4},
{val = self.action,      keypos = 5}
}
 
--[[
-- The old protection templates used an ad-hoc protection category system,
-- with some templates prioritising namespaces in their categories, and
-- others prioritising the protection reason. To emulate this in this module
-- we use the config table cfg.reasonsWithNamespacePriority to set the
-- reasons for which namespaces have priority over protection reason.
-- If we are dealing with one of those reasons, move the namespace table to
-- the end of the order table, i.e. give it highest priority. If not, the
-- reason should have highest priority, so move that to the end of the table
-- instead.
--]]
table.insert(order, table.remove(order, self.reason and cfg.reasonsWithNamespacePriority[self.reason] and 2 or 3))
--[[
-- Define the attempt order. Inactive subtables (subtables with nil "value"
-- fields) are moved to the end, where they will later be given the key
-- "all". This is to cut down on the number of table lookups in
-- cfg.protectionCategories, which grows exponentially with the number of
-- non-nil keys. We keep track of the number of active subtables with the
-- noActive parameter.
--]]
local noActive, attemptOrder
do
local active, inactive = {}, {}
for i, t in ipairs(order) do
if t.val then
active[#active + 1] = t
else
inactive[#inactive + 1] = t
end
end
noActive = #active
attemptOrder = active
for i, t in ipairs(inactive) do
attemptOrder[#attemptOrder + 1] = t
end
end
--[[
-- Check increasingly generic key combinations until we find a match. If a
-- specific category exists for the combination of key fragments we are
-- given, that match will be found first. If not, we keep trying different
-- key fragment combinations until we match using the key
-- "all-all-all-all-all".
--
-- To generate the keys, we index the key subtables using a binary matrix
-- with indexes i and j. j is only calculated up to the number of active
-- subtables. For example, if there were three active subtables, the matrix
-- would look like this, with 0 corresponding to the key fragment "all", and
-- 1 corresponding to other key fragments.
--
--  j 1  2  3
-- i 
-- 1  1  1  1
-- 2  0  1  1
-- 3  1  0  1
-- 4  0  0  1
-- 5  1  1  0
-- 6  0  1  0
-- 7  1  0  0
-- 8  0  0  0
--
-- Values of j higher than the number of active subtables are set
-- to the string "all".
--
-- A key for cfg.protectionCategories is constructed for each value of i.
-- The position of the value in the key is determined by the keypos field in
-- each subtable.
--]]
local cats = cfg.protectionCategories
for i = 1, 2^noActive do
local key = {}
for j, t in ipairs(attemptOrder) do
if j > noActive then
key[t.keypos] = 'all'
else
local quotient = i / 2 ^ (j - 1)
quotient = math.ceil(quotient)
if quotient % 2 == 1 then
key[t.keypos] = t.val
else
else
key[t.keypos] = 'all'
ret = ret .. 'This ${PAGETYPE} has been'
end
end
end
ret = ret .. ' reduced to a'
end
.. ' simplified, "bare bones" version so that it may be completely'
key = table.concat(key, '|')
.. ' rewritten to ensure it meets the policies of'
local attempt = cats[key]
.. ' [[WP:NPOV|Neutral Point of View]] and [[WP:V|Verifiability]].'
if attempt then
.. ' Standard Wikipedia policies will apply to its rewriting—which'
return makeCategoryLink(attempt, title.text)
.. ' will eventually be open to all editors—and will be strictly'
end
.. ' enforced. The ${PAGETYPE} has been ${PROTECTIONLEVEL} while'
end
.. ' it is being rebuilt.\n\n'
return ''
.. 'Any insertion of material directly from'
end
.. ' pre-protection revisions of the ${PAGETYPE} will be removed, as'
.. ' will any material added to the ${PAGETYPE} that is not properly'
.. ' sourced. The associated talk page(s) were also cleared on the'
.. " same date.\n\n"
.. "If you can edit this page, please discuss all changes and"
.. " additions on the ${TALKPAGE} first. '''Do not override"
.. " this action, and do not remove protection from this page,"
.. " unless you are authorized by the Wikimedia Foundation"
.. " to do so. No editor may remove this notice.'''"


function Protection:isIncorrect()
return ret
local expiry = self.expiry
end,
return not self:shouldHaveProtectionCategory()
image = 'Office-protection-shackle.svg',
or type(expiry) == 'number' and expiry < os.time()
},
end
sock = {
description = 'For pages protected due to'
.. ' [[Wikipedia:Sock puppetry|sock puppetry]]',
text = '${INTROFRAGMENT} to prevent [[Wikipedia:Sock puppetry|sock puppets]] of'
.. ' [[Wikipedia:Blocking policy|blocked]] or'
.. ' [[Wikipedia:Banning policy|banned users]]'
.. ' from editing it.',
tooltip = '${TOOLTIPFRAGMENT} to prevent sock puppets of blocked or banned users from'
.. ' editing it',
},
template = {
description = 'For [[Wikipedia:High-risk templates|high-risk]]'
.. ' templates and Lua modules',
text = 'This is a permanently [[Help:Protection|protected]] ${PAGETYPE},'
.. ' as it is [[Wikipedia:High-risk templates|high-risk]].',
explanation = 'Please discuss any changes on the ${TALKPAGE}; you may'
.. ' ${EDITREQUEST} to ask an'
.. ' [[Wikipedia:Administrators|administrator]] or'
.. ' [[Wikipedia:Template editor|template editor]] to make an edit if'
.. ' it is [[Help:Minor edit#When to mark an edit as a minor edit'
.. '|uncontroversial]] or supported by'
.. ' [[Wikipedia:Consensus|consensus]]. You can also'
.. ' [[Wikipedia:Requests for page protection|request]] that the page be'
.. ' unprotected.',
tooltip = 'This high-risk ${PAGETYPE} is permanently ${PROTECTIONLEVEL}'
.. ' to prevent vandalism',
alt = 'Permanently protected ${PAGETYPE}',
},
usertalk = {
description = 'For pages protected against disruptive edits by a'
.. ' particular user',
text = '${INTROFRAGMENT} to prevent ${VANDAL} from using it to make disruptive edits,'
.. ' such as abusing the'
.. ' &#123;&#123;[[Template:unblock|unblock]]&#125;&#125; template.',
explanation = 'If you cannot edit this user talk page and you need to'
.. ' make a change or leave a message, you can'
.. ' [[Wikipedia:Requests for page protection'
.. '#Current requests for edits to a protected page'
.. '|request an edit]],'
.. ' [[Wikipedia:Requests for page protection'
.. '#Current requests for reduction in protection level'
.. '|request unprotection]],'
.. ' [[Special:Userlogin|log in]],'
.. ' or [[Special:UserLogin/signup|create an account]].',
},
vandalism = {
description = 'For pages protected against'
.. ' [[Wikipedia:Vandalism|vandalism]]',
text = '${INTROFRAGMENT} due to [[Wikipedia:Vandalism|vandalism]].',
explanation = function (protectionObj, args)
local ret = ''
if protectionObj.level == 'sysop' then
ret = ret .. "This protection is '''not''' an endorsement of the"
.. ' ${CURRENTVERSION}. '
end
return ret .. '${EXPLANATIONBLURB}'
end,
tooltip = '${TOOLTIPFRAGMENT} due to vandalism',
}
},
move = {
dispute = {
description = 'For pages protected against page moves due to'
.. ' disputes over the page title',
explanation = "This protection is '''not''' an endorsement of the"
.. ' ${CURRENTVERSION}. ${EXPLANATIONBLURB}',
image = 'Move-protection-shackle.svg'
},
vandalism = {
description = 'For pages protected against'
.. ' [[Wikipedia:Vandalism#Page-move vandalism'
.. ' |page-move vandalism]]'
}
},
autoreview = {},
upload = {}
},


function Protection:isTemplateProtectedNonTemplate()
--------------------------------------------------------------------------------
local action, namespace = self.action, self.title.namespace
--
return self.level == 'templateeditor'
--                            GENERAL DATA TABLES
and (
--
(action ~= 'edit' and action ~= 'move')
--------------------------------------------------------------------------------
or (namespace ~= 10 and namespace ~= 828)
)
end
 
function Protection:makeCategoryLinks()
local msg = self._cfg.msg
local ret = {self:makeProtectionCategory()}
if self:isIncorrect() then
ret[#ret + 1] = makeCategoryLink(
msg['tracking-category-incorrect'],
self.title.text
)
end
if self:isTemplateProtectedNonTemplate() then
ret[#ret + 1] = makeCategoryLink(
msg['tracking-category-template'],
self.title.text
)
end
return table.concat(ret)
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Blurb class
-- Protection blurbs
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


local Blurb = {}
-- This table produces the protection blurbs available with the
Blurb.__index = Blurb
-- ${PROTECTIONBLURB} parameter. It is sorted by protection action and
-- protection level, and is checked by the module in the following order:
-- 1. page's protection action, page's protection level
-- 2. page's protection action, default protection level
-- 3. "edit" protection action, default protection level
--
-- It is possible to use banner parameters inside this table.
-- *required* - this table needs edit, move, autoreview and upload subtables.
protectionBlurbs = {
edit = {
default = 'This ${PAGETYPE} is currently [[Help:Protection|'
.. 'protected]] from editing',
autoconfirmed = 'Editing of this ${PAGETYPE} by [[Wikipedia:User access'
.. ' levels#New users|new]] or [[Wikipedia:User access levels#Unregistered'
.. ' users|unregistered]] users is currently [[Help:Protection|disabled]]',
extendedconfirmed = 'This ${PAGETYPE} is currently under extended confirmed protection',
},
move = {
default = 'This ${PAGETYPE} is currently [[Help:Protection|protected]]'
.. ' from [[Help:Moving a page|page moves]]'
},
autoreview = {
default = 'All edits made to this ${PAGETYPE} by'
.. ' [[Wikipedia:User access levels#New users|new]] or'
.. ' [[Wikipedia:User access levels#Unregistered users|unregistered]]'
.. ' users are currently'
.. ' [[Wikipedia:Pending changes|subject to review]]'
},
upload = {
default = 'Uploading new versions of this ${PAGETYPE} is currently disabled'
}
},


Blurb.bannerTextFields = {
text = true,
explanation = true,
tooltip = true,
alt = true,
link = true
}


function Blurb.new(protectionObj, args, cfg)
--------------------------------------------------------------------------------
return setmetatable({
-- Explanation blurbs
_cfg = cfg,
--------------------------------------------------------------------------------
_protectionObj = protectionObj,
_args = args
}, Blurb)
end


-- Private methods --
-- This table produces the explanation blurbs available with the
-- ${EXPLANATIONBLURB} parameter. It is sorted by protection action,
-- protection level, and whether the page is a talk page or not. If the page is
-- a talk page it will have a talk key of "talk"; otherwise it will have a talk
-- key of "subject". The table is checked in the following order:
-- 1. page's protection action, page's protection level, page's talk key
-- 2. page's protection action, page's protection level, default talk key
-- 3. page's protection action, default protection level, page's talk key
-- 4. page's protection action, default protection level, default talk key
--
-- It is possible to use banner parameters inside this table.
-- *required* - this table needs edit, move, autoreview and upload subtables.
explanationBlurbs = {
edit = {
autoconfirmed = {
subject = 'See the [[Wikipedia:Protection policy|'
.. 'protection policy]] and ${PROTECTIONLOG} for more details. If you'
.. ' cannot edit this ${PAGETYPE} and you wish to make a change, you can'
.. ' ${EDITREQUEST}, discuss changes on the ${TALKPAGE},'
.. ' [[Wikipedia:Requests for page protection'
.. '#Current requests for reduction in protection level'
.. '|request unprotection]], [[Special:Userlogin|log in]], or'
.. ' [[Special:UserLogin/signup|create an account]].',
default = 'See the [[Wikipedia:Protection policy|'
.. 'protection policy]] and ${PROTECTIONLOG} for more details. If you'
.. ' cannot edit this ${PAGETYPE} and you wish to make a change, you can'
.. ' [[Wikipedia:Requests for page protection'
.. '#Current requests for reduction in protection level'
.. '|request unprotection]], [[Special:Userlogin|log in]], or'
.. ' [[Special:UserLogin/signup|create an account]].',
},
extendedconfirmed = {
default = 'Extended confirmed protection prevents edits from all unregistered editors'
.. ' and registered users with fewer than 30 days tenure and 500 edits.'
.. ' The [[Wikipedia:Protection policy#extended|policy on community use]]'
.. ' specifies that extended confirmed protection can be applied to combat'
.. ' disruption, if semi-protection has proven to be ineffective.'
.. ' Extended confirmed protection may also be applied to enforce'
.. ' [[Wikipedia:Arbitration Committee|arbitration sanctions]].'
.. ' Please discuss any changes on the ${TALKPAGE}; you may'
.. ' ${EDITREQUEST} to ask for uncontroversial changes supported by'
.. ' [[Wikipedia:Consensus|consensus]].'
},
default = {
subject = 'See the [[Wikipedia:Protection policy|'
.. 'protection policy]] and ${PROTECTIONLOG} for more details.'
.. ' Please discuss any changes on the ${TALKPAGE}; you'
.. ' may ${EDITREQUEST} to ask an'
.. ' [[Wikipedia:Administrators|administrator]] to make an edit if it'
.. ' is [[Help:Minor edit#When to mark an edit as a minor edit'
.. '|uncontroversial]] or supported by [[Wikipedia:Consensus'
.. '|consensus]]. You may also [[Wikipedia:Requests for'
.. ' page protection#Current requests for reduction in protection level'
.. '|request]] that this page be unprotected.',
default = 'See the [[Wikipedia:Protection policy|'
.. 'protection policy]] and ${PROTECTIONLOG} for more details.'
.. ' You may [[Wikipedia:Requests for page'
.. ' protection#Current requests for edits to a protected page|request an'
.. ' edit]] to this page, or [[Wikipedia:Requests for'
.. ' page protection#Current requests for reduction in protection level'
.. '|ask]] for it to be unprotected.'
}
},
move = {
default = {
subject = 'See the [[Wikipedia:Protection policy|'
.. 'protection policy]] and ${PROTECTIONLOG} for more details.'
.. ' The page may still be edited but cannot be moved'
.. ' until unprotected. Please discuss any suggested moves on the'
.. ' ${TALKPAGE} or at [[Wikipedia:Requested moves]]. You can also'
.. ' [[Wikipedia:Requests for page protection|request]] that the page be'
.. ' unprotected.',
default = 'See the [[Wikipedia:Protection policy|'
.. 'protection policy]] and ${PROTECTIONLOG} for more details.'
.. ' The page may still be edited but cannot be moved'
.. ' until unprotected. Please discuss any suggested moves at'
.. ' [[Wikipedia:Requested moves]]. You can also'
.. ' [[Wikipedia:Requests for page protection|request]] that the page be'
.. ' unprotected.'
}
},
autoreview = {
default = {
default = 'See the [[Wikipedia:Protection policy|'
.. 'protection policy]] and ${PROTECTIONLOG} for more details.'
.. ' Edits to this ${PAGETYPE} by new and unregistered users'
.. ' will not be visible to readers until they are accepted by'
.. ' a reviewer. To avoid the need for your edits to be'
.. ' reviewed, you may'
.. ' [[Wikipedia:Requests for page protection'
.. '#Current requests for reduction in protection level'
.. '|request unprotection]], [[Special:Userlogin|log in]], or'
.. ' [[Special:UserLogin/signup|create an account]].'
},
},
upload = {
default = {
default = 'See the [[Wikipedia:Protection policy|'
.. 'protection policy]] and ${PROTECTIONLOG} for more details.'
.. ' The page may still be edited but new versions of the file'
.. ' cannot be uploaded until it is unprotected. You can'
.. ' request that a new version be uploaded by using a'
.. ' [[Wikipedia:Edit requests|protected edit request]], or you'
.. ' can  [[Wikipedia:Requests for page protection|request]]'
.. ' that the file be unprotected.'
}
}
},


function Blurb:_formatDate(num)
--------------------------------------------------------------------------------
-- Formats a Unix timestamp into dd Month, YYYY format.
-- Protection levels
lang = lang or mw.language.getContentLanguage()
--------------------------------------------------------------------------------
local success, date = pcall(
lang.formatDate,
lang,
self._cfg.msg['expiry-date-format'] or 'j F Y',
'@' .. tostring(num)
)
if success then
return date
end
end


function Blurb:_getExpandedMessage(msgKey)
-- This table provides the data for the ${PROTECTIONLEVEL} parameter, which
return self:_substituteParameters(self._cfg.msg[msgKey])
-- produces a short label for different protection levels. It is sorted by
end
-- protection action and protection level, and is checked in the following
-- order:
-- 1. page's protection action, page's protection level
-- 2. page's protection action, default protection level
-- 3. "edit" protection action, default protection level
--
-- It is possible to use banner parameters inside this table.
-- *required* - this table needs edit, move, autoreview and upload subtables.
protectionLevels = {
edit = {
default = 'protected',
templateeditor = 'template-protected',
extendedconfirmed = 'extended-protected',
autoconfirmed = 'semi-protected',
},
move = {
default = 'move-protected'
},
autoreview = {
},
upload = {
default = 'upload-protected'
}
},


function Blurb:_substituteParameters(msg)
--------------------------------------------------------------------------------
if not self._params then
-- Images
local parameterFuncs = {}
--------------------------------------------------------------------------------


parameterFuncs.CURRENTVERSION    = self._makeCurrentVersionParameter
-- This table lists different padlock images for each protection action and
parameterFuncs.EDITREQUEST        = self._makeEditRequestParameter
-- protection level. It is used if an image is not specified in any of the
parameterFuncs.EXPIRY            = self._makeExpiryParameter
-- banner data tables, and if the page does not satisfy the conditions for using
parameterFuncs.EXPLANATIONBLURB  = self._makeExplanationBlurbParameter
-- the ['image-filename-indef'] image. It is checked in the following order:
parameterFuncs.IMAGELINK          = self._makeImageLinkParameter
-- 1. page's protection action, page's protection level
parameterFuncs.INTROBLURB        = self._makeIntroBlurbParameter
-- 2. page's protection action, default protection level
parameterFuncs.INTROFRAGMENT      = self._makeIntroFragmentParameter
images = {
parameterFuncs.PAGETYPE          = self._makePagetypeParameter
edit = {
parameterFuncs.PROTECTIONBLURB    = self._makeProtectionBlurbParameter
default = 'Full-protection-shackle.svg',
parameterFuncs.PROTECTIONDATE    = self._makeProtectionDateParameter
templateeditor = 'Template-protection-shackle.svg',
parameterFuncs.PROTECTIONLEVEL    = self._makeProtectionLevelParameter
extendedconfirmed = 'Extended-protection-shackle.svg',
parameterFuncs.PROTECTIONLOG      = self._makeProtectionLogParameter
autoconfirmed = 'Semi-protection-shackle.svg'
parameterFuncs.TALKPAGE          = self._makeTalkPageParameter
},
parameterFuncs.TOOLTIPBLURB      = self._makeTooltipBlurbParameter
move = {
parameterFuncs.TOOLTIPFRAGMENT    = self._makeTooltipFragmentParameter
default = 'Move-protection-shackle.svg',
parameterFuncs.VANDAL            = self._makeVandalTemplateParameter
},
autoreview = {
self._params = setmetatable({}, {
default = 'Pending-protection-shackle.svg'
__index = function (t, k)
},
local param
upload = {
if parameterFuncs[k] then
default = 'Upload-protection-shackle.svg'
param = parameterFuncs[k](self)
}
end
},
param = param or ''
t[k] = param
return param
end
})
end
msg = msg:gsub('${(%u+)}', self._params)
return msg
end


function Blurb:_makeCurrentVersionParameter()
-- Pages with a reason specified in this table will show the special "indef"
-- A link to the page history or the move log, depending on the kind of
-- padlock, defined in the 'image-filename-indef' message, if no expiry is set.
-- protection.
indefImageReasons = {
local pagename = self._protectionObj.title.prefixedText
template = true
if self._protectionObj.action == 'move' then
},
-- We need the move log link.
return makeFullUrl(
'Special:Log',
{type = 'move', page = pagename},
self:_getExpandedMessage('current-version-move-display')
)
else
-- We need the history link.
return makeFullUrl(
pagename,
{action = 'history'},
self:_getExpandedMessage('current-version-edit-display')
)
end
end


function Blurb:_makeEditRequestParameter()
--------------------------------------------------------------------------------
local mEditRequest = require('Module:Submit an edit request')
-- Image links
local action = self._protectionObj.action
--------------------------------------------------------------------------------
local level = self._protectionObj.level
-- Get the edit request type.
local requestType
if action == 'edit' then
if level == 'autoconfirmed' then
requestType = 'semi'
elseif level == 'extendedconfirmed' then
requestType = 'extended'
elseif level == 'templateeditor' then
requestType = 'template'
end
end
requestType = requestType or 'full'
-- Get the display value.
local display = self:_getExpandedMessage('edit-request-display')


return mEditRequest._link{type = requestType, display = display}
-- This table provides the data for the ${IMAGELINK} parameter, which gets
end
-- the image link for small padlock icons based on the page's protection action
-- and protection level. It is checked in the following order:
-- 1. page's protection action, page's protection level
-- 2. page's protection action, default protection level
-- 3. "edit" protection action, default protection level
--
-- It is possible to use banner parameters inside this table.
-- *required* - this table needs edit, move, autoreview and upload subtables.
imageLinks = {
edit = {
default = 'Wikipedia:Protection policy#full',
templateeditor = 'Wikipedia:Protection policy#template',
extendedconfirmed = 'Wikipedia:Protection policy#extended',
autoconfirmed = 'Wikipedia:Protection policy#semi'
},
move = {
default = 'Wikipedia:Protection policy#move'
},
autoreview = {
default = 'Wikipedia:Protection policy#pending'
},
upload = {
default = 'Wikipedia:Protection policy#upload'
}
},


function Blurb:_makeExpiryParameter()
--------------------------------------------------------------------------------
local expiry = self._protectionObj.expiry
-- Padlock indicator names
if type(expiry) == 'number' then
--------------------------------------------------------------------------------
return self:_formatDate(expiry)
else
return expiry
end
end


function Blurb:_makeExplanationBlurbParameter()
-- This table provides the "name" attribute for the <indicator> extension tag
-- Cover special cases first.
-- with which small padlock icons are generated. All indicator tags on a page
if self._protectionObj.title.namespace == 8 then
-- are displayed in alphabetical order based on this attribute, and with
-- MediaWiki namespace
-- indicator tags with duplicate names, the last tag on the page wins.
return self:_getExpandedMessage('explanation-blurb-nounprotect')
-- The attribute is chosen based on the protection action; table keys must be a
end
-- protection action name or the string "default".
padlockIndicatorNames = {
autoreview = 'pp-autoreview',
default = 'pp-default'
},


-- Get explanation blurb table keys
--------------------------------------------------------------------------------
local action = self._protectionObj.action
-- Protection categories
local level = self._protectionObj.level
--------------------------------------------------------------------------------
local talkKey = self._protectionObj.title.isTalkPage and 'talk' or 'subject'


-- Find the message in the explanation blurb table and substitute any
--[[
-- parameters.
-- The protection categories are stored in the protectionCategories table.
local explanations = self._cfg.explanationBlurbs
-- Keys to this table are made up of the following strings:
local msg
--
if explanations[action][level] and explanations[action][level][talkKey] then
-- 1. the expiry date
msg = explanations[action][level][talkKey]
-- 2. the namespace
elseif explanations[action][level] and explanations[action][level].default then
-- 3. the protection reason (e.g. "dispute" or "vandalism")
msg = explanations[action][level].default
-- 4. the protection level (e.g. "sysop" or "autoconfirmed")
elseif explanations[action].default and explanations[action].default[talkKey] then
-- 5. the action (e.g. "edit" or "move")
msg = explanations[action].default[talkKey]
--
elseif explanations[action].default and explanations[action].default.default then
-- When the module looks up a category in the table, first it will will check to
msg = explanations[action].default.default
-- see a key exists that corresponds to all five parameters. For example, a
else
-- user page semi-protected from vandalism for two weeks would have the key
error(string.format(
-- "temp-user-vandalism-autoconfirmed-edit". If no match is found, the module
'could not find explanation blurb for action "%s", level "%s" and talk key "%s"',
-- changes the first part of the key to "all" and checks the table again. It
action,
-- keeps checking increasingly generic key combinations until it finds the
level,
-- field, or until it reaches the key "all-all-all-all-all".
talkKey
--
), 8)
-- The module uses a binary matrix to determine the order in which to search.
end
-- This is best demonstrated by a table. In this table, the "0" values
return self:_substituteParameters(msg)
-- represent "all", and the "1" values represent the original data (e.g.
end
-- "indef" or "file" or "vandalism").
--
--        expiry    namespace reason  level     action
-- order
-- 1      1        1        1        1        1
-- 2      0        1        1        1        1
-- 3      1        0        1        1        1
-- 4      0        0        1        1        1
-- 5      1        1        0        1        1
-- 6      0        1        0        1        1
-- 7      1        0        0        1        1
-- 8      0        0        0        1        1
-- 9      1        1        1        0        1
-- 10    0        1        1        0        1
-- 11    1        0        1        0        1
-- 12    0        0        1        0        1
-- 13    1        1        0        0        1
-- 14    0        1        0        0        1
-- 15    1        0        0        0        1
-- 16    0        0        0        0        1
-- 17    1        1        1        1        0
-- 18    0        1        1        1        0
-- 19    1        0        1        1        0
-- 20    0        0        1        1        0
-- 21    1        1        0        1        0
-- 22    0        1        0        1        0
-- 23    1        0        0        1        0
-- 24    0        0        0        1        0
-- 25    1        1        1        0        0
-- 26    0        1        1        0        0
-- 27    1        0        1        0        0
-- 28    0        0        1        0        0
-- 29    1        1        0        0        0
-- 30    0        1        0        0        0
-- 31    1        0        0        0        0
-- 32    0        0        0        0        0
--
-- In this scheme the action has the highest priority, as it is the last
-- to change, and the expiry has the least priority, as it changes the most.
-- The priorities of the expiry, the protection level and the action are
-- fixed, but the priorities of the reason and the namespace can be swapped
-- through the use of the cfg.bannerDataNamespaceHasPriority table.
--]]


function Blurb:_makeImageLinkParameter()
-- If the reason specified to the template is listed in this table,
local imageLinks = self._cfg.imageLinks
-- namespace data will take priority over reason data in the protectionCategories
local action = self._protectionObj.action
-- table.
local level = self._protectionObj.level
reasonsWithNamespacePriority = {
local msg
vandalism = true,
if imageLinks[action][level] then
},
msg = imageLinks[action][level]
elseif imageLinks[action].default then
msg = imageLinks[action].default
else
msg = imageLinks.edit.default
end
return self:_substituteParameters(msg)
end


function Blurb:_makeIntroBlurbParameter()
-- The string to use as a namespace key for the protectionCategories table for each
if self._protectionObj:isTemporary() then
-- namespace number.
return self:_getExpandedMessage('intro-blurb-expiry')
categoryNamespaceKeys = {
else
[  2] = 'user',
return self:_getExpandedMessage('intro-blurb-noexpiry')
[  3] = 'user',
end
[  4] = 'project',
end
[  6] = 'file',
[  8] = 'mediawiki',
[ 10] = 'template',
[ 12] = 'project',
[ 14] = 'category',
[100] = 'portal',
[828] = 'module',
},


function Blurb:_makeIntroFragmentParameter()
protectionCategories = {
if self._protectionObj:isTemporary() then
['all|all|all|all|all']                    = 'Wikipedia fully protected pages',
return self:_getExpandedMessage('intro-fragment-expiry')
['all|all|office|all|all']                  = 'Wikipedia Office-protected pages',
else
['all|all|reset|all|all']                  = 'Wikipedia Office-protected pages',
return self:_getExpandedMessage('intro-fragment-noexpiry')
['all|all|dmca|all|all']                    = 'Wikipedia Office-protected pages',
end
['all|all|mainpage|all|all']                = 'Wikipedia fully protected main page files',
end
['all|all|all|extendedconfirmed|all']      = 'Wikipedia extended-confirmed-protected pages',
['all|all|ecp|extendedconfirmed|all']      = 'Wikipedia extended-confirmed-protected pages',
['all|template|all|all|edit']              = 'Wikipedia fully protected templates',
['all|all|all|autoconfirmed|edit']          = 'Wikipedia semi-protected pages',
['indef|all|all|autoconfirmed|edit']        = 'Wikipedia indefinitely semi-protected pages',
['all|all|blp|autoconfirmed|edit']          = 'Wikipedia indefinitely semi-protected biographies of living people',
['temp|all|blp|autoconfirmed|edit']        = 'Wikipedia temporarily semi-protected biographies of living people',
['all|all|dispute|autoconfirmed|edit']      = 'Wikipedia pages semi-protected due to dispute',
['all|all|sock|autoconfirmed|edit']        = 'Wikipedia pages semi-protected from banned users',
['all|all|vandalism|autoconfirmed|edit']    = 'Wikipedia pages semi-protected against vandalism',
['all|category|all|autoconfirmed|edit']    = 'Wikipedia semi-protected categories',
['all|file|all|autoconfirmed|edit']        = 'Wikipedia semi-protected files',
['all|portal|all|autoconfirmed|edit']      = 'Wikipedia semi-protected portals',
['all|project|all|autoconfirmed|edit']      = 'Wikipedia semi-protected project pages',
['all|talk|all|autoconfirmed|edit']        = 'Wikipedia semi-protected talk pages',
['all|template|all|autoconfirmed|edit']    = 'Wikipedia semi-protected templates',
['all|user|all|autoconfirmed|edit']        = 'Wikipedia semi-protected user and user talk pages',
['all|all|all|templateeditor|edit']        = 'Wikipedia template-protected pages other than templates and modules',
['all|template|all|templateeditor|edit']    = 'Wikipedia template-protected templates',
['all|template|all|templateeditor|move']    = 'Wikipedia template-protected templates', -- move-protected templates
['all|all|blp|sysop|edit']                  = 'Wikipedia indefinitely protected biographies of living people',
['temp|all|blp|sysop|edit']                = 'Wikipedia temporarily protected biographies of living people',
['all|all|dispute|sysop|edit']              = 'Wikipedia pages protected due to dispute',
['all|all|sock|sysop|edit']                = 'Wikipedia pages protected from banned users',
['all|all|vandalism|sysop|edit']            = 'Wikipedia pages protected against vandalism',
['all|category|all|sysop|edit']            = 'Wikipedia fully protected categories',
['all|file|all|sysop|edit']                = 'Wikipedia fully protected files',
['all|project|all|sysop|edit']              = 'Wikipedia fully protected project pages',
['all|talk|all|sysop|edit']                = 'Wikipedia fully protected talk pages',
['all|template|all|extendedconfirmed|edit'] = 'Wikipedia extended-confirmed-protected templates',
['all|template|all|sysop|edit']            = 'Wikipedia fully protected templates',
['all|user|all|sysop|edit']                = 'Wikipedia fully protected user and user talk pages',
['all|module|all|all|edit']                = 'Wikipedia fully protected modules',
['all|module|all|templateeditor|edit']      = 'Wikipedia template-protected modules',
['all|module|all|extendedconfirmed|edit']  = 'Wikipedia extended-confirmed-protected modules',
['all|module|all|autoconfirmed|edit']      = 'Wikipedia semi-protected modules',
['all|all|all|sysop|move']                  = 'Wikipedia move-protected pages',
['indef|all|all|sysop|move']                = 'Wikipedia indefinitely move-protected pages',
['all|all|dispute|sysop|move']              = 'Wikipedia pages move-protected due to dispute',
['all|all|vandalism|sysop|move']            = 'Wikipedia pages move-protected due to vandalism',
['all|portal|all|sysop|move']              = 'Wikipedia move-protected portals',
['all|project|all|sysop|move']              = 'Wikipedia move-protected project pages',
['all|talk|all|sysop|move']                = 'Wikipedia move-protected talk pages',
['all|template|all|sysop|move']            = 'Wikipedia move-protected templates',
['all|user|all|sysop|move']                = 'Wikipedia move-protected user and user talk pages',
['all|all|all|autoconfirmed|autoreview']    = 'Wikipedia pending changes protected pages',
['all|file|all|all|upload']                = 'Wikipedia upload-protected files',
},


function Blurb:_makePagetypeParameter()
--------------------------------------------------------------------------------
local pagetypes = self._cfg.pagetypes
-- Expiry category config
return pagetypes[self._protectionObj.title.namespace]
--------------------------------------------------------------------------------
or pagetypes.default
or error('no default pagetype defined', 8)
end


function Blurb:_makeProtectionBlurbParameter()
-- This table configures the expiry category behaviour for each protection
local protectionBlurbs = self._cfg.protectionBlurbs
-- action.
local action = self._protectionObj.action
-- * If set to true, setting that action will always categorise the page if
local level = self._protectionObj.level
--  an expiry parameter is not set.
local msg
-- * If set to false, setting that action will never categorise the page.
if protectionBlurbs[action][level] then
-- * If set to nil, the module will categorise the page if:
msg = protectionBlurbs[action][level]
--  1) an expiry parameter is not set, and
elseif protectionBlurbs[action].default then
--  2) a reason is provided, and
msg = protectionBlurbs[action].default
--  3) the specified reason is not blacklisted in the reasonsWithoutExpiryCheck
elseif protectionBlurbs.edit.default then
--      table.
msg = protectionBlurbs.edit.default
else
error('no protection blurb defined for protectionBlurbs.edit.default', 8)
end
return self:_substituteParameters(msg)
end


function Blurb:_makeProtectionDateParameter()
expiryCheckActions = {
local protectionDate = self._protectionObj.protectionDate
edit = nil,
if type(protectionDate) == 'number' then
move = false,
return self:_formatDate(protectionDate)
autoreview = true,
else
upload = false
return protectionDate
},
end
end


function Blurb:_makeProtectionLevelParameter()
reasonsWithoutExpiryCheck = {
local protectionLevels = self._cfg.protectionLevels
blp = true,
local action = self._protectionObj.action
template = true,
local level = self._protectionObj.level
},
local msg
if protectionLevels[action][level] then
msg = protectionLevels[action][level]
elseif protectionLevels[action].default then
msg = protectionLevels[action].default
elseif protectionLevels.edit.default then
msg = protectionLevels.edit.default
else
error('no protection level defined for protectionLevels.edit.default', 8)
end
return self:_substituteParameters(msg)
end


function Blurb:_makeProtectionLogParameter()
--------------------------------------------------------------------------------
local pagename = self._protectionObj.title.prefixedText
-- Pagetypes
if self._protectionObj.action == 'autoreview' then
--------------------------------------------------------------------------------
-- We need the pending changes log.
return makeFullUrl(
'Special:Log',
{type = 'stable', page = pagename},
self:_getExpandedMessage('pc-log-display')
)
else
-- We need the protection log.
return makeFullUrl(
'Special:Log',
{type = 'protect', page = pagename},
self:_getExpandedMessage('protection-log-display')
)
end
end


function Blurb:_makeTalkPageParameter()
-- This table produces the page types available with the ${PAGETYPE} parameter.
return string.format(
-- Keys are namespace numbers, or the string "default" for the default value.
'[[%s:%s#%s|%s]]',
pagetypes = {
mw.site.namespaces[self._protectionObj.title.namespace].talk.name,
[0] = 'article',
self._protectionObj.title.text,
[6] = 'file',
self._args.section or 'top',
[10] = 'template',
self:_getExpandedMessage('talk-page-link-display')
[14] = 'category',
)
[828] = 'module',
end
default = 'page'
},


function Blurb:_makeTooltipBlurbParameter()
--------------------------------------------------------------------------------
if self._protectionObj:isTemporary() then
-- Strings marking indefinite protection
return self:_getExpandedMessage('tooltip-blurb-expiry')
--------------------------------------------------------------------------------
else
return self:_getExpandedMessage('tooltip-blurb-noexpiry')
end
end


function Blurb:_makeTooltipFragmentParameter()
-- This table contains values passed to the expiry parameter that mean the page
if self._protectionObj:isTemporary() then
-- is protected indefinitely.
return self:_getExpandedMessage('tooltip-fragment-expiry')
indefStrings = {
else
['indef'] = true,
return self:_getExpandedMessage('tooltip-fragment-noexpiry')
['indefinite'] = true,
end
['indefinitely'] = true,
end
['infinite'] = true,
},


function Blurb:_makeVandalTemplateParameter()
--------------------------------------------------------------------------------
return mw.getCurrentFrame():expandTemplate{
-- Group hierarchy
title="vandal-m",
--------------------------------------------------------------------------------
args={self._args.user or self._protectionObj.title.baseText}
}
end


-- Public methods --
-- This table maps each group to all groups that have a superset of the original
-- group's page editing permissions.
hierarchy = {
sysop = {},
reviewer = {'sysop'},
filemover = {'sysop'},
templateeditor = {'sysop'},
extendedconfirmed = {'sysop'},
autoconfirmed = {'reviewer', 'filemover', 'templateeditor', 'extendedconfirmed'},
user = {'autoconfirmed'},
['*'] = {'user'}
},


function Blurb:makeBannerText(key)
--------------------------------------------------------------------------------
-- Validate input.
-- Wrapper templates and their default arguments
if not key or not Blurb.bannerTextFields[key] then
--------------------------------------------------------------------------------
error(string.format(
'"%s" is not a valid banner config field',
tostring(key)
), 2)
end


-- Generate the text.
-- This table contains wrapper templates used with the module, and their
local msg = self._protectionObj.bannerConfig[key]
-- default arguments. Templates specified in this table should contain the
if type(msg) == 'string' then
-- following invocation, and no other template content:
return self:_substituteParameters(msg)
--
elseif type(msg) == 'function' then
-- {{#invoke:Protection banner|main}}
msg = msg(self._protectionObj, self._args)
--
if type(msg) ~= 'string' then
-- If other content is desired, it can be added between
error(string.format(
-- <noinclude>...</noinclude> tags.
'bad output from banner config function with key "%s"'
--
.. ' (expected string, got %s)',
-- When a user calls one of these wrapper templates, they will use the
tostring(key),
-- default arguments automatically. However, users can override any of the
type(msg)
-- arguments.
), 4)
wrappers = {
end
['Template:Pp']                         = {},
return self:_substituteParameters(msg)
['Template:Pp-extended']                = {'ecp'},
end
['Template:Pp-blp']                    = {'blp'},
end
-- we don't need Template:Pp-create
['Template:Pp-dispute']                = {'dispute'},
['Template:Pp-main-page']              = {'mainpage'},
['Template:Pp-move']                    = {action = 'move', catonly = 'yes'},
['Template:Pp-move-dispute']            = {'dispute', action = 'move', catonly = 'yes'},
-- we don't need Template:Pp-move-indef
['Template:Pp-move-vandalism']          = {'vandalism', action = 'move', catonly = 'yes'},
['Template:Pp-office']                  = {'office'},
['Template:Pp-office-dmca']            = {'dmca'},
['Template:Pp-pc']                      = {action = 'autoreview', small = true},
['Template:Pp-pc1']                    = {action = 'autoreview', small = true},
['Template:Pp-reset']                  = {'reset'},
['Template:Pp-semi-indef']              = {small = true},
['Template:Pp-sock']                    = {'sock'},
['Template:Pp-template']                = {'template', small = true},
['Template:Pp-upload']                  = {action = 'upload'},
['Template:Pp-usertalk']                = {'usertalk'},
['Template:Pp-vandalism']              = {'vandalism'},
},


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- BannerTemplate class
--  
--                                MESSAGES
--
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


local BannerTemplate = {}
msg = {
BannerTemplate.__index = BannerTemplate


function BannerTemplate.new(protectionObj, cfg)
--------------------------------------------------------------------------------
local obj = {}
-- Intro blurb and intro fragment
obj._cfg = cfg
--------------------------------------------------------------------------------


-- Set the image filename.
-- These messages specify what is produced by the ${INTROBLURB} and
local imageFilename = protectionObj.bannerConfig.image
-- ${INTROFRAGMENT} parameters. If the protection is temporary they use the
if imageFilename then
-- intro-blurb-expiry or intro-fragment-expiry, and if not they use
obj._imageFilename = imageFilename
-- intro-blurb-noexpiry or intro-fragment-noexpiry.
else
-- It is possible to use banner parameters in these messages.
-- If an image filename isn't specified explicitly in the banner config,
['intro-blurb-expiry'] = '${PROTECTIONBLURB} until ${EXPIRY}.',
-- generate it from the protection status and the namespace.
['intro-blurb-noexpiry'] = '${PROTECTIONBLURB}.',
local action = protectionObj.action
['intro-fragment-expiry'] = '${PROTECTIONBLURB} until ${EXPIRY},',
local level = protectionObj.level
['intro-fragment-noexpiry'] = '${PROTECTIONBLURB}',
local namespace = protectionObj.title.namespace
local reason = protectionObj.reason
-- Deal with special cases first.
if (
namespace == 10
or namespace == 828
or reason and obj._cfg.indefImageReasons[reason]
)
and action == 'edit'
and level == 'sysop'
and not protectionObj:isTemporary()
then
-- Fully protected modules and templates get the special red "indef"
-- padlock.
obj._imageFilename = obj._cfg.msg['image-filename-indef']
else
-- Deal with regular protection types.
local images = obj._cfg.images
if images[action] then
if images[action][level] then
obj._imageFilename = images[action][level]
elseif images[action].default then
obj._imageFilename = images[action].default
end
end
end
end
return setmetatable(obj, BannerTemplate)
end
 
function BannerTemplate:renderImage()
local filename = self._imageFilename
or self._cfg.msg['image-filename-default']
or 'Transparent.gif'
return makeFileLink{
file = filename,
size = (self.imageWidth or 20) .. 'px',
alt = self._imageAlt,
link = self._imageLink,
caption = self.imageCaption
}
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Banner class
-- Tooltip blurb
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


local Banner = setmetatable({}, BannerTemplate)
-- These messages specify what is produced by the ${TOOLTIPBLURB} parameter.
Banner.__index = Banner
-- If the protection is temporary the tooltip-blurb-expiry message is used, and
-- if not the tooltip-blurb-noexpiry message is used.
-- It is possible to use banner parameters in these messages.
['tooltip-blurb-expiry'] = 'This ${PAGETYPE} is ${PROTECTIONLEVEL} until ${EXPIRY}.',
['tooltip-blurb-noexpiry'] = 'This ${PAGETYPE} is ${PROTECTIONLEVEL}.',
['tooltip-fragment-expiry'] = 'This ${PAGETYPE} is ${PROTECTIONLEVEL} until ${EXPIRY},',
['tooltip-fragment-noexpiry'] = 'This ${PAGETYPE} is ${PROTECTIONLEVEL}',


function Banner.new(protectionObj, blurbObj, cfg)
--------------------------------------------------------------------------------
local obj = BannerTemplate.new(protectionObj, cfg) -- This doesn't need the blurb.
-- Special explanation blurb
obj.imageWidth = 40
--------------------------------------------------------------------------------
obj.imageCaption = blurbObj:makeBannerText('alt') -- Large banners use the alt text for the tooltip.
obj._reasonText = blurbObj:makeBannerText('text')
obj._explanationText = blurbObj:makeBannerText('explanation')
obj._page = protectionObj.title.prefixedText -- Only makes a difference in testing.
return setmetatable(obj, Banner)
end


function Banner:__tostring()
-- An explanation blurb for pages that cannot be unprotected, e.g. for pages
-- Renders the banner.
-- in the MediaWiki namespace.
makeMessageBox = makeMessageBox or require('Module:Message box').main
-- It is possible to use banner parameters in this message.
local reasonText = self._reasonText or error('no reason text set', 2)
['explanation-blurb-nounprotect'] = 'See the [[Wikipedia:Protection policy|'
local explanationText = self._explanationText
.. 'protection policy]] and ${PROTECTIONLOG} for more details.'
local mbargs = {
.. ' Please discuss any changes on the ${TALKPAGE}; you'
page = self._page,
.. ' may ${EDITREQUEST} to ask an'
type = 'protection',
.. ' [[Wikipedia:Administrators|administrator]] to make an edit if it'
image = self:renderImage(),
.. ' is [[Help:Minor edit#When to mark an edit as a minor edit'
text = string.format(
.. '|uncontroversial]] or supported by [[Wikipedia:Consensus'
"'''%s'''%s",
.. '|consensus]].',
reasonText,
explanationText and '<br />' .. explanationText or ''
)
}
return makeMessageBox('mbox', mbargs)
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Padlock class
-- Protection log display values
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


local Padlock = setmetatable({}, BannerTemplate)
-- These messages determine the display values for the protection log link
Padlock.__index = Padlock
-- or the pending changes log link produced by the ${PROTECTIONLOG} parameter.
-- It is possible to use banner parameters in these messages.
['protection-log-display'] = 'protection log',
['pc-log-display'] = 'pending changes log',


function Padlock.new(protectionObj, blurbObj, cfg)
--------------------------------------------------------------------------------
local obj = BannerTemplate.new(protectionObj, cfg) -- This doesn't need the blurb.
-- Current version display values
obj.imageWidth = 20
--------------------------------------------------------------------------------
obj.imageCaption = blurbObj:makeBannerText('tooltip')
obj._imageAlt = blurbObj:makeBannerText('alt')
obj._imageLink = blurbObj:makeBannerText('link')
obj._indicatorName = cfg.padlockIndicatorNames[protectionObj.action]
or cfg.padlockIndicatorNames.default
or 'pp-default'
return setmetatable(obj, Padlock)
end


function Padlock:__tostring()
-- These messages determine the display values for the page history link
local frame = mw.getCurrentFrame()
-- or the move log link produced by the ${CURRENTVERSION} parameter.
-- The nowiki tag helps prevent whitespace at the top of articles.
-- It is possible to use banner parameters in these messages.
return frame:extensionTag{name = 'nowiki'} .. frame:extensionTag{
['current-version-move-display'] = 'current title',
name = 'indicator',
['current-version-edit-display'] = 'current version',
args = {name = self._indicatorName},
content = self:renderImage()
}
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Exports
-- Talk page
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


local p = {}
-- This message determines the display value of the talk page link produced
-- with the ${TALKPAGE} parameter.
-- It is possible to use banner parameters in this message.
['talk-page-link-display'] = 'talk page',


function p._exportClasses()
--------------------------------------------------------------------------------
-- This is used for testing purposes.
-- Edit requests
return {
--------------------------------------------------------------------------------
Protection = Protection,
Blurb = Blurb,
BannerTemplate = BannerTemplate,
Banner = Banner,
Padlock = Padlock,
}
end


function p._main(args, cfg, title)
-- This message determines the display value of the edit request link produced
args = args or {}
-- with the ${EDITREQUEST} parameter.
cfg = cfg or require(CONFIG_MODULE)
-- It is possible to use banner parameters in this message.
['edit-request-display'] = 'submit an edit request',


local protectionObj = Protection.new(args, cfg, title)
--------------------------------------------------------------------------------
-- Expiry date format
--------------------------------------------------------------------------------


local ret = {}
-- This is the format for the blurb expiry date. It should be valid input for
-- the first parameter of the #time parser function.
['expiry-date-format'] = 'F j, Y "at" H:i e',


-- If a page's edit protection is equally or more restrictive than its
--------------------------------------------------------------------------------
-- protection from some other action, then don't bother displaying anything
-- Tracking categories
-- for the other action (except categories).
--------------------------------------------------------------------------------
if not yesno(args.catonly) and (protectionObj.action == 'edit' or
args.demolevel or
not getReachableNodes(
cfg.hierarchy,
protectionObj.level
)[effectiveProtectionLevel('edit', protectionObj.title)])
then
-- Initialise the blurb object
local blurbObj = Blurb.new(protectionObj, args, cfg)
-- Render the banner
if protectionObj:shouldShowLock() then
ret[#ret + 1] = tostring(
(yesno(args.small) and Padlock or Banner)
.new(protectionObj, blurbObj, cfg)
)
end
end


-- Render the categories
-- These messages determine which tracking categories the module outputs.
if yesno(args.category) ~= false then
['tracking-category-incorrect'] = 'Wikipedia pages with incorrect protection templates',
ret[#ret + 1] = protectionObj:makeCategoryLinks()
['tracking-category-template'] = 'Wikipedia template-protected pages other than templates and modules',
end
return table.concat(ret)
end


function p.main(frame, cfg)
--------------------------------------------------------------------------------
cfg = cfg or require(CONFIG_MODULE)
-- Images
--------------------------------------------------------------------------------


-- Find default args, if any.
-- These are images that are not defined by their protection action and protection level.
local parent = frame.getParent and frame:getParent()
['image-filename-indef'] = 'Full-protection-shackle.svg',
local defaultArgs = parent and cfg.wrappers[parent:getTitle():gsub('/sandbox$', '')]
['image-filename-default'] = 'Transparent.gif',


-- Find user args, and use the parent frame if we are being called from a
--------------------------------------------------------------------------------
-- wrapper template.
-- End messages
getArgs = getArgs or require('Module:Arguments').getArgs
--------------------------------------------------------------------------------
local userArgs = getArgs(frame, {
}
parentOnly = defaultArgs,
frameOnly = not defaultArgs
})


-- Build the args table. User-specified args overwrite default args.
--------------------------------------------------------------------------------
local args = {}
-- End configuration
for k, v in pairs(defaultArgs or {}) do
--------------------------------------------------------------------------------
args[k] = v
}
end
for k, v in pairs(userArgs) do
args[k] = v
end
return p._main(args, cfg)
end
 
return p

Latest revision as of 22:18, 3 December 2023

Documentation for this module may be created at Module:Protection banner/config/doc

-- This module provides configuration data for [[Module:Protection banner]].

return {

--------------------------------------------------------------------------------
--
--                                BANNER DATA
--
--------------------------------------------------------------------------------

--[[
-- Banner data consists of six fields:
-- * text - the main protection text that appears at the top of protection
--   banners.
-- * explanation - the text that appears below the main protection text, used
--   to explain the details of the protection.
-- * tooltip - the tooltip text you see when you move the mouse over a small
--   padlock icon.
-- * link - the page that the small padlock icon links to.
-- * alt - the alt text for the small padlock icon. This is also used as tooltip
--   text for the large protection banners.
-- * image - the padlock image used in both protection banners and small padlock
--   icons.
--
-- The module checks in three separate tables to find a value for each field.
-- First it checks the banners table, which has values specific to the reason
-- for the page being protected. Then the module checks the defaultBanners
-- table, which has values specific to each protection level. Finally, the
-- module checks the masterBanner table, which holds data for protection
-- templates to use if no data has been found in the previous two tables.
--
-- The values in the banner data can take parameters. These are specified
-- using ${TEXTLIKETHIS} (a dollar sign preceding a parameter name
-- enclosed in curly braces).
--
--                          Available parameters:
--
-- ${CURRENTVERSION} - a link to the page history or the move log, with the
-- display message "current-version-edit-display" or
-- "current-version-move-display".
--
-- ${EDITREQUEST} - a link to create an edit request for the current page.
--
-- ${EXPLANATIONBLURB} - an explanation blurb, e.g. "Please discuss any changes
-- on the talk page; you may submit a request to ask an administrator to make
-- an edit if it is minor or supported by consensus."
--
-- ${IMAGELINK} - a link to set the image to, depending on the protection
-- action and protection level.
--
-- ${INTROBLURB} - the PROTECTIONBLURB parameter, plus the expiry if an expiry
-- is set. E.g. "Editing of this page by new or unregistered users is currently 
-- disabled until dd Month YYYY."
--
-- ${INTROFRAGMENT} - the same as ${INTROBLURB}, but without final punctuation
-- so that it can be used in run-on sentences.
--
-- ${PAGETYPE} - the type of the page, e.g. "article" or "template".
-- Defined in the cfg.pagetypes table.
--
-- ${PROTECTIONBLURB} - a blurb explaining the protection level of the page, e.g.
-- "Editing of this page by new or unregistered users is currently disabled"
--
-- ${PROTECTIONDATE} - the protection date, if it has been supplied to the
-- template.
--
-- ${PROTECTIONLEVEL} - the protection level, e.g. "fully protected" or
-- "semi-protected".
--
-- ${PROTECTIONLOG} - a link to the protection log or the pending changes log,
-- depending on the protection action.
--
-- ${TALKPAGE} - a link to the talk page. If a section is specified, links
-- straight to that talk page section.
--
-- ${TOOLTIPBLURB} - uses the PAGETYPE, PROTECTIONTYPE and EXPIRY parameters to
-- create a blurb like "This template is semi-protected", or "This article is
-- move-protected until DD Month YYYY".
--
-- ${VANDAL} - links for the specified username (or the root page name)
-- using Module:Vandal-m.
--
--                                 Functions
--
-- For advanced users, it is possible to use Lua functions instead of strings
-- in the banner config tables. Using functions gives flexibility that is not
-- possible just by using parameters. Functions take two arguments, the
-- protection object and the template arguments, and they must output a string.
--
-- For example:
--
-- text = function (protectionObj, args)
--     if protectionObj.level == 'autoconfirmed' then
--         return 'foo'
--     else
--         return 'bar'
--     end
-- end
--
-- Some protection object properties and methods that may be useful:
-- protectionObj.action - the protection action
-- protectionObj.level - the protection level
-- protectionObj.reason - the protection reason
-- protectionObj.expiry - the expiry. Nil if unset, the string "indef" if set
--     to indefinite, and the protection time in unix time if temporary.
-- protectionObj.protectionDate - the protection date in unix time, or nil if
--     unspecified.
-- protectionObj.bannerConfig - the banner config found by the module. Beware
--     of editing the config field used by the function, as it could create an
--     infinite loop.
-- protectionObj:isProtected - returns a boolean showing whether the page is
--     protected.
-- protectionObj:isTemporary - returns a boolean showing whether the expiry is
--     temporary.
-- protectionObj:isIncorrect - returns a boolean showing whether the protection
--     template is incorrect.
--]]

-- The master banner data, used if no values have been found in banners or
-- defaultBanners.
masterBanner = {
	text = '${INTROBLURB}',
	explanation = '${EXPLANATIONBLURB}',
	tooltip = '${TOOLTIPBLURB}',
	link = '${IMAGELINK}',
	alt = 'Page ${PROTECTIONLEVEL}'
},

-- The default banner data. This holds banner data for different protection
-- levels.
-- *required* - this table needs edit, move, autoreview and upload subtables.
defaultBanners = {
	edit = {},
	move = {},
	autoreview = {
		default = {
			alt = 'Page protected with pending changes',
			tooltip = 'All edits by unregistered and new users are subject to review prior to becoming visible to unregistered users',
			image = 'Pending-protection-shackle.svg'
		}
	},
	upload = {}
},

-- The banner data. This holds banner data for different protection reasons.
-- In fact, the reasons specified in this table control which reasons are
-- valid inputs to the first positional parameter.
--
-- There is also a non-standard "description" field that can be used for items
-- in this table. This is a description of the protection reason for use in the
-- module documentation.
--
-- *required* - this table needs edit, move, autoreview and upload subtables.
banners = {
	edit = {
		blp = {
			description = 'For pages protected to promote compliance with the'
				.. ' [[Wikipedia:Biographies of living persons'
				.. '|biographies of living persons]] policy',
			text = '${INTROFRAGMENT} to promote compliance with'
				.. ' [[Wikipedia:Biographies of living persons'
				.. "|Wikipedia's&nbsp;policy on&nbsp;the&nbsp;biographies"
				.. ' of&nbsp;living&nbsp;people]].',
			tooltip = '${TOOLTIPFRAGMENT} to promote compliance with the policy on'
				.. ' biographies of living persons',
		},
		dmca = {
			description = 'For pages protected by the Wikimedia Foundation'
				.. ' due to [[Digital Millennium Copyright Act]] takedown requests',
			explanation = function (protectionObj, args)
				local ret = 'Pursuant to a rights owner notice under the Digital'
					.. ' Millennium Copyright Act (DMCA) regarding some content'
					.. ' in this article, the Wikimedia Foundation acted under'
					.. ' applicable law and took down and restricted the content'
					.. ' in question.'
				if args.notice then
					ret = ret .. ' A copy of the received notice can be found here: '
						.. args.notice .. '.'
				end
				ret = ret .. ' For more information, including websites discussing'
					.. ' how to file a counter-notice, please see'
					.. " [[Wikipedia:Office actions]] and the article's ${TALKPAGE}."
					.. "'''Do not remove this template from the article until the"
					.. " restrictions are withdrawn'''."
				return ret
			end,
			image = 'Office-protection-shackle.svg',
		},
		dispute = {
			description = 'For pages protected due to editing disputes',
			text = function (protectionObj, args)
				-- Find the value of "disputes".
				local display = 'disputes'
				local disputes
				if args.section then
					disputes = string.format(
						'[[%s:%s#%s|%s]]',
						mw.site.namespaces[protectionObj.title.namespace].talk.name,
						protectionObj.title.text,
						args.section,
						display
					)
				else
					disputes = display
				end

				-- Make the blurb, depending on the expiry.
				local msg
				if type(protectionObj.expiry) == 'number' then
					msg = '${INTROFRAGMENT} or until editing %s have been resolved.'
				else
					msg = '${INTROFRAGMENT} until editing %s have been resolved.'
				end
				return string.format(msg, disputes)
			end,
			explanation = "This protection is '''not''' an endorsement of the"
				.. ' ${CURRENTVERSION}. ${EXPLANATIONBLURB}',
			tooltip = '${TOOLTIPFRAGMENT} due to editing disputes',
		},
		ecp = {
			description = 'For articles in topic areas authorized by'
				.. ' [[Wikipedia:Arbitration Committee|ArbCom]] or'
				.. ' meets the criteria for community use',
			tooltip = 'This ${PAGETYPE} is ${PROTECTIONLEVEL}',
			alt = 'Extended-protected ${PAGETYPE}',
		},
		mainpage = {
			description = 'For pages protected for being displayed on the [[Main Page]]',
			text = 'This file is currently'
				.. ' [[Wikipedia:This page is protected|protected]] from'
				.. ' editing because it is currently or will soon be displayed'
				.. ' on the [[Main Page]].',
			explanation = 'Images on the Main Page are protected due to their high'
				.. ' visibility. Please discuss any necessary changes on the ${TALKPAGE}.'
				.. '<br /><span style="font-size:90%;">'
				.. "'''Administrators:''' Once this image is definitely off the Main Page,"
				.. ' please unprotect this file, or reduce to semi-protection,'
				.. ' as appropriate.</span>',
		},
		office = {
			description = 'For pages protected by the Wikimedia Foundation',
			text = function (protectionObj, args)
				local ret = 'This ${PAGETYPE} is currently under the'
					.. ' scrutiny of the'
					.. ' [[Wikipedia:Office actions|Wikimedia Foundation Office]]'
					.. ' and is protected.'
				if protectionObj.protectionDate then
					ret = ret .. ' It has been protected since ${PROTECTIONDATE}.'
				end
				return ret
			end,
			explanation = "If you can edit this page, please discuss all changes and"
				.. " additions on the ${TALKPAGE} first. '''Do not remove protection from this"
				.. " page unless you are authorized by the Wikimedia Foundation to do"
				.. " so.'''",
			image = 'Office-protection-shackle.svg',
		},
		reset = {
			description = 'For pages protected by the Wikimedia Foundation and'
				.. ' "reset" to a bare-bones version',
 			text = 'This ${PAGETYPE} is currently under the'
					.. ' scrutiny of the'
					.. ' [[Wikipedia:Office actions|Wikimedia Foundation Office]]'
					.. ' and is protected.',
			explanation = function (protectionObj, args)
				local ret = ''
				if protectionObj.protectionDate then
					ret = ret .. 'On ${PROTECTIONDATE} this ${PAGETYPE} was'
				else
					ret = ret .. 'This ${PAGETYPE} has been'
				end
				ret = ret .. ' reduced to a'
				.. ' simplified, "bare bones" version so that it may be completely'
				.. ' rewritten to ensure it meets the policies of'
				.. ' [[WP:NPOV|Neutral Point of View]] and [[WP:V|Verifiability]].'
				.. ' Standard Wikipedia policies will apply to its rewriting—which'
				.. ' will eventually be open to all editors—and will be strictly'
				.. ' enforced. The ${PAGETYPE} has been ${PROTECTIONLEVEL} while'
				.. ' it is being rebuilt.\n\n'
				.. 'Any insertion of material directly from'
				.. ' pre-protection revisions of the ${PAGETYPE} will be removed, as'
				.. ' will any material added to the ${PAGETYPE} that is not properly'
				.. ' sourced. The associated talk page(s) were also cleared on the'
				.. " same date.\n\n"
				.. "If you can edit this page, please discuss all changes and"
				.. " additions on the ${TALKPAGE} first. '''Do not override"
				.. " this action, and do not remove protection from this page,"
				.. " unless you are authorized by the Wikimedia Foundation"
				.. " to do so. No editor may remove this notice.'''"

				return ret
			end,
			image = 'Office-protection-shackle.svg',
		},
		sock = {
			description = 'For pages protected due to'
				.. ' [[Wikipedia:Sock puppetry|sock puppetry]]',
			text = '${INTROFRAGMENT} to prevent [[Wikipedia:Sock puppetry|sock puppets]] of'
				.. ' [[Wikipedia:Blocking policy|blocked]] or'
				.. ' [[Wikipedia:Banning policy|banned users]]'
				.. ' from editing it.',
			tooltip = '${TOOLTIPFRAGMENT} to prevent sock puppets of blocked or banned users from'
				.. ' editing it',
		},
		template = {
			description = 'For [[Wikipedia:High-risk templates|high-risk]]'
				.. ' templates and Lua modules',
			text = 'This is a permanently [[Help:Protection|protected]] ${PAGETYPE},'
				.. ' as it is [[Wikipedia:High-risk templates|high-risk]].',
			explanation = 'Please discuss any changes on the ${TALKPAGE}; you may'
				.. ' ${EDITREQUEST} to ask an'
				.. ' [[Wikipedia:Administrators|administrator]] or'
				.. ' [[Wikipedia:Template editor|template editor]] to make an edit if'
				.. ' it is [[Help:Minor edit#When to mark an edit as a minor edit'
				.. '|uncontroversial]] or supported by'
				.. ' [[Wikipedia:Consensus|consensus]]. You can also'
				.. ' [[Wikipedia:Requests for page protection|request]] that the page be'
				.. ' unprotected.',
			tooltip = 'This high-risk ${PAGETYPE} is permanently ${PROTECTIONLEVEL}'
				.. ' to prevent vandalism',
			alt = 'Permanently protected ${PAGETYPE}',
		},
		usertalk = {
			description = 'For pages protected against disruptive edits by a'
				.. ' particular user',
			text = '${INTROFRAGMENT} to prevent ${VANDAL} from using it to make disruptive edits,'
				.. ' such as abusing the'
				.. ' &#123;&#123;[[Template:unblock|unblock]]&#125;&#125; template.',
			explanation = 'If you cannot edit this user talk page and you need to'
				.. ' make a change or leave a message, you can'
				.. ' [[Wikipedia:Requests for page protection'
				.. '#Current requests for edits to a protected page'
				.. '|request an edit]],'
				.. ' [[Wikipedia:Requests for page protection'
				.. '#Current requests for reduction in protection level'
				.. '|request unprotection]],'
				.. ' [[Special:Userlogin|log in]],'
				.. ' or [[Special:UserLogin/signup|create an account]].',
		},
		vandalism = {
			description = 'For pages protected against'
				.. ' [[Wikipedia:Vandalism|vandalism]]',
			text = '${INTROFRAGMENT} due to [[Wikipedia:Vandalism|vandalism]].',
			explanation = function (protectionObj, args)
				local ret = ''
				if protectionObj.level == 'sysop' then
					ret = ret .. "This protection is '''not''' an endorsement of the"
						.. ' ${CURRENTVERSION}. '
				end
				return ret .. '${EXPLANATIONBLURB}'
			end,
			tooltip = '${TOOLTIPFRAGMENT} due to vandalism',
		}
	},
	move = {
		dispute = {
			description = 'For pages protected against page moves due to'
				.. ' disputes over the page title',
			explanation = "This protection is '''not''' an endorsement of the"
				.. ' ${CURRENTVERSION}. ${EXPLANATIONBLURB}',
			image = 'Move-protection-shackle.svg'
		},
		vandalism = {
			description = 'For pages protected against'
				.. ' [[Wikipedia:Vandalism#Page-move vandalism'
				.. ' |page-move vandalism]]'
		}
	},
	autoreview = {},
	upload = {}
},

--------------------------------------------------------------------------------
--
--                            GENERAL DATA TABLES
--
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
-- Protection blurbs
--------------------------------------------------------------------------------

-- This table produces the protection blurbs available with the
-- ${PROTECTIONBLURB} parameter. It is sorted by protection action and
-- protection level, and is checked by the module in the following order:
-- 1. page's protection action, page's protection level
-- 2. page's protection action, default protection level
-- 3. "edit" protection action, default protection level
--
-- It is possible to use banner parameters inside this table.
-- *required* - this table needs edit, move, autoreview and upload subtables.
protectionBlurbs = {
	edit = {
		default = 'This ${PAGETYPE} is currently [[Help:Protection|'
			.. 'protected]] from editing',
		autoconfirmed = 'Editing of this ${PAGETYPE} by [[Wikipedia:User access'
			.. ' levels#New users|new]] or [[Wikipedia:User access levels#Unregistered'
			.. ' users|unregistered]] users is currently [[Help:Protection|disabled]]',
		extendedconfirmed = 'This ${PAGETYPE} is currently under extended confirmed protection',
	},
	move = {
		default = 'This ${PAGETYPE} is currently [[Help:Protection|protected]]'
			.. ' from [[Help:Moving a page|page moves]]'
	},
	autoreview = {
		default = 'All edits made to this ${PAGETYPE} by'
			.. ' [[Wikipedia:User access levels#New users|new]] or'
			.. ' [[Wikipedia:User access levels#Unregistered users|unregistered]]'
			.. ' users are currently'
			.. ' [[Wikipedia:Pending changes|subject to review]]'
	},
	upload = {
		default = 'Uploading new versions of this ${PAGETYPE} is currently disabled'
	}
},


--------------------------------------------------------------------------------
-- Explanation blurbs
--------------------------------------------------------------------------------

-- This table produces the explanation blurbs available with the
-- ${EXPLANATIONBLURB} parameter. It is sorted by protection action,
-- protection level, and whether the page is a talk page or not. If the page is
-- a talk page it will have a talk key of "talk"; otherwise it will have a talk
-- key of "subject". The table is checked in the following order:
-- 1. page's protection action, page's protection level, page's talk key
-- 2. page's protection action, page's protection level, default talk key
-- 3. page's protection action, default protection level, page's talk key
-- 4. page's protection action, default protection level, default talk key
--
-- It is possible to use banner parameters inside this table.
-- *required* - this table needs edit, move, autoreview and upload subtables.
explanationBlurbs = {
	edit = {
		autoconfirmed = {
			subject = 'See the [[Wikipedia:Protection policy|'
				.. 'protection policy]] and ${PROTECTIONLOG} for more details. If you'
				.. ' cannot edit this ${PAGETYPE} and you wish to make a change, you can'
				.. ' ${EDITREQUEST}, discuss changes on the ${TALKPAGE},'
				.. ' [[Wikipedia:Requests for page protection'
				.. '#Current requests for reduction in protection level'
				.. '|request unprotection]], [[Special:Userlogin|log in]], or'
				.. ' [[Special:UserLogin/signup|create an account]].',
			default = 'See the [[Wikipedia:Protection policy|'
				.. 'protection policy]] and ${PROTECTIONLOG} for more details. If you'
				.. ' cannot edit this ${PAGETYPE} and you wish to make a change, you can'
				.. ' [[Wikipedia:Requests for page protection'
				.. '#Current requests for reduction in protection level'
				.. '|request unprotection]], [[Special:Userlogin|log in]], or'
				.. ' [[Special:UserLogin/signup|create an account]].',
		},
		extendedconfirmed = {
			default = 'Extended confirmed protection prevents edits from all unregistered editors'
				.. ' and registered users with fewer than 30 days tenure and 500 edits.'
				.. ' The [[Wikipedia:Protection policy#extended|policy on community use]]'
				.. ' specifies that extended confirmed protection can be applied to combat'
				.. ' disruption, if semi-protection has proven to be ineffective.'
				.. ' Extended confirmed protection may also be applied to enforce'
				.. ' [[Wikipedia:Arbitration Committee|arbitration sanctions]].'
				.. ' Please discuss any changes on the ${TALKPAGE}; you may'
				.. ' ${EDITREQUEST} to ask for uncontroversial changes supported by'
				.. ' [[Wikipedia:Consensus|consensus]].'
		},
		default = {
			subject = 'See the [[Wikipedia:Protection policy|'
				.. 'protection policy]] and ${PROTECTIONLOG} for more details.'
				.. ' Please discuss any changes on the ${TALKPAGE}; you'
				.. ' may ${EDITREQUEST} to ask an'
				.. ' [[Wikipedia:Administrators|administrator]] to make an edit if it'
				.. ' is [[Help:Minor edit#When to mark an edit as a minor edit'
				.. '|uncontroversial]] or supported by [[Wikipedia:Consensus'
				.. '|consensus]]. You may also [[Wikipedia:Requests for'
				.. ' page protection#Current requests for reduction in protection level'
				.. '|request]] that this page be unprotected.',
			default = 'See the [[Wikipedia:Protection policy|'
				.. 'protection policy]] and ${PROTECTIONLOG} for more details.'
				.. ' You may [[Wikipedia:Requests for page'
				.. ' protection#Current requests for edits to a protected page|request an'
				.. ' edit]] to this page, or [[Wikipedia:Requests for'
				.. ' page protection#Current requests for reduction in protection level'
				.. '|ask]] for it to be unprotected.'
		}
	},
	move = {
		default = {
			subject = 'See the [[Wikipedia:Protection policy|'
				.. 'protection policy]] and ${PROTECTIONLOG} for more details.'
				.. ' The page may still be edited but cannot be moved'
				.. ' until unprotected. Please discuss any suggested moves on the'
				.. ' ${TALKPAGE} or at [[Wikipedia:Requested moves]]. You can also'
				.. ' [[Wikipedia:Requests for page protection|request]] that the page be'
				.. ' unprotected.',
			default = 'See the [[Wikipedia:Protection policy|'
				.. 'protection policy]] and ${PROTECTIONLOG} for more details.'
				.. ' The page may still be edited but cannot be moved'
				.. ' until unprotected. Please discuss any suggested moves at'
				.. ' [[Wikipedia:Requested moves]]. You can also'
				.. ' [[Wikipedia:Requests for page protection|request]] that the page be'
				.. ' unprotected.'
		}
	},
	autoreview = {
		default = {
			default = 'See the [[Wikipedia:Protection policy|'
				.. 'protection policy]] and ${PROTECTIONLOG} for more details.'
				.. ' Edits to this ${PAGETYPE} by new and unregistered users'
				.. ' will not be visible to readers until they are accepted by'
				.. ' a reviewer. To avoid the need for your edits to be'
				.. ' reviewed, you may'
				.. ' [[Wikipedia:Requests for page protection'
				.. '#Current requests for reduction in protection level'
				.. '|request unprotection]], [[Special:Userlogin|log in]], or'
				.. ' [[Special:UserLogin/signup|create an account]].'
		},
	},
	upload = {
		default = {
			default = 'See the [[Wikipedia:Protection policy|'
				.. 'protection policy]] and ${PROTECTIONLOG} for more details.'
				.. ' The page may still be edited but new versions of the file'
				.. ' cannot be uploaded until it is unprotected. You can'
				.. ' request that a new version be uploaded by using a'
				.. ' [[Wikipedia:Edit requests|protected edit request]], or you'
				.. ' can  [[Wikipedia:Requests for page protection|request]]'
				.. ' that the file be unprotected.'
		}
	}
},

--------------------------------------------------------------------------------
-- Protection levels
--------------------------------------------------------------------------------

-- This table provides the data for the ${PROTECTIONLEVEL} parameter, which
-- produces a short label for different protection levels. It is sorted by
-- protection action and protection level, and is checked in the following
-- order:
-- 1. page's protection action, page's protection level
-- 2. page's protection action, default protection level
-- 3. "edit" protection action, default protection level
--
-- It is possible to use banner parameters inside this table.
-- *required* - this table needs edit, move, autoreview and upload subtables.
protectionLevels = {
	edit = {
		default = 'protected',
		templateeditor = 'template-protected',
		extendedconfirmed = 'extended-protected',
		autoconfirmed = 'semi-protected',
	},
	move = {
		default = 'move-protected'
	},
	autoreview = {
	},
	upload = {
		default = 'upload-protected'
	}
},

--------------------------------------------------------------------------------
-- Images
--------------------------------------------------------------------------------

-- This table lists different padlock images for each protection action and
-- protection level. It is used if an image is not specified in any of the
-- banner data tables, and if the page does not satisfy the conditions for using
-- the ['image-filename-indef'] image. It is checked in the following order:
-- 1. page's protection action, page's protection level
-- 2. page's protection action, default protection level
images = {
	edit = {
		default = 'Full-protection-shackle.svg',
		templateeditor = 'Template-protection-shackle.svg',
		extendedconfirmed = 'Extended-protection-shackle.svg',
		autoconfirmed = 'Semi-protection-shackle.svg'
	},
	move = {
		default = 'Move-protection-shackle.svg',
	},
	autoreview = {
		default = 'Pending-protection-shackle.svg'
	},
	upload = {
		default = 'Upload-protection-shackle.svg'
	}
},

-- Pages with a reason specified in this table will show the special "indef"
-- padlock, defined in the 'image-filename-indef' message, if no expiry is set.
indefImageReasons = {
	template = true
},

--------------------------------------------------------------------------------
-- Image links
--------------------------------------------------------------------------------

-- This table provides the data for the ${IMAGELINK} parameter, which gets
-- the image link for small padlock icons based on the page's protection action
-- and protection level. It is checked in the following order:
-- 1. page's protection action, page's protection level
-- 2. page's protection action, default protection level
-- 3. "edit" protection action, default protection level
--
-- It is possible to use banner parameters inside this table.
-- *required* - this table needs edit, move, autoreview and upload subtables.
imageLinks = {
	edit = {
		default = 'Wikipedia:Protection policy#full',
		templateeditor = 'Wikipedia:Protection policy#template',
		extendedconfirmed = 'Wikipedia:Protection policy#extended',
		autoconfirmed = 'Wikipedia:Protection policy#semi'
	},
	move = {
		default = 'Wikipedia:Protection policy#move'
	},
	autoreview = {
		default = 'Wikipedia:Protection policy#pending'
	},
	upload = {
		default = 'Wikipedia:Protection policy#upload'
	}
},

--------------------------------------------------------------------------------
-- Padlock indicator names
--------------------------------------------------------------------------------

-- This table provides the "name" attribute for the <indicator> extension tag
-- with which small padlock icons are generated. All indicator tags on a page
-- are displayed in alphabetical order based on this attribute, and with
-- indicator tags with duplicate names, the last tag on the page wins.
-- The attribute is chosen based on the protection action; table keys must be a
-- protection action name or the string "default".
padlockIndicatorNames = {
	autoreview = 'pp-autoreview',
	default = 'pp-default'
},

--------------------------------------------------------------------------------
-- Protection categories
--------------------------------------------------------------------------------

--[[
-- The protection categories are stored in the protectionCategories table.
-- Keys to this table are made up of the following strings:
--
-- 1. the expiry date
-- 2. the namespace
-- 3. the protection reason (e.g. "dispute" or "vandalism")
-- 4. the protection level (e.g. "sysop" or "autoconfirmed")
-- 5. the action (e.g. "edit" or "move")
-- 
-- When the module looks up a category in the table, first it will will check to
-- see a key exists that corresponds to all five parameters. For example, a
-- user page semi-protected from vandalism for two weeks would have the key
-- "temp-user-vandalism-autoconfirmed-edit". If no match is found, the module
-- changes the first part of the key to "all" and checks the table again. It
-- keeps checking increasingly generic key combinations until it finds the
-- field, or until it reaches the key "all-all-all-all-all".
--
-- The module uses a binary matrix to determine the order in which to search.
-- This is best demonstrated by a table. In this table, the "0" values
-- represent "all", and the "1" values represent the original data (e.g.
-- "indef" or "file" or "vandalism").
--
--        expiry    namespace reason   level     action
-- order
-- 1      1         1         1        1         1
-- 2      0         1         1        1         1
-- 3      1         0         1        1         1
-- 4      0         0         1        1         1
-- 5      1         1         0        1         1
-- 6      0         1         0        1         1
-- 7      1         0         0        1         1
-- 8      0         0         0        1         1
-- 9      1         1         1        0         1
-- 10     0         1         1        0         1
-- 11     1         0         1        0         1
-- 12     0         0         1        0         1
-- 13     1         1         0        0         1
-- 14     0         1         0        0         1
-- 15     1         0         0        0         1
-- 16     0         0         0        0         1
-- 17     1         1         1        1         0
-- 18     0         1         1        1         0
-- 19     1         0         1        1         0
-- 20     0         0         1        1         0
-- 21     1         1         0        1         0
-- 22     0         1         0        1         0
-- 23     1         0         0        1         0
-- 24     0         0         0        1         0
-- 25     1         1         1        0         0
-- 26     0         1         1        0         0
-- 27     1         0         1        0         0
-- 28     0         0         1        0         0
-- 29     1         1         0        0         0
-- 30     0         1         0        0         0
-- 31     1         0         0        0         0
-- 32     0         0         0        0         0
--
-- In this scheme the action has the highest priority, as it is the last
-- to change, and the expiry has the least priority, as it changes the most.
-- The priorities of the expiry, the protection level and the action are
-- fixed, but the priorities of the reason and the namespace can be swapped
-- through the use of the cfg.bannerDataNamespaceHasPriority table.
--]]

-- If the reason specified to the template is listed in this table,
-- namespace data will take priority over reason data in the protectionCategories
-- table.
reasonsWithNamespacePriority = {
	vandalism = true,
},

-- The string to use as a namespace key for the protectionCategories table for each
-- namespace number.
categoryNamespaceKeys = {
	[  2] = 'user',
	[  3] = 'user',
	[  4] = 'project',
	[  6] = 'file',
	[  8] = 'mediawiki',
	[ 10] = 'template',
	[ 12] = 'project',
	[ 14] = 'category',
	[100] = 'portal',
	[828] = 'module',
},

protectionCategories = {
	['all|all|all|all|all']                     = 'Wikipedia fully protected pages',
	['all|all|office|all|all']                  = 'Wikipedia Office-protected pages',
	['all|all|reset|all|all']                   = 'Wikipedia Office-protected pages',
	['all|all|dmca|all|all']                    = 'Wikipedia Office-protected pages',
	['all|all|mainpage|all|all']                = 'Wikipedia fully protected main page files',
	['all|all|all|extendedconfirmed|all']       = 'Wikipedia extended-confirmed-protected pages',
	['all|all|ecp|extendedconfirmed|all']       = 'Wikipedia extended-confirmed-protected pages',
	['all|template|all|all|edit']               = 'Wikipedia fully protected templates',
	['all|all|all|autoconfirmed|edit']          = 'Wikipedia semi-protected pages',
	['indef|all|all|autoconfirmed|edit']        = 'Wikipedia indefinitely semi-protected pages',
	['all|all|blp|autoconfirmed|edit']          = 'Wikipedia indefinitely semi-protected biographies of living people',
	['temp|all|blp|autoconfirmed|edit']         = 'Wikipedia temporarily semi-protected biographies of living people',
	['all|all|dispute|autoconfirmed|edit']      = 'Wikipedia pages semi-protected due to dispute',
	['all|all|sock|autoconfirmed|edit']         = 'Wikipedia pages semi-protected from banned users',
	['all|all|vandalism|autoconfirmed|edit']    = 'Wikipedia pages semi-protected against vandalism',
	['all|category|all|autoconfirmed|edit']     = 'Wikipedia semi-protected categories',
	['all|file|all|autoconfirmed|edit']         = 'Wikipedia semi-protected files',
	['all|portal|all|autoconfirmed|edit']       = 'Wikipedia semi-protected portals',
	['all|project|all|autoconfirmed|edit']      = 'Wikipedia semi-protected project pages',
	['all|talk|all|autoconfirmed|edit']         = 'Wikipedia semi-protected talk pages',
	['all|template|all|autoconfirmed|edit']     = 'Wikipedia semi-protected templates',
	['all|user|all|autoconfirmed|edit']         = 'Wikipedia semi-protected user and user talk pages',
	['all|all|all|templateeditor|edit']         = 'Wikipedia template-protected pages other than templates and modules',
	['all|template|all|templateeditor|edit']    = 'Wikipedia template-protected templates',
	['all|template|all|templateeditor|move']    = 'Wikipedia template-protected templates', -- move-protected templates
	['all|all|blp|sysop|edit']                  = 'Wikipedia indefinitely protected biographies of living people',
	['temp|all|blp|sysop|edit']                 = 'Wikipedia temporarily protected biographies of living people',
	['all|all|dispute|sysop|edit']              = 'Wikipedia pages protected due to dispute',
	['all|all|sock|sysop|edit']                 = 'Wikipedia pages protected from banned users',
	['all|all|vandalism|sysop|edit']            = 'Wikipedia pages protected against vandalism',
	['all|category|all|sysop|edit']             = 'Wikipedia fully protected categories',
	['all|file|all|sysop|edit']                 = 'Wikipedia fully protected files',
	['all|project|all|sysop|edit']              = 'Wikipedia fully protected project pages',
	['all|talk|all|sysop|edit']                 = 'Wikipedia fully protected talk pages',
	['all|template|all|extendedconfirmed|edit'] = 'Wikipedia extended-confirmed-protected templates',
	['all|template|all|sysop|edit']             = 'Wikipedia fully protected templates',
	['all|user|all|sysop|edit']                 = 'Wikipedia fully protected user and user talk pages',
	['all|module|all|all|edit']                 = 'Wikipedia fully protected modules',
	['all|module|all|templateeditor|edit']      = 'Wikipedia template-protected modules',
	['all|module|all|extendedconfirmed|edit']   = 'Wikipedia extended-confirmed-protected modules',
	['all|module|all|autoconfirmed|edit']       = 'Wikipedia semi-protected modules',
	['all|all|all|sysop|move']                  = 'Wikipedia move-protected pages',
	['indef|all|all|sysop|move']                = 'Wikipedia indefinitely move-protected pages',
	['all|all|dispute|sysop|move']              = 'Wikipedia pages move-protected due to dispute',
	['all|all|vandalism|sysop|move']            = 'Wikipedia pages move-protected due to vandalism',
	['all|portal|all|sysop|move']               = 'Wikipedia move-protected portals',
	['all|project|all|sysop|move']              = 'Wikipedia move-protected project pages',
	['all|talk|all|sysop|move']                 = 'Wikipedia move-protected talk pages',
	['all|template|all|sysop|move']             = 'Wikipedia move-protected templates',
	['all|user|all|sysop|move']                 = 'Wikipedia move-protected user and user talk pages',
	['all|all|all|autoconfirmed|autoreview']    = 'Wikipedia pending changes protected pages',
	['all|file|all|all|upload']                 = 'Wikipedia upload-protected files',
},

--------------------------------------------------------------------------------
-- Expiry category config
--------------------------------------------------------------------------------

-- This table configures the expiry category behaviour for each protection
-- action.
-- * If set to true, setting that action will always categorise the page if
--   an expiry parameter is not set.
-- * If set to false, setting that action will never categorise the page.
-- * If set to nil, the module will categorise the page if:
--   1) an expiry parameter is not set, and
--   2) a reason is provided, and
--   3) the specified reason is not blacklisted in the reasonsWithoutExpiryCheck
--      table.

expiryCheckActions = {
	edit = nil,
	move = false,
	autoreview = true,
	upload = false
},

reasonsWithoutExpiryCheck = {
	blp = true,
	template = true,
},

--------------------------------------------------------------------------------
-- Pagetypes
--------------------------------------------------------------------------------

-- This table produces the page types available with the ${PAGETYPE} parameter.
-- Keys are namespace numbers, or the string "default" for the default value.
pagetypes = {
	[0] = 'article',
	[6] = 'file',
	[10] = 'template',
	[14] = 'category',
	[828] = 'module',
	default = 'page'
},

--------------------------------------------------------------------------------
-- Strings marking indefinite protection
--------------------------------------------------------------------------------

-- This table contains values passed to the expiry parameter that mean the page
-- is protected indefinitely.
indefStrings = {
	['indef'] = true,
	['indefinite'] = true,
	['indefinitely'] = true,
	['infinite'] = true,
},

--------------------------------------------------------------------------------
-- Group hierarchy
--------------------------------------------------------------------------------

-- This table maps each group to all groups that have a superset of the original
-- group's page editing permissions.
hierarchy = {
	sysop = {},
	reviewer = {'sysop'},
	filemover = {'sysop'},
	templateeditor = {'sysop'},
	extendedconfirmed = {'sysop'},
	autoconfirmed = {'reviewer', 'filemover', 'templateeditor', 'extendedconfirmed'},
	user = {'autoconfirmed'},
	['*'] = {'user'}
},

--------------------------------------------------------------------------------
-- Wrapper templates and their default arguments
--------------------------------------------------------------------------------

-- This table contains wrapper templates used with the module, and their
-- default arguments. Templates specified in this table should contain the
-- following invocation, and no other template content:
--
-- {{#invoke:Protection banner|main}}
--
-- If other content is desired, it can be added between
-- <noinclude>...</noinclude> tags.
--
-- When a user calls one of these wrapper templates, they will use the
-- default arguments automatically. However, users can override any of the
-- arguments.
wrappers = {
	['Template:Pp']                         = {},
	['Template:Pp-extended']                = {'ecp'},
	['Template:Pp-blp']                     = {'blp'},
	-- we don't need Template:Pp-create
	['Template:Pp-dispute']                 = {'dispute'},
	['Template:Pp-main-page']               = {'mainpage'},
	['Template:Pp-move']                    = {action = 'move', catonly = 'yes'},
	['Template:Pp-move-dispute']            = {'dispute', action = 'move', catonly = 'yes'},
	-- we don't need Template:Pp-move-indef
	['Template:Pp-move-vandalism']          = {'vandalism', action = 'move', catonly = 'yes'},
	['Template:Pp-office']                  = {'office'},
	['Template:Pp-office-dmca']             = {'dmca'},
	['Template:Pp-pc']                      = {action = 'autoreview', small = true},
	['Template:Pp-pc1']                     = {action = 'autoreview', small = true},
	['Template:Pp-reset']                   = {'reset'},
	['Template:Pp-semi-indef']              = {small = true},
	['Template:Pp-sock']                    = {'sock'},
	['Template:Pp-template']                = {'template', small = true},
	['Template:Pp-upload']                  = {action = 'upload'},
	['Template:Pp-usertalk']                = {'usertalk'},
	['Template:Pp-vandalism']               = {'vandalism'},
},

--------------------------------------------------------------------------------
-- 
--                                 MESSAGES
-- 
--------------------------------------------------------------------------------

msg = {

--------------------------------------------------------------------------------
-- Intro blurb and intro fragment
--------------------------------------------------------------------------------

-- These messages specify what is produced by the ${INTROBLURB} and
-- ${INTROFRAGMENT} parameters. If the protection is temporary they use the
-- intro-blurb-expiry or intro-fragment-expiry, and if not they use
-- intro-blurb-noexpiry or intro-fragment-noexpiry.
-- It is possible to use banner parameters in these messages.
['intro-blurb-expiry'] = '${PROTECTIONBLURB} until ${EXPIRY}.',
['intro-blurb-noexpiry'] = '${PROTECTIONBLURB}.',
['intro-fragment-expiry'] = '${PROTECTIONBLURB} until ${EXPIRY},',
['intro-fragment-noexpiry'] = '${PROTECTIONBLURB}',

--------------------------------------------------------------------------------
-- Tooltip blurb
--------------------------------------------------------------------------------

-- These messages specify what is produced by the ${TOOLTIPBLURB} parameter.
-- If the protection is temporary the tooltip-blurb-expiry message is used, and
-- if not the tooltip-blurb-noexpiry message is used.
-- It is possible to use banner parameters in these messages.
['tooltip-blurb-expiry'] = 'This ${PAGETYPE} is ${PROTECTIONLEVEL} until ${EXPIRY}.',
['tooltip-blurb-noexpiry'] = 'This ${PAGETYPE} is ${PROTECTIONLEVEL}.',
['tooltip-fragment-expiry'] = 'This ${PAGETYPE} is ${PROTECTIONLEVEL} until ${EXPIRY},',
['tooltip-fragment-noexpiry'] = 'This ${PAGETYPE} is ${PROTECTIONLEVEL}',

--------------------------------------------------------------------------------
-- Special explanation blurb
--------------------------------------------------------------------------------

-- An explanation blurb for pages that cannot be unprotected, e.g. for pages
-- in the MediaWiki namespace.
-- It is possible to use banner parameters in this message.
['explanation-blurb-nounprotect'] = 'See the [[Wikipedia:Protection policy|'
	.. 'protection policy]] and ${PROTECTIONLOG} for more details.'
	.. ' Please discuss any changes on the ${TALKPAGE}; you'
	.. ' may ${EDITREQUEST} to ask an'
	.. ' [[Wikipedia:Administrators|administrator]] to make an edit if it'
	.. ' is [[Help:Minor edit#When to mark an edit as a minor edit'
	.. '|uncontroversial]] or supported by [[Wikipedia:Consensus'
	.. '|consensus]].',

--------------------------------------------------------------------------------
-- Protection log display values
--------------------------------------------------------------------------------

-- These messages determine the display values for the protection log link
-- or the pending changes log link produced by the ${PROTECTIONLOG} parameter.
-- It is possible to use banner parameters in these messages.
['protection-log-display'] = 'protection log',
['pc-log-display'] = 'pending changes log',

--------------------------------------------------------------------------------
-- Current version display values
--------------------------------------------------------------------------------

-- These messages determine the display values for the page history link
-- or the move log link produced by the ${CURRENTVERSION} parameter.
-- It is possible to use banner parameters in these messages.
['current-version-move-display'] = 'current title',
['current-version-edit-display'] = 'current version',

--------------------------------------------------------------------------------
-- Talk page
--------------------------------------------------------------------------------

-- This message determines the display value of the talk page link produced
-- with the ${TALKPAGE} parameter.
-- It is possible to use banner parameters in this message.
['talk-page-link-display'] = 'talk page',

--------------------------------------------------------------------------------
-- Edit requests
--------------------------------------------------------------------------------

-- This message determines the display value of the edit request link produced
-- with the ${EDITREQUEST} parameter.
-- It is possible to use banner parameters in this message.
['edit-request-display'] = 'submit an edit request',

--------------------------------------------------------------------------------
-- Expiry date format
--------------------------------------------------------------------------------

-- This is the format for the blurb expiry date. It should be valid input for
-- the first parameter of the #time parser function.
['expiry-date-format'] = 'F j, Y "at" H:i e',

--------------------------------------------------------------------------------
-- Tracking categories
--------------------------------------------------------------------------------

-- These messages determine which tracking categories the module outputs.
['tracking-category-incorrect'] = 'Wikipedia pages with incorrect protection templates',
['tracking-category-template'] = 'Wikipedia template-protected pages other than templates and modules',

--------------------------------------------------------------------------------
-- Images
--------------------------------------------------------------------------------

-- These are images that are not defined by their protection action and protection level.
['image-filename-indef'] = 'Full-protection-shackle.svg',
['image-filename-default'] = 'Transparent.gif',

--------------------------------------------------------------------------------
-- End messages
--------------------------------------------------------------------------------
}

--------------------------------------------------------------------------------
-- End configuration
--------------------------------------------------------------------------------
}