Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions lua/definitions/mw.lua
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,21 @@ function mw.language:formatDate(format, timestamp, localTime)
return day or ''
end
return os.date(outFormat, ostimeWrapper(timestamp)) --[[@as string]]
elseif format == 'Y-m-d' then
if not timestamp then
return os.date('!%Y-%m-%d') --[[@as string]]
end
if type(timestamp) == 'string' and string.sub(timestamp, 1, 1) == '@' then
local seconds = tonumber(string.sub(timestamp, 2))
if not seconds then return '' end
return os.date('!%Y-%m-%d', seconds) --[[@as string]]
end
if type(timestamp) == 'string' then
local year, month, day = parseDateString(timestamp)
if not year then return '' end
return year .. '-' .. month .. '-' .. day
end
return os.date('!%Y-%m-%d', ostimeWrapper(timestamp)) --[[@as string]]
end
return ''
end
Expand Down
Binary file modified lua/spec/snapshots/dota2 rankings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
335 changes: 335 additions & 0 deletions lua/spec/team_participants_dates_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,335 @@
--- Triple Comment to Enable our LLS Plugin
describe('TeamParticipants player dates', function()
local TeamParticipantsRepository
local Variables
local PageVariableNamespace
local LpdbQuery

before_each(function()
Variables = require('Module:Variables')
Variables.varDefine('tournament_startdate', '2024-01-01')
Variables.varDefine('tournament_enddate', '2024-12-31')
PageVariableNamespace = require('Module:PageVariableNamespace')
TeamParticipantsRepository = require('Module:TeamParticipants/Repository')
LpdbQuery = stub(mw.ext.LiquipediaDB, 'lpdb', function() return {} end)
end)

after_each(function()
LpdbQuery:revert()
Variables.varDefine('tournament_startdate')
Variables.varDefine('tournament_enddate')
end)

describe('getPlayersDates', function()
it('skips players with no pageName or TBD without querying', function()
local result = TeamParticipantsRepository.getPlayersDates(
{
{pageName = nil, extradata = {}},
{pageName = 'TBD', extradata = {}},
},
{'Team Liquid'}
)
assert.are_same({}, result)
assert.stub(LpdbQuery).called(0)
end)

it('returns explicit dates without querying LPDB when both are set for all players', function()
local result = TeamParticipantsRepository.getPlayersDates(
{
{pageName = 'Alexis', extradata = {joinDate = '2024-03-01', leaveDate = '2024-09-01'}},
},
{'Team Liquid'}
)
assert.are_equal('2024-03-01', result['Alexis'].joinDate)
assert.are_equal('2024-09-01', result['Alexis'].leaveDate)
assert.stub(LpdbQuery).called(0)
end)

it('fetches joinDate from active transfer for active player', function()
LpdbQuery:revert()
LpdbQuery = stub(mw.ext.LiquipediaDB, 'lpdb', function()
return {{date = '2024-03-15', player = 'Alexis'}}
end)

local result = TeamParticipantsRepository.getPlayersDates(
{{pageName = 'Alexis', extradata = {}}},
{'Team Liquid'}
)
assert.are_equal('2024-03-15', result['Alexis'].joinDate)
assert.is_nil(result['Alexis'].leaveDate)
end)

it('falls back to activeAlt when active query returns nothing', function()
local callCount = 0
LpdbQuery:revert()
LpdbQuery = stub(mw.ext.LiquipediaDB, 'lpdb', function()
callCount = callCount + 1
if callCount == 2 then
return {{date = '2024-04-01', player = 'Alexis'}}
end
return {}
end)

local result = TeamParticipantsRepository.getPlayersDates(
{{pageName = 'Alexis', extradata = {}}},
{'Team Liquid'}
)
assert.are_equal('2024-04-01', result['Alexis'].joinDate)
assert.are_equal(2, callCount)
end)

it('fetches joinDate and leaveDate for former player', function()
local callCount = 0
LpdbQuery:revert()
LpdbQuery = stub(mw.ext.LiquipediaDB, 'lpdb', function()
callCount = callCount + 1
if callCount == 1 then
return {{date = '2024-02-01', player = 'Alexis'}} -- active → joinDate
elseif callCount == 3 then
return {{date = '2024-08-15', player = 'Alexis'}} -- former → leaveDate
end
return {}
end)

local result = TeamParticipantsRepository.getPlayersDates(
{{pageName = 'Alexis', extradata = {status = 'former'}}},
{'Team Liquid'}
)
assert.are_equal('2024-02-01', result['Alexis'].joinDate)
assert.are_equal('2024-08-15', result['Alexis'].leaveDate)
end)

it('falls back to inactive query when former returns nothing for former player', function()
local callCount = 0
LpdbQuery:revert()
LpdbQuery = stub(mw.ext.LiquipediaDB, 'lpdb', function()
callCount = callCount + 1
if callCount == 4 then
return {{date = '2024-09-30', player = 'Alexis'}} -- inactive → leaveDate
end
return {}
end)

local result = TeamParticipantsRepository.getPlayersDates(
{{pageName = 'Alexis', extradata = {status = 'former'}}},
{'Team Liquid'}
)
assert.is_nil(result['Alexis'].joinDate)
assert.are_equal('2024-09-30', result['Alexis'].leaveDate)
assert.are_equal(4, callCount) -- active, activeAlt, former, inactive
end)

it('explicit joinDate takes precedence over LPDB result', function()
LpdbQuery:revert()
LpdbQuery = stub(mw.ext.LiquipediaDB, 'lpdb', function()
return {{date = '2024-03-15', player = 'Alexis'}}
end)

local result = TeamParticipantsRepository.getPlayersDates(
{{pageName = 'Alexis', extradata = {joinDate = '2023-01-01'}}},
{'Team Liquid'}
)
assert.are_equal('2023-01-01', result['Alexis'].joinDate)
end)

it('queries against the team-template columns, not display-name columns', function()
local capturedConditions
LpdbQuery:revert()
LpdbQuery = stub(mw.ext.LiquipediaDB, 'lpdb', function(_, options)
capturedConditions = options.conditions
return {}
end)

TeamParticipantsRepository.getPlayersDates(
{{pageName = 'Alexis', extradata = {}}},
{'team liquid'}
)

assert.is_truthy(capturedConditions:find('toteamtemplate', 1, true))
assert.is_truthy(capturedConditions:find('fromteamtemplate', 1, true))
assert.is_nil(capturedConditions:find('[[toteam::', 1, true))
assert.is_nil(capturedConditions:find('[[fromteam::', 1, true))
end)

it('batches multiple players into a single query per status', function()
local callCount = 0
local capturedConditions = {}
LpdbQuery:revert()
LpdbQuery = stub(mw.ext.LiquipediaDB, 'lpdb', function(_, options)
callCount = callCount + 1
table.insert(capturedConditions, options.conditions)
if callCount == 1 then
return {{date = '2024-03-15', player = 'Alexis'}}
elseif callCount == 2 then
return {{date = '2024-04-20', player = 'Bob'}}
end
return {}
end)

local result = TeamParticipantsRepository.getPlayersDates(
{
{pageName = 'Alexis', extradata = {}},
{pageName = 'Bob', extradata = {}},
},
{'Team Liquid'}
)

assert.are_equal('2024-03-15', result['Alexis'].joinDate)
assert.are_equal('2024-04-20', result['Bob'].joinDate)
-- 2 queries total (active + activeAlt) for 2 players, not 4 (one per player per status)
assert.are_equal(2, callCount)
assert.is_truthy(capturedConditions[1]:find('Alexis', 1, true))
assert.is_truthy(capturedConditions[1]:find('Bob', 1, true))
-- Second query (activeAlt) should only ask about Bob since Alexis already resolved
assert.is_nil(capturedConditions[2]:find('"Alexis"', 1, true))
assert.is_truthy(capturedConditions[2]:find('Bob', 1, true))
end)

it('picks the latest transfer per player when multiple rows are returned', function()
LpdbQuery:revert()
LpdbQuery = stub(mw.ext.LiquipediaDB, 'lpdb', function()
return {
{date = '2024-05-01', player = 'Alexis'},
{date = '2024-03-01', player = 'Alexis'},
{date = '2024-04-01', player = 'Bob'},
}
end)

local result = TeamParticipantsRepository.getPlayersDates(
{
{pageName = 'Alexis', extradata = {}},
{pageName = 'Bob', extradata = {}},
},
{'Team Liquid'}
)
assert.are_equal('2024-05-01', result['Alexis'].joinDate)
assert.are_equal('2024-04-01', result['Bob'].joinDate)
end)

it('matches transfers under either underscore or space variant of the page name', function()
LpdbQuery:revert()
LpdbQuery = stub(mw.ext.LiquipediaDB, 'lpdb', function()
return {{date = '2024-06-01', player = 'Some Player'}}
end)

local result = TeamParticipantsRepository.getPlayersDates(
{{pageName = 'Some_Player', extradata = {}}},
{'Team Liquid'}
)
assert.are_equal('2024-06-01', result['Some_Player'].joinDate)
end)

it('only queries former/inactive for players whose status is former', function()
local capturedConditions = {}
LpdbQuery:revert()
LpdbQuery = stub(mw.ext.LiquipediaDB, 'lpdb', function(_, options)
table.insert(capturedConditions, options.conditions)
return {}
end)

TeamParticipantsRepository.getPlayersDates(
{
{pageName = 'Active', extradata = {}},
{pageName = 'Former', extradata = {status = 'former'}},
},
{'Team Liquid'}
)

-- 4 calls total: active, activeAlt (both players), former, inactive (only former player)
assert.are_equal(4, #capturedConditions)
assert.is_truthy(capturedConditions[1]:find('Active', 1, true))
assert.is_truthy(capturedConditions[1]:find('Former', 1, true))
-- Latter two queries should only mention 'Former'
assert.is_nil(capturedConditions[3]:find('"Active"', 1, true))
assert.is_truthy(capturedConditions[3]:find('Former', 1, true))
end)
end)

describe('setPageVars', function()
it('writes joindate and leavedate to global vars under team prefixes', function()
local TeamTemplateMock = require('wikis.commons.Mock.TeamTemplate')
TeamTemplateMock.setUp()
local globalVars = PageVariableNamespace()

TeamParticipantsRepository.setPageVars({
aliases = {'team liquid'},
opponent = {
players = {{
pageName = 'Alexis',
flag = 'us',
displayName = 'alexis',
faction = nil,
apiId = nil,
extradata = {
type = 'player',
joinDate = '2024-03-15',
leaveDate = nil,
},
}},
},
})

assert.are_equal('2024-03-15', globalVars:get('Team Liquid_p1joindate'))
assert.is_nil(globalVars:get('Team Liquid_p1leavedate'))
TeamTemplateMock.tearDown()
end)

it('writes both joindate and leavedate for former player', function()
local TeamTemplateMock = require('wikis.commons.Mock.TeamTemplate')
TeamTemplateMock.setUp()
local globalVars = PageVariableNamespace()

TeamParticipantsRepository.setPageVars({
aliases = {'team liquid'},
opponent = {
players = {{
pageName = 'Alexis',
flag = 'us',
displayName = 'alexis',
faction = nil,
apiId = nil,
extradata = {
type = 'player',
status = 'former',
joinDate = '2024-02-01',
leaveDate = '2024-08-15',
},
}},
},
})

assert.are_equal('2024-02-01', globalVars:get('Team Liquid_p1joindate'))
assert.are_equal('2024-08-15', globalVars:get('Team Liquid_p1leavedate'))
TeamTemplateMock.tearDown()
end)
end)

describe('parsePlayer date input', function()
it('stores explicit joindate from wiki input in extradata', function()
local TeamParticipantsWikiParser = require('Module:TeamParticipants/Parse/Wiki')
local player = TeamParticipantsWikiParser.parsePlayer{'Alexis', joindate = '2024-03-01'}
assert.are_equal('2024-03-01', player.extradata.joinDate)
assert.is_nil(player.extradata.leaveDate)
end)

it('stores explicit leavedate from wiki input in extradata', function()
local TeamParticipantsWikiParser = require('Module:TeamParticipants/Parse/Wiki')
local player = TeamParticipantsWikiParser.parsePlayer{'Alexis', leavedate = '2024-09-01'}
assert.is_nil(player.extradata.joinDate)
assert.are_equal('2024-09-01', player.extradata.leaveDate)
end)

it('stores nothing for missing date input', function()
local TeamParticipantsWikiParser = require('Module:TeamParticipants/Parse/Wiki')
local player = TeamParticipantsWikiParser.parsePlayer{'Alexis'}
assert.is_nil(player.extradata.joinDate)
assert.is_nil(player.extradata.leaveDate)
end)

it('treats empty string date input as nil', function()
local TeamParticipantsWikiParser = require('Module:TeamParticipants/Parse/Wiki')
local player = TeamParticipantsWikiParser.parsePlayer{'Alexis', joindate = ''}
assert.is_nil(player.extradata.joinDate)
end)
end)
end)
17 changes: 17 additions & 0 deletions lua/wikis/commons/TeamParticipants/Controller.lua
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ function TeamParticipantsController.fromTemplate(frame)
local parsedData = TeamParticipantsWikiParser.parseWikiInput(parsedArgs)
TeamParticipantsController.importParticipants(parsedData)
TeamParticipantsController.fillIncompleteRosters(parsedData)
TeamParticipantsController.enrichPlayerDates(parsedData)

local shouldStore = Logic.readBoolOrNil(args.store) ~= false and Lpdb.isStorageEnabled()

Expand Down Expand Up @@ -142,6 +143,22 @@ function TeamParticipantsController.mergeManualAndImportedPlayers(manualPlayers,
end)
end

--- Enriches each player with join/leave dates from the transfer LPDB table.
--- Explicit dates from wiki input take precedence over auto-fetched ones.
---@param parsedData {participants: TeamParticipant[], expectedPlayerCount: integer?}
function TeamParticipantsController.enrichPlayerDates(parsedData)
Array.forEach(parsedData.participants, function(participant)
local players = participant.opponent.players or {}
local datesByPlayer = TeamParticipantsRepository.getPlayersDates(players, participant.aliases)
Array.forEach(players, function(player)
local dates = datesByPlayer[player.pageName] or {}
player.extradata = player.extradata or {}
player.extradata.joinDate = dates.joinDate
player.extradata.leaveDate = dates.leaveDate
end)
Comment thread
Eetwalt marked this conversation as resolved.
end)
end

--- Fills incomplete rosters for all participants with TBD players if needed.
--- May mutate the input.
---@param parsedData {participants: TeamParticipant[], expectedPlayerCount: integer?}
Expand Down
2 changes: 2 additions & 0 deletions lua/wikis/commons/TeamParticipants/Parse/Wiki.lua
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ function TeamParticipantsWikiParser.parsePlayer(playerInput)
played = Logic.nilOr(playedInput, true),
results = Logic.nilOr(resultsInput, playedInput, true),
number = tonumber(playerInput.number),
joinDate = Logic.nilIfEmpty(playerInput.joindate),
leaveDate = Logic.nilIfEmpty(playerInput.leavedate),
}
return player
end
Expand Down
Loading
Loading