lila/app/controllers/User.scala
Thibault Duplessis b96b982209 Merge branch 'master' into antichess
* master: (116 commits)
  use Game.updatedAt when last move time is not available
  integrate analysis board with correspondence games
  improve analysis integration
  add screenshot
  fix analysis board highlights
  more cache tweaks
  don't show games older than 5 minutes
  improve current game detection
  hr "hrvatski" translation #11283. Author: gus_fring.
  update sl translation
  hu "Magyar" translation #11279. Author: OMMHOA. Couldn't translate perfectly "proceed" so it's "go" instead.
  ca "Català, valencià" translation #11278. Author: pedrolo.
  uk "українська" translation #11276. Author: IvTK.
  nl "Nederlands" translation #11274. Author: rokbe. correspondensie -> correspondentie
  sv "svenska" translation #11273. Author: nuwonga.
  sq "Shqip" translation #11271. Author: xhevati.
  pl "polski" translation #11268. Author: pirouetti.
  tr "Türkçe" translation #11265. Author: mabolek.
  sv "svenska" translation #11264. Author: Weckipecki.
  ca "Català, valencià" translation #11263. Author: Borchess.
  ...

Conflicts:
	modules/chess
	ui/analyse/src/ctrl.js
2014-12-24 15:47:38 +01:00

190 lines
6.5 KiB
Scala

