Skip to content

Commit

Permalink
Use cds id as key for groups
Browse files Browse the repository at this point in the history
  • Loading branch information
kunyavskiy committed Sep 25, 2023
1 parent 3888e31 commit 745be02
Show file tree
Hide file tree
Showing 20 changed files with 1,236 additions and 477 deletions.
17 changes: 13 additions & 4 deletions schemas/advanced.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -286,14 +286,20 @@
}
}
},
"org.icpclive.api.tunning.GroupInfoOverride<kotlin.Boolean?,kotlin.Boolean?>": {
"org.icpclive.api.tunning.GroupInfoOverride<kotlin.String?,kotlin.Boolean?,kotlin.Boolean?,kotlin.Boolean?>": {
"type": "object",
"properties": {
"displayName": {
"type": "string"
},
"isHidden": {
"type": "boolean"
},
"isOutOfContest": {
"type": "boolean"
},
"awardsGroupChampion": {
"type": "boolean"
}
},
"additionalProperties": false,
Expand All @@ -304,18 +310,21 @@
"type": "object",
"patternProperties": {
".*": {
"$ref": "#/$defs/org.icpclive.api.tunning.GroupInfoOverride<kotlin.Boolean?,kotlin.Boolean?>"
"$ref": "#/$defs/org.icpclive.api.tunning.GroupInfoOverride<kotlin.String?,kotlin.Boolean?,kotlin.Boolean?,kotlin.Boolean?>"
}
}
},
"org.icpclive.api.tunning.OrganizationInfoOverride<kotlin.String?,kotlin.String?>": {
"org.icpclive.api.tunning.OrganizationInfoOverride<kotlin.String?,kotlin.String?,org.icpclive.api.MediaType?>": {
"type": "object",
"properties": {
"displayName": {
"type": "string"
},
"fullName": {
"type": "string"
},
"logo": {
"$ref": "#/$defs/org.icpclive.api.MediaType?<kotlin.String,kotlinx.serialization.Sealed<MediaType>>"
}
},
"additionalProperties": false,
Expand All @@ -326,7 +335,7 @@
"type": "object",
"patternProperties": {
".*": {
"$ref": "#/$defs/org.icpclive.api.tunning.OrganizationInfoOverride<kotlin.String?,kotlin.String?>"
"$ref": "#/$defs/org.icpclive.api.tunning.OrganizationInfoOverride<kotlin.String?,kotlin.String?,org.icpclive.api.MediaType?>"
}
}
},
Expand Down
8 changes: 7 additions & 1 deletion src/backend/src/main/kotlin/org/icpclive/admin/Info.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package org.icpclive.admin

import kotlinx.coroutines.flow.first
import org.icpclive.api.GroupInfo
import org.icpclive.api.InefficientContestInfoApi
import org.icpclive.data.DataBus

@OptIn(InefficientContestInfoApi::class)
suspend fun getTeams() = DataBus.contestInfoFlow.await().first().teamList.filterNot { it.isHidden }

suspend fun getRegions() = getTeams().flatMap { it.groups }.distinct().sorted()
@OptIn(InefficientContestInfoApi::class)
suspend fun getRegions() : List<GroupInfo> {
val info = DataBus.contestInfoFlow.await().first()
val used = info.teamList.flatMap { it.groups }.toSet()
return info.groupList.filter { it.cdsId in used }
}

suspend fun getHashtags() = getTeams().filter { it.hashTag != null }.associateBy({ it.hashTag!! }, { it.id })
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ object Controllers {
val ticker = SingleWidgetController(TickerSettings(), WidgetManager, ::TickerWidget)
val scoreboard = SingleWidgetController(ScoreboardSettings(), WidgetManager, ::ScoreboardWidget)
val fullScreenClock = SingleWidgetController(FullScreenClockSettings(), WidgetManager, ::FullScreenClockWidget)
private val teamViews = TeamViewPosition.values().asList().associateWith { TeamViewController(WidgetManager, it) }
private val teamViews = TeamViewPosition.entries.associateWith { TeamViewController(WidgetManager, it) }
fun teamView(position: TeamViewPosition): TeamViewController = teamViews[position]!!

val locator = LocatorWidgetController(WidgetManager)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,36 @@ private fun ProblemInfo.toClicsProblem() = Problem(
)

private fun GroupInfo.toClicsGroup() = Group(
id = name,
name = name,
id = cdsId,
name = displayName,
)

private fun OrganizationInfo.toClicsOrg() = Organization(
id = cdsId,
name = displayName,
formal_name = fullName,
logo = listOfNotNull(logo?.toClicsMedia())
)

private fun MediaType.toClicsMedia() = when (this) {
is MediaType.Object -> null
is MediaType.Photo -> Media("image", url)
is MediaType.TaskStatus -> null
is MediaType.Video -> Media("video", url)
is MediaType.WebRTCGrabberConnection -> null
is MediaType.WebRTCProxyConnection -> null
}

private fun TeamInfo.toClicsTeam() = Team(
id = contestSystemId,
name = fullName,
hidden = isHidden,
group_ids = groups,
organization_id = organizationId
organization_id = organizationId,
photo = listOfNotNull(medias[TeamMediaType.PHOTO]?.toClicsMedia()),
video = listOfNotNull(medias[TeamMediaType.RECORD]?.toClicsMedia()),
desktop = listOfNotNull(medias[TeamMediaType.SCREEN]?.toClicsMedia()),
webcam = listOfNotNull(medias[TeamMediaType.CAMERA]?.toClicsMedia()),
)


Expand Down Expand Up @@ -256,12 +270,12 @@ object ClicsExporter {
}
}
diff(problemsMap, newInfo.problemList, ProblemInfo::contestSystemId, ProblemInfo::toClicsProblem, Event::ProblemEvent)
diffChange(groupsMap, newInfo.groupList, GroupInfo::name, GroupInfo::toClicsGroup, Event::GroupsEvent)
diffChange(groupsMap, newInfo.groupList, GroupInfo::cdsId, GroupInfo::toClicsGroup, Event::GroupsEvent)
diffChange(orgsMap, newInfo.organizationList, OrganizationInfo::cdsId, OrganizationInfo::toClicsOrg, Event::OrganizationEvent)

diff(teamsMap, newInfo.teamList, TeamInfo::contestSystemId, TeamInfo::toClicsTeam, Event::TeamEvent)

diffRemove(groupsMap, newInfo.groupList, GroupInfo::name, Event::GroupsEvent)
diffRemove(groupsMap, newInfo.groupList, GroupInfo::cdsId, Event::GroupsEvent)
diffRemove(orgsMap, newInfo.organizationList, OrganizationInfo::cdsId, Event::OrganizationEvent)
}

Expand Down Expand Up @@ -470,7 +484,7 @@ object ClicsExporter {
for ((award, teams) in scoreboardSnapshot.awards) {
val (id, citation) = when (award) {
is org.icpclive.api.Award.Medal -> "${award.medalType}-medal" to "${award.medalType.replaceFirstChar { it.uppercase() }} medal"
is org.icpclive.api.Award.GroupChampion -> "group-winner-${award.group}" to "${info.groups[award.group]!!.name} champion"
is org.icpclive.api.Award.GroupChampion -> "group-winner-${award.group}" to "${info.groups[award.group]!!.displayName} champion"
is org.icpclive.api.Award.Winner -> "Winner" to "${info.name} champion"
}
add(Award(id, citation, teams.map { info.teams[it]!!.contestSystemId }))
Expand Down
6 changes: 4 additions & 2 deletions src/cds/src/main/kotlin/org/icpclive/api/ContestInfo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ public data class TeamInfo(

@Serializable
public data class GroupInfo(
val name: String,
val cdsId: String,
val displayName: String,
val isHidden: Boolean,
val isOutOfContest: Boolean,
val awardsGroupChampion: Boolean = !isHidden,
Expand All @@ -191,6 +192,7 @@ public data class OrganizationInfo(
val cdsId: String,
val displayName: String,
val fullName: String,
val logo: MediaType?,
)

@Serializable
Expand Down Expand Up @@ -266,7 +268,7 @@ public data class ContestInfo(
ContestStatus.RUNNING -> (Clock.System.now() - startTime) * emulationSpeed
ContestStatus.OVER, ContestStatus.FINALIZED -> contestLength
}
val groups: Map<String, GroupInfo> by lazy { groupList.associateBy { it.name } }
val groups: Map<String, GroupInfo> by lazy { groupList.associateBy { it.cdsId } }
val teams: Map<Int, TeamInfo> by lazy { teamList.associateBy { it.id } }
val cdsTeams: Map<String, TeamInfo> by lazy { teamList.associateBy { it.contestSystemId } }
val organizations: Map<String, OrganizationInfo> by lazy { organizationList.associateBy { it.cdsId } }
Expand Down
24 changes: 19 additions & 5 deletions src/cds/src/main/kotlin/org/icpclive/api/tunning/Advanced.kt
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,17 @@ public data class ProblemInfoOverride(
)

/**
* @param displayName Name of the group to be displayed in admin and export
* @param isHidden Totally hide all teams from this group
* @param isOutOfContest Teams from this group will be visible everywhere, but will not have any rank assigned to them in the leaderboard
* @param awardsGroupChampion If true, the group champion award would be generated for this group.
*/
@Serializable
public data class GroupInfoOverride(
val displayName: String? = null,
val isHidden: Boolean? = null,
val isOutOfContest: Boolean? = null
val isOutOfContest: Boolean? = null,
val awardsGroupChampion: Boolean? = null
)

/**
Expand All @@ -79,10 +83,17 @@ public data class RankingSettings(
public val penaltyRoundingMode: PenaltyRoundingMode? = null
)


/**
* @param displayName Name of the team shown in most places.
* @param fullName Full name of the organization. Will be mostly shown on admin pages.
* @param logo Organization logo. Not displayed anywhere for now, but can be exported to e.g., icpc resolved.
*/
@Serializable
public data class OrganizationInfoOverride(
val displayName: String? = null,
val fullName: String? = null
val fullName: String? = null,
val logo: MediaType? = null
)

/**
Expand Down Expand Up @@ -221,15 +232,18 @@ public fun ContestInfo.toAdvancedProperties(fields: Set<String>) : AdvancedPrope
)
},
groupOverrides = groupList.associate {
it.name to GroupInfoOverride(
it.cdsId to GroupInfoOverride(
displayName = it.displayName.takeIfAsked("groupDisplayName"),
isHidden = it.isHidden.takeIfAsked("isHidden"),
isOutOfContest = it.isOutOfContest.takeIfAsked("isOutOfContest")
isOutOfContest = it.isOutOfContest.takeIfAsked("isOutOfContest"),
awardsGroupChampion = it.awardsGroupChampion.takeIfAsked("awardGroupChampion")
)
},
organizationOverrides = organizationList.associate {
it.cdsId to OrganizationInfoOverride(
displayName = it.displayName.takeIfAsked("orgDisplayName"),
fullName = it.fullName.takeIfAsked("orgFullName")
fullName = it.fullName.takeIfAsked("orgFullName"),
logo = it.logo.takeIfAsked("logo")
)
},
scoreboardOverrides = RankingSettings(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,11 @@ internal fun applyAdvancedProperties(
override.groups?.let { addAll(it) }
}
for (group in info.groupList) {
remove(group.name)
remove(group.cdsId)
}
}
val groups = mergeGroups(
info.groupList + newGroups.map { GroupInfo(it, isHidden = false, isOutOfContest = false) },
info.groupList + newGroups.map { GroupInfo(it, it, isHidden = false, isOutOfContest = false) },
overrides.groupOverrides
)
val newOrganizations = buildSet {
Expand All @@ -222,7 +222,7 @@ internal fun applyAdvancedProperties(
}
}
val organizations = mergeOrganizations(
info.organizationList + newOrganizations.map { OrganizationInfo(it, it, it) },
info.organizationList + newOrganizations.map { OrganizationInfo(it, it, it, null) },
overrides.organizationOverrides
)

Expand Down Expand Up @@ -278,6 +278,7 @@ private fun mergeOrganizations(
cdsId = org.cdsId,
displayName = override.displayName ?: org.displayName,
fullName = override.fullName ?: org.fullName,
logo = override.logo ?: org.logo
)
}

Expand All @@ -287,13 +288,15 @@ private fun mergeGroups(
) = mergeOverrides(
groups,
overrides,
GroupInfo::name,
GroupInfo::cdsId,
unusedMessage = { "No group for override: $it" }
) { group, override ->
GroupInfo(
name = group.name,
cdsId = group.cdsId,
displayName = override.displayName ?: group.displayName,
isHidden = override.isHidden ?: group.isHidden,
isOutOfContest = override.isOutOfContest ?: group.isOutOfContest
isOutOfContest = override.isOutOfContest ?: group.isOutOfContest,
awardsGroupChampion = override.awardsGroupChampion ?: group.awardsGroupChampion
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ internal class CATSDataSource(val settings: CatsSettings) : FullReloadContestDat
fullName = team.name,
displayName = team.name,
contestSystemId = team.account_id.toString(),
groups = listOf(),
groups = emptyList(),
hashTag = null,
medias = mapOf(),
isHidden = false,
Expand Down
7 changes: 4 additions & 3 deletions src/cds/src/main/kotlin/org/icpclive/cds/clics/ClicsModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ internal class ClicsModel(
return null
}

private fun Group.toApi() : GroupInfo = GroupInfo(name, isHidden = false, isOutOfContest = false)
private fun Group.toApi() : GroupInfo = GroupInfo(id, name, isHidden = false, isOutOfContest = false, awardsGroupChampion = true)

private fun Team.toApi(): TeamInfo {
val teamOrganization = organization_id?.let { organisations[it] }
Expand All @@ -61,7 +61,7 @@ internal class ClicsModel(
displayName = teamName(teamOrganization?.name, name),
contestSystemId = id,
isHidden = hidden,
groups = group_ids.mapNotNull { groups[it]?.name },
groups = group_ids.mapNotNull { groups[it]?.id },
hashTag = teamOrganization?.hashtag,
medias = buildMap {
photo.firstOrNull()?.mediaType()?.let { put(TeamMediaType.PHOTO, it) }
Expand Down Expand Up @@ -90,6 +90,7 @@ internal class ClicsModel(
cdsId = id,
displayName = name,
fullName = formalName,
logo = logo
)

val contestInfo: ContestInfo
Expand Down Expand Up @@ -139,7 +140,7 @@ internal class ClicsModel(
id = organization.id,
name = organization.name,
formalName = organization.formal_name ?: organization.name,
logo = organization.logo.lastOrNull()?.href?.let { it },
logo = organization.logo.lastOrNull()?.mediaType(),
hashtag = organization.twitter_hashtag,
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.icpclive.cds.clics.model

import org.icpclive.api.MediaType

internal data class ClicsOrganisationInfo(
val id: String,
val name: String,
val formalName: String,
val logo: String?,
val logo: MediaType?,
val hashtag: String?
)
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ internal class CmsDataSource(val settings: CmsSettings) : FullReloadContestDataS
OrganizationInfo(
cdsId = k,
displayName = v.name,
fullName = v.name
fullName = v.name,
logo = MediaType.Photo(settings.url)
)
}
val teams = usersLoader.load().map {(k, v) ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ internal class EjudgeDataSource(val settings: EjudgeSettings) : FullReloadContes
fullName = participantName,
displayName = participantName,
contestSystemId = participant.getAttribute("id"),
groups = listOf(),
groups = emptyList(),
hashTag = null,
medias = emptyMap(),
isOutOfContest = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ internal class PCMSDataSource(val settings: PCMSSettings) : FullReloadContestDat
freezeTime = freezeTime,
problemList = problems,
teamList = teams,
groupList = teams.flatMap { it.groups }.distinct().map { GroupInfo(it, isHidden = false, isOutOfContest = false) },
groupList = teams.flatMap { it.groups }.distinct().map { GroupInfo(it, it, isHidden = false, isOutOfContest = false, awardsGroupChampion = true) },
organizationList = emptyList(),
penaltyRoundingMode = when (resultType) {
ContestResultType.IOI -> PenaltyRoundingMode.ZERO
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ internal class TestSysDataSource(val settings: TestSysSettings) : FullReloadCont
fullName = name,
displayName = name,
contestSystemId = id,
groups = listOf(),
groups = emptyList(),
hashTag = null,
medias = emptyMap(),
isOutOfContest = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ internal abstract class AbstractScoreboardCalculator : ScoreboardCalculator {
val awards = buildMap<Award, MutableSet<Int>> {
put(Award.Winner, mutableSetOf())
info.medals.forEach { put(Award.Medal(it.name), mutableSetOf()) }
info.groupList.forEach { if (it.awardsGroupChampion) put(Award.GroupChampion(it.name), mutableSetOf()) }
info.groupList.forEach { if (it.awardsGroupChampion) put(Award.GroupChampion(it.cdsId), mutableSetOf()) }
}
val order = order_.map { it.first }
val ranks = MutableList(order.size) { 0 }
Expand Down
Loading

0 comments on commit 745be02

Please sign in to comment.