Module:Authority control: Difference between revisions

From Sidlangs
Jump to navigation Jump to search
(get example id from wikidata rather than using locally defined, add function to produce table of errors, adjust tracking categories)
 
m (1 revision imported: This: work pls)
 
(5 intermediate revisions by 4 users not shown)
Line 1: Line 1:
require('strict')
require('strict')
local p = {}
local p = {}
local arg = mw.getCurrentFrame().args.config
local configfile = 'Module:Authority control/config' .. (arg and arg~='' and ('/' .. arg) or '')
local config = mw.loadData(configfile)
local title = mw.title.getCurrentTitle()
local title = mw.title.getCurrentTitle()
local namespace = title.namespace
local namespace = title.namespace
local testcases = (string.sub(title.subpageText,1,9) == 'testcases')
local testcases = title.subpageText == config.i18n.testcases
local config = require("Module:Authority control/config")
 
local function needsAttention(sortkey)
return '[[' .. config.i18n.category .. ':' .. config.i18n.attentioncat .. '|' .. sortkey .. title.text .. ']]'
end


local function addCat(cat,sortkey)
local function addCat(cat,sortkey)
if cat and cat ~= '' and (namespace == 0 or namespace == 14 or testcases) then
if cat and cat ~= '' and (namespace == 0 or namespace == 14 or testcases) then
local redlinkcat = ''
local redlinkcat = ''
if testcases == false and mw.title.new(cat, 14).exists == false then
if testcases == false then
redlinkcat = '[[Category:Pages with red-linked authority control categories]]'
local success, exists = pcall(function() return mw.title.new(cat, 14).exists end)
if success and not exists then  
redlinkcat = needsAttention('N')
end
end
end
if sortkey then
if sortkey then
cat = '[[Category:'..cat..'|' .. sortkey .. title.text .. ']]'
cat = '[[' .. config.i18n.category .. ':'..cat..'|' .. sortkey .. title.text .. ']]'
else
else
cat = '[[Category:'..cat..']]'
cat = '[[' .. config.i18n.category .. ':'..cat..']]'
end
end
cat = cat .. redlinkcat
cat = cat .. redlinkcat
Line 25: Line 34:


local function getCatForId(id,faulty)
local function getCatForId(id,faulty)
local cat = 'Articles with '
local cat = string.format(
if faulty then cat = cat .. 'faulty ' end
config.i18n.cat,
cat = cat .. id .. ' identifiers'
(faulty and config.i18n.faulty..' ' or '') .. id
)
return addCat(cat)
return addCat(cat)
end
end


local function getIdsFromWikidata(qid,property)
local function getIdsFromWikidata(qid,property)
local function getquals(statement,qualid)
if statement.qualifiers and statement.qualifiers['P'..qualid] then
return mw.wikibase.renderSnak(statement.qualifiers['P'..qualid][1])
else
return false
end
end
local ids = {}
local ids = {}
if not mw.wikibase or not qid then
if qid then
return ids
for _, statement in ipairs(mw.wikibase.getBestStatements(qid,property)) do
end
local statements = mw.wikibase.getBestStatements(qid,property)
if statements then
for _, statement in ipairs( statements ) do
if statement.mainsnak.datavalue then
if statement.mainsnak.datavalue then
table.insert( ids, statement.mainsnak.datavalue.value )
local val = statement.mainsnak.datavalue.value
if val then
local namedas = getquals(statement,1810) or getquals(statement,742) or ''
table.insert(ids,{id=val,name=namedas})
end
end
end
end
end
Line 47: Line 64:
end
end