package controllers
import play.api.mvc._, Results._
import lila.api.Context
import lila.app._
import lila.app.mashup.GameFilterMenu
import lila.common.LilaCookie
import lila.db.api.$find
import lila.game.{ GameRepo, Pov }
import lila.rating.PerfType
import lila.security.Permission
import lila.user.tube.userTube
import lila.user.{ User => UserModel, UserRepo }
import views._
object User extends LilaController {
private def env = Env.user
private def gamePaginator = Env.game.paginator
private def forms = lila.user.DataForm
private def relationApi = Env.relation.api
def tv(username: String) = Open { implicit ctx =>
OptionFuResult(UserRepo named username) { user =>
(GameRepo lastPlayed user) orElse
(GameRepo lastPlayed user) flatMap {
_.fold(fuccess(Redirect(routes.User.show(username)))) { pov =>
Round.watch(pov, userTv = user.some)
}
}
}
}
def show(username: String) = Open { implicit ctx =>
filter(username, none, 1)
}
def showMini(username: String) = Open { implicit ctx =>
OptionFuResult(UserRepo named username) { user =>
GameRepo lastPlayed user zip
(ctx.userId ?? { relationApi.blocks(user.id, _) }) zip
(ctx.isAuth ?? { Env.pref.api.followable(user.id) }) zip
(ctx.userId ?? { relationApi.relation(_, user.id) }) map {
case (((pov, blocked), followable), relation) =>
Ok(html.user.mini(user, pov, blocked, followable, relation))
.withHeaders(CACHE_CONTROL -> "max-age=5")
}
}
}
def showFilter(username: String, filterName: String, page: Int) = Open { implicit ctx =>
filter(username, filterName.some, page)
}
def online = Open { implicit req =>
val max = 1000
UserRepo.byIdsSortRating(env.onlineUserIdMemo.keys, max) map { html.user.online(_, max) }
}
private def filter(
username: String,
filterOption: Option[String],
page: Int,
status: Results.Status = Results.Ok)(implicit ctx: Context) =
Reasonable(page) {
OptionFuResult(UserRepo named username) { u =>
(u.enabled || isGranted(_.UserSpy)).fold({
if (lila.common.HTTPRequest.isSynchronousHttp(ctx.req))
userShow(u, filterOption, page)
else
userGames(u, filterOption, page)
} map { status(_) },
fuccess(NotFound(html.user.disabled(u)))
)
}
}
private def userShow(u: UserModel, filterOption: Option[String], page: Int)(implicit ctx: Context) = for {
info Env.current.userInfo(u, ctx)
filterName = filterOption | "all"
filters = GameFilterMenu(info, ctx.me, filterName)
pag <- GameFilterMenu.paginatorOf(
user = u,
info = info.some,
filter = filters.current,
me = ctx.me,
page = page)
relation <- ctx.userId ?? { relationApi.relation(_, u.id) }
notes <- ctx.me ?? { me =>
relationApi friends me.id flatMap { env.noteApi.get(u, me, _) }
}
followable <- ctx.isAuth ?? { Env.pref.api followable u.id }
blocked <- ctx.userId ?? { relationApi.blocks(u.id, _) }
} yield html.user.show(u, info, pag, filters, relation, notes, followable, blocked)
private def userGames(u: UserModel, filterOption: Option[String], page: Int)(implicit ctx: Context) = {
val filterName = filterOption | "all"
GameFilterMenu.paginatorOf(
user = u,
info = none,
filter = GameFilterMenu.currentOf(GameFilterMenu.all, filterName),
me = ctx.me,
page = page
) map { html.user.games(u, _, filterName) }
}
def list = Open { implicit ctx =>
val nb = 10
for {
bullet env.cached topPerf PerfType.Bullet.key
blitz env.cached topPerf PerfType.Blitz.key
classical env.cached topPerf PerfType.Classical.key
chess960 env.cached topPerf PerfType.Chess960.key
kingOfTheHill env.cached topPerf PerfType.KingOfTheHill.key
threeCheck env.cached topPerf PerfType.ThreeCheck.key
antichess <- env.cached topPerf PerfType.Antichess.key
nbAllTime env.cached topNbGame nb map2 { (user: UserModel) =>
user -> user.count.game
}
nbWeek Env.game.cached activePlayerUidsWeek nb flatMap { pairs =>
UserRepo.byOrderedIds(pairs.map(_.userId)) map (_ zip pairs.map(_.nb))
}
tourneyWinners Env.tournament.winners scheduled nb
online env.cached topOnline 30
} yield html.user.list(
tourneyWinners = tourneyWinners,
online = online,
bullet = bullet,
blitz = blitz,
classical = classical,
chess960 = chess960,
kingOfTheHill = kingOfTheHill,
threeCheck = threeCheck,
antichess = antichess,
nbWeek = nbWeek,
nbAllTime = nbAllTime)
}
def mod(username: String) = Secure(_.UserSpy) { implicit ctx =>
me => OptionFuOk(UserRepo named username) { user =>
Env.evaluation.evaluator find user zip
(Env.security userSpy user.id) map {
case (eval, spy) => html.user.mod(user, spy, eval)
}
}
}
def evaluate(username: String) = Secure(_.UserEvaluate) { implicit ctx =>
me => OptionFuResult(UserRepo named username) { user =>
Env.evaluation.evaluator.generate(user.id, true) inject Redirect(routes.User.show(username).url + "?mod")
}
}
def writeNote(username: String) = AuthBody { implicit ctx =>
me => OptionFuResult(UserRepo named username) { user =>
implicit val req = ctx.body
env.forms.note.bindFromRequest.fold(
err => filter(username, none, 1, Results.BadRequest),
text => env.noteApi.write(user, text, me) inject Redirect(routes.User.show(username).url + "?note")
)
}
}
def opponents(username: String) = Open { implicit ctx =>
OptionFuOk(UserRepo named username) { user =>
lila.game.BestOpponents(user.id, 50) flatMap { ops =>
ctx.isAuth.fold(
Env.pref.api.followables(ops map (_._1.id)),
fuccess(List.fill(50)(true))
) flatMap { followables =>
(ops zip followables).map {
case ((u, nb), followable) => ctx.userId ?? { myId =>
relationApi.relation(myId, u.id)
} map { lila.relation.Related(u, nb, followable, _) }
}.sequenceFu map { relateds =>
html.user.opponents(user, relateds)
}
}
}
}
}
def autocomplete = Open { implicit ctx =>
get("term", ctx.req).filter(_.nonEmpty).fold(BadRequest("No search term provided").fuccess: Fu[Result]) { term =>
JsonOk(UserRepo usernamesLike term)
}
}
}