list of online bots

pull/5979/head
Thibault Duplessis 2020-01-30 10:24:12 -06:00
parent 848e9c7f20
commit a99185651b
8 changed files with 107 additions and 2 deletions

View File

@ -92,4 +92,11 @@ final class Bot(
)
).fuccess
else f
def online = Open { implicit ctx =>
// env.user.botIds().map(_ take 20) flatMap env.user.repo.byIds map { users =>
env.user.repo.byIds(env.bot.onlineBots.get) map { users =>
Ok(views.html.user.bots(users))
}
}
}

View File

@ -99,7 +99,7 @@ object studentDashboard {
)
private def challengeTd(user: lila.user.User)(implicit ctx: Context) =
if (ctx.me.exists(user.is)) td
if (ctx is user) td
else {
val online = isOnline(user.id)
td(

View File

@ -16,7 +16,8 @@ object bits {
trans.ratingStats()
),
a(cls := active.active("tournament"), href := routes.Tournament.leaderboard)(trans.tournamentWinners()),
a(cls := active.active("shield"), href := routes.Tournament.shields)("Shields")
a(cls := active.active("shield"), href := routes.Tournament.shields)("Shields"),
a(cls := active.active("bots"), href := routes.Bot.online)("Online bots")
)
def miniClosed(u: User)(implicit ctx: Context) = frag(

View File

@ -0,0 +1,78 @@
package views.html
package user
import lila.api.Context
import lila.app.templating.Environment._
import lila.app.ui.ScalatagsTemplate._
import lila.common.String.html.richText
import lila.user.User
import controllers.routes
object bots {
def apply(users: List[User])(implicit ctx: Context) = {
val title = s"Online bots"
views.html.base.layout(
title = title,
moreCss = frag(cssTag("slist"), cssTag("user.list")),
wrapClass = "full-screen-force"
)(
main(cls := "page-menu bots")(
user.bits.communityMenu("bots"),
div(cls := "bots page-menu__content box")(
div(cls := "box__top")(h1(title)),
table(cls := "slist slist-pad")(
tbody(
users.sortBy(-_.playTime.??(_.total)) map { u =>
tr(
td(userLink(u)),
u.profile
.ifTrue(ctx.noKid)
.ifTrue(!u.marks.troll || ctx.is(u))
.flatMap(_.nonEmptyBio)
.map { bio =>
td(richText(shorten(bio, 400), nl2br = false))
} | td,
td(cls := "rating")(u.best3Perfs.map {
showPerfRating(u, _)
}),
u.playTime.fold(td) { playTime =>
td(
p(
cls := "text",
dataIcon := "C",
st.title := trans.tpTimeSpentPlaying.txt(showPeriod(playTime.totalPeriod))
)(showPeriod(playTime.totalPeriod)),
playTime.nonEmptyTvPeriod.map { tvPeriod =>
p(
cls := "text",
dataIcon := "1",
st.title := trans.tpTimeSpentOnTV.txt(showPeriod(tvPeriod))
)(showPeriod(tvPeriod))
}
)
},
if (ctx is u) td
else {
td(
a(
dataIcon := "U",
cls := List("button button-empty text" -> true),
st.title := trans.challengeToPlay.txt(),
href := s"${routes.Lobby.home()}?user=${u.username}#friend"
)(trans.play())
)
}
)
}
)
)
)
)
)
}
}

View File

@ -531,6 +531,7 @@ GET /api/user/:name/games controllers.Api.userGames(name: String)
GET /api/bot/game/stream/:id controllers.Bot.gameStream(id: String)
POST /api/bot/game/:id/move/:uci controllers.Bot.move(id: String, uci: String, offeringDraw: Option[Boolean] ?= None)
POST /api/bot/*cmd controllers.Bot.command(cmd: String)
GET /player/bots controllers.Bot.online
# Account
GET /account/passwd controllers.Account.passwd

View File

@ -24,4 +24,6 @@ final class OnlineBots(
}
cache.put(userId)
}
def get: Set[lila.user.User.ID] = cache.keySet
}

View File

@ -21,4 +21,6 @@ final class ExpireCallbackMemo(ttl: Duration, callback: String => Unit)(implicit
def remove(key: String) = cache invalidate key
def count = cache.estimatedSize.toInt
def keySet: Set[String] = cache.asMap.keys.toSet
}

View File

@ -70,3 +70,17 @@ $user-list-width: 30ch;
}
}
}
.bots {
td:nth-child(3), td:nth-child(4) {
white-space: nowrap;
}
.rating {
span {
&::before {
margin: 0;
}
margin: 0 .3em;
}
}
}