Modul:Wikidata/ValueComparison

aus Wikipedia, der freien Enzyklopädie
-- local functions
local function compareIdentifiers(params, categories, datatype, entityClaims)
	mw.log('compareIdentifiers(): starting to compare')

-- check whether provided property has correct data type
	if datatype ~= 'external-id' then
		mw.log('compareIdentifiers(): "' .. params['property'] .. '" is not an external-id property')
		return categories
	end

-- check whether any claims of the given property are found in the connected item
	local claims = entityClaims or {}
	local hasProp = claims[params['property']]
	if not hasProp then -- no claim of that property
		mw.log('compareIdentifiers(): connected item does not have a claim with property "' .. params['property'] .. '"')
		if params['localValue'] ~= '' and params['cat_wd_missing'] then
			table.insert(categories, params['cat_wd_missing'])
		end
		return categories
	end

-- claim(s) of that property found, so do the actual value comparison ...
	if type(hasProp) == 'table' and #hasProp == 1 then -- exactly one claim found, so simply process it
		local claim = claims[params['property']][1]
		if (claim.mainsnak.snaktype == 'novalue' or claim.mainsnak.snaktype == 'somevalue') and claim.rank ~= 'deprecated' and params['localValue'] ~= '' then -- Wikidata: novalue or unknown value, but local value given
			mw.log('compareIdentifiers(): novalue/somevalue in Wikidata, custom value locally')
			if params['cat_wd_missing'] then
				table.insert(categories, params['cat_wd_missing'])
			end
			if params['cat_wd_different'] then
				table.insert(categories, params['cat_wd_different'])
			end
			return categories
		end
		if claim.mainsnak.snaktype == 'value' and claim.rank ~= 'deprecated' then -- Wikidata custom value
			mw.log('compareIdentifiers(): custom value in Wikidata')
			if params['localValue'] == '' and params['cat_local_missing'] then -- no local value provided
				table.insert(categories, params['cat_local_missing'])
			elseif params['localValue'] ~= claim.mainsnak.datavalue.value and params['cat_wd_different'] then -- different local value provided
				table.insert(categories, params['cat_wd_different'])
			end
			return categories
		end
	else -- more than one claim found, loop over them
		if params['localValue'] == '' then -- no or empty local value provided
			local throw_wp_missing_cat = true
			for i, claim in ipairs(hasProp) do
				if (claim.mainsnak.snaktype == 'novalue' or claim.mainsnak.snaktype == 'somevalue') and claim.rank ~= 'deprecated' then
					throw_wp_missing_cat = false -- disputable
				end
			end
			if throw_wp_missing_cat and params['cat_local_missing'] then
				mw.log('compareIdentifiers(): local value missing')
				table.insert(categories, params['cat_local_missing'])
			end
			return categories
		else -- custom local value provided
			local throw_wd_missing_cat = true
			local throw_different_value_cat = true
			for i, claim in ipairs(hasProp) do
				if claim.mainsnak.snaktype == 'value' and claim.rank ~= 'deprecated' and claim.mainsnak.datavalue.value == params['localValue'] then
					throw_wd_missing_cat = false
					throw_different_value_cat = false
				end
			end
			mw.log('compareIdentifiers(): custom local value')
			if throw_wd_missing_cat and params['cat_wd_missing'] then
				table.insert(categories, params['cat_wd_missing'])
			end
			if throw_different_value_cat and params['cat_wd_different'] then
				table.insert(categories, params['cat_wd_different'])
			end
			return categories
		end
	end
	return categories
end

local function initParameters(args, parentArgs) -- args is input provided in the template code, parentArgs is input provided in the template transclusion code (usually an article page)
	local params = {}
	
	params['enableComparison'] = parentArgs['wikidata_vergleich'] or nil
	
	params['logic'] = args['logic'] or 'identifiers' -- TODO; this should be "or nil" later
	params['property'] = args['eigenschaft'] or nil
	params['localValue'] = args['lokaler_identifikator'] or ''
	params['namespaces'] = args['namensräume'] or '0'

	params['cat_local_missing'] = args['kat_fehlt_lokal'] or nil -- no equivalent concept in Wikidata
	params['cat_wd_missing'] = args['kat_fehlt_in_wd'] or nil -- conceptually as in Q28858528
	params['cat_wd_different'] = args['kat_wd_verschieden'] or nil -- conceptually as in Q29075121