local function makelink(conf,val,nextid,qid) --validate values and create a link
local _makelink = function(conf,val,nextid,qid) --validate values and create a link
local function tooltip(text,label)
if label and label~='' then
return mw.getCurrentFrame():expandTemplate{title = "Tooltip", args = {text,label}}
else
return text
end
end
local link
local link
if nextid==1 then
if nextid==1 then
Line 59: Line 83:
end
end
local valid_value = false
local valid_value = false
if conf.link2 then -- use function to validate and generate link
if conf.customlink then -- use function to validate and generate link
if conf.link2(val) then
local label = nextid>1 and nextid
link = link .. conf.link2(val)
local newlink= require(config.auxiliary)[conf.customlink](val.id,label)
if newlink then
link = link .. newlink
valid_value = true
valid_value = true
end
end
else
else
if conf.pattern then -- use pattern to determine validity if defined
if conf.pattern then -- use pattern to determine validity if defined
valid_value = val:match(conf.pattern)
valid_value = string.match(val.id,'^'..conf.pattern..'$')
elseif conf.patterns then
elseif conf.patterns then
for i = 1,#conf.patterns do
for _,pattern in ipairs(conf.patterns) do
valid_value = val:match(conf.patterns[i])
valid_value = val.id:match('^'..pattern..'$')
if valid_value then break end
if valid_value then break end
end
end
elseif conf.valid then -- otherwise use function to determine validity
elseif conf.valid then -- otherwise use function to determine validity
valid_value = conf.valid(val)
valid_value = require(config.auxiliary)[conf.valid](val.id)
else -- no validation possible
else -- no validation possible
valid_value = val
valid_value = val.id
end
end
if valid_value then
if valid_value then
link = link .. '<span class="uid">'
local newlink
if not conf.label or nextid>1 then
local label = conf.label
conf.label = tostring(nextid)
if not label or nextid>1 then
label = tostring(nextid)
end
end
if conf.link then
if conf.link then
valid_value = valid_value:gsub('%%', '%%%%')
valid_value = valid_value:gsub('%%', '%%%%')
link = link .. '[' .. mw.ustring.gsub(conf.link,'%$1',valid_value) .. ' ' .. conf.label .. ']'
newlink = '[' .. mw.ustring.gsub(conf.link,'%$1',valid_value) .. ' ' .. label .. ']'
else
else
link = link .. valid_value
newlink = valid_value
end
end
link = link .. '</span>'
link = link .. '<span class="uid">'..tooltip(newlink,val.name)..'</span>'
end
end
end
end
Line 96: Line 123:
--local preview = require("Module:If preview")
--local preview = require("Module:If preview")
local wdlink = qid and '[[:wikidata:' .. qid .. '#P' .. conf.property .. ']]' or ''
local wdlink = qid and '[[:wikidata:' .. qid .. '#P' .. conf.property .. ']]' or ''
link = link .. '[[File:345-409 Ambox warning centered.svg|20px|frameless|link=' .. wdlink ..'|The '..conf[1]..' id '..val..' is not valid.]]'
local tooltip = string.format(
config.i18n.idnotvalid,
conf[1],
val.id
)
link = link .. '[[File:' .. config.i18n.warningicon .. '|20px|frameless|link=' .. wdlink .. '|' .. tooltip .. '.]]'
if conf.errorcat then
if conf.errorcat then
link = link .. addCat(conf.errorcat)
link = link .. addCat(conf.errorcat)
Line 102: Line 134:
link = link .. getCatForId(conf.category or conf[1],true)
link = link .. getCatForId(conf.category or conf[1],true)
end
end
link = link .. addCat('All articles with faulty authority control information',conf[1])-- .. preview._warning({'The '..conf[1]..' id '..val..' is not valid.'})
link = link .. addCat(config.i18n.allfaultycat,conf[1])-- .. preview._warning({'The '..conf[1]..' id '..val..' is not valid.'})
end
end
return link
return link
Line 111: Line 143:
--[[==========================================================================]]
--[[==========================================================================]]
function p.authorityControl(frame)
function p.authorityControl(frame)
local resolveEntity = require('Module:ResolveEntityId')
local function resolveQID(qid)
local function resolveQID(qid)
if qid then
if qid then
qid = 'Q'..mw.ustring.gsub(qid, '^[Qq]', '')
qid = 'Q'..mw.ustring.gsub(qid, '^[Qq]', '')
qid = resolveEntity._id(qid) --nil if unresolvable
if mw.wikibase.isValidEntityId(qid) and mw.wikibase.entityExists(qid) then
local sitelink = mw.wikibase.getSitelink(qid)
if sitelink then
return mw.wikibase.getEntityIdForTitle(sitelink) or mw.wikibase.getEntity(qid).id
end
return mw.wikibase.getEntity(qid).id
end
end
end
return qid
end
end
local conf = config.config
local conf = config.config
local parentArgs = frame:getParent().args
local parentArgs = frame:getParent().args
local iParentArgs = 0 --count original/manual parent args
local iMatches = 0
local auxCats = ''
local auxCats = ''
local rct = 0 -- total number of links returned
local rct = false -- boolean to track if there are any links to be returned
local qid
local qid,topic
local wikilink = function(qid,hideifequal)
local label,sitelink = mw.wikibase.getLabel(qid),mw.wikibase.getSitelink(qid)
if label then
if sitelink then
local target = mw.title.new(sitelink)
if target==title or (target.isRedirect and target.redirectTarget==title) then -- do not link
return label
else -- make wikilink to article
return '[[' .. sitelink .. '|' .. label .. ']]'
end
else
return label
end
else
auxCats = auxCats .. needsAttention('L')
return qid
end
end
if namespace == 0 then
if namespace == 0 then
qid = mw.wikibase.getEntityIdForCurrentPage()
qid = mw.wikibase.getEntityIdForCurrentPage()
end
end
if not qid then
if qid then -- article is connected to Wikidata item
qid = resolveQID(parentArgs['qid']) --use qid parameter if no wikidata item is connected
if parentArgs.qid and (resolveQID(parentArgs.qid) ~= qid) then -- non-matching qid parameter
auxCats = auxCats .. needsAttention('D')
end
else -- page is not connected to any Wikidata item
qid = resolveQID(parentArgs.qid) -- check qid parameter if no wikidata item is connected
if qid then -- qid parameter is valid, set topic to display
topic = mw.wikibase.getLabel(qid)
if topic then
if mw.ustring.lower(title.subpageText) == mw.ustring.lower(topic) then -- suppress topic display if subpagename equals topic up to case change
topic = nil
end
if topic and mw.wikibase.getSitelink(qid) then -- make wikilink to article
topic = '[[' .. mw.wikibase.getSitelink(qid) .. '|' .. topic .. ']]'
end
else
auxCats = auxCats .. needsAttention('L')
end
elseif parentArgs.qid and parentArgs.qid~='' then -- invalid qid has been supplied, add to tracking cat
auxCats = auxCats .. needsAttention('Q')
end
end
end
local qids = {} -- setup any additional QIDs
local qids = {} -- setup any additional QIDs
if parentArgs.additional and parentArgs.additional ~= '' then
if parentArgs.additional=='auto' and qid then  -- check P527 for parts to add additional qids
local checkparts = function(property)
local parts = mw.wikibase.getBestStatements(qid,property)
if parts then
for _,part in ipairs(parts) do
if part.mainsnak.datavalue and part.mainsnak.datavalue.value.id then
local resolvedqid = resolveQID(part.mainsnak.datavalue.value.id)
if resolvedqid then
table.insert(qids,resolvedqid)
end end end end end
for _,part in ipairs(config.auto_additional) do
checkparts('P'..tostring(part))
end
elseif parentArgs.additional and parentArgs.additional ~= '' then
for _,v in ipairs(mw.text.split(parentArgs.additional,"%s*,%s*")) do
for _,v in ipairs(mw.text.split(parentArgs.additional,"%s*,%s*")) do
table.insert(qids,resolveQID(v))
v = resolveQID(v)
if v then
if v == qid then -- duplicate of qid parameter
auxCats = auxCats .. needsAttention('R')
end
table.insert(qids,v)
else -- invalid QID specified
auxCats = auxCats .. needsAttention('A')
end
end
end
end
end


local sections = {}
local sections = {}
for _ = 1,#config.sectionNames + #qids do table.insert(sections,{}) end
local localparams = false
local numsections = 0
for _,_ in ipairs(config.sections) do numsections = numsections + 1 end
for _ = 1,#qids+numsections do table.insert(sections,{}) end
local qslink = '' -- setup link to add using QuickStatements
local qslink = '' -- setup link to add using QuickStatements


