complete tournament TV

This commit is contained in:
Thibault Duplessis 2016-01-25 19:28:42 +07:00
parent 4d40bbc417
commit d998fdec7d
7 changed files with 93 additions and 44 deletions

View file

@ -317,19 +317,14 @@ object GameRepo {
}).sequenceFu
def bestOpponents(userId: String, limit: Int): Fu[List[(String, Int)]] = {
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework, AggregationFramework.{
Descending,
GroupField,
Limit,
Match,
Sort,
SumValue,
Unwind
}
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework._
gameTube.coll.aggregate(Match(BSONDocument(F.playerUids -> userId)), List(
Match(BSONDocument(F.playerUids -> BSONDocument("$size" -> 2))),
Sort(Descending(F.createdAt)),
Limit(1000), // only look in the last 1000 games
Project(BSONDocument(
F.playerUids -> true,
F.id -> false)),
Unwind(F.playerUids),
Match(BSONDocument(F.playerUids -> BSONDocument("$ne" -> userId))),
GroupField(F.playerUids)("gs" -> SumValue(1)),

View file

@ -110,8 +110,15 @@ final class JsonView(
_ ?? { pairing =>
GameRepo game pairing.gameId flatMap {
_ ?? { game =>
cached ranking tour map { ranking =>
RankedPairing(ranking)(pairing) map { FeaturedGame(game, _) }
cached ranking tour flatMap { ranking =>
PlayerRepo.pairByTourAndUserIds(tour.id, pairing.user1, pairing.user2) map { pairOption =>
for {
players <- pairOption
(p1, p2) = players
rp1 <- RankedPlayer(ranking)(p1)
rp2 <- RankedPlayer(ranking)(p2)
} yield FeaturedGame(game, rp1, rp2)
}
}
}
}
@ -157,10 +164,24 @@ final class JsonView(
podium),
timeToLive = 1 second)
private def featuredJson(featured: FeaturedGame) = Json.obj(
"game" -> gameJson(featured.game),
"rank1" -> featured.rankedPairing.rank1,
"rank2" -> featured.rankedPairing.rank2)
private def featuredJson(featured: FeaturedGame) = {
def playerJson(rp: RankedPlayer) = {
val light = getLightUser(rp.player.userId)
Json.obj(
"rank" -> rp.rank,
"name" -> light.fold(rp.player.userId)(_.name),
"title" -> light.flatMap(_.title),
"rating" -> rp.player.rating,
"ratingDiff" -> rp.player.ratingDiff)
}
Json.obj(
"id" -> featured.game.id,
"fen" -> (chess.format.Forsyth exportBoard featured.game.toChess.board),
"color" -> featured.game.firstColor.name,
"lastMove" -> ~featured.game.castleLastMoveTime.lastMoveString,
"player1" -> playerJson(featured.player1),
"player2" -> playerJson(featured.player2))
}
private def myInfoJson(i: PlayerInfo) = Json.obj(
"rank" -> i.rank,
@ -173,7 +194,7 @@ final class JsonView(
val light = userId flatMap getLightUser
Json.obj(
"name" -> light.map(_.name),
"title" -> light.map(_.title),
"title" -> light.flatMap(_.title),
"rating" -> rating
).noNull
}
@ -210,7 +231,7 @@ final class JsonView(
Json.obj(
"rank" -> rankedPlayer.rank,
"name" -> light.fold(p.userId)(_.name),
"title" -> light.map(_.title),
"title" -> light.flatMap(_.title),
"rating" -> p.rating,
"provisional" -> p.provisional.option(true),
"withdraw" -> p.withdraw.option(true),

View file

@ -135,6 +135,13 @@ object PlayerRepo {
"uid" -> BSONDocument("$in" -> userIds)
)).cursor[Player]().collect[List]()
def pairByTourAndUserIds(tourId: String, id1: String, id2: String): Fu[Option[(Player, Player)]] =
byTourAndUserIds(tourId, List(id1, id2)) map {
case List(p1, p2) if p1.is(id1) && p2.is(id2) => Some(p1 -> p2)
case List(p1, p2) if p1.is(id2) && p2.is(id1) => Some(p2 -> p1)
case _ => none
}
def setPerformance(player: Player, performance: Int) =
coll.update(selectId(player.id), BSONDocument("$set" -> BSONDocument("e" -> performance))).void

View file

@ -42,6 +42,24 @@ object RankedPairing {
} yield RankedPairing(pairing, r1 + 1, r2 + 1)
}
case class RankedPlayer(rank: Int, player: Player) {
def is(other: RankedPlayer) = player is other.player
override def toString = s"$rank. ${player.userId}[${player.rating}]"
}
object RankedPlayer {
def apply(ranking: Ranking)(player: Player): Option[RankedPlayer] =
ranking get player.userId map { rank =>
RankedPlayer(rank + 1, player)
}
}
case class FeaturedGame(
game: lila.game.Game,
rankedPairing: RankedPairing)
player1: RankedPlayer,
player2: RankedPlayer)
case class Winner(tourId: String, tourName: String, userId: String)

View file

@ -14,13 +14,3 @@ package object tournament extends PackageObject with WithPlay with WithSocket {
private[tournament]type Waiting = Map[String, Int]
}
package tournament {
case class RankedPlayer(rank: Int, player: Player) {
def is(other: RankedPlayer) = player is other.player
override def toString = s"$rank. ${player.userId}[${player.rating}]"
}
case class Winner(tourId: String, tourName: String, userId: String)
}

View file

@ -360,6 +360,26 @@ ol.scheduled_tournaments a {
}
#tournament_side .featured {
margin-bottom: 10px;
line-height: 0;
}
#tournament_side .featured .vstext {
height: 20px;
border-width: 1px 1px 0 0;
width: 100%;
padding: 0;
text-align: left;
}
#tournament_side .featured .vstext.bottom {
border-width: 0 1px 1px 0;
}
#tournament_side .featured .vstext strong {
display: inline-block;
height: 20px;
width: 12.5%;
text-align: center;
line-height: 20px;
background: #ccc;
margin-right: 10px;
}
#tournament_side .box {
border: 1px solid #ccc;

View file

@ -14,23 +14,21 @@ function user(p, it) {
};
}
function featured(f) {
return m('div.featured', [
m('div.vstext.clearfix', [
m('div.left', [
f.game.user1.name,
m('br'),
f.game.user1.title ? f.game.user1.title + ' ' : '',
f.game.user1.rating
]),
m('div.right', [
f.game.user2.name,
m('br'),
f.game.user2.rating,
f.game.user2.title ? ' ' + f.game.user2.title : ''
])
function featured(f, n) {
return m('div.featured', {
config: function(el, isUpdate, ctx) {
if (ctx.id !== f.id) $('body').trigger('lichess.content_loaded');
}
}, [
m('div.vstext.top', [
m('strong', '#' + f.player2.rank),
util.player(f.player2)
]),
util.miniBoard(f.game)
util.miniBoard(f),
m('div.vstext.bottom', [
m('strong', '#' + f.player1.rank),
util.player(f.player1)
])
]);
}