-- 	params['cat_no_item'] = args['kat_kein_objekt'] or 'Kategorie:Wikipedia:Artikel ohne Wikidata-Datenobjekt' -- better call {{Wikidata-Registrierung}} explicitly in the template
-- 	params['cat_same_value'] = args['kat_gleicher_wert'] or nil -- conceptually as in Q29075123; undesired at dewiki
--	params['cat_using_wd'] = args['kat_nutzt_wd'] or nil -- conceptually as in Q40218570; at dewiki we do not use identifiers directly yet
	
	return params
end

local function makeWikitext(categories)
    local wikitext = ''
    for i, category in ipairs(categories) do
		wikitext = wikitext .. '[[' .. category .. ']]'
	end
    return wikitext
end

-- functions to be exported
local WikidataValueComparison = {}

WikidataValueComparison.MaintenanceCategories = function(params)
	local categories = {}

-- check whether the comparison was suppressed (usually in the template transclusion)
	if params['enableComparison']=='nein' then
		mw.log('WikidataValueComparison.MaintenanceCategories(): comparison disabled via template parameter "wikidata_vergleich"')
		return categories
	end

-- check if local namespace of transcluding page is in list of approved namespaces
	local namespaceOk = false
	local ns = mw.title.getCurrentTitle().namespace
	for v in mw.text.gsplit(params['namespaces'] or '0', ',', true) do
		if tonumber(v) == ns then
			namespaceOk = true
		end
	end
	if not namespaceOk then -- skip comparison if not in approved namespace
		mw.log('WikidataValueComparison.MaintenanceCategories(): wrong namespace')
		return categories
	end

-- check whether the article is connected to Wikidata
	local entity = mw.wikibase.getEntity()
	if not entity then -- skip comparison if unconnected
		mw.log('WikidataValueComparison.MaintenanceCategories(): no Wikidata item connected')
		if params['cat_no_item'] then
			table.insert(categories, params['cat_no_item'])
		end
		return categories
	end

-- check whether the provided P-identifier is useful (provided, valid format, existent in repository, and of 'external-id' datatype)
	if not params['property'] then
		mw.log('WikidataValueComparison.MaintenanceCategories(): no P-identifier provided')
		return categories
	end
	
	if not string.match(params['property'], '^P[1-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?$') then -- P-identifiers with more than 9 digits are generally not recognized by the system
		mw.log('WikidataValueComparison.MaintenanceCategories(): invalid P-identifier "' .. params['property'] ..'" provided')
		return categories
	end

	if mw.wikibase.entityExists(params['property']) then -- attention: https://phabricator.wikimedia.org/T143970 https://phabricator.wikimedia.org/T192462
		propObject = mw.wikibase.getEntity(params['property'])
	else
		mw.log('WikidataValueComparison.MaintenanceCategories(): invalid/non-existent property "' .. params['property'] .. '"')
		return categories
	end
	
	-- at this point, the generic checks are finished and we have "categories={}", a "propObject" (with field "datatype") and an "entity" (with field "claims") variable; from here, everything else is data type dependent
	if params['logic'] == 'identifiers' then
		local success, categories = pcall(compareIdentifiers, params, categories, propObject.datatype, entity.claims)
		if success then
			mw.log('WikidataValueComparison.MaintenanceCategories(): finished to compare')
			return categories
		else
			mw.log('WikidataValueComparison.MaintenanceCategories(): error while comparing: ' .. categories)
			return categories
		end
	end
	mw.log('Logic: "' .. params['logic'] .. '"')
	
	if next(categories) == nil then -- check if categories table is empty
		mw.log('WikidataValueComparison.MaintenanceCategories(): value comparison successful, but nothing to categorize')
	end
	return categories
end --WikidataValueComparison.MaintenanceCategories()

-- export
local p = {}

function p.compareValues(frame)
	local success, params = pcall(initParameters, frame.args, frame:getParent().args)
	
	local success, categories = pcall(WikidataValueComparison['MaintenanceCategories'], params)
	
	local success, wikitext = pcall(makeWikitext, categories)
	return wikitext or ''
end --p.compareValues()

function p.WikidataValueComparison() -- export for use in other modules
	return WikidataValueComparison
end

return p