Line 146: Line 241:
local show = {} -- setup list
local show = {} -- setup list
local showall = true
local showall = true
local function stripP(pid)
if pid:match("^[Pp]%d+$") then
pid = mw.ustring.gsub(pid,'[Pp]','') --strip P from property number
end
if pid:match("^%d+$") then
return tonumber(pid)
end
end
local function addshowlist(list)
local function addshowlist(list)
if list and list ~= '' then
if list and list ~= '' then
for _,v in ipairs(mw.text.split(string.lower(list),"%s*,%s*")) do
for _,v in ipairs(mw.text.split(string.lower(list),"%s*,%s*")) do
if config.whitelists[v] then
local vprop = stripP(v)
for _,w in ipairs(config.whitelists[v].properties) do
if vprop then -- e.g. show=P214 to show one particular property
show[w] = true
show[vprop] = true
else -- e.g. show=arts to use whitelist
if config.whitelists[v] then
for _,w in ipairs(config.whitelists[v].properties) do
show[w] = true
end
end
end
end
end
Line 163: Line 271:
local suppresslist = mw.text.split(parentArgs.suppress,"%s*,%s*") -- split parameter by comma
local suppresslist = mw.text.split(parentArgs.suppress,"%s*,%s*") -- split parameter by comma
for _,v in ipairs(suppresslist) do
for _,v in ipairs(suppresslist) do
if v:match("^[Pp]%d+$") then
v = stripP(string.upper(v))
v = mw.ustring.gsub(v,'[Pp]','') --strip P from property number
if v then
end
show[v] = false
if v:match("^%d+$") then
auxCats = auxCats .. '[[' .. config.i18n.category .. ':' .. config.i18n.suppressedcat .. ']]'
v = tonumber(v)
else
else
v = string.upper(v) -- convert to uppercase
auxCats = auxCats .. needsAttention('P')
end
end
show[v] = false
end
end
end
end
Line 198: Line 304:
showb = false
showb = false
end
end
if addit then
if not showb then
if not showb then
tval[params.property] = false -- indicates the identifier is suppressed
tval[params.property] = false -- indicates the identifier is suppressed
elseif not addit then
end
else
local val = parentArgs[mw.ustring.lower(params[1])] or parentArgs[params[1]]
local val = parentArgs[mw.ustring.lower(params[1])] or parentArgs[params[1]]
if not showb or val == '' then
if val and val~='' then -- add local parameter to list if not already in
tval[params.property] = false -- indicates the identifier is suppressed
localparams = true
auxCats = auxCats .. '[[Category:Articles with suppressed authority control identifiers|'..params[1]..']]'
elseif val then -- add local parameter to list if not already in  
iParentArgs = iParentArgs + 1
local bnew = true
local bnew = true
for _, w in pairs(tval[params.property]) do
for _, w in pairs(tval[params.property]) do
if val == w then
if val == w.id then
bnew = false
bnew = false
end
end
Line 219: Line 320:
qslink = qslink .. '%7C%7C' .. qid .. '%7CP' .. params.property .. '%7C%22' .. mw.uri.encode(val,"PATH") .. '%22%7CS143%7CQ328'
qslink = qslink .. '%7C%7C' .. qid .. '%7CP' .. params.property .. '%7C%22' .. mw.uri.encode(val,"PATH") .. '%22%7CS143%7CQ328'
end
end
table.insert(tval[params.property],val)
table.insert(tval[params.property],{id=val,name=''})
else
iMatches = iMatches+1
end
end
end
end
Line 238: Line 337:
local row = ''
local row = ''
for _,val in ipairs(tval[params.property]) do
for _,val in ipairs(tval[params.property]) do
local link = makelink(params,val,nextIdVal,qid)
local link = _makelink(params,val,nextIdVal,qid)
row = row .. link
row = row .. link
table.insert(tlinks,link)
table.insert(tlinks,link)
Line 246: Line 345:
row = row .. '\n'
row = row .. '\n'
table.insert(sections[addit or params.section],row)
table.insert(sections[addit or params.section],row)
rct = rct + 1
rct = true
end
end
end
end
Line 262: Line 361:
makeSections(qid,false)
makeSections(qid,false)
for c = 1,#qids do
for c = 1,#qids do
makeSections(qids[c],#config.sectionNames+c)
makeSections(qids[c],numsections+c)
end
end


--configure Navbox
--configure Navbox
local outString = ''
local outString = ''
if rct > 0 then -- there is at least one link to display
if rct or localparams then -- there is at least one link to display
local Navbox = require('Module:Navbox')
local Navbox = require('Module:Navbox')
local sect,lastsect = 0,0
local sect,lastsect = 0,0
Line 274: Line 373:
navboxclass = 'authority-control',
navboxclass = 'authority-control',
bodyclass = 'hlist',
bodyclass = 'hlist',
state = parentArgs.state or 'autocollapse',
state = parentArgs.state or config.i18n.autocollapse,
navbar = 'off'
navbar = 'off'
}
}
for c=1,#config.sectionNames+#qids do
for c=1,numsections+#qids do
if #sections[c] ~= 0 then -- section is non-empty
if #sections[c] ~= 0 then -- section is non-empty
sect = sect + 1
sect = sect + 1
lastsect = c
lastsect = c
local sectname
local sectname
if c <= #config.sectionNames then -- regular section
if c <= numsections then -- regular section
sectname = config.sectionNames[c]
sectname = config.sections[c].name
else -- section from additional qid
else -- section from additional qid
sectname = mw.wikibase.getLabel(qids[c-#config.sectionNames]) .. pencil(qids[c-#config.sectionNames])
local qid = qids[c-numsections]
sectname = wikilink(qid) .. pencil(qid)
end
end
navboxArgs['group' .. c] = sectname
navboxArgs['group' .. c] = sectname
Line 291: Line 391:
end
end
end
end
local aclink = '[[Help:Authority control|Authority control]]'
if localparams then
if qslink ~= '' then
lastsect = lastsect + 1
qslink = '<span class="qs autoconfirmed-show">&#32;[[File:Commons to Wikidata QuickStatements.svg|20px|link=https://quickstatements.toolforge.org/#/v1=' .. qslink .. '|Add values to Wikidata.]]</span>'
sect = sect + 1
navboxArgs['group' .. lastsect] = config.i18n.warning
local warning = frame:expandTemplate{title = config.i18n.errortemplate, args = {config.i18n.localparams}}
if qslink ~= '' then
warning = warning .. ' ' .. config.i18n.movetowd .. '<span class="qs autoconfirmed-show">&#32;[[File:Commons to Wikidata QuickStatements.svg|20px|link=https://quickstatements.toolforge.org/#/v1=' .. qslink .. '|' .. config.i18n.addtowd .. ']]</span>'
elseif not qid then
if namespace == 0 then
warning = warning .. ' ' .. config.i18n.connecttowd
elseif namespace==14 or namespace==2 or namespace==118 then
warning = warning .. ' ' .. config.i18n.qidcode
end
end
navboxArgs['list' .. lastsect] = warning
end
end
if sect == 1 then -- special display when only one section
if topic then -- display in expanded form with topic
if lastsect == 1 or lastsect == 8 then -- no special label when only general or other IDs are present
navboxArgs.title = config.i18n.aclink .. ' &ndash; ' .. topic .. pencil(qid)
navboxArgs['group' .. lastsect] = aclink .. pencil(qid) .. qslink
elseif sect == 1 then -- special display when only one section
elseif lastsect <= #config.sectionNames then -- other regular section
if lastsect <= numsections then
navboxArgs['group' .. lastsect] = aclink .. ': ' .. config.sectionNames[lastsect] .. pencil(qid) .. qslink
if config.sections[lastsect].hidelabelwhenalone then -- no special label when only general or other IDs are present
navboxArgs['group' .. lastsect] = config.i18n.aclink .. pencil(qid)
else -- other regular section
navboxArgs['group' .. lastsect] = config.i18n.aclink .. ': ' .. navboxArgs['group' .. lastsect] .. pencil(qid)
end
else -- section from additional qid
else -- section from additional qid
navboxArgs['group' .. lastsect] = aclink .. ': ' .. navboxArgs['group' .. lastsect] .. qslink
navboxArgs['group' .. lastsect] = config.i18n.aclink .. ': ' .. navboxArgs['group' .. lastsect]
end
end
else -- add title to navbox
else -- add title to navbox
navboxArgs.title = aclink .. pencil(qid) .. qslink
navboxArgs.title = config.i18n.aclink .. pencil(qid)
end
end
outString = Navbox._navbox(navboxArgs)
outString = Navbox._navbox(navboxArgs)
end
end


if parentArgs.state then
if parentArgs.state
if namespace == 0 or testcases then
and parentArgs.state~=''
local sCat
and parentArgs.state~=config.i18n.collapsed
if parentArgs.state == 'collapsed' then sCat = 'AC using state parameter: collapsed'
and parentArgs.state~=config.i18n.expanded
elseif parentArgs.state == 'expanded' then sCat = 'AC using state parameter: expanded'
and parentArgs.state~=config.i18n.autocollapse then --invalid state parameter
elseif parentArgs.state == 'autocollapse' then sCat = 'AC using state parameter: autocollapse'
auxCats = auxCats .. needsAttention('S')
else sCat = 'AC using state parameter: other'
end
auxCats = auxCats .. addCat(sCat)
end
end
end
if testcases then
if testcases then
auxCats = mw.ustring.gsub(auxCats, '(%[%[)(Category)', '%1:%2') --for easier checking
auxCats = mw.ustring.gsub(auxCats, '(%[%[)(' .. config.i18n.category .. ')', '%1:%2') --for easier checking
end
end


Line 327: Line 439:
outString = outString..auxCats
outString = outString..auxCats
if namespace ~= 0 then
if namespace ~= 0 then
outString = mw.ustring.gsub(outString,'(%[%[)(Category:Articles)([^%|%]]+)%|?[^%|%]]*(%]%])','%1:%2%3%4')
outString = mw.ustring.gsub(outString,'(%[%[)(' .. config.i18n.category .. ':' .. config.i18n.Articles .. ')([^%|%]]+)%|?[^%|%]]*(%]%])','%1:%2%3%4')
outString = mw.ustring.gsub(outString,'(%[%[)(Category:All articles)([^%|%]]+)%|?[^%|%]]*(%]%])','%1:%2%3%4')
outString = mw.ustring.gsub(outString,'(%[%[)(' .. config.i18n.category .. ':' .. config.i18n.All_articles .. ')([^%|%]]+)%|?[^%|%]]*(%]%])','%1:%2%3%4')
end
end
local check = require('Module:Check for unknown parameters')._check
local check = require('Module:Check for unknown parameters')._check
Line 337: Line 449:
sortkey = title.fullText
sortkey = title.fullText
end
end
local tracking = check({
outString = outString .. check({
['unknown']='[[Category:Pages using authority control with parameters|' .. sortkey .. ']]',
['unknown'] = '[[' .. config.i18n.category .. ':' .. config.i18n.pageswithparams .. '|' .. sortkey .. ']]',
['preview']='Page using [[Template:Authority control]] with "_VALUE_", please move this to Wikidata.',
['preview'] = config.i18n.previewwarning, 'show', 'country', 'suppress', 'additional', 'qid', 'state'
'show', 'country', 'suppress', 'additional', 'qid', 'state'
}, parentArgs)
}, parentArgs)
if namespace == 0 -- mainspace
or namespace == 14 -- category
or namespace == 2 -- user
or namespace == 118 then -- draft
outString = outString .. tracking
end
return outString
return outString
end
end


-- Creates a human-readable standalone wikitable version of conf, and tracking categories with page counts, for use in the documentation
p.makelink = function(conf,val,nextid,qid)
function p.docConfTable(frame)
return _makelink(conf,val,nextid,qid)
local wikiTable = '<table class="wikitable sortable">'..
  '<tr><th>Code</th>'..
  '<th>Identifier</th>'..
  '<th data-sort-type=number>Wikidata property</th>'..
  '<th>Section</th>'..
  '<th>Appears as</th>'..
  '<th>[[:Category:Articles with authority control information|Articles]] ([[:Category:Articles with faulty authority control information|Faults]])</th></tr>'
local columns = 6
local lang = mw.getContentLanguage()
local a, P, f = 0, 0, 0 --cumulative sums
local getlink = require("Module:Wikidata table")._getLink
local function checkcat(category,label)
local ret='[[:Category:'..category..'|'..label..']]'
if mw.title.new(category,14).exists == false then
ret = ret..' <span class="plainlinks" style="font-size:85%;">&#91;['..tostring(mw.uri.fullUrl('Category:'..category,'action=edit&preload=Template:Authority_control/preload'))..' create]&#93;</span>'
end
return ret
end
for _, conf in pairs(config.config) do
local category = conf.category or conf[1]
local articleCat = 'Articles with '..category..' identifiers'
local articleCount = mw.site.stats.pagesInCategory(articleCat,'pages')
local errorCat = conf.errorcat or 'Articles with faulty '..(conf.category or conf[1])..' identifiers'
local errorCount =  mw.site.stats.pagesInCategory(errorCat,'pages')
P = P + 1 --property count
a = a + articleCount
f = f + errorCount
local example = mw.wikibase.getBestStatements('P'..conf.property,'P1855') or ''
if example then
example = example[1].qualifiers['P'..conf.property][1].datavalue.value
example = mw.getCurrentFrame():expandTemplate{title = "Hlist", args = {'\n' .. makelink(conf,example,1)}} .. '\n'
end
local name = mw.wikibase.getBestStatements('P'..conf.property,"P1629")
if name then
if name[1] then
name = name[1].mainsnak.datavalue.value.id
if name then
name = getlink(name)
end
else
name = false
end
end
if conf.remark then
wikiTable = wikiTable..'<tr><td rowspan=2>'
else
wikiTable = wikiTable..'<tr><td>'
end
wikiTable = wikiTable..'[['..(conf.idlink or conf[1]..' (identifier)')..'|'..conf[1]..']]</td>'
wikiTable = wikiTable..'<td>'..(name or '')..'</td>'..
'<td data-sort-value='..conf.property..'>'..frame:expandTemplate{title='Wikidata property link',args={id='f',conf.property}}..'</td>'..
'<td>'..config.sectionNames[conf.section]..'</td>'..
'<td>'..example..'</td>'..
'<td style="text-align: right;">'..checkcat(articleCat,lang:formatNum(articleCount))..' ('..checkcat(errorCat,errorCount)..')</td></tr>'
if conf.remark then
wikiTable = wikiTable.."<tr><td colspan=" .. columns-1 .. ">'''Remarks:''' "..conf.remark.."</td></tr>"
end
end
wikiTable = wikiTable..'<tr><th style="text-align: right;" colspan=' .. columns-2 .. '>Totals</th>'..
'<th style="text-align: right;">'..P..'</th>'..
'<th style="text-align: right;">'..lang:formatNum(a)..' ([[:Category:All articles with faulty authority control information|'..f..']])</th></tr></table>'
return require('Module:Suppress categories').main(wikiTable)
end
 
function p.errorTable(frame)
local Table = '<table class="wikitable sortable">'..
  '<tr><th>Code</th>'..
  '<th>Wikidata property</th>'..
  '<th>Faulty IDs</th>'..
  '<th>[[:Category:Articles with faulty authority control information|Tracking category]]</th></tr>'
local f, P = 0, 0, 0 --cumulative sums
for _, conf in pairs(config.config) do
local category = conf.errorcat or 'Articles with faulty '..(conf.category or conf[1])..' identifiers'
local count =  mw.site.stats.pagesInCategory(category,'pages')
if count > 0 then
P = P + 1
f = f + count
Table = Table..'<tr><th>[['..(conf.idlink or conf[1]..' (identifier)')..'|'..conf[1]..']]</th>'..
'<td>'..frame:expandTemplate{ title = 'Wikidata property link', args = { id = 'f', conf.property } } .. '</td>'..
'<td style="text-align:center;">'..tostring(count)..'</td>'..
'<td>[[:Category:'..category..']]</td></tr>'
end
end
Table = Table..'<tr><th colspan=2 style="text-align: right;">Totals</th>'..
'<th style="text-align:center;">' .. '[[:Category:All articles with faulty authority control information|' .. tostring(f) .. ']]</th>'..
'<th style="text-align:center;">'..tostring(P)..'</th></tr></table>'
return Table
end
 
function p.whitelisttable(frame)
local Table = '<table class="wikitable sortable">'..
  '<tr><th>Code</th>'..
  '<th>Topic</th>'..
  '<th>Identifiers</th></tr>'
for code, wlist in pairs(config.whitelists) do
Table = Table .. '<tr><th>' .. code .. '</th>'..
'<td>[[' .. mw.wikibase.getSitelink('Q' .. wlist.topic) .. ']]</td>'
local plist = {}
for _, property in pairs(wlist.properties) do
table.insert(plist,frame:expandTemplate{title='Wikidata property link', args={'P' .. property}})
end
Table = Table .. '<td>' .. table.concat(plist,', ') .. '</td></tr>'
end
Table = Table .. '</table>'
return Table
end
 
-- Main/External Call for Pages with authority control identifiers
function p.autoDetect( frame )
local function whichTOC( frame ) -- standardize TOC behavior via {{CatAutoTOC}}
return frame:expandTemplate{ title = 'CatAutoTOC', args = { align = 'center' } }
end
local ac_conf = require('Module:Authority control/config').config
local rmCats = require('Module:Suppress categories').main
--For use in [[Category:Articles with faulty authority control information]], i.e. on [[Category:Articles with faulty VIAF identifiers]]
local function wpfaulty( frame, id )
for _, conf in pairs(ac_conf) do
if conf.category == id or conf[1] == id then
local outString = frame:expandTemplate{ title = 'Cat more', args = {'Wikipedia:Authority control', conf.idlink or conf[1]..' (identifier)', ':d:Property:P'..conf.property} }
.. frame:expandTemplate{ title = 'Possibly empty category' }
.. frame:expandTemplate{ title = 'Wikipedia category', args = { hidden = 'yes', tracking = 'yes' } }
.. frame:expandTemplate{ title = 'Polluted category' }
.. whichTOC( frame )
.. '\nPages in this category should only be added by [[Module:Authority control]].'
.. addCat('Articles with '..id..' identifiers')
.. addCat('Articles with faulty authority control information',id)
return outString
end
end
return ''
end
--For use in [[Category:Articles with authority control information]], i.e. on [[Category:Articles with VIAF identifiers]]
local function wp(frame,id )
for _, conf in pairs( ac_conf ) do
if conf.category == id or conf[1] == id then
local link = '[[' .. (conf.idlink or conf[1] .. ' (identifier)') .. '|' .. conf[1] .. ']]'
local outString = frame:expandTemplate{ title = 'Category explanation', args = {'articles with '..link..' identifiers.'..' Please do not add [[Wikipedia:Categorization#Subcategorization|subcategories]].'} }
.. frame:expandTemplate{ title = 'Cat more', args = {'Wikipedia:Authority control', ':d:Property:P'..conf.property} }
.. frame:expandTemplate{ title = 'Possibly empty category' }
.. frame:expandTemplate{ title = 'Wikipedia category', args = { hidden = 'yes', tracking = 'yes' } }
.. whichTOC( frame )
.. '\nPages in this category should only be added by [[Module:Authority control]].'
.. addCat('Articles with authority control information',id)
return outString
end
end
return ''
end
if namespace == 14 then --cat space
local wpfaultyID = mw.ustring.match(title.text, 'Articles with faulty ([%w%.%- ]+) identifiers')
local wpID      = mw.ustring.match(title.text, 'Articles with ([%w%.%- ]+) identifiers')
if wpfaultyID then
return wpfaulty(frame,wpfaultyID)-- must be before wpID check, in case they both match
elseif wpID then
return wp(frame, wpID)-- to keep the regex simple
else
return '[[Category:Pages with authority control identifiers unknown category]]'
end
end
return ''
end
end


return p
return p

Latest revision as of 18:16, 3 January 2024

{{#ifeq:Authority control|doc|{{#if:|Template:Pp}}|{{#switch:

 {{#if:
 |     
 | {{#ifeq:Module|Module
   | module
   | other
   }}
 }}
| module =

| other | #default = Template:Error }}}}

Lua error in Module:Lua_banner at line 112: attempt to index field 'edit' (a nil value). This module contains the code for the {{Authority control}} template.

Please see Template:Authority control/doc.

{{#if:{{#ifeq:Authori|sandbox|1}}{{#ifeq:Authority control|doc|1}}|| }}


require('strict')
local p = {}
local arg = mw.getCurrentFrame().args.config
local configfile = 'Module:Authority control/config' .. (arg and arg~='' and ('/' .. arg) or '')
local config = mw.loadData(configfile)
local title = mw.title.getCurrentTitle()
local namespace = title.namespace
local testcases = title.subpageText == config.i18n.testcases

local function needsAttention(sortkey)
	return '[[' .. config.i18n.category .. ':' .. config.i18n.attentioncat .. '|' .. sortkey .. title.text .. ']]'
end

local function addCat(cat,sortkey)
	if cat and cat ~= '' and (namespace == 0 or namespace == 14 or testcases) then
		local redlinkcat = ''
		if testcases == false then
			local success, exists = pcall(function() return mw.title.new(cat, 14).exists end)
			if success and not exists then 
				redlinkcat = needsAttention('N')
			end
		end
		if sortkey then
			cat = '[[' .. config.i18n.category .. ':'..cat..'|' .. sortkey .. title.text .. ']]'
		else
			cat = '[[' .. config.i18n.category .. ':'..cat..']]'
		end
		cat = cat .. redlinkcat
		return cat
	else
		return ''
	end
end

local function getCatForId(id,faulty)
	local cat = string.format(
		config.i18n.cat,
		(faulty and config.i18n.faulty..' ' or '') .. id
	)
	return addCat(cat)
end

local function getIdsFromWikidata(qid,property)
	local function getquals(statement,qualid)
		if statement.qualifiers and statement.qualifiers['P'..qualid] then
			return mw.wikibase.renderSnak(statement.qualifiers['P'..qualid][1])
		else
			return false
		end
	end
	local ids = {}
	if qid then
		for _, statement in ipairs(mw.wikibase.getBestStatements(qid,property)) do
			if statement.mainsnak.datavalue then
				local val = statement.mainsnak.datavalue.value
				if val then
					local namedas = getquals(statement,1810) or getquals(statement,742) or ''
					table.insert(ids,{id=val,name=namedas})
				end
			end
		end
	end
	return ids
end

local _makelink = function(conf,val,nextid,qid) --validate values and create a link
	local function tooltip(text,label)
		if label and label~='' then
			return mw.getCurrentFrame():expandTemplate{title = "Tooltip", args = {text,label}}
		else
			return text
		end
	end
	local link
	if nextid==1 then
		if conf.prefix then
			link = '*' .. conf.prefix .. '\n**'
		else
			link = '*'
		end
	else
		link = '\n**'
	end
	local valid_value = false
	if conf.customlink then -- use function to validate and generate link
		local label = nextid>1 and nextid
		local newlink= require(config.auxiliary)[conf.customlink](val.id,label)
		if newlink then
			link = link .. newlink
			valid_value = true
		end
	else
		if conf.pattern then -- use pattern to determine validity if defined
			valid_value = string.match(val.id,'^'..conf.pattern..'$')
		elseif conf.patterns then
			for _,pattern in ipairs(conf.patterns) do
				valid_value = val.id:match('^'..pattern..'$')
				if valid_value then break end
			end
		elseif conf.valid then -- otherwise use function to determine validity
			valid_value = require(config.auxiliary)[conf.valid](val.id)
		else -- no validation possible
			valid_value = val.id
		end
		if valid_value then
			local newlink
			local label = conf.label
			if not label or nextid>1 then
				label = tostring(nextid)
			end
			if conf.link then
				valid_value = valid_value:gsub('%%', '%%%%')
				newlink = '[' .. mw.ustring.gsub(conf.link,'%$1',valid_value) .. ' ' .. label .. ']'
			else
				newlink = valid_value
			end
			link = link .. '<span class="uid">'..tooltip(newlink,val.name)..'</span>'
		end
	end
	if valid_value then
		link = link .. getCatForId(conf.category or conf[1])
	else
		--local preview = require("Module:If preview")
		local wdlink = qid and '[[:wikidata:' .. qid .. '#P' .. conf.property .. ']]' or ''
		local tooltip = string.format(
			config.i18n.idnotvalid,
			conf[1],
			val.id
		)
		link = link .. '[[File:' .. config.i18n.warningicon .. '|20px|frameless|link=' .. wdlink .. '|' .. tooltip .. '.]]'
		if conf.errorcat then
			link = link .. addCat(conf.errorcat)
		else
			link = link .. getCatForId(conf.category or conf[1],true)
		end
		link = link .. addCat(config.i18n.allfaultycat,conf[1])-- .. preview._warning({'The '..conf[1]..' id '..val..' is not valid.'})
	end
	return link
end

--[[==========================================================================]]
--[[                                   Main                                   ]]
--[[==========================================================================]]
function p.authorityControl(frame)
	local function resolveQID(qid)
		if qid then
			qid = 'Q'..mw.ustring.gsub(qid, '^[Qq]', '')
			if mw.wikibase.isValidEntityId(qid) and mw.wikibase.entityExists(qid) then
				local sitelink = mw.wikibase.getSitelink(qid)
				if sitelink then
					return mw.wikibase.getEntityIdForTitle(sitelink) or mw.wikibase.getEntity(qid).id
				end
				return mw.wikibase.getEntity(qid).id
			end
		end
	end
	local conf = config.config
	local parentArgs = frame:getParent().args
	local auxCats = ''
	local rct = false -- boolean to track if there are any links to be returned
	local qid,topic
	local wikilink = function(qid,hideifequal)
		local label,sitelink = mw.wikibase.getLabel(qid),mw.wikibase.getSitelink(qid)
		if label then
			if sitelink then
				local target = mw.title.new(sitelink)
				if target==title or (target.isRedirect and target.redirectTarget==title) then -- do not link
					return label
				else -- make wikilink to article
					return '[[' .. sitelink .. '|' .. label .. ']]'
				end
			else
				return label
			end
		else
			auxCats = auxCats .. needsAttention('L')
			return qid
		end
	end
	if namespace == 0 then
		qid = mw.wikibase.getEntityIdForCurrentPage()
	end
	if qid then -- article is connected to Wikidata item
		if parentArgs.qid and (resolveQID(parentArgs.qid) ~= qid) then -- non-matching qid parameter
			auxCats = auxCats .. needsAttention('D')
		end
	else -- page is not connected to any Wikidata item
		qid = resolveQID(parentArgs.qid) -- check qid parameter if no wikidata item is connected
		if qid then -- qid parameter is valid, set topic to display
			topic = mw.wikibase.getLabel(qid)
			if topic then
				if mw.ustring.lower(title.subpageText) == mw.ustring.lower(topic) then -- suppress topic display if subpagename equals topic up to case change
					topic = nil
				end
				if topic and mw.wikibase.getSitelink(qid) then -- make wikilink to article
					topic = '[[' .. mw.wikibase.getSitelink(qid) .. '|' .. topic .. ']]'
				end
			else
				auxCats = auxCats .. needsAttention('L')
			end
		elseif parentArgs.qid and parentArgs.qid~='' then -- invalid qid has been supplied, add to tracking cat
			auxCats = auxCats .. needsAttention('Q')
		end
	end
	local qids = {} -- setup any additional QIDs
	if parentArgs.additional=='auto' and qid then  -- check P527 for parts to add additional qids
		local checkparts = function(property)
			local parts = mw.wikibase.getBestStatements(qid,property)
			if parts then
				for _,part in ipairs(parts) do
					if part.mainsnak.datavalue and part.mainsnak.datavalue.value.id then
						local resolvedqid = resolveQID(part.mainsnak.datavalue.value.id)
						if resolvedqid then
							table.insert(qids,resolvedqid)
		end end end end end
		for _,part in ipairs(config.auto_additional) do
			checkparts('P'..tostring(part))
		end
	elseif parentArgs.additional and parentArgs.additional ~= '' then
		for _,v in ipairs(mw.text.split(parentArgs.additional,"%s*,%s*")) do
			v = resolveQID(v)
			if v then
				if v == qid then -- duplicate of qid parameter
					auxCats = auxCats .. needsAttention('R')
				end
				table.insert(qids,v)
			else -- invalid QID specified
				auxCats = auxCats .. needsAttention('A')
			end
		end
	end

	local sections = {}
	local localparams = false
	local numsections = 0
	for _,_ in ipairs(config.sections) do numsections = numsections + 1 end
	for _ = 1,#qids+numsections do table.insert(sections,{}) end
	local qslink = '' -- setup link to add using QuickStatements

	-- check which identifiers to show/suppress in template
	local show = {} -- setup list
	local showall = true
	local function stripP(pid)
		if pid:match("^[Pp]%d+$") then
			pid = mw.ustring.gsub(pid,'[Pp]','') --strip P from property number
		end
		if pid:match("^%d+$") then
			return tonumber(pid)
		end
	end
	local function addshowlist(list)
		if list and list ~= '' then
			for _,v in ipairs(mw.text.split(string.lower(list),"%s*,%s*")) do
				local vprop = stripP(v)
				if vprop then -- e.g. show=P214 to show one particular property
					show[vprop] = true
				else -- e.g. show=arts to use whitelist
					if config.whitelists[v] then
						for _,w in ipairs(config.whitelists[v].properties) do
							show[w] = true
						end
					end
				end
			end
			showall = false
		end
	end
	addshowlist(frame.args.show) -- check show= parameter on wrapper template
	addshowlist(parentArgs.show or parentArgs.country) -- check show parameter on article template
	if parentArgs.suppress then
		local suppresslist = mw.text.split(parentArgs.suppress,"%s*,%s*") -- split parameter by comma
		for _,v in ipairs(suppresslist) do
			v = stripP(string.upper(v))
			if v then
				show[v] = false
				auxCats = auxCats .. '[[' .. config.i18n.category .. ':' .. config.i18n.suppressedcat .. ']]'
			else
				auxCats = auxCats .. needsAttention('P')
			end
		end
	end
	
	local function makeSections(qid,addit)
		local tval = {}
		local function parameter_is_used(property)
			local used = false
			if property then
				if tval[property] then
					if tval[property][1] then
						used = true
					end
				elseif tval[property] == false then -- property has been manually suppressed
					used = true
				end
			end
			return used
		end
		for _, params in ipairs(conf) do
			tval[params.property] = getIdsFromWikidata(qid, 'P' .. params.property) -- setup table for values with property number as key
			local showb = true
			if (show[params.property] == nil) and (show[string.upper(params[1])] == nil ) then
				showb = showall -- if not specified then depends on showall
			elseif (show[params.property] == false) or (show[string.upper(params[1])] == false) then -- if either are false then id will be suppressed
				showb = false
			end
			if not showb then
				tval[params.property] = false -- indicates the identifier is suppressed
			elseif not addit then
				local val = parentArgs[mw.ustring.lower(params[1])] or parentArgs[params[1]]
				if val and val~='' then -- add local parameter to list if not already in
					localparams = true
					local bnew = true
					for _, w in pairs(tval[params.property]) do
						if val == w.id then
							bnew = false
						end
					end
					if bnew then -- add new value to table
						if qid then
							qslink = qslink .. '%7C%7C' .. qid .. '%7CP' .. params.property .. '%7C%22' .. mw.uri.encode(val,"PATH") .. '%22%7CS143%7CQ328'
						end
						table.insert(tval[params.property],{id=val,name=''})
					end
				end
			end
			local suppress = false
			if params.suppressedbyproperty then
				for _,sc in ipairs(params.suppressedbyproperty) do
					if parameter_is_used(sc) then
						suppress = true
					end
				end
			end
			if tval[params.property] ~= false and not suppress then
				local tlinks = {} -- setup table for links
				local nextIdVal = 1
				local row = ''
				for _,val in ipairs(tval[params.property]) do
					local link = _makelink(params,val,nextIdVal,qid)
					row = row .. link
					table.insert(tlinks,link)
					nextIdVal = nextIdVal + 1
				end
				if nextIdVal>=2 then
					row = row .. '\n'
					table.insert(sections[addit or params.section],row)
					rct = true
				end
			end
		end
	end
	local function pencil(qid)
		if not qid then
			return ''
		end
		local args = { pid = 'identifiers' } -- #target the list of identifiers
		args.qid = qid
		return require('Module:EditAtWikidata')._showMessage(args)
	end

	makeSections(qid,false)
	for c = 1,#qids do
		makeSections(qids[c],numsections+c)
	end

	--configure Navbox
	local outString = ''
	if rct or localparams then -- there is at least one link to display
		local Navbox = require('Module:Navbox')
		local sect,lastsect = 0,0
		local navboxArgs = {
			name  = 'Authority control',
			navboxclass = 'authority-control',
			bodyclass = 'hlist',
			state = parentArgs.state or config.i18n.autocollapse,
			navbar = 'off'
		}
		for c=1,numsections+#qids do
			if #sections[c] ~= 0 then -- section is non-empty
				sect = sect + 1
				lastsect = c
				local sectname
				if c <= numsections then -- regular section
					sectname = config.sections[c].name
				else -- section from additional qid
					local qid = qids[c-numsections]
					sectname = wikilink(qid) .. pencil(qid)
				end
				navboxArgs['group' .. c] = sectname
				navboxArgs['list' .. c] = table.concat(sections[c])
			end
		end
		if localparams then
			lastsect = lastsect + 1
			sect = sect + 1
			navboxArgs['group' .. lastsect] = config.i18n.warning
			local warning = frame:expandTemplate{title = config.i18n.errortemplate, args = {config.i18n.localparams}}
			if qslink ~= '' then
				warning = warning .. ' ' .. config.i18n.movetowd .. '<span class="qs autoconfirmed-show">&#32;[[File:Commons to Wikidata QuickStatements.svg|20px|link=https://quickstatements.toolforge.org/#/v1=' .. qslink .. '|' .. config.i18n.addtowd .. ']]</span>'
			elseif not qid then
				if namespace == 0 then
					warning = warning .. ' ' .. config.i18n.connecttowd
				elseif namespace==14 or namespace==2 or namespace==118 then
					warning = warning .. ' ' .. config.i18n.qidcode
				end
			end
			navboxArgs['list' .. lastsect] = warning
		end
		if topic then -- display in expanded form with topic
			navboxArgs.title = config.i18n.aclink .. ' &ndash; ' .. topic .. pencil(qid)
		elseif sect == 1 then -- special display when only one section
			if lastsect <= numsections then
				if config.sections[lastsect].hidelabelwhenalone then -- no special label when only general or other IDs are present
					navboxArgs['group' .. lastsect] = config.i18n.aclink .. pencil(qid)
				else -- other regular section
					navboxArgs['group' .. lastsect] = config.i18n.aclink .. ': ' .. navboxArgs['group' .. lastsect] .. pencil(qid)
				end
			else -- section from additional qid
				navboxArgs['group' .. lastsect] = config.i18n.aclink .. ': ' .. navboxArgs['group' .. lastsect]
			end
		else -- add title to navbox
			navboxArgs.title = config.i18n.aclink .. pencil(qid)
		end
		outString = Navbox._navbox(navboxArgs)
	end

	if parentArgs.state
		and parentArgs.state~=''
		and parentArgs.state~=config.i18n.collapsed
		and parentArgs.state~=config.i18n.expanded
		and parentArgs.state~=config.i18n.autocollapse then --invalid state parameter
		auxCats = auxCats .. needsAttention('S')
	end
	if testcases then
		auxCats = mw.ustring.gsub(auxCats, '(%[%[)(' .. config.i18n.category .. ')', '%1:%2') --for easier checking
	end

	--out
	outString = outString..auxCats
	if namespace ~= 0 then
		outString = mw.ustring.gsub(outString,'(%[%[)(' .. config.i18n.category .. ':' .. config.i18n.Articles .. ')([^%|%]]+)%|?[^%|%]]*(%]%])','%1:%2%3%4')
		outString = mw.ustring.gsub(outString,'(%[%[)(' .. config.i18n.category .. ':' .. config.i18n.All_articles .. ')([^%|%]]+)%|?[^%|%]]*(%]%])','%1:%2%3%4')
	end
	local check = require('Module:Check for unknown parameters')._check
	local sortkey
	if namespace == 0 then
		sortkey = '*' .. title.text
	else
		sortkey = title.fullText
	end
	outString = outString .. check({
		['unknown'] = '[[' .. config.i18n.category .. ':' .. config.i18n.pageswithparams .. '|' .. sortkey .. ']]',
		['preview'] = config.i18n.previewwarning, 'show', 'country', 'suppress', 'additional', 'qid', 'state'
		}, parentArgs)
	return outString
end

p.makelink = function(conf,val,nextid,qid)
	return _makelink(conf,val,nextid,qid)
end

return p