round app compiles
parent
d2cd87f940
commit
f9bcb6afbf
|
@ -25,6 +25,9 @@ private[controllers] trait LilaController
|
|||
protected implicit val LilaPlainResultZero = new Zero[PlainResult] {
|
||||
val zero = Results.NotFound
|
||||
}
|
||||
protected implicit val LilaHtmlZero = new Zero[Html] {
|
||||
val zero = Html("")
|
||||
}
|
||||
|
||||
protected implicit final class LilaPimpedResult(result: Result) {
|
||||
def fuccess = scala.concurrent.Future successful result
|
||||
|
@ -99,15 +102,16 @@ private[controllers] trait LilaController
|
|||
// protected def NoEngine[A <: Result](a: ⇒ A)(implicit ctx: Context): Result =
|
||||
// ctx.me.fold(false)(_.engine).fold(Forbidden(views.html.site.noEngine()), a)
|
||||
|
||||
protected def JsonOk[A: Writes](fua: Fu[A]) = fua map { a =>
|
||||
protected def JsonOk[A: Writes](fua: Fu[A]) = fua map { a ⇒
|
||||
Ok(Json toJson a) as JSON
|
||||
}
|
||||
|
||||
// protected def JsFuk(js: Fu[String], headers: (String, String)*) =
|
||||
// JsOk(js.unsafePerformFu, headers: _*)
|
||||
protected def JsonOptionOk[A: Writes](fua: Fu[Option[A]])(implicit ctx: Context) = fua flatMap {
|
||||
_.fold(notFound(ctx))(a ⇒ fuccess(Ok(Json toJson a) as JSON))
|
||||
}
|
||||
|
||||
// protected def JsOk(js: String, headers: (String, String)*) =
|
||||
// Ok(js) as JAVASCRIPT withHeaders (headers: _*)
|
||||
protected def JsOk(fua: Fu[String], headers: (String, String)*) =
|
||||
fua map { a ⇒ Ok(a) as JAVASCRIPT withHeaders (headers: _*) }
|
||||
|
||||
// protected def ValidOk(valid: Valid[Unit]): Result = valid.fold(
|
||||
// e ⇒ BadRequest(e.shows),
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
package controllers
|
||||
|
||||
import lila.api._
|
||||
import lila.user.Context
|
||||
|
||||
import play.api.mvc._, Results._
|
||||
import lila.app._
|
||||
import views._
|
||||
|
||||
object Notification extends LilaController {
|
||||
|
||||
def remove(id: String) = TODO
|
||||
private def api = Env.notification.api
|
||||
|
||||
def remove(id: String) = Auth { implicit ctx ⇒
|
||||
me ⇒
|
||||
Ok(api.remove(me.id, id)).fuccess
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,171 @@
|
|||
package controllers
|
||||
|
||||
import lila.api._
|
||||
import lila.user.Context
|
||||
import lila.app._
|
||||
import views._
|
||||
import lila.user.{ Context, UserRepo }
|
||||
import lila.game.{ Pov, GameRepo, Game ⇒ GameModel }
|
||||
import lila.round.{ RoomRepo, Room }
|
||||
import lila.round.actorApi.GetGameVersion
|
||||
import lila.tournament.{ Tournament ⇒ Tourney }
|
||||
import makeTimeout.large
|
||||
|
||||
import play.api.mvc._, Results._
|
||||
import akka.pattern.ask
|
||||
import play.api.mvc._
|
||||
import play.api.libs.json._
|
||||
import play.api.libs.iteratee._
|
||||
import play.api.templates.Html
|
||||
|
||||
object Round extends LilaController {
|
||||
object Round extends LilaController with TheftPrevention with RoundEventPerformer {
|
||||
|
||||
def watcher(gameId: String, color: String) = TODO
|
||||
private def env = Env.round
|
||||
// private def rematcher = Env.setup.rematcher
|
||||
private def bookmarkApi = Env.bookmark.api
|
||||
private def analyser = Env.analyse.analyser
|
||||
// private def tournamentRepo = Env.tournament.repo
|
||||
private def gameJs = Env.game.gameJs
|
||||
|
||||
def player(fullId: String) = TODO
|
||||
def websocketWatcher(gameId: String, color: String) = WebSocket.async[JsValue] { req ⇒
|
||||
reqToCtx(req) flatMap { implicit ctx ⇒
|
||||
env.socketHandler.joinWatcher(
|
||||
gameId,
|
||||
color,
|
||||
~getInt("version"),
|
||||
~get("sri"),
|
||||
ctx)
|
||||
}
|
||||
}
|
||||
|
||||
def websocketPlayer(fullId: String) = WebSocket.async[JsValue] { req ⇒
|
||||
reqToCtx(req) flatMap { implicit ctx ⇒
|
||||
env.socketHandler.joinPlayer(
|
||||
fullId,
|
||||
~getInt("version"),
|
||||
~get("sri"),
|
||||
~get("tk2"),
|
||||
ctx)
|
||||
}
|
||||
}
|
||||
|
||||
def signedJs(gameId: String) = Open { implicit ctx ⇒
|
||||
JsOk(GameRepo token gameId map gameJs.sign, CACHE_CONTROL -> "max-age=3600")
|
||||
}
|
||||
|
||||
def player(fullId: String) = Open { implicit ctx ⇒
|
||||
OptionFuResult(GameRepo pov fullId) { pov ⇒
|
||||
pov.game.started.fold(
|
||||
for {
|
||||
// TODO zip that shit
|
||||
roomHtml ← pov.game.hasChat optionFu {
|
||||
RoomRepo room pov.gameId map { room ⇒
|
||||
html.round.room(html.round.roomInner(room.decodedMessages), false)
|
||||
}
|
||||
}
|
||||
v ← version(pov.gameId)
|
||||
bookmarkers ← bookmarkApi userIdsByGame pov.game
|
||||
engine ← pov.opponent.userId.zmap(UserRepo.isEngine)
|
||||
analysed ← analyser has pov.gameId
|
||||
tour = none[Tourney]
|
||||
// TODO tournamentRepo byId pov.game.tournamentId
|
||||
} yield PreventTheft(pov) {
|
||||
Ok(html.round.player(
|
||||
pov,
|
||||
v,
|
||||
engine,
|
||||
roomHtml,
|
||||
bookmarkers,
|
||||
analysed,
|
||||
tour = tour))
|
||||
},
|
||||
Ok("TODO").fuccess
|
||||
// TODO Redirect(routes.Setup.await(fullId)).fuccess
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
def watcher(gameId: String, color: String) = Open { implicit ctx ⇒
|
||||
OptionFuResult(GameRepo.pov(gameId, color)) { pov ⇒
|
||||
pov.game.started.fold(watch _, join _)(pov)
|
||||
}
|
||||
}
|
||||
|
||||
private def join(pov: Pov)(implicit ctx: Context): Fu[Result] =
|
||||
GameRepo initialFen pov.gameId zip version(pov.gameId) map {
|
||||
case (fen, version) ⇒ Ok("TODO") // TODO
|
||||
// Ok(html.setup.join(
|
||||
// pov, version, env.setup.friendConfigMemo get pov.game.id, fen
|
||||
// ))
|
||||
}
|
||||
|
||||
private def watch(pov: Pov)(implicit ctx: Context): Fu[Result] =
|
||||
bookmarkApi userIdsByGame pov.game zip
|
||||
version(pov.gameId) zip
|
||||
(RoomRepo room pov.gameId map { room ⇒
|
||||
html.round.room(html.round.roomInner(room.decodedMessages), true)
|
||||
}) zip
|
||||
(analyser has pov.gameId) zip
|
||||
fuccess(none[Tourney]) map {
|
||||
// TODO (tournamentRepo byId pov.game.tournamentId) map {
|
||||
case ((((bookmarkers, v), roomHtml), analysed), tour) ⇒
|
||||
Ok(html.round.watcher(
|
||||
pov, v, roomHtml, bookmarkers, analysed, tour))
|
||||
}
|
||||
|
||||
private def hand = env.hand
|
||||
def abort(fullId: String) = performAndRedirect(fullId, hand.abort)
|
||||
def resign(fullId: String) = performAndRedirect(fullId, hand.resign)
|
||||
def resignForce(fullId: String) = performAndRedirect(fullId, hand.resignForce)
|
||||
def drawClaim(fullId: String) = performAndRedirect(fullId, hand.drawClaim)
|
||||
def drawAccept(fullId: String) = performAndRedirect(fullId, hand.drawAccept)
|
||||
def drawOffer(fullId: String) = performAndRedirect(fullId, hand.drawOffer)
|
||||
def drawCancel(fullId: String) = performAndRedirect(fullId, hand.drawCancel)
|
||||
def drawDecline(fullId: String) = performAndRedirect(fullId, hand.drawDecline)
|
||||
|
||||
def rematch(fullId: String) = TODO
|
||||
// Action {
|
||||
// rematcher offerOrAccept fullId flatMap { validResult ⇒
|
||||
// validResult.fold(
|
||||
// err ⇒ putFailures(err) map { _ ⇒
|
||||
// Redirect(routes.Round.player(fullId))
|
||||
// }, {
|
||||
// case (nextFullId, events) ⇒ performEvents(fullId)(events) map { _ ⇒
|
||||
// Redirect(routes.Round.player(nextFullId))
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
def rematchCancel(fullId: String) = performAndRedirect(fullId, hand.rematchCancel)
|
||||
def rematchDecline(fullId: String) = performAndRedirect(fullId, hand.rematchDecline)
|
||||
|
||||
def takebackAccept(fullId: String) = performAndRedirect(fullId, hand.takebackAccept)
|
||||
def takebackOffer(fullId: String) = performAndRedirect(fullId, hand.takebackOffer)
|
||||
def takebackCancel(fullId: String) = performAndRedirect(fullId, hand.takebackCancel)
|
||||
def takebackDecline(fullId: String) = performAndRedirect(fullId, hand.takebackDecline)
|
||||
|
||||
def tableWatcher(gameId: String, color: String) = Open { implicit ctx ⇒
|
||||
OptionOk(GameRepo.pov(gameId, color)) { html.round.table.watch(_) }
|
||||
}
|
||||
|
||||
def tablePlayer(fullId: String) = Open { implicit ctx ⇒
|
||||
OptionFuOk(GameRepo pov fullId) { pov ⇒
|
||||
fuccess(none[Tourney]) map { tour ⇒
|
||||
// TODO tournamentRepo byId pov.game.tournamentId map { tour ⇒
|
||||
pov.game.playable.fold(
|
||||
html.round.table.playing(pov),
|
||||
html.round.table.end(pov, tour))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def players(gameId: String) = Open { implicit ctx ⇒
|
||||
import templating.Environment.playerLink
|
||||
JsonOptionOk(GameRepo game gameId map2 { (game: GameModel) ⇒
|
||||
(game.players collect {
|
||||
case player if player.isHuman ⇒ player.color.name -> playerLink(player).body
|
||||
} toMap) ++ ctx.me.zmap(me ⇒ Map("me" -> me.usernameWithElo))
|
||||
})
|
||||
}
|
||||
|
||||
private def version(gameId: String): Fu[Int] =
|
||||
env.socketHub ? GetGameVersion(gameId) mapTo manifest[Int]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package controllers
|
||||
|
||||
import lila.app._
|
||||
import lila.game.Event
|
||||
import lila.round.actorApi.GameEvents
|
||||
import lila.game.Game.takeGameId
|
||||
|
||||
import play.api.mvc._, Results._
|
||||
|
||||
trait RoundEventPerformer {
|
||||
|
||||
protected type FuValidEvents = Fu[Valid[List[Event]]]
|
||||
|
||||
protected def performAndRedirect(fullId: String, op: String ⇒ FuValidEvents) =
|
||||
Action {
|
||||
perform(fullId, op)
|
||||
Redirect(routes.Round.player(fullId))
|
||||
}
|
||||
|
||||
protected def perform(fullId: String, op: String ⇒ FuValidEvents) {
|
||||
op(fullId) foreach { validEvents ⇒
|
||||
validEvents.fold(
|
||||
err ⇒ logwarn("[round] fail to perform on game %s\n%s".format(fullId, err)),
|
||||
performEvents(fullId)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
protected def performEvents(fullId: String)(events: List[Event]) {
|
||||
Env.round.socketHub ! GameEvents(takeGameId(fullId), events)
|
||||
}
|
||||
}
|
|
@ -4,14 +4,12 @@ import lila.app._
|
|||
import views._
|
||||
|
||||
import play.api.mvc._
|
||||
import scalaz.effects._
|
||||
|
||||
object Bookmark extends LilaController {
|
||||
|
||||
private def api = env.bookmark.api
|
||||
private def gameRepo = env.game.gameRepo
|
||||
private def api = Env.bookmark.api
|
||||
|
||||
def toggle(gameId: String) = Auth { implicit ctx ⇒
|
||||
me ⇒ IOk(api.toggle(gameId, me.id))
|
||||
me ⇒ api.toggle(gameId, me.id)
|
||||
}
|
||||
}
|
|
@ -2,18 +2,18 @@ package controllers
|
|||
|
||||
import lila.app._
|
||||
import views._
|
||||
import http.Context
|
||||
import game.{ DbGame, Pov }
|
||||
import security.Granter
|
||||
import lila.user.Context
|
||||
import lila.game.Pov
|
||||
import lila.security.Granter
|
||||
|
||||
import play.api.mvc._
|
||||
import play.api.mvc.Results.Redirect
|
||||
|
||||
trait TheftPrevention {
|
||||
private[controllers] trait TheftPrevention {
|
||||
|
||||
protected def PreventTheft(pov: Pov)(ok: ⇒ Result)(implicit ctx: Context): Result =
|
||||
isTheft(pov).fold(Redirect(routes.Round.watcher(pov.gameId, pov.color.name)), ok)
|
||||
|
||||
protected def isTheft(pov: Pov)(implicit ctx: Context) =
|
||||
pov.player.userId != ctx.userId && !Granter.superAdmin(ctx.me)
|
||||
pov.player.userId != ctx.userId && !(ctx.me zmap Granter.superAdmin)
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
package controllers
|
||||
|
||||
import lila.app._
|
||||
import views._
|
||||
import lila.game.Pov
|
||||
// import lila.tournament.{ Created, Started, Finished }
|
||||
import lila.tournament.{ Tournament ⇒ Tourney }
|
||||
import lila.user.Context
|
||||
|
||||
import play.api.mvc._
|
||||
import play.api.libs.json._
|
||||
import play.api.libs.iteratee._
|
||||
import play.api.libs.concurrent._
|
||||
import play.api.templates.Html
|
||||
|
||||
object Tournament extends LilaController {
|
||||
|
||||
// private def repo = env.tournament.repo
|
||||
// private def forms = env.tournament.forms
|
||||
// private def api = env.tournament.api
|
||||
// private def socket = env.tournament.socket
|
||||
// private def messenger = env.tournament.messenger
|
||||
// private def userRepo = env.user.userRepo
|
||||
// private def gameRepo = env.game.gameRepo
|
||||
|
||||
val home = TODO
|
||||
// Open { implicit ctx ⇒
|
||||
// Async {
|
||||
// futureTournaments zip userRepo.sortedByToints(10).toFuture map {
|
||||
// case (((created, started), finished), leaderboard) ⇒
|
||||
// Ok(html.tournament.home(created, started, finished, leaderboard))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// val faq = Open { implicit ctx ⇒ Ok(html.tournament.faqPage()) }
|
||||
|
||||
// val homeReload = Open { implicit ctx ⇒
|
||||
// Async {
|
||||
// futureTournaments map {
|
||||
// case ((created, started), finished) ⇒
|
||||
// Ok(html.tournament.homeInner(created, started, finished))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// private def futureTournaments =
|
||||
// repo.created.toFuture zip repo.started.toFuture zip repo.finished(20).toFuture
|
||||
|
||||
def show(id: String) = TODO
|
||||
// Open { implicit ctx ⇒
|
||||
// IOResult(for {
|
||||
// t ← repo byId id
|
||||
// res ← t match {
|
||||
// case Some(tour: Created) ⇒ showCreated(tour) map { Ok(_) }
|
||||
// case Some(tour: Started) ⇒ showStarted(tour) map { Ok(_) }
|
||||
// case Some(tour: Finished) ⇒ showFinished(tour) map { Ok(_) }
|
||||
// case _ ⇒ io(NotFound(html.tournament.notFound()))
|
||||
// }
|
||||
// } yield res)
|
||||
// }
|
||||
|
||||
// private def showCreated(tour: Created)(implicit ctx: Context) = for {
|
||||
// roomHtml ← messenger render tour
|
||||
// } yield html.tournament.show.created(
|
||||
// tour = tour,
|
||||
// roomHtml = Html(roomHtml),
|
||||
// version = version(tour.id))
|
||||
|
||||
// private def showStarted(tour: Started)(implicit ctx: Context) = for {
|
||||
// roomHtml ← messenger render tour
|
||||
// games ← gameRepo games (tour recentGameIds 4)
|
||||
// pov ← tour.userCurrentPov(ctx.me).fold(io(none[Pov]))(gameRepo.pov)
|
||||
// } yield html.tournament.show.started(
|
||||
// tour = tour,
|
||||
// roomHtml = Html(roomHtml),
|
||||
// version = version(tour.id),
|
||||
// games = games,
|
||||
// pov = pov)
|
||||
|
||||
// private def showFinished(tour: Finished)(implicit ctx: Context) = for {
|
||||
// roomHtml ← messenger render tour
|
||||
// games ← gameRepo games (tour recentGameIds 4)
|
||||
// } yield html.tournament.show.finished(
|
||||
// tour = tour,
|
||||
// roomHtml = Html(roomHtml),
|
||||
// version = version(tour.id),
|
||||
// games = games)
|
||||
|
||||
// def join(id: String) = AuthBody { implicit ctx ⇒
|
||||
// implicit me ⇒
|
||||
// NoEngine {
|
||||
// IOptionIORedirect(repo createdById id) { tour ⇒
|
||||
// api.join(tour, me).fold(
|
||||
// err ⇒ putStrLn(err.shows) map (_ ⇒ routes.Tournament.home()),
|
||||
// res ⇒ res map (_ ⇒ routes.Tournament.show(tour.id))
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// def withdraw(id: String) = Auth { implicit ctx ⇒
|
||||
// implicit me ⇒
|
||||
// IOptionIORedirect(repo byId id) { tour ⇒
|
||||
// api.withdraw(tour, me.id) inject routes.Tournament.show(tour.id)
|
||||
// }
|
||||
// }
|
||||
|
||||
// def earlyStart(id: String) = Auth { implicit ctx ⇒
|
||||
// implicit me ⇒
|
||||
// IOptionIORedirect(repo.createdByIdAndCreator(id, me.id)) { tour ⇒
|
||||
// ~api.earlyStart(tour) inject routes.Tournament.show(tour.id)
|
||||
// }
|
||||
// }
|
||||
|
||||
// def reload(id: String) = Open { implicit ctx ⇒
|
||||
// IOptionIOk(repo byId id) {
|
||||
// case tour: Created ⇒ reloadCreated(tour)
|
||||
// case tour: Started ⇒ reloadStarted(tour)
|
||||
// case tour: Finished ⇒ reloadFinished(tour)
|
||||
// }
|
||||
// }
|
||||
|
||||
// private def reloadCreated(tour: Created)(implicit ctx: Context) = io {
|
||||
// val inner = html.tournament.show.createdInner(tour)
|
||||
// html.tournament.show.inner(none)(inner)
|
||||
// }
|
||||
|
||||
// private def reloadStarted(tour: Started)(implicit ctx: Context) = for {
|
||||
// games ← gameRepo games (tour recentGameIds 4)
|
||||
// pov ← tour.userCurrentPov(ctx.me).fold(io(none[Pov]))(gameRepo.pov)
|
||||
// } yield {
|
||||
// val pairings = html.tournament.pairings(tour)
|
||||
// val inner = html.tournament.show.startedInner(tour, games, pov)
|
||||
// html.tournament.show.inner(pairings.some)(inner)
|
||||
// }
|
||||
|
||||
// private def reloadFinished(tour: Finished)(implicit ctx: Context) =
|
||||
// gameRepo games (tour recentGameIds 4) map { games ⇒
|
||||
// val pairings = html.tournament.pairings(tour)
|
||||
// val inner = html.tournament.show.finishedInner(tour, games)
|
||||
// html.tournament.show.inner(pairings.some)(inner)
|
||||
// }
|
||||
|
||||
// def form = Auth { implicit ctx ⇒
|
||||
// me ⇒
|
||||
// NoEngine {
|
||||
// Ok(html.tournament.form(forms.create, forms))
|
||||
// }
|
||||
// }
|
||||
|
||||
// def create = AuthBody { implicit ctx ⇒
|
||||
// implicit me ⇒
|
||||
// NoEngine {
|
||||
// IOResult {
|
||||
// implicit val req = ctx.body
|
||||
// forms.create.bindFromRequest.fold(
|
||||
// err ⇒ io(BadRequest(html.tournament.form(err, forms))),
|
||||
// setup ⇒ api.createTournament(setup, me) map { tour ⇒
|
||||
// Redirect(routes.Tournament.show(tour.id))
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// def websocket(id: String) = WebSocket.async[JsValue] { req ⇒
|
||||
// implicit val ctx = reqToCtx(req)
|
||||
// socket.join(id, getInt("version"), get("sri"), ctx.me).unsafePerformIO
|
||||
// }
|
||||
|
||||
// private def version(tournamentId: String): Int = socket blockingVersion tournamentId
|
||||
}
|
|
@ -10,6 +10,10 @@ import scala.math.{ min, max, round }
|
|||
|
||||
trait RoundHelper {
|
||||
|
||||
def moretimeSeconds = roundEnv.moretimeSeconds
|
||||
|
||||
def gameAnimationDelay = roundEnv.animationDelay
|
||||
|
||||
def roundPlayerJsData(pov: Pov, version: Int) = {
|
||||
import pov._
|
||||
Json.obj(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@(game: DbGame)(implicit ctx: Context)
|
||||
@(game: Game)(implicit ctx: Context)
|
||||
|
||||
@if(isGranted(Permission.ViewBlurs)) {
|
||||
@game.players.map { p =>
|
|
@ -1,4 +1,4 @@
|
|||
@(game: DbGame)(implicit ctx: Context)
|
||||
@(game: Game)(implicit ctx: Context)
|
||||
|
||||
<a class="continue_from_here" title="@trans.continueFromHere()">@game.fenString</a>
|
||||
<span class="opponent_choice">
|
|
@ -1,4 +1,4 @@
|
|||
@(pov: Pov, version: Int, engine: Boolean, roomHtml: Option[Html], bookmarkers: List[String], analysed: Boolean, tour: Option[lila.app.tournament.Tournament])(implicit ctx: Context)
|
||||
@(pov: Pov, version: Int, engine: Boolean, roomHtml: Option[Html], bookmarkers: List[String], analysed: Boolean, tour: Option[lila.tournament.Tournament])(implicit ctx: Context)
|
||||
|
||||
@import pov._
|
||||
|
||||
|
@ -21,8 +21,8 @@ signedJs = routes.Round.signedJs(pov.gameId).toString.some) {
|
|||
data-table-url="@routes.Round.tablePlayer(fullId)"
|
||||
data-players-url="@routes.Round.players(gameId)">
|
||||
<div class="lichess_board_wrap">
|
||||
@widget.connection()
|
||||
<div class="lichess_board with_marks">@Html(ui.Board.render(pov))</div>
|
||||
@site.connection()
|
||||
<div class="lichess_board with_marks">@Html(lila.app.ui.Board.render(pov))</div>
|
||||
<div id="premove">@trans.premoveEnabledClickAnywhereToCancel()</div>
|
||||
</div>
|
||||
<div class="lichess_ground">
|
||||
|
@ -61,10 +61,14 @@ signedJs = routes.Round.signedJs(pov.gameId).toString.some) {
|
|||
<a href="@routes.Analyse.replay(gameId, color.name)">@trans.replayAndAnalyse()</a>
|
||||
@if(game.pgnImport.isEmpty) {
|
||||
<br />
|
||||
@* TODO
|
||||
<a href="@routes.Analyse.stats(gameId)">@trans.viewGameStats()</a>
|
||||
*@
|
||||
}
|
||||
<br />
|
||||
@* TODO
|
||||
<a class="view_pgn_toggle" href="@routes.Analyse.pgn(game.id)">View PGN</a>
|
||||
*@
|
||||
</nav>
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
@(inner: Html, spectator: Boolean)(implicit ctx: Context)
|
||||
|
||||
@base.chatRoom(
|
||||
title = spectator.fold(trans.spectatorRoom, trans.chatRoom).str(),
|
||||
cssClass = spectator.fold("spectator", "kings"))(inner)
|
|
@ -0,0 +1,7 @@
|
|||
@(messages: List[(String, String)])(implicit ctx: Context)
|
||||
|
||||
@messages.map {
|
||||
case (author, text) => {
|
||||
<li class="@author@{ (author == "system").??(" trans_me") }">@text</li>
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
@(pov: Pov, tour: Option[lila.app.tournament.Tournament])(implicit ctx: Context)
|
||||
@(pov: Pov, tour: Option[lila.tournament.Tournament])(implicit ctx: Context)
|
||||
|
||||
@import pov._
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
@(game: DbGame)(implicit ctx: Context)
|
||||
@(game: Game)(implicit ctx: Context)
|
||||
|
||||
@winner(player: DbPlayer) = {
|
||||
@winner(player: Player) = {
|
||||
<div class="lichess_player @player.color">
|
||||
<div class="lichess_piece king @player.color"></div>
|
||||
<p>
|
|
@ -22,7 +22,9 @@
|
|||
@game.next.map { next =>
|
||||
<a class="button" href="@routes.Round.watcher(next, opponent.color.name)">@trans.viewRematch()</a>
|
||||
}
|
||||
@* TODO
|
||||
@game.tournamentId.map { tourId =>
|
||||
<a class="button" href="@routes.Tournament.show(tourId)">@trans.viewTournament()</a>
|
||||
}
|
||||
*@
|
||||
</div>
|
|
@ -1,4 +1,4 @@
|
|||
@(player: DbPlayer, engine: Boolean = false)(implicit ctx: Context)
|
||||
@(player: Player, engine: Boolean = false)(implicit ctx: Context)
|
||||
|
||||
@ai(level: Int) = {
|
||||
<div class="username connected">
|
|
@ -1,4 +1,4 @@
|
|||
@(pov: Pov, version: Int, roomHtml: Html, bookmarkers: List[String], analysed: Boolean, tour: Option[lila.app.tournament.Tournament])(implicit ctx: Context)
|
||||
@(pov: Pov, version: Int, roomHtml: Html, bookmarkers: List[String], analysed: Boolean, tour: Option[lila.tournament.Tournament])(implicit ctx: Context)
|
||||
|
||||
@import pov._
|
||||
|
||||
|
@ -20,8 +20,8 @@ underchat = underchat.some) {
|
|||
data-table-url="@routes.Round.tableWatcher(gameId, color.name)"
|
||||
data-players-url="@routes.Round.players(gameId)">
|
||||
<div class="lichess_board_wrap">
|
||||
@widget.connection()
|
||||
<div class="lichess_board with_marks">@Html(ui.Board.render(pov))</div>
|
||||
@site.connection()
|
||||
<div class="lichess_board with_marks">@Html(lila.app.ui.Board.render(pov))</div>
|
||||
<div id="dont_touch">@trans.youAreViewingThisGameAsASpectator()</div>
|
||||
</div>
|
||||
<div class="lichess_ground">
|
||||
|
@ -59,10 +59,14 @@ underchat = underchat.some) {
|
|||
<a href="@routes.Round.watcher(gameId, (!color).name)">@trans.flipBoard()</a>
|
||||
@if(game.pgnImport.isEmpty) {
|
||||
<br />
|
||||
@* TODO
|
||||
<a href="@routes.Analyse.stats(gameId)">@trans.viewGameStats()</a>
|
||||
*@
|
||||
}
|
||||
<br />
|
||||
@* TODO
|
||||
<a class="view_pgn_toggle" href="@routes.Analyse.pgn(game.id)">View PGN</a>
|
||||
*@
|
||||
</nav>
|
||||
}
|
||||
}
|
48
conf/routes
48
conf/routes
|
@ -38,34 +38,34 @@ GET /games/search controllers.Search.form(page: Int ?= 1)
|
|||
GET /$gameId<[\w\-]{8}> controllers.Round.watcher(gameId: String, color: String = "white")
|
||||
GET /$gameId<[\w\-]{8}>/$color<white|black> controllers.Round.watcher(gameId: String, color: String)
|
||||
GET /$fullId<[\w\-]{12}> controllers.Round.player(fullId: String)
|
||||
# GET /$gameId<[\w\-]{8}>/$color<white|black>/socket controllers.Round.websocketWatcher(gameId: String, color: String)
|
||||
# GET /$gameId<[\w\-]{8}>/s.js controllers.Round.signedJs(gameId: String)
|
||||
# GET /$fullId<[\w\-]{12}>/socket controllers.Round.websocketPlayer(fullId: String)
|
||||
# GET /$fullId<[\w\-]{12}>/abort controllers.Round.abort(fullId: String)
|
||||
# GET /$fullId<[\w\-]{12}>/resign controllers.Round.resign(fullId: String)
|
||||
# GET /$fullId<[\w\-]{12}>/resign/force controllers.Round.resignForce(fullId: String)
|
||||
# GET /$fullId<[\w\-]{12}>/draw/claim controllers.Round.drawClaim(fullId: String)
|
||||
# GET /$fullId<[\w\-]{12}>/draw/accept controllers.Round.drawAccept(fullId: String)
|
||||
# GET /$fullId<[\w\-]{12}>/draw/offer controllers.Round.drawOffer(fullId: String)
|
||||
# GET /$fullId<[\w\-]{12}>/draw/cancel controllers.Round.drawCancel(fullId: String)
|
||||
# GET /$fullId<[\w\-]{12}>/draw/decline controllers.Round.drawDecline(fullId: String)
|
||||
# GET /$fullId<[\w\-]{12}>/rematch controllers.Round.rematch(fullId: String)
|
||||
# GET /$fullId<[\w\-]{12}>/rematch/cancel controllers.Round.rematchCancel(fullId: String)
|
||||
# GET /$fullId<[\w\-]{12}>/rematch/decline controllers.Round.rematchDecline(fullId: String)
|
||||
# GET /$fullId<[\w\-]{12}>/takeback/accept controllers.Round.takebackAccept(fullId: String)
|
||||
# GET /$fullId<[\w\-]{12}>/takeback/offer controllers.Round.takebackOffer(fullId: String)
|
||||
# GET /$fullId<[\w\-]{12}>/takeback/cancel controllers.Round.takebackCancel(fullId: String)
|
||||
# GET /$fullId<[\w\-]{12}>/takeback/decline controllers.Round.takebackDecline(fullId: String)
|
||||
# GET /$gameId<[\w\-]{8}>/$color<white|black>/table controllers.Round.tableWatcher(gameId: String, color: String)
|
||||
# GET /$fullId<[\w\-]{12}>/table controllers.Round.tablePlayer(fullId: String)
|
||||
# GET /$gameId<[\w\-]{8}>/players controllers.Round.players(gameId: String)
|
||||
#
|
||||
GET /$gameId<[\w\-]{8}>/$color<white|black>/socket controllers.Round.websocketWatcher(gameId: String, color: String)
|
||||
GET /$gameId<[\w\-]{8}>/s.js controllers.Round.signedJs(gameId: String)
|
||||
GET /$fullId<[\w\-]{12}>/socket controllers.Round.websocketPlayer(fullId: String)
|
||||
GET /$fullId<[\w\-]{12}>/abort controllers.Round.abort(fullId: String)
|
||||
GET /$fullId<[\w\-]{12}>/resign controllers.Round.resign(fullId: String)
|
||||
GET /$fullId<[\w\-]{12}>/resign/force controllers.Round.resignForce(fullId: String)
|
||||
GET /$fullId<[\w\-]{12}>/draw/claim controllers.Round.drawClaim(fullId: String)
|
||||
GET /$fullId<[\w\-]{12}>/draw/accept controllers.Round.drawAccept(fullId: String)
|
||||
GET /$fullId<[\w\-]{12}>/draw/offer controllers.Round.drawOffer(fullId: String)
|
||||
GET /$fullId<[\w\-]{12}>/draw/cancel controllers.Round.drawCancel(fullId: String)
|
||||
GET /$fullId<[\w\-]{12}>/draw/decline controllers.Round.drawDecline(fullId: String)
|
||||
GET /$fullId<[\w\-]{12}>/rematch controllers.Round.rematch(fullId: String)
|
||||
GET /$fullId<[\w\-]{12}>/rematch/cancel controllers.Round.rematchCancel(fullId: String)
|
||||
GET /$fullId<[\w\-]{12}>/rematch/decline controllers.Round.rematchDecline(fullId: String)
|
||||
GET /$fullId<[\w\-]{12}>/takeback/accept controllers.Round.takebackAccept(fullId: String)
|
||||
GET /$fullId<[\w\-]{12}>/takeback/offer controllers.Round.takebackOffer(fullId: String)
|
||||
GET /$fullId<[\w\-]{12}>/takeback/cancel controllers.Round.takebackCancel(fullId: String)
|
||||
GET /$fullId<[\w\-]{12}>/takeback/decline controllers.Round.takebackDecline(fullId: String)
|
||||
GET /$gameId<[\w\-]{8}>/$color<white|black>/table controllers.Round.tableWatcher(gameId: String, color: String)
|
||||
GET /$fullId<[\w\-]{12}>/table controllers.Round.tablePlayer(fullId: String)
|
||||
GET /$gameId<[\w\-]{8}>/players controllers.Round.players(gameId: String)
|
||||
|
||||
# Tournament
|
||||
# GET /tournament controllers.Tournament.home
|
||||
# GET /tournament/reload controllers.Tournament.homeReload
|
||||
# GET /tournament/new controllers.Tournament.form
|
||||
# POST /tournament/new controllers.Tournament.create
|
||||
# GET /tournament/$id<[\w\-]{8}> controllers.Tournament.show(id: String)
|
||||
GET /tournament/$id<[\w\-]{8}> controllers.Tournament.show(id: String)
|
||||
# GET /tournament/$id<[\w\-]{8}>/socket controllers.Tournament.websocket(id: String)
|
||||
# POST /tournament/$id<[\w\-]{8}>/join controllers.Tournament.join(id: String)
|
||||
# POST /tournament/$id<[\w\-]{8}>/withdraw controllers.Tournament.withdraw(id: String)
|
||||
|
@ -152,7 +152,7 @@ GET /wiki/:slug controllers.Wiki.show(slug: String)
|
|||
# GET /lobby/log controllers.Lobby.log
|
||||
#
|
||||
# Bookmark
|
||||
# POST /bookmark/$gameId<[\w\-]{8}> controllers.Bookmark.toggle(gameId: String)
|
||||
POST /bookmark/$gameId<[\w\-]{8}> controllers.Bookmark.toggle(gameId: String)
|
||||
|
||||
# Forum
|
||||
GET /forum controllers.ForumCateg.index
|
||||
|
|
|
@ -127,6 +127,12 @@ trait WithPlay extends Zeros { self: PackageObject ⇒
|
|||
def doUnless(cond: Boolean): Fu[A] = doIf(!cond)
|
||||
}
|
||||
|
||||
implicit final class LilaPimpedBooleanForFuture(b: Boolean) {
|
||||
|
||||
def optionFu[A](v: ⇒ Fu[A]): Fu[Option[A]] =
|
||||
if (b) v map (_.some) else fuccess(none)
|
||||
}
|
||||
|
||||
object makeTimeout {
|
||||
|
||||
import akka.util.Timeout
|
||||
|
|
|
@ -393,35 +393,35 @@ object Game {
|
|||
|
||||
def takeGameId(fullId: String) = fullId take gameIdSize
|
||||
|
||||
def make(
|
||||
game: ChessGame,
|
||||
whitePlayer: Player,
|
||||
blackPlayer: Player,
|
||||
ai: Option[(Color, Int)],
|
||||
creatorColor: Color,
|
||||
mode: Mode,
|
||||
variant: Variant,
|
||||
source: Source,
|
||||
pgnImport: Option[PgnImport]): Game = Game(
|
||||
id = IdGenerator.game,
|
||||
token = IdGenerator.token,
|
||||
whitePlayer = whitePlayer withEncodedPieces game.allPieces,
|
||||
blackPlayer = blackPlayer withEncodedPieces game.allPieces,
|
||||
status = Status.Created,
|
||||
turns = game.turns,
|
||||
clock = game.clock,
|
||||
lastMove = None,
|
||||
check = None,
|
||||
creatorColor = creatorColor,
|
||||
positionHashes = "",
|
||||
castles = "KQkq",
|
||||
mode = mode,
|
||||
variant = variant,
|
||||
lastMoveTime = None,
|
||||
metadata = Metadata(
|
||||
source = source,
|
||||
pgnImport = pgnImport).some,
|
||||
createdAt = DateTime.now)
|
||||
def make(
|
||||
game: ChessGame,
|
||||
whitePlayer: Player,
|
||||
blackPlayer: Player,
|
||||
ai: Option[(Color, Int)],
|
||||
creatorColor: Color,
|
||||
mode: Mode,
|
||||
variant: Variant,
|
||||
source: Source,
|
||||
pgnImport: Option[PgnImport]): Game = Game(
|
||||
id = IdGenerator.game,
|
||||
token = IdGenerator.token,
|
||||
whitePlayer = whitePlayer withEncodedPieces game.allPieces,
|
||||
blackPlayer = blackPlayer withEncodedPieces game.allPieces,
|
||||
status = Status.Created,
|
||||
turns = game.turns,
|
||||
clock = game.clock,
|
||||
lastMove = None,
|
||||
check = None,
|
||||
creatorColor = creatorColor,
|
||||
positionHashes = "",
|
||||
castles = "KQkq",
|
||||
mode = mode,
|
||||
variant = variant,
|
||||
lastMoveTime = None,
|
||||
metadata = Metadata(
|
||||
source = source,
|
||||
pgnImport = pgnImport).some,
|
||||
createdAt = DateTime.now)
|
||||
|
||||
import lila.db.Tube
|
||||
import play.api.libs.json._
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package lila.game
|
||||
|
||||
final class GameJs(path: String, useCache: Boolean) {
|
||||
private[game] final class GameJs(path: String, useCache: Boolean) {
|
||||
|
||||
def unsigned: String = useCache.fold(cached, readFromSource)
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ object GameRepo {
|
|||
import Game._
|
||||
import Game.ShortFields._
|
||||
|
||||
def game(gameId: ID): Fu[Option[Game]] = $find byId gameId
|
||||
|
||||
def player(gameId: ID, color: Color): Fu[Option[Player]] =
|
||||
$find byId gameId map2 { (game: Game) ⇒ game player color }
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import play.api.templates.Html
|
|||
import akka.actor.ActorRef
|
||||
import akka.pattern.ask
|
||||
|
||||
final class Api(socketHub: ActorRef, renderer: ActorRef) {
|
||||
private[notification] final class Api(socketHub: ActorRef, renderer: ActorRef) {
|
||||
|
||||
private val repo = mutable.Map[String, List[Notification]]()
|
||||
import makeTimeout.large
|
||||
|
|
|
@ -70,7 +70,8 @@ final class Env(
|
|||
|
||||
lazy val messenger = new Messenger(i18nKeys)
|
||||
|
||||
val animationDelay = AnimationDelay
|
||||
def animationDelay = AnimationDelay
|
||||
def moretimeSeconds = Moretime.toSeconds
|
||||
|
||||
{
|
||||
import scala.concurrent.duration._
|
||||
|
|
|
@ -65,15 +65,6 @@ final class Messenger(i18nKeys: I18nKeys) {
|
|||
}
|
||||
}
|
||||
|
||||
// def render(game: Game): Fu[Option[String]] =
|
||||
// game.hasChat.fold(render(game.id) map (_.some), io(None))
|
||||
|
||||
// def render(roomId: String): Fu[String] =
|
||||
// roomRepo room roomId map (_.render)
|
||||
|
||||
// def renderWatcher(game: Game): Fu[String] =
|
||||
// watcherRoomRepo room game.id map (_.render)
|
||||
|
||||
private def cleanupText(text: String) = {
|
||||
val cleanedUp = text.trim.replace(""""""", "'")
|
||||
(cleanedUp.size <= 140 && cleanedUp.nonEmpty) option cleanedUp
|
||||
|
|
|
@ -2,8 +2,7 @@ package lila.round
|
|||
|
||||
case class Room(id: String, messages: List[String]) {
|
||||
|
||||
// def render: String =
|
||||
// messages map ((Room.render _) compose Room.decode) mkString ""
|
||||
def decodedMessages = messages map Room.decode
|
||||
|
||||
def rematchCopy(id: String, nb: Int) = copy(
|
||||
id = id,
|
||||
|
|
|
@ -3,7 +3,7 @@ package lila.round
|
|||
import lila.db.api._
|
||||
import tube.roomTube
|
||||
|
||||
private[round] object RoomRepo {
|
||||
object RoomRepo {
|
||||
|
||||
def room(id: String): Fu[Room] = $find byId id map (_ | Room(id, Nil))
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ private[round] final class Socket(
|
|||
}
|
||||
withMember(uid) { member ⇒
|
||||
history ? GetEventsSince(v) foreach {
|
||||
case MaybeEvents(events) ⇒ events.fold(resync(member))(batch(member, _))
|
||||
case maybeEvents ⇒ maybeEvents.fold(resync(member))(batch(member, _))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,6 @@ case class GameEvents(gameId: String, events: List[Event])
|
|||
case class GetGameVersion(gameId: String)
|
||||
case object GetVersion
|
||||
case class GetEventsSince(version: Int)
|
||||
case class MaybeEvents(events: Option[List[VersionedEvent]])
|
||||
case class AddEvent(event: Event)
|
||||
case object ClockSync
|
||||
case class IsConnectedOnGame(gameId: String, color: Color)
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
package lila.tournament
|
||||
|
||||
case class Tournament(id: String)
|
||||
case class Tournament(id: String) {
|
||||
|
||||
def isRunning = false
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
package controllers
|
||||
|
||||
import lila.app._
|
||||
import views._
|
||||
|
||||
object Notification extends LilaController {
|
||||
|
||||
private def api = env.notificationApi
|
||||
|
||||
def remove(id: String) = Auth { implicit ctx ⇒
|
||||
me ⇒
|
||||
Ok(api.remove(me.id, id))
|
||||
}
|
||||
}
|
|
@ -1,153 +0,0 @@
|
|||
package controllers
|
||||
|
||||
import lila.app._
|
||||
import views._
|
||||
import http.Context
|
||||
import game.{ DbGame, Pov }
|
||||
import round.Event
|
||||
import socket.Util.connectionFail
|
||||
|
||||
import play.api.mvc._
|
||||
import play.api.libs.json._
|
||||
import play.api.libs.iteratee._
|
||||
import play.api.templates.Html
|
||||
import scalaz.effects._
|
||||
|
||||
object Round extends LilaController with TheftPrevention with RoundEventPerformer {
|
||||
|
||||
private def gameRepo = env.game.gameRepo
|
||||
private def socket = env.round.socket
|
||||
private def hand = env.round.hand
|
||||
private def messenger = env.round.messenger
|
||||
private def rematcher = env.setup.rematcher
|
||||
private def bookmarkApi = env.bookmark.api
|
||||
private def userRepo = env.user.userRepo
|
||||
private def analyser = env.analyse.analyser
|
||||
private def tournamentRepo = env.tournament.repo
|
||||
private def gameJs = env.game.gameJs
|
||||
|
||||
def websocketWatcher(gameId: String, color: String) = WebSocket.async[JsValue] { req ⇒
|
||||
implicit val ctx = reqToCtx(req)
|
||||
socket.joinWatcher(
|
||||
gameId,
|
||||
color,
|
||||
getInt("version"),
|
||||
get("sri"),
|
||||
ctx).unsafePerformIO
|
||||
}
|
||||
|
||||
def websocketPlayer(fullId: String) = WebSocket.async[JsValue] { req ⇒
|
||||
implicit val ctx = reqToCtx(req)
|
||||
socket.joinPlayer(
|
||||
fullId,
|
||||
getInt("version"),
|
||||
get("sri"),
|
||||
get("tk2"),
|
||||
ctx).unsafePerformIO
|
||||
}
|
||||
|
||||
def signedJs(gameId: String) = Open { implicit ctx ⇒
|
||||
JsIOk(gameRepo token gameId map gameJs.sign, CACHE_CONTROL -> "max-age=3600")
|
||||
}
|
||||
|
||||
def player(fullId: String) = Open { implicit ctx ⇒
|
||||
IOptionIOResult(gameRepo pov fullId) { pov ⇒
|
||||
pov.game.started.fold(
|
||||
for {
|
||||
roomHtml ← messenger render pov.game
|
||||
bookmarkers ← bookmarkApi userIdsByGame pov.game
|
||||
engine ← pov.opponent.userId.fold(io(false))(userRepo.isEngine)
|
||||
analysed ← analyser has pov.gameId
|
||||
tour ← tournamentRepo byId pov.game.tournamentId
|
||||
} yield PreventTheft(pov) {
|
||||
Ok(html.round.player(
|
||||
pov,
|
||||
version(pov.gameId),
|
||||
engine,
|
||||
roomHtml map Html.apply,
|
||||
bookmarkers,
|
||||
analysed,
|
||||
tour = tour))
|
||||
},
|
||||
io(Redirect(routes.Setup.await(fullId)))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
def watcher(gameId: String, color: String) = Open { implicit ctx ⇒
|
||||
IOptionIOResult(gameRepo.pov(gameId, color)) { pov ⇒
|
||||
pov.game.started.fold(watch _, join _)(pov)
|
||||
}
|
||||
}
|
||||
|
||||
private def join(pov: Pov)(implicit ctx: Context): IO[Result] =
|
||||
gameRepo initialFen pov.gameId map { initialFen ⇒
|
||||
Ok(html.setup.join(
|
||||
pov, version(pov.gameId), env.setup.friendConfigMemo get pov.game.id, initialFen
|
||||
))
|
||||
}
|
||||
|
||||
private def watch(pov: Pov)(implicit ctx: Context): IO[Result] = for {
|
||||
bookmarkers ← bookmarkApi userIdsByGame pov.game
|
||||
roomHtml ← messenger renderWatcher pov.game
|
||||
analysed ← analyser has pov.gameId
|
||||
tour ← tournamentRepo byId pov.game.tournamentId
|
||||
} yield Ok(html.round.watcher(pov, version(pov.gameId), Html(roomHtml), bookmarkers, analysed, tour))
|
||||
|
||||
def abort(fullId: String) = performAndRedirect(fullId, hand.abort)
|
||||
def resign(fullId: String) = performAndRedirect(fullId, hand.resign)
|
||||
def resignForce(fullId: String) = performAndRedirect(fullId, hand.resignForce)
|
||||
def drawClaim(fullId: String) = performAndRedirect(fullId, hand.drawClaim)
|
||||
def drawAccept(fullId: String) = performAndRedirect(fullId, hand.drawAccept)
|
||||
def drawOffer(fullId: String) = performAndRedirect(fullId, hand.drawOffer)
|
||||
def drawCancel(fullId: String) = performAndRedirect(fullId, hand.drawCancel)
|
||||
def drawDecline(fullId: String) = performAndRedirect(fullId, hand.drawDecline)
|
||||
|
||||
def rematch(fullId: String) = Action {
|
||||
rematcher offerOrAccept fullId flatMap { validResult ⇒
|
||||
validResult.fold(
|
||||
err ⇒ putFailures(err) map { _ ⇒
|
||||
Redirect(routes.Round.player(fullId))
|
||||
}, {
|
||||
case (nextFullId, events) ⇒ performEvents(fullId)(events) map { _ ⇒
|
||||
Redirect(routes.Round.player(nextFullId))
|
||||
}
|
||||
}
|
||||
)
|
||||
} unsafePerformIO
|
||||
}
|
||||
def rematchCancel(fullId: String) = performAndRedirect(fullId, hand.rematchCancel)
|
||||
def rematchDecline(fullId: String) = performAndRedirect(fullId, hand.rematchDecline)
|
||||
|
||||
def takebackAccept(fullId: String) = performAndRedirect(fullId, hand.takebackAccept)
|
||||
def takebackOffer(fullId: String) = performAndRedirect(fullId, hand.takebackOffer)
|
||||
def takebackCancel(fullId: String) = performAndRedirect(fullId, hand.takebackCancel)
|
||||
def takebackDecline(fullId: String) = performAndRedirect(fullId, hand.takebackDecline)
|
||||
|
||||
def tableWatcher(gameId: String, color: String) = Open { implicit ctx ⇒
|
||||
IOptionOk(gameRepo.pov(gameId, color)) { html.round.table.watch(_) }
|
||||
}
|
||||
|
||||
def tablePlayer(fullId: String) = Open { implicit ctx ⇒
|
||||
IOptionIOk(gameRepo pov fullId) { pov ⇒
|
||||
tournamentRepo byId pov.game.tournamentId map { tour ⇒
|
||||
pov.game.playable.fold(
|
||||
html.round.table.playing(pov),
|
||||
html.round.table.end(pov, tour))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def players(gameId: String) = Open { implicit ctx ⇒
|
||||
import templating.Environment.playerLink
|
||||
JsonIOk(gameRepo game gameId map { gameOption ⇒
|
||||
~(gameOption map { game ⇒
|
||||
(game.players collect {
|
||||
case player if player.isHuman ⇒ player.color.name -> playerLink(player).body
|
||||
} toMap) ++ ~ctx.me.map(me ⇒ Map("me" -> me.usernameWithElo))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
private def version(gameId: String): Int = socket blockingVersion gameId
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package controllers
|
||||
|
||||
import lila.app._
|
||||
import core.CoreEnv
|
||||
import round.Event
|
||||
import game.{ DbGame, Pov }
|
||||
|
||||
import play.api.mvc._
|
||||
import play.api.mvc.Results._
|
||||
import scalaz.effects._
|
||||
|
||||
trait RoundEventPerformer {
|
||||
|
||||
protected def env: CoreEnv
|
||||
|
||||
protected type IOValidEvents = IO[Valid[List[Event]]]
|
||||
|
||||
protected def performAndRedirect(fullId: String, op: String ⇒ IOValidEvents) =
|
||||
Action {
|
||||
perform(fullId, op).unsafePerformIO
|
||||
Redirect(routes.Round.player(fullId))
|
||||
}
|
||||
|
||||
protected def perform(fullId: String, op: String ⇒ IOValidEvents): IO[Unit] =
|
||||
op(fullId) flatMap { validEvents ⇒
|
||||
validEvents.fold(_ => io(), performEvents(fullId))
|
||||
}
|
||||
|
||||
protected def performEvents(fullId: String)(events: List[Event]): IO[Unit] = io {
|
||||
env.round.socket.send(DbGame takeGameId fullId, events)
|
||||
}
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
package controllers
|
||||
|
||||
import lila.app._
|
||||
import views._
|
||||
import game.Pov
|
||||
import tournament.{ Created, Started, Finished }
|
||||
import http.Context
|
||||
import lila.common.Futuristic.ioToFuture
|
||||
|
||||
import scalaz.effects._
|
||||
import play.api.mvc._
|
||||
import play.api.libs.json._
|
||||
import play.api.libs.iteratee._
|
||||
import play.api.libs.concurrent._
|
||||
import play.api.templates.Html
|
||||
import play.api.libs.concurrent.Execution.Implicits._
|
||||
|
||||
object Tournament extends LilaController {
|
||||
|
||||
private def repo = env.tournament.repo
|
||||
private def forms = env.tournament.forms
|
||||
private def api = env.tournament.api
|
||||
private def socket = env.tournament.socket
|
||||
private def messenger = env.tournament.messenger
|
||||
private def userRepo = env.user.userRepo
|
||||
private def gameRepo = env.game.gameRepo
|
||||
|
||||
val home = Open { implicit ctx ⇒
|
||||
Async {
|
||||
futureTournaments zip userRepo.sortedByToints(10).toFuture map {
|
||||
case (((created, started), finished), leaderboard) ⇒
|
||||
Ok(html.tournament.home(created, started, finished, leaderboard))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val faq = Open { implicit ctx ⇒ Ok(html.tournament.faqPage()) }
|
||||
|
||||
val homeReload = Open { implicit ctx ⇒
|
||||
Async {
|
||||
futureTournaments map {
|
||||
case ((created, started), finished) ⇒
|
||||
Ok(html.tournament.homeInner(created, started, finished))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def futureTournaments =
|
||||
repo.created.toFuture zip repo.started.toFuture zip repo.finished(20).toFuture
|
||||
|
||||
def show(id: String) = Open { implicit ctx ⇒
|
||||
IOResult(for {
|
||||
t ← repo byId id
|
||||
res ← t match {
|
||||
case Some(tour: Created) ⇒ showCreated(tour) map { Ok(_) }
|
||||
case Some(tour: Started) ⇒ showStarted(tour) map { Ok(_) }
|
||||
case Some(tour: Finished) ⇒ showFinished(tour) map { Ok(_) }
|
||||
case _ ⇒ io(NotFound(html.tournament.notFound()))
|
||||
}
|
||||
} yield res)
|
||||
}
|
||||
|
||||
private def showCreated(tour: Created)(implicit ctx: Context) = for {
|
||||
roomHtml ← messenger render tour
|
||||
} yield html.tournament.show.created(
|
||||
tour = tour,
|
||||
roomHtml = Html(roomHtml),
|
||||
version = version(tour.id))
|
||||
|
||||
private def showStarted(tour: Started)(implicit ctx: Context) = for {
|
||||
roomHtml ← messenger render tour
|
||||
games ← gameRepo games (tour recentGameIds 4)
|
||||
pov ← tour.userCurrentPov(ctx.me).fold(io(none[Pov]))(gameRepo.pov)
|
||||
} yield html.tournament.show.started(
|
||||
tour = tour,
|
||||
roomHtml = Html(roomHtml),
|
||||
version = version(tour.id),
|
||||
games = games,
|
||||
pov = pov)
|
||||
|
||||
private def showFinished(tour: Finished)(implicit ctx: Context) = for {
|
||||
roomHtml ← messenger render tour
|
||||
games ← gameRepo games (tour recentGameIds 4)
|
||||
} yield html.tournament.show.finished(
|
||||
tour = tour,
|
||||
roomHtml = Html(roomHtml),
|
||||
version = version(tour.id),
|
||||
games = games)
|
||||
|
||||
def join(id: String) = AuthBody { implicit ctx ⇒
|
||||
implicit me ⇒
|
||||
NoEngine {
|
||||
IOptionIORedirect(repo createdById id) { tour ⇒
|
||||
api.join(tour, me).fold(
|
||||
err ⇒ putStrLn(err.shows) map (_ ⇒ routes.Tournament.home()),
|
||||
res ⇒ res map (_ ⇒ routes.Tournament.show(tour.id))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def withdraw(id: String) = Auth { implicit ctx ⇒
|
||||
implicit me ⇒
|
||||
IOptionIORedirect(repo byId id) { tour ⇒
|
||||
api.withdraw(tour, me.id) inject routes.Tournament.show(tour.id)
|
||||
}
|
||||
}
|
||||
|
||||
def earlyStart(id: String) = Auth { implicit ctx ⇒
|
||||
implicit me ⇒
|
||||
IOptionIORedirect(repo.createdByIdAndCreator(id, me.id)) { tour ⇒
|
||||
~api.earlyStart(tour) inject routes.Tournament.show(tour.id)
|
||||
}
|
||||
}
|
||||
|
||||
def reload(id: String) = Open { implicit ctx ⇒
|
||||
IOptionIOk(repo byId id) {
|
||||
case tour: Created ⇒ reloadCreated(tour)
|
||||
case tour: Started ⇒ reloadStarted(tour)
|
||||
case tour: Finished ⇒ reloadFinished(tour)
|
||||
}
|
||||
}
|
||||
|
||||
private def reloadCreated(tour: Created)(implicit ctx: Context) = io {
|
||||
val inner = html.tournament.show.createdInner(tour)
|
||||
html.tournament.show.inner(none)(inner)
|
||||
}
|
||||
|
||||
private def reloadStarted(tour: Started)(implicit ctx: Context) = for {
|
||||
games ← gameRepo games (tour recentGameIds 4)
|
||||
pov ← tour.userCurrentPov(ctx.me).fold(io(none[Pov]))(gameRepo.pov)
|
||||
} yield {
|
||||
val pairings = html.tournament.pairings(tour)
|
||||
val inner = html.tournament.show.startedInner(tour, games, pov)
|
||||
html.tournament.show.inner(pairings.some)(inner)
|
||||
}
|
||||
|
||||
private def reloadFinished(tour: Finished)(implicit ctx: Context) =
|
||||
gameRepo games (tour recentGameIds 4) map { games ⇒
|
||||
val pairings = html.tournament.pairings(tour)
|
||||
val inner = html.tournament.show.finishedInner(tour, games)
|
||||
html.tournament.show.inner(pairings.some)(inner)
|
||||
}
|
||||
|
||||
def form = Auth { implicit ctx ⇒
|
||||
me ⇒
|
||||
NoEngine {
|
||||
Ok(html.tournament.form(forms.create, forms))
|
||||
}
|
||||
}
|
||||
|
||||
def create = AuthBody { implicit ctx ⇒
|
||||
implicit me ⇒
|
||||
NoEngine {
|
||||
IOResult {
|
||||
implicit val req = ctx.body
|
||||
forms.create.bindFromRequest.fold(
|
||||
err ⇒ io(BadRequest(html.tournament.form(err, forms))),
|
||||
setup ⇒ api.createTournament(setup, me) map { tour ⇒
|
||||
Redirect(routes.Tournament.show(tour.id))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def websocket(id: String) = WebSocket.async[JsValue] { req ⇒
|
||||
implicit val ctx = reqToCtx(req)
|
||||
socket.join(id, getInt("version"), get("sri"), ctx.me).unsafePerformIO
|
||||
}
|
||||
|
||||
private def version(tournamentId: String): Int = socket blockingVersion tournamentId
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
@(roomHtml: Html, spectator: Boolean)(implicit ctx: Context)
|
||||
|
||||
@base.chatRoom(
|
||||
title = spectator.fold(trans.spectatorRoom, trans.chatRoom).str(),
|
||||
cssClass = spectator.fold("spectator", "kings"))(roomHtml)
|
Loading…
Reference in New Issue