2013-03-20 08:23:41 -06:00
|
|
|
package controllers
|
|
|
|
|
2015-05-19 09:59:12 -06:00
|
|
|
import play.api.libs.json.Json
|
2013-09-11 04:38:16 -06:00
|
|
|
import play.api.mvc._, Results._
|
|
|
|
|
2014-01-13 14:11:17 -07:00
|
|
|
import lila.api.Context
|
2013-03-20 08:23:41 -06:00
|
|
|
import lila.app._
|
2014-06-28 03:58:38 -06:00
|
|
|
import lila.app.mashup.GameFilterMenu
|
2013-06-28 05:52:52 -06:00
|
|
|
import lila.common.LilaCookie
|
|
|
|
import lila.db.api.$find
|
2015-04-25 23:44:35 -06:00
|
|
|
import lila.evaluation.{ PlayerAggregateAssessment }
|
2014-08-15 05:44:32 -06:00
|
|
|
import lila.game.{ GameRepo, Pov }
|
|
|
|
import lila.rating.PerfType
|
2013-03-20 08:23:41 -06:00
|
|
|
import lila.security.Permission
|
2013-05-08 09:41:12 -06:00
|
|
|
import lila.user.tube.userTube
|
2014-02-17 02:12:19 -07:00
|
|
|
import lila.user.{ User => UserModel, UserRepo }
|
2013-06-28 05:52:52 -06:00
|
|
|
import views._
|
2013-03-20 08:23:41 -06:00
|
|
|
|
|
|
|
object User extends LilaController {
|
|
|
|
|
2013-05-08 09:41:12 -06:00
|
|
|
private def env = Env.user
|
|
|
|
private def gamePaginator = Env.game.paginator
|
2013-03-20 08:23:41 -06:00
|
|
|
private def forms = lila.user.DataForm
|
2014-04-17 06:10:08 -06:00
|
|
|
private def relationApi = Env.relation.api
|
2013-05-08 09:41:12 -06:00
|
|
|
|
2014-08-15 05:44:32 -06:00
|
|
|
def tv(username: String) = Open { implicit ctx =>
|
|
|
|
OptionFuResult(UserRepo named username) { user =>
|
2014-12-26 14:18:32 -07:00
|
|
|
(GameRepo lastPlayedPlaying user) orElse
|
2014-12-23 17:34:13 -07:00
|
|
|
(GameRepo lastPlayed user) flatMap {
|
2014-12-20 07:01:19 -07:00
|
|
|
_.fold(fuccess(Redirect(routes.User.show(username)))) { pov =>
|
2014-08-15 05:44:32 -06:00
|
|
|
Round.watch(pov, userTv = user.some)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-17 02:12:19 -07:00
|
|
|
def show(username: String) = Open { implicit ctx =>
|
2014-03-16 14:57:15 -06:00
|
|
|
filter(username, none, 1)
|
2013-07-26 16:29:07 -06:00
|
|
|
}
|
|
|
|
|
2014-02-17 02:12:19 -07:00
|
|
|
def showMini(username: String) = Open { implicit ctx =>
|
|
|
|
OptionFuResult(UserRepo named username) { user =>
|
2014-12-26 14:18:32 -07:00
|
|
|
GameRepo lastPlayedPlaying user zip
|
2014-04-17 06:10:08 -06:00
|
|
|
(ctx.userId ?? { relationApi.blocks(user.id, _) }) zip
|
2015-05-29 21:31:59 -06:00
|
|
|
(ctx.userId ?? { Env.game.crosstableApi(user.id, _) }) zip
|
2014-05-03 01:39:20 -06:00
|
|
|
(ctx.isAuth ?? { Env.pref.api.followable(user.id) }) zip
|
2014-04-22 17:28:19 -06:00
|
|
|
(ctx.userId ?? { relationApi.relation(_, user.id) }) map {
|
2015-05-29 21:31:59 -06:00
|
|
|
case ((((pov, blocked), crosstable), followable), relation) =>
|
|
|
|
Ok(html.user.mini(user, pov, blocked, followable, relation, crosstable))
|
2014-05-14 14:01:22 -06:00
|
|
|
.withHeaders(CACHE_CONTROL -> "max-age=5")
|
2014-04-17 03:34:55 -06:00
|
|
|
}
|
2013-12-24 06:58:54 -07:00
|
|
|
}
|
2013-05-20 22:12:10 -06:00
|
|
|
}
|
2013-05-08 09:41:12 -06:00
|
|
|
|
2014-02-17 02:12:19 -07:00
|
|
|
def showFilter(username: String, filterName: String, page: Int) = Open { implicit ctx =>
|
2014-03-16 14:57:15 -06:00
|
|
|
filter(username, filterName.some, page)
|
2013-05-20 22:12:10 -06:00
|
|
|
}
|
|
|
|
|
2014-02-17 02:12:19 -07:00
|
|
|
def online = Open { implicit req =>
|
2014-04-23 12:04:52 -06:00
|
|
|
val max = 1000
|
2015-06-04 15:37:31 -06:00
|
|
|
var fu = UserRepo.byIdsSortRating(env.onlineUserIdMemo.keys, max)
|
|
|
|
negotiate(
|
|
|
|
html = fu map { html.user.online(_, max) },
|
|
|
|
api = _ => fu map { list => Ok(Json.toJson(list.map(env.jsonView(_, true)))) }
|
|
|
|
)
|
2013-07-26 04:50:29 -06:00
|
|
|
}
|
|
|
|
|
2014-04-22 17:22:57 -06:00
|
|
|
private def filter(
|
|
|
|
username: String,
|
|
|
|
filterOption: Option[String],
|
|
|
|
page: Int,
|
|
|
|
status: Results.Status = Results.Ok)(implicit ctx: Context) =
|
2013-05-08 09:41:12 -06:00
|
|
|
Reasonable(page) {
|
2014-02-17 02:12:19 -07:00
|
|
|
OptionFuResult(UserRepo named username) { u =>
|
2015-05-19 09:59:12 -06:00
|
|
|
if (u.enabled || isGranted(_.UserSpy)) negotiate(
|
|
|
|
html = {
|
|
|
|
if (lila.common.HTTPRequest.isSynchronousHttp(ctx.req)) userShow(u, filterOption, page)
|
|
|
|
else userGames(u, filterOption, page) map {
|
|
|
|
case (filterName, pag) => html.user.games(u, pag, filterName)
|
|
|
|
}
|
|
|
|
} map { status(_) },
|
|
|
|
api = _ => userGames(u, filterOption, page) map {
|
2015-05-24 07:17:15 -06:00
|
|
|
case (filterName, pag) => Ok(Env.api.userGameApi.filter(filterName, pag))
|
2015-05-19 09:59:12 -06:00
|
|
|
})
|
|
|
|
else negotiate(
|
|
|
|
html = fuccess(NotFound(html.user.disabled(u))),
|
|
|
|
api = _ => fuccess(NotFound(Json.obj("error" -> "No such user, or account closed"))))
|
2013-10-20 02:03:23 -06:00
|
|
|
}
|
2013-05-04 17:12:53 -06:00
|
|
|
}
|
2013-03-20 07:24:47 -06:00
|
|
|
|
2014-03-16 14:57:15 -06:00
|
|
|
private def userShow(u: UserModel, filterOption: Option[String], page: Int)(implicit ctx: Context) = for {
|
2013-10-20 02:03:23 -06:00
|
|
|
info ← Env.current.userInfo(u, ctx)
|
2014-12-26 09:59:14 -07:00
|
|
|
filters = GameFilterMenu(info, ctx.me, filterOption)
|
2014-11-17 18:54:16 -07:00
|
|
|
pag <- GameFilterMenu.paginatorOf(
|
|
|
|
user = u,
|
|
|
|
info = info.some,
|
|
|
|
filter = filters.current,
|
|
|
|
me = ctx.me,
|
|
|
|
page = page)
|
2014-04-17 06:10:08 -06:00
|
|
|
relation <- ctx.userId ?? { relationApi.relation(_, u.id) }
|
2014-04-22 17:22:57 -06:00
|
|
|
notes <- ctx.me ?? { me =>
|
|
|
|
relationApi friends me.id flatMap { env.noteApi.get(u, me, _) }
|
|
|
|
}
|
2014-05-03 01:39:20 -06:00
|
|
|
followable <- ctx.isAuth ?? { Env.pref.api followable u.id }
|
2014-05-26 06:49:43 -06:00
|
|
|
blocked <- ctx.userId ?? { relationApi.blocks(u.id, _) }
|
|
|
|
} yield html.user.show(u, info, pag, filters, relation, notes, followable, blocked)
|
2013-05-08 09:41:12 -06:00
|
|
|
|
2014-06-28 03:58:38 -06:00
|
|
|
private def userGames(u: UserModel, filterOption: Option[String], page: Int)(implicit ctx: Context) = {
|
2014-12-26 09:59:14 -07:00
|
|
|
import lila.app.mashup.GameFilter.{ All, Playing }
|
2014-12-30 03:37:42 -07:00
|
|
|
filterOption.fold({
|
2015-04-04 06:05:40 -06:00
|
|
|
Env.simul isHosting u.id map (_.fold(Playing, All).name)
|
2014-12-30 03:37:42 -07:00
|
|
|
})(fuccess) flatMap { filterName =>
|
|
|
|
GameFilterMenu.paginatorOf(
|
|
|
|
user = u,
|
|
|
|
info = none,
|
|
|
|
filter = GameFilterMenu.currentOf(GameFilterMenu.all, filterName),
|
|
|
|
me = ctx.me,
|
|
|
|
page = page
|
2015-05-19 09:59:12 -06:00
|
|
|
) map { filterName -> _ }
|
2014-12-26 09:59:14 -07:00
|
|
|
}
|
2014-06-28 03:58:38 -06:00
|
|
|
}
|
|
|
|
|
2014-08-02 11:33:46 -06:00
|
|
|
def list = Open { implicit ctx =>
|
|
|
|
val nb = 10
|
|
|
|
for {
|
2014-08-03 14:03:17 -06:00
|
|
|
bullet ← env.cached topPerf PerfType.Bullet.key
|
|
|
|
blitz ← env.cached topPerf PerfType.Blitz.key
|
|
|
|
classical ← env.cached topPerf PerfType.Classical.key
|
2015-01-12 13:56:55 -07:00
|
|
|
correspondence ← env.cached topPerf PerfType.Correspondence.key
|
2014-08-03 14:03:17 -06:00
|
|
|
chess960 ← env.cached topPerf PerfType.Chess960.key
|
|
|
|
kingOfTheHill ← env.cached topPerf PerfType.KingOfTheHill.key
|
|
|
|
threeCheck ← env.cached topPerf PerfType.ThreeCheck.key
|
2014-12-22 19:34:49 -07:00
|
|
|
antichess <- env.cached topPerf PerfType.Antichess.key
|
2015-01-03 18:30:17 -07:00
|
|
|
atomic <- env.cached topPerf PerfType.Atomic.key
|
2015-03-09 08:22:54 -06:00
|
|
|
horde <- env.cached topPerf PerfType.Horde.key
|
2014-08-02 11:33:46 -06:00
|
|
|
nbAllTime ← env.cached topNbGame nb map2 { (user: UserModel) =>
|
|
|
|
user -> user.count.game
|
|
|
|
}
|
|
|
|
nbWeek ← Env.game.cached activePlayerUidsWeek nb flatMap { pairs =>
|
2014-12-23 06:06:00 -07:00
|
|
|
UserRepo.byOrderedIds(pairs.map(_.userId)) map (_ zip pairs.map(_.nb))
|
2014-08-02 11:33:46 -06:00
|
|
|
}
|
|
|
|
tourneyWinners ← Env.tournament.winners scheduled nb
|
2015-01-13 08:47:06 -07:00
|
|
|
online ← env.cached topOnline 40
|
2015-05-29 03:51:12 -06:00
|
|
|
res <- negotiate(
|
|
|
|
html = fuccess(Ok(html.user.list(
|
|
|
|
tourneyWinners = tourneyWinners,
|
|
|
|
online = online,
|
|
|
|
bullet = bullet,
|
|
|
|
blitz = blitz,
|
|
|
|
classical = classical,
|
|
|
|
correspondence = correspondence,
|
|
|
|
chess960 = chess960,
|
|
|
|
kingOfTheHill = kingOfTheHill,
|
|
|
|
threeCheck = threeCheck,
|
|
|
|
antichess = antichess,
|
|
|
|
atomic = atomic,
|
|
|
|
horde = horde,
|
|
|
|
nbWeek = nbWeek,
|
|
|
|
nbAllTime = nbAllTime))),
|
|
|
|
api = _ => fuccess {
|
|
|
|
implicit val userWrites = play.api.libs.json.Writes[UserModel] { env.jsonView(_, true) }
|
|
|
|
Ok(Json.obj(
|
|
|
|
"online" -> online,
|
|
|
|
"bullet" -> bullet,
|
|
|
|
"blitz" -> blitz,
|
|
|
|
"classical" -> classical,
|
|
|
|
"correspondence" -> correspondence,
|
|
|
|
"chess960" -> chess960,
|
|
|
|
"kingOfTheHill" -> kingOfTheHill,
|
|
|
|
"threeCheck" -> threeCheck,
|
|
|
|
"antichess" -> antichess,
|
|
|
|
"atomic" -> atomic,
|
|
|
|
"horde" -> horde))
|
|
|
|
})
|
|
|
|
} yield res
|
2013-05-08 09:41:12 -06:00
|
|
|
}
|
2013-03-20 08:23:41 -06:00
|
|
|
|
2014-02-17 02:12:19 -07:00
|
|
|
def mod(username: String) = Secure(_.UserSpy) { implicit ctx =>
|
|
|
|
me => OptionFuOk(UserRepo named username) { user =>
|
2015-04-25 23:44:35 -06:00
|
|
|
(Env.security userSpy user.id) zip
|
|
|
|
(Env.mod.assessApi.getPlayerAggregateAssessment(user.id)) flatMap {
|
|
|
|
case (spy, playerAggregateAssessment) =>
|
|
|
|
(Env.playban.api bans spy.otherUsers.map(_.id)) map { bans =>
|
|
|
|
html.user.mod(user, spy, playerAggregateAssessment, bans)
|
|
|
|
}
|
|
|
|
}
|
2014-01-13 14:11:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-22 17:22:57 -06:00
|
|
|
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")
|
|
|
|
)
|
2013-05-15 13:28:46 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-17 02:12:19 -07:00
|
|
|
def opponents(username: String) = Open { implicit ctx =>
|
|
|
|
OptionFuOk(UserRepo named username) { user =>
|
2014-05-03 01:39:20 -06:00
|
|
|
lila.game.BestOpponents(user.id, 50) flatMap { ops =>
|
2014-05-21 12:56:50 -06:00
|
|
|
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)
|
|
|
|
}
|
2014-05-03 01:39:20 -06:00
|
|
|
}
|
2013-05-19 18:01:20 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-17 02:12:19 -07:00
|
|
|
def autocomplete = Open { implicit ctx =>
|
2014-06-01 17:01:39 -06:00
|
|
|
get("term", ctx.req).filter(_.nonEmpty).fold(BadRequest("No search term provided").fuccess: Fu[Result]) { term =>
|
2013-05-06 15:52:48 -06:00
|
|
|
JsonOk(UserRepo usernamesLike term)
|
|
|
|
}
|
|
|
|
}
|
2013-03-20 08:23:41 -06:00
|
|
|
}
|