|
|
Line 5: |
Line 5: |
| local mArguments = require('Module:Arguments') | | local mArguments = require('Module:Arguments') |
| local mProtectionLevel = require('Module:Effective protection level')._main | | local mProtectionLevel = require('Module:Effective protection level')._main |
| | local mFileLink = require('Module:File link') |
| local yesno = require('Module:Yesno') | | local yesno = require('Module:Yesno') |
| local mMessageBox -- only needs to be loaded if we are outputting a banner, so lazily initialise | | local mMessageBox -- only needs to be loaded if we are outputting a banner, so lazily initialise |
|
| |
|
| -------------------------------------------------------------------------------- | | -- Load config |
| -- Configuration
| | local cfg = mw.loadData('Module:Protection banner/config') |
| --------------------------------------------------------------------------------
| |
|
| |
|
| local cfg = {} | | local p = {} |
| | |
| cfg.defaultBanners = {
| |
| edit = {},
| |
| move = {},
| |
| create = {},
| |
| autoreview = {}
| |
| }
| |
| | |
| cfg.banners = {
| |
| -- A table of protection banners, sorted by protection type.
| |
|
| |
| -- $1 = Intro blurb, e.g. "This page is currently
| |
| -- [[Help:Protection|protected]] from editing"
| |
| -- $2 = "until" or "or until" depending on the expiry
| |
| -- $3 = "disputes", with or without a section link
| |
| -- $4 = the type of the page, e.g. "article", "template", or "page"
| |
| -- $5 = A blurb "it has been protected for x years, x months and x days."
| |
| -- $6 = the protection date
| |
| -- $7 = {{vandal-m|username}} replacement
| |
| edit = {
| |
| blp = {
| |
| text = '$1 to promote compliance with'
| |
| .. '[[Wikipedia:Biographies of living persons'
| |
| .. "|Wikipedia's policy on the biographies"
| |
| .. ' of living people]]',
| |
| tooltip = '$1 to promote compliance with the policy on biographies of'
| |
| .. ' living people',
| |
| categoryOrder = 'reason',
| |
| },
| |
| dispute = {
| |
| text = '$1 $2 editing $3 have been resolved',
| |
| tooltip = 'due to editing disputes',
| |
| dispute = true,
| |
| categoryOrder = 'reason',
| |
| },
| |
| office = {
| |
| text = 'This $4 is currently under the scrutiny of the'
| |
| .. ' [[Wikipedia:Office actions|Wikimedia Foundation Office]]'
| |
| .. ' and is protected. $5',
| |
| categoryOrder = 'reason',
| |
| },
| |
| reset = {
| |
| text = 'On $6 this article was 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 article has been placed under a level of'
| |
| .. ' semi-protection temporarily during the rebuilding of this'
| |
| .. ' article.\n\nAny insertion of material directly from'
| |
| .. ' pre-protection revisions of the article will be removed, as'
| |
| .. ' will any material added to the article that is not properly'
| |
| .. ' sourced. The associated talk page(s) were also cleared on the'
| |
| .. " same date.\n\n'''Administrators may not override this action"
| |
| .. ' without approval from someone from the [[WP:OFFICE|Office]].'
| |
| .. " No editor may remove this notice.'''",
| |
| categoryOrder = 'reason',
| |
| categoryReason = 'office',
| |
| },
| |
| sock = {
| |
| text = '$1 to prevent [[Wikipedia:Sock puppetry|sock puppets]] of'
| |
| .. ' [[Wikipedia:Blocking policy|blocked]] or'
| |
| .. ' [[Wikipedia:List of banned users|banned users]]'
| |
| .. ' from editing it',
| |
| tooltip = '$1 to prevent sock puppets of blocked or banned users from'
| |
| .. ' editing it',
| |
| categoryOrder = 'reason',
| |
| },
| |
| usertalk = {
| |
| text = '$1 to prevent $7 from using it to make disruptive edits, such'
| |
| .. ' as abusing the'
| |
| .. ' {{[[Template:unblock|unblock]]}} 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]].',
| |
| categoryReason = 'all',
| |
| },
| |
| vandalism = {
| |
| text = '$1 due to [[Wikipedia:Vandalism|vandalism]]',
| |
| tooltip = '$1 due to vandalism',
| |
| categoryOrder = 'namespace',
| |
| }
| |
| },
| |
| move = {
| |
| dispute = {
| |
| },
| |
| vandalism = {
| |
| },
| |
| move = {
| |
| }
| |
| },
| |
| create = {
| |
| },
| |
| autoreview = {
| |
| pc1 = {
| |
| },
| |
| pc2 = {
| |
| }
| |
| }
| |
| }
| |
| | |
| cfg.images = {
| |
| full = 'Padlock.svg',
| |
| semi = 'Padlock-silver.svg',
| |
| template = 'Padlock-pink.svg',
| |
| pc1 = 'Padlock-silver-light.svg',
| |
| pc2 = 'Padlock-orange.svg',
| |
| move = 'Padlock-olive.svg',
| |
| indef = 'Padlock-red.svg',
| |
| office = 'Padlock-black.svg',
| |
| create = 'Padlock-skyblue.svg'
| |
| }
| |
| | |
| cfg.categories = {
| |
| -- The key strings follow this format:
| |
| -- type, level, ns, reason, expiry
| |
| ['all-all-all-all-all'] = 'Wikipedia protected pages',
| |
| ['all-all-all-office-all'] = 'Wikipedia Office-protected pages',
| |
| ['edit-all-template-all-all'] = 'Wikipedia protected templates',
| |
| ['edit-autoconfirmed-all-all-all'] = 'Wikipedia semi-protected pages',
| |
| ['edit-autoconfirmed-all-all-indef'] = 'Wikipedia indefinitely semi-protected pages',
| |
| ['edit-autoconfirmed-all-blp-all'] = 'Wikipedia indefinitely semi-protected biographies of living people',
| |
| ['edit-autoconfirmed-all-blp-temp'] = 'Wikipedia temporarily semi-protected biographies of living people',
| |
| ['edit-autoconfirmed-all-dispute-all'] = 'Wikipedia pages semi-protected due to dispute',
| |
| ['edit-autoconfirmed-all-sock-all'] = 'Wikipedia pages semi-protected from banned users',
| |
| ['edit-autoconfirmed-all-vandalism-all'] = 'Wikipedia pages semi-protected against vandalism',
| |
| ['edit-autoconfirmed-category-all-all'] = 'Wikipedia semi-protected categories',
| |
| ['edit-autoconfirmed-file-all-all'] = 'Semi-protected images',
| |
| ['edit-autoconfirmed-portal-all-all'] = 'Semi-protected portals',
| |
| ['edit-autoconfirmed-project-all-all'] = 'Semi-protected project pages',
| |
| ['edit-autoconfirmed-talk-all-all'] = 'Semi-protected talk pages',
| |
| ['edit-autoconfirmed-template-all-all'] = 'Wikipedia semi-protected templates',
| |
| ['edit-autoconfirmed-template-all-all'] = 'Wikipedia semi-protected templates',
| |
| ['edit-autoconfirmed-user-all-all'] = 'Wikipedia semi-protected user and user talk pages',
| |
| ['edit-sysop-all-blp-all'] = 'Wikipedia indefinitely protected biographies of living people',
| |
| ['edit-sysop-all-blp-temp'] = 'Wikipedia temporarily protected biographies of living people',
| |
| ['edit-sysop-all-dispute-all'] = 'Wikipedia pages protected due to dispute',
| |
| ['edit-sysop-all-sock-all'] = 'Wikipedia pages protected from banned users',
| |
| ['edit-sysop-all-vandalism-all'] = 'Wikipedia pages protected against vandalism',
| |
| ['edit-sysop-category-all-all'] = 'Wikipedia protected categories',
| |
| ['edit-sysop-file-all-all'] = 'Protected images',
| |
| ['edit-sysop-project-all-all'] = 'Protected project pages',
| |
| ['edit-sysop-talk-all-all'] = 'Protected talk pages',
| |
| ['edit-sysop-template-all-all'] = 'Wikipedia protected templates',
| |
| ['edit-sysop-user-all-all'] = 'Wikipedia protected user and user talk pages',
| |
| ['move-sysop-all-all-all'] = 'Wikipedia move-protected pages',
| |
| ['move-sysop-all-all-indef'] = 'Wikipedia indefinitely move-protected pages',
| |
| ['move-sysop-all-dispute-all'] = 'Wikipedia pages move-protected due to dispute',
| |
| ['move-sysop-all-vandalism-all'] = 'Wikipedia pages move-protected due to vandalism',
| |
| ['move-sysop-portal-all-all'] = 'Wikipedia move-protected portals',
| |
| ['move-sysop-portal-all-all'] = 'Wikipedia move-protected portals',
| |
| ['move-sysop-project-all-all'] = 'Wikipedia move-protected project pages',
| |
| ['move-sysop-talk-all-all'] = 'Wikipedia move-protected talk pages',
| |
| ['move-sysop-template-all-all'] = 'Wikipedia move-protected templates',
| |
| ['move-sysop-user-all-all'] = 'Wikipedia move-protected user and user talk pages',
| |
| ['autoreview-autoconfirmed-all-all-all'] = 'Wikipedia pending changes protected pages (level 1)',
| |
| ['autoreview-reviewer-all-all-all'] = 'Wikipedia pending changes protected pages (level 2)',
| |
| }
| |
| | |
| cfg.categoryNamespaces = {
| |
| [2] = 'user',
| |
| [3] = 'user',
| |
| [4] = 'project',
| |
| [6] = 'file',
| |
| [10] = 'template',
| |
| [12] = 'project',
| |
| [14] = 'category',
| |
| [100] = 'portal',
| |
| }
| |
| | |
| cfg.pagetypeNamespaces = {
| |
| [0] = 'article',
| |
| [6] = 'file',
| |
| [10] = 'template',
| |
| [14] = 'category',
| |
| [828] = 'module',
| |
| default = 'page'
| |
| }
| |
| | |
| cfg.errorCategories = {
| |
| incorrect = 'Wikipedia pages with incorrect protection templates',
| |
| noExpiry = 'Wikipedia protected pages without expiry',
| |
| create = 'Wikipedia pages tagged as create-protected',
| |
| template = 'Wikipedia template-protected pages other than templates and modules'
| |
| } | |
|
| |
|
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| -- Helper functions | | -- Helper functions |
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| | |
| | local function validateField(tName, t, field, expectType, nilOk) |
| | local val = t[field] |
| | local valType = type(val) |
| | if not (valType == expectType or nilOk and valType == 'nil') then |
| | error(string.format( |
| | "type error in '%s' field '%s' (%s%s expected, got %s)", |
| | tName, |
| | tostring(field), |
| | expectType, |
| | nilOk and ' or nil' or '', |
| | valType |
| | ), 2) |
| | end |
| | end |
|
| |
|
| local function toTableEnd(t, pos) | | local function toTableEnd(t, pos) |
Line 218: |
Line 40: |
|
| |
|
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| -- Banner object | | -- Main functions |
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
|
| |
|
| local banner = {}
| | function p.main(frame) |
| | | local args = mArguments.getArgs(frame) |
| function banner.new(args) | | return p._main(args) |
| local obj = {} | |
| setmetatable(obj, {
| |
| __index = banner
| |
| })
| |
|
| |
| -- Set the protection action.
| |
| -- This is the action we are supposed to be protecting the page against,
| |
| -- and does not necessarily correspond to the actual protection status.
| |
| obj.action = args.action or 'edit'
| |
|
| |
| -- Get the title object of the page we are working on.
| |
| if args.page then
| |
| obj.title = mw.title.new(args.page)
| |
| else | |
| obj.title = mw.title.getCurrentTitle()
| |
| end
| |
|
| |
| -- Get the protection level of the title object for the given protection
| |
| -- action. This is always a string, even for invalid actions.
| |
| do
| |
| local protectionData = p.getProtectionData(obj.title)
| |
| local protectionLevel = protectionData[obj.action]
| |
| obj.protectionLevel = protectionLevel or '*'
| |
| end
| |
| | |
| -- Fetch the banner data and copy it into the object.
| |
| -- This could be problematic if the data table and the banner object have
| |
| -- any duplicate keys, so check for those.
| |
| do
| |
| local data
| |
| if args.reason
| |
| and cfg.banners[obj.action]
| |
| and cfg.banners[obj.action][args.reason]
| |
| then
| |
| data = cfg.banners[obj.action][args.reason]
| |
| elseif cfg.defaultBanners[obj.action] then
| |
| data = cfg.defaultBanners[obj.action]
| |
| elseif cfg.defaultBanners.edit then
| |
| data = cfg.defaultBanners.edit
| |
| else
| |
| error('no banner data found; please define data for cfg.defaultBanners')
| |
| end
| |
| local usedFields = {}
| |
| for k in pairs(banner) do
| |
| usedFields[k] = true
| |
| end
| |
| for k in pairs(obj) do
| |
| usedFields[k] = true
| |
| end
| |
| for k, v in pairs(data) do
| |
| if usedFields[k] then
| |
| error('banner.new: duplicate config key "' .. tostring(k) .. '" detected')
| |
| else
| |
| obj[k] = v
| |
| end
| |
| end
| |
| end
| |
| | |
| -- Find whether we are outputting a padlock or a full banner.
| |
| if obj.small == nil then
| |
| -- Let the config data take precedence over user-specified arguments
| |
| obj.small = yesno(args.small) or false
| |
| end
| |
| | |
| return obj
| |
| end | | end |
|
| |
|
| function banner:fetchImageName() | | function p._main(args) |
| local image | | local protectionLevel = p.getProtectionLevel(args) |
| if self.reason == 'office' or self.reason == 'reset' then
| | local isSmall = yesno(args.small) or false |
| image = cfg.images.office
| | local bannerConfig = p.getBannerConfig(protectionLevel, args) |
| elseif self.title.namespace == 10 or self.title.namespace == 828 then | |
| -- We are in the template or module namespaces.
| |
| if self.protectionLevel == 'templateeditor' then
| |
| image = cfg.images.template
| |
| elseif self.protectionLevel == 'sysop' then
| |
| image = cfg.images.indef
| |
| end
| |
| elseif self.action == 'create' then | |
| image = cfg.images.create
| |
| elseif self.action == 'move'
| |
| and (
| |
| self.protectionLevel == 'templateeditor'
| |
| or self.protectionLevel == 'sysop'
| |
| )
| |
| then
| |
| image = cfg.images.move
| |
| elseif self.action == 'edit' then
| |
| if self.protectionLevel == 'sysop' then
| |
| image = cfg.images.full
| |
| elseif self.protectionLevel == 'autoconfirmed' then
| |
| image = cfg.images.semi
| |
| end
| |
| elseif self.action == 'autoreview' then
| |
| if self.protectionLevel == 'autoconfirmed' then
| |
| image = cfg.images.pc1
| |
| elseif self.protectionLevel == 'reviewer' then
| |
| image = cfg.images.pc2
| |
| end
| |
| else
| |
| image = 'Transparent.gif'
| |
| end
| |
| return image
| |
| end
| |
|
| |
|
| function banner:renderImageLink(image, size, link, text, alt)
| | local ret = '' |
| --[[
| | if isSmall then |
| -- Renders the image link wikitext All parameters are optional
| | ret = ret .. p.makePadlock(protectionLevel, args, bannerConfig) |
| -- apart from the display text.
| |
| --
| |
| -- @parameters:
| |
| -- image - the image name
| |
| -- size - the image size, as a number
| |
| -- link - page linked to by the image
| |
| -- text - the tooltip text
| |
| -- alt - the alt text
| |
| --
| |
| -- All parameters are optional apart from the text parameter.
| |
| --]]
| |
| image = image or 'Transparent.gif' | |
| size = size or 20
| |
| if link then | |
| link = '|link=' .. link | |
| else | | else |
| link = '' | | ret = ret .. p.makeBanner(protectionLevel, args, bannerConfig) |
| end | | end |
| text = text or error('No text parameter supplied to p.renderImageLink') | | ret = ret .. p.getProtectionCategory(protectionLevel, args) |
| if alt then
| | ret = ret .. p.getTrackingCategories(protectionLevel, args) |
| alt = '|alt=' .. alt
| |
| else
| |
| alt = ''
| |
| end
| |
| return string.format('[[Image:%s|%dpx%s|%s%s]]', image, size, link, text, alt)
| |
| end
| |
| | |
| function banner:renderPadlock(image, right)
| |
| --[[
| |
| -- Renders the html of the padlock seen in the top-right-hand corner
| |
| -- of protected pages.
| |
| --
| |
| -- @parameters:
| |
| -- image - the image wikitext (required)
| |
| -- right - the "right" css property value, as a string (optional)
| |
| --]]
| |
| image = image or error('No image parameter specified in p.renderPadlock')
| |
| local root = mw.html.create('div')
| |
| root
| |
| :addClass('metadata topicon nopopups')
| |
| :attr('id', 'protected-icon')
| |
| :css{display = 'none', right = right or '55px'}
| |
| :wikitext(image)
| |
| return tostring(root)
| |
| end
| |
| | |
| function banner:renderBanner(page, image, text)
| |
| --[[
| |
| -- Renders the large protection banner placed at the top of articles,
| |
| -- using the data provided in the data table.
| |
| --
| |
| -- @parameters:
| |
| -- page - demo page parameter to pass to {{mbox}}
| |
| -- image - the image wikitext
| |
| -- text - the text to display
| |
| --
| |
| -- All parameters are optional.
| |
| --]]
| |
| mMessageBox = require('Module:Message box')
| |
| local mbargs = { -- arguments for the message box module
| |
| page = page,
| |
| type = 'protection',
| |
| image = image,
| |
| text = text
| |
| }
| |
| return mMessageBox.main('mbox', mbargs)
| |
| end
| |
| | |
| function banner:export()
| |
| -- Add the banner/padlock, protection category, and tracking categories.
| |
| local ret = ''
| |
| ret = ret .. self:renderBannerOrPadlock()
| |
| ret = ret .. self:renderProtectionCategory() | |
| ret = ret .. self:renderTrackingCategories()
| |
| return ret | | return ret |
| end | | end |
|
| |
|
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
| -- Main functions | | -- Protection functions |
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
|
| |
|
| local p = {}
| | function p.getProtectionLevel(args) |
| | | local title |
| function p.main(frame) | | if args.page then |
| local args = mArguments.getArgs(frame) | | title = mw.title.new(args.page) |
| return p._main(args) | | else |
| | title = mw.title.getCurrentTitle() |
| | end |
| | local protectionData = p.getProtectionData(title) |
| | protectionLevel = protectionData[args.action or 'edit'] |
| | return protectionLevel or '*' |
| end | | end |
|
| |
|
Line 447: |
Line 107: |
| }) | | }) |
| return protectionData | | return protectionData |
| | end |
| | |
| | -------------------------------------------------------------------------------- |
| | -- Banner config functions |
| | -------------------------------------------------------------------------------- |
| | |
| | function p.getBannerConfig(protectionLevel, args) |
| | end |
| | |
| | -------------------------------------------------------------------------------- |
| | -- Padlock functions |
| | -------------------------------------------------------------------------------- |
| | |
| | function p.makePadlock(protectionLevel, args, bannerConfig) |
| | local data = p.makePadlockData(protectionLevel, args, bannerConfig) |
| | return p.renderPadlock(data) |
| | end |
| | |
| | function p.makePadlockData(protectionLevel, args, bannerConfig) |
| | end |
| | |
| | function p.renderPadlock(data) |
| | data = data or {} |
| | local image = mFileLink.new(data.filename or 'Transparent.gif') |
| | :width(20) |
| | :link(data.link) |
| | :alt(data.alt) |
| | :render() |
| | local root = mw.html.create('div') |
| | root |
| | :addClass('metadata topicon nopopups') |
| | :attr('id', 'protected-icon') |
| | :css{display = 'none', right = data.right or '55px'} |
| | :wikitext(image) |
| | return tostring(root) |
| | end |
| | |
| | -------------------------------------------------------------------------------- |
| | -- Banner functions |
| | -------------------------------------------------------------------------------- |
| | |
| | function p.makeBanner(protectionLevel, args, bannerConfig) |
| | local data = p.makeBannerData(protectionLevel, args, bannerConfig) |
| | return p.renderBanner(data) |
| | end |
| | |
| | function p.makeBannerData(protectionLevel, args, bannerConfig) |
| | end |
| | |
| | function p.renderBanner(data) |
| | data = data or {} |
| | local image = mFileLink.new(data.filename) |
| | :width(40) |
| | :caption(data.mouseover) |
| | :render() |
| | local mbargs = { |
| | page = data.page, |
| | type = 'protection', |
| | image = image, |
| | text = string.format( |
| | "'''%s'''%s", |
| | data.reasonText, |
| | data.explanationText and '<br />' .. data.explanationText or '' |
| | ) |
| | } |
| | return mMessageBox.main('mbox', mbargs) |
| | end |
| | |
| | -------------------------------------------------------------------------------- |
| | -- Protection category functions |
| | -------------------------------------------------------------------------------- |
| | |
| | function p.getProtectionCategory(protectionLevel, args) |
| end | | end |
|
| |
|
Line 636: |
Line 369: |
| .. ' please define the category for key "all-all-all-all-all"' | | .. ' please define the category for key "all-all-all-all-all"' |
| ) | | ) |
| | end |
| | |
| | -------------------------------------------------------------------------------- |
| | -- Tracking category functions |
| | -------------------------------------------------------------------------------- |
| | |
| | function p.getTrackingCategories(protectionLevel, args) |
| end | | end |
|
| |
|