tournament TV WIP
This commit is contained in:
parent
5136172150
commit
8eb06fccc5
|
@ -50,7 +50,8 @@ object BSONHandlers {
|
|||
createdAt = r date "createdAt",
|
||||
createdBy = r str "createdBy",
|
||||
startsAt = startsAt,
|
||||
winnerId = r strO "winner")
|
||||
winnerId = r strO "winner",
|
||||
featuredId = r strO "featured")
|
||||
}
|
||||
def writes(w: BSON.Writer, o: Tournament) = BSONDocument(
|
||||
"_id" -> o.id,
|
||||
|
@ -72,7 +73,8 @@ object BSONHandlers {
|
|||
"createdAt" -> w.date(o.createdAt),
|
||||
"createdBy" -> w.str(o.createdBy),
|
||||
"startsAt" -> w.date(o.startsAt),
|
||||
"winner" -> o.winnerId)
|
||||
"winner" -> o.winnerId,
|
||||
"featured" -> o.featuredId)
|
||||
}
|
||||
|
||||
implicit val playerBSONHandler = new BSON[Player] {
|
||||
|
|
|
@ -15,7 +15,11 @@ final class JsonView(
|
|||
cached: Cached,
|
||||
performance: Performance) {
|
||||
|
||||
private case class CachableData(pairings: JsArray, games: JsArray, podium: Option[JsArray])
|
||||
private case class CachableData(
|
||||
pairings: JsArray,
|
||||
games: JsArray,
|
||||
featured: Option[JsObject],
|
||||
podium: Option[JsArray])
|
||||
|
||||
def apply(
|
||||
tour: Tournament,
|
||||
|
@ -54,6 +58,7 @@ final class JsonView(
|
|||
"lastGames" -> data.games,
|
||||
"standing" -> stand,
|
||||
"me" -> myInfo.map(myInfoJson),
|
||||
"featured" -> data.featured,
|
||||
"podium" -> data.podium,
|
||||
"playerInfo" -> playerInfoJson,
|
||||
"quote" -> lila.quote.Quote.one(tour.id)
|
||||
|
@ -100,6 +105,19 @@ final class JsonView(
|
|||
)
|
||||
}
|
||||
|
||||
private def fetchFeaturedGame(tour: Tournament): Fu[Option[FeaturedGame]] =
|
||||
tour.featuredId.ifTrue(tour.isStarted) ?? PairingRepo.byId flatMap {
|
||||
_ ?? { pairing =>
|
||||
GameRepo game pairing.gameId flatMap {
|
||||
_ ?? { game =>
|
||||
cached ranking tour map { ranking =>
|
||||
RankedPairing(ranking)(pairing) map { FeaturedGame(game, _) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def sheetNbs(userId: String, sheet: ScoreSheet, pairings: Pairings) = sheet match {
|
||||
case s: arena.ScoringSystem.Sheet => Json.obj(
|
||||
"game" -> s.scores.size,
|
||||
|
@ -129,13 +147,21 @@ final class JsonView(
|
|||
for {
|
||||
pairings <- PairingRepo.recentByTour(id, 40)
|
||||
games <- GameRepo games pairings.take(4).map(_.gameId)
|
||||
tour <- TournamentRepo byId id
|
||||
featured <- tour ?? fetchFeaturedGame
|
||||
podium <- podiumJson(id)
|
||||
} yield CachableData(
|
||||
JsArray(pairings map pairingJson),
|
||||
JsArray(games map gameJson),
|
||||
featured map featuredJson,
|
||||
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 myInfoJson(i: PlayerInfo) = Json.obj(
|
||||
"rank" -> i.rank,
|
||||
"withdraw" -> i.withdraw)
|
||||
|
|
|
@ -23,7 +23,8 @@ case class Tournament(
|
|||
createdAt: DateTime,
|
||||
createdBy: String,
|
||||
startsAt: DateTime,
|
||||
winnerId: Option[String] = None) {
|
||||
winnerId: Option[String] = None,
|
||||
featuredId: Option[String] = None) {
|
||||
|
||||
def isCreated = status == Status.Created
|
||||
def isStarted = status == Status.Started
|
||||
|
|
|
@ -69,10 +69,11 @@ private[tournament] final class TournamentApi(
|
|||
play.api.Logger("tourpairing").warn(s"Give up making http://lichess.org/tournament/${tour.id} ${pairings.size} pairings in ${nowMillis - startAt}ms")
|
||||
funit
|
||||
case pairings => pairings.map { pairing =>
|
||||
PairingRepo.insert(pairing) >> autoPairing(tour, pairing)
|
||||
}.sequenceFu.map {
|
||||
_ map StartGame.apply foreach { sendTo(tour.id, _) }
|
||||
} >>- {
|
||||
PairingRepo.insert(pairing) >>
|
||||
autoPairing(tour, pairing) addEffect { game =>
|
||||
sendTo(tour.id, StartGame(game))
|
||||
}
|
||||
}.sequenceFu >> featureOneOf(tour, pairings, ranking) >>- {
|
||||
val time = nowMillis - startAt
|
||||
if (time > 100)
|
||||
play.api.Logger("tourpairing").debug(s"Done making http://lichess.org/tournament/${tour.id} ${pairings.size} pairings in ${time}ms")
|
||||
|
@ -82,6 +83,16 @@ private[tournament] final class TournamentApi(
|
|||
}
|
||||
}
|
||||
|
||||
private def featureOneOf(tour: Tournament, pairings: Pairings, ranking: Ranking): Funit =
|
||||
tour.featuredId.ifTrue(pairings.nonEmpty) ?? PairingRepo.byId map2
|
||||
RankedPairing(ranking) map (_.flatten) flatMap { curOption =>
|
||||
val candidates = pairings flatMap RankedPairing(ranking)
|
||||
if (curOption.exists(_.pairing.playing)) funit
|
||||
else candidates.sortBy(-_.bestRank).headOption ?? { best =>
|
||||
TournamentRepo.setFeaturedGameId(tour.id, best.pairing.gameId)
|
||||
}
|
||||
}
|
||||
|
||||
def tourAndRanks(game: Game): Fu[Option[TourAndRanks]] = ~{
|
||||
for {
|
||||
tourId <- game.tournamentId
|
||||
|
|
|
@ -114,6 +114,16 @@ object TournamentRepo {
|
|||
BSONDocument("$set" -> BSONDocument("winner" -> userId))
|
||||
).void
|
||||
|
||||
def setFeaturedGameId(tourId: String, gameId: String) = coll.update(
|
||||
selectId(tourId),
|
||||
BSONDocument("$set" -> BSONDocument("featured" -> gameId))
|
||||
).void
|
||||
|
||||
def featuredGameId(tourId: String) = coll.find(
|
||||
selectId(tourId),
|
||||
BSONDocument("featured" -> true)
|
||||
).one[BSONDocument].map(_.flatMap(_.getAs[String]("featured")))
|
||||
|
||||
private def allCreatedSelect(aheadMinutes: Int) = createdSelect ++ BSONDocument(
|
||||
"$or" -> BSONArray(
|
||||
BSONDocument("schedule" -> BSONDocument("$exists" -> false)),
|
||||
|
|
|
@ -25,3 +25,23 @@ case class TourAndRanks(
|
|||
tour: Tournament,
|
||||
whiteRank: Int,
|
||||
blackRank: Int)
|
||||
|
||||
case class RankedPairing(pairing: Pairing, rank1: Int, rank2: Int) {
|
||||
|
||||
def bestRank = rank1 min rank2
|
||||
def rankSum = rank1 + rank2
|
||||
|
||||
def bestColor = chess.Color(rank1 < rank2)
|
||||
}
|
||||
|
||||
object RankedPairing {
|
||||
|
||||
def apply(ranking: Ranking)(pairing: Pairing): Option[RankedPairing] = for {
|
||||
r1 <- ranking get pairing.user1
|
||||
r2 <- ranking get pairing.user2
|
||||
} yield RankedPairing(pairing, r1 + 1, r2 + 1)
|
||||
}
|
||||
|
||||
case class FeaturedGame(
|
||||
game: lila.game.Game,
|
||||
rankedPairing: RankedPairing)
|
||||
|
|
|
@ -355,10 +355,22 @@ ol.scheduled_tournaments a {
|
|||
position: relative;
|
||||
float: right;
|
||||
width: 252px;
|
||||
border: 1px solid #ccc;
|
||||
text-align: center;
|
||||
transition: 0.13s;
|
||||
}
|
||||
#tournament_side .featured {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#tournament_side .box {
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
#tournament_side .cg-board-wrap {
|
||||
width: 252px;
|
||||
height: 252px;
|
||||
}
|
||||
#tournament_side .vstext {
|
||||
width: 240px;
|
||||
}
|
||||
#tournament_side .scroll-shadow-soft {
|
||||
max-height: 510px;
|
||||
overflow: auto;
|
||||
|
|
|
@ -3,8 +3,6 @@ var partial = require('chessground').util.partial;
|
|||
var util = require('./util');
|
||||
var status = require('game').status;
|
||||
|
||||
var statusClasses = ['playing', 'draw', 'win', 'loss'];
|
||||
|
||||
function user(p, it) {
|
||||
return {
|
||||
tag: p.s === 0 ? 'playing' : (
|
||||
|
@ -16,6 +14,26 @@ 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 : ''
|
||||
])
|
||||
]),
|
||||
util.miniBoard(f.game)
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports = function(ctrl) {
|
||||
var pairing = function(p) {
|
||||
return {
|
||||
|
@ -31,9 +49,12 @@ module.exports = function(ctrl) {
|
|||
]
|
||||
};
|
||||
};
|
||||
return m('div.all_pairings.scroll-shadow-soft', {
|
||||
onclick: function() {
|
||||
return !ctrl.vm.disableClicks;
|
||||
}
|
||||
}, ctrl.data.pairings.map(pairing));
|
||||
return [
|
||||
ctrl.data.featured ? featured(ctrl.data.featured) : null,
|
||||
m('div.box.all_pairings.scroll-shadow-soft', {
|
||||
onclick: function() {
|
||||
return !ctrl.vm.disableClicks;
|
||||
}
|
||||
}, ctrl.data.pairings.map(pairing))
|
||||
];
|
||||
};
|
||||
|
|
|
@ -32,7 +32,7 @@ module.exports = function(ctrl) {
|
|||
var avgOp = pairingsLen ? Math.round(data.pairings.reduce(function(a, b) {
|
||||
return a + b.op.rating;
|
||||
}, 0) / pairingsLen) : null;
|
||||
return m('div.player', {
|
||||
return m('div.box.player', {
|
||||
config: function(el, isUpdate) {
|
||||
if (!isUpdate) $('body').trigger('lichess.content_loaded');
|
||||
}
|
||||
|
|
|
@ -3,19 +3,23 @@ var partial = require('chessground').util.partial;
|
|||
|
||||
var boardContent = m('div.cg-board-wrap', m('div.cg-board'));
|
||||
|
||||
function miniBoard(game) {
|
||||
return m('a', {
|
||||
key: game.id,
|
||||
href: '/' + game.id + (game.color === 'white' ? '' : '/black'),
|
||||
class: 'mini_board live_' + game.id + ' parse_fen is2d',
|
||||
'data-color': game.color,
|
||||
'data-fen': game.fen,
|
||||
'data-lastmove': game.lastMove,
|
||||
config: function(el, isUpdate) {
|
||||
if (!isUpdate) lichess.parseFen($(el));
|
||||
}
|
||||
}, boardContent);
|
||||
}
|
||||
|
||||
function miniGame(game) {
|
||||
return m('div', [
|
||||
m('a', {
|
||||
key: game.id,
|
||||
href: '/' + game.id + (game.color === 'white' ? '' : '/black'),
|
||||
class: 'mini_board live_' + game.id + ' parse_fen is2d',
|
||||
'data-color': game.color,
|
||||
'data-fen': game.fen,
|
||||
'data-lastmove': game.lastMove,
|
||||
config: function(el, isUpdate) {
|
||||
if (!isUpdate) lichess.parseFen($(el));
|
||||
}
|
||||
}, boardContent),
|
||||
miniBoard(game),
|
||||
m('div.vstext.clearfix', [
|
||||
m('div.left', [
|
||||
game.user1.name,
|
||||
|
@ -90,6 +94,7 @@ module.exports = {
|
|||
games: function(games) {
|
||||
return m('div.game_list.playing', games.map(miniGame));
|
||||
},
|
||||
miniBoard: miniBoard,
|
||||
clock: function(time) {
|
||||
return function(el, isUpdate) {
|
||||
if (!isUpdate) $(el).clock({
|
||||
|
|
Loading…
Reference in a new issue