puzzle WIP
parent
982e35841d
commit
27ef01c7a4
|
@ -139,6 +139,24 @@ final class Puzzle(
|
|||
}
|
||||
}
|
||||
|
||||
def voteTheme(id: String, themeStr: String) =
|
||||
AuthBody { implicit ctx => me =>
|
||||
NoBot {
|
||||
PuzzleTheme.find(themeStr) ?? { theme =>
|
||||
implicit val req = ctx.body
|
||||
env.puzzle.forms.themeVote
|
||||
.bindFromRequest()
|
||||
.fold(
|
||||
jsonFormError,
|
||||
vote => {
|
||||
vote foreach { v => lila.mon.puzzle.voteTheme(theme.key.value, v).increment() }
|
||||
env.puzzle.api.theme.vote(Puz.Id(id), me, theme, vote) inject jsonOkResult
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile API: select a bunch of puzzles for offline use */
|
||||
def batchSelect =
|
||||
Auth { implicit ctx => me =>
|
||||
|
|
|
@ -87,6 +87,7 @@ GET /training/themes controllers.Puzzle.themes
|
|||
GET /training/:themeOrId controllers.Puzzle.show(themeOrId: String)
|
||||
GET /training/:theme/$id<\w{5}> controllers.Puzzle.showWithTheme(theme: String, id: String)
|
||||
POST /training/$id<\w{5}>/vote controllers.Puzzle.vote(id: String)
|
||||
POST /training/$id<\w{5}>/vote/:theme controllers.Puzzle.voteTheme(id: String, theme: String)
|
||||
POST /training/complete/:theme/$id<\w{5}> controllers.Puzzle.complete(theme: String, id: String)
|
||||
|
||||
# User Analysis
|
||||
|
|
|
@ -420,7 +420,6 @@ object mon {
|
|||
object puzzle {
|
||||
object selector {
|
||||
val time = timer("puzzle.selector.time").withoutTags()
|
||||
val vote = histogram("puzzle.selector.vote").withoutTags()
|
||||
}
|
||||
object batch {
|
||||
object selector {
|
||||
|
@ -433,8 +432,14 @@ object mon {
|
|||
def attempt(user: Boolean, theme: String) =
|
||||
counter("puzzle.attempt.count").withTags(Map("user" -> user, "theme" -> theme))
|
||||
}
|
||||
def vote(up: Boolean) = counter("puzzle.vote.count").withTag("dir", if (up) "up" else "down")
|
||||
val crazyGlicko = counter("puzzle.crazyGlicko").withoutTags()
|
||||
def vote(up: Boolean) = counter("puzzle.vote.count").withTag("up", up)
|
||||
def voteTheme(key: String, up: Boolean) = counter("puzzle.selector.voteTheme").withTags(
|
||||
Map(
|
||||
"up" -> up,
|
||||
"theme" -> key
|
||||
)
|
||||
)
|
||||
val crazyGlicko = counter("puzzle.crazyGlicko").withoutTags()
|
||||
}
|
||||
object game {
|
||||
def finish(variant: String, speed: String, source: String, mode: String, status: String) =
|
||||
|
|
|
@ -8,6 +8,7 @@ import lila.db.BSON
|
|||
import lila.db.dsl._
|
||||
import lila.game.Game
|
||||
import lila.rating.Glicko
|
||||
import scala.util.Try
|
||||
|
||||
private[puzzle] object BsonHandlers {
|
||||
|
||||
|
@ -48,6 +49,17 @@ private[puzzle] object BsonHandlers {
|
|||
id => BSONString(id.toString)
|
||||
)
|
||||
|
||||
implicit val RoundThemeHandler = tryHandler[PuzzleRound.Theme](
|
||||
{ case BSONString(v) =>
|
||||
PuzzleTheme
|
||||
.find(v.tail)
|
||||
.fold[Try[PuzzleRound.Theme]](handlerBadValue(s"Invalid puzzle round theme $v")) { theme =>
|
||||
Success(PuzzleRound.Theme(theme.key, v.head == '+'))
|
||||
}
|
||||
},
|
||||
rt => BSONString(s"${if (rt.vote) "+" else "-"}${rt.theme}")
|
||||
)
|
||||
|
||||
implicit val RoundHandler = new BSON[PuzzleRound] {
|
||||
import PuzzleRound.BSONFields._
|
||||
def reads(r: BSON.Reader) = PuzzleRound(
|
||||
|
@ -55,6 +67,7 @@ private[puzzle] object BsonHandlers {
|
|||
date = r.date(date),
|
||||
win = r.bool(win),
|
||||
vote = r.boolO(vote),
|
||||
themes = r.get[List[PuzzleRound.Theme]](themes),
|
||||
weight = r.intO(weight)
|
||||
)
|
||||
def writes(w: BSON.Writer, r: PuzzleRound) =
|
||||
|
|
|
@ -29,8 +29,8 @@ final private[puzzle] class PuzzleApi(
|
|||
|
||||
object round {
|
||||
|
||||
def find(user: User, puzzle: Puzzle): Fu[Option[PuzzleRound]] =
|
||||
colls.round(_.byId[PuzzleRound](PuzzleRound.Id(user.id, puzzle.id).toString))
|
||||
def find(user: User, puzzleId: Puzzle.Id): Fu[Option[PuzzleRound]] =
|
||||
colls.round(_.byId[PuzzleRound](PuzzleRound.Id(user.id, puzzleId).toString))
|
||||
|
||||
def upsert(a: PuzzleRound) = colls.round(_.update.one($id(a.id), a, upsert = true))
|
||||
|
||||
|
@ -68,5 +68,18 @@ final private[puzzle] class PuzzleApi(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
def vote(user: User, id: Puzzle.Id, theme: PuzzleTheme, vote: Option[Boolean]): Funit =
|
||||
round.find(user, id) flatMap {
|
||||
_ ?? { round =>
|
||||
???
|
||||
}
|
||||
}
|
||||
// colls.round {
|
||||
// _.byId[
|
||||
// .findAndUpdate[PuzzleRound](
|
||||
// $id(PuzzleRound.Id(user.id, id)),
|
||||
// $set($doc(PuzzleRound.BSONFields.vote -> vote))
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,13 +61,7 @@ final private[puzzle] class PuzzleFinisher(
|
|||
if (theme == PuzzleTheme.any.key) g else g.average(puzzle.glicko)
|
||||
}
|
||||
.filter(_.sanityCheck)
|
||||
val round = PuzzleRound(
|
||||
id = PuzzleRound.Id(user.id, puzzle.id),
|
||||
date = now,
|
||||
win = result.win,
|
||||
vote = none,
|
||||
weight = none
|
||||
)
|
||||
val round = PuzzleRound(id = PuzzleRound.Id(user.id, puzzle.id), date = now, win = result.win)
|
||||
val userPerf =
|
||||
user.perfs.puzzle.addOrReset(_.puzzle.crazyGlicko, s"puzzle ${puzzle.id}")(userRating, now) pipe {
|
||||
p =>
|
||||
|
|
|
@ -12,4 +12,8 @@ object PuzzleForm {
|
|||
val vote = Form(
|
||||
single("vote" -> boolean)
|
||||
)
|
||||
|
||||
val themeVote = Form(
|
||||
single("vote" -> optional(boolean))
|
||||
)
|
||||
}
|
||||
|
|
|
@ -8,12 +8,15 @@ case class PuzzleRound(
|
|||
id: PuzzleRound.Id,
|
||||
date: DateTime,
|
||||
win: Boolean,
|
||||
vote: Option[Boolean],
|
||||
// tags: List[RoundTag],
|
||||
weight: Option[Int]
|
||||
vote: Option[Boolean] = None,
|
||||
themes: List[PuzzleRound.Theme] = Nil,
|
||||
weight: Option[Int] = None
|
||||
) {
|
||||
|
||||
def userId = id.userId
|
||||
|
||||
def themeVote(theme: PuzzleTheme.Key, vote: Option[Boolean]): Option[Boolean] =
|
||||
themes.find(_.theme == theme)
|
||||
}
|
||||
|
||||
object PuzzleRound {
|
||||
|
@ -25,11 +28,14 @@ object PuzzleRound {
|
|||
override def toString = s"${userId}$idSep${puzzleId}"
|
||||
}
|
||||
|
||||
case class Theme(theme: PuzzleTheme.Key, vote: Boolean)
|
||||
|
||||
object BSONFields {
|
||||
val id = "_id"
|
||||
val date = "d"
|
||||
val win = "w"
|
||||
val vote = "v"
|
||||
val themes = "t"
|
||||
val weight = "w"
|
||||
val user = "u" // student denormalization
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue