diff --git a/app/controllers/Lobby.scala b/app/controllers/Lobby.scala index 50ab3ddbe5..6f4f698e4f 100644 --- a/app/controllers/Lobby.scala +++ b/app/controllers/Lobby.scala @@ -37,10 +37,11 @@ object Lobby extends LilaController with Results { myHook = myHook, timeline = timelineRecent, posts = forumRecent(ctx.me, teamCache.teamIds), - tours = openTours + tours = openTours, + filter = env.setup.filter ).map(_.fold(Redirect(_), { case (preload, posts, tours, featured) ⇒ status(html.lobby.home( - toJson(preload), + toJson(preload).pp, myHook, posts, tours, diff --git a/app/controllers/Setup.scala b/app/controllers/Setup.scala index f72eb244f1..7e7aecc964 100644 --- a/app/controllers/Setup.scala +++ b/app/controllers/Setup.scala @@ -52,12 +52,13 @@ object Setup extends LilaController with TheftPrevention with RoundEventPerforme } } - val filterForm = TODO - // Open { implicit ctx ⇒ - // IOk(forms.filterFilled map { html.setup.filter(_) }) - // } + val filterForm = Open { implicit ctx ⇒ + IOk(forms.filterFilled map { html.setup.filter(_) }) + } - val filter = TODO + val filter = process(forms.filter) { config ⇒ + implicit ctx ⇒ processor filter config inject routes.Lobby.home() + } def join(id: String) = Open { implicit ctx ⇒ IOptionIOResult(gameRepo game id) { game ⇒ diff --git a/app/lobby/Preload.scala b/app/lobby/Preload.scala index 1ef90833fa..5b7143d722 100644 --- a/app/lobby/Preload.scala +++ b/app/lobby/Preload.scala @@ -7,6 +7,7 @@ import forum.PostLiteView import controllers.routes import socket.History import tournament.Created +import setup.FilterConfig import play.api.mvc.Call import play.api.libs.concurrent.Akka @@ -35,7 +36,8 @@ final class Preload( myHook: Option[Hook], timeline: IO[List[Entry]], posts: IO[List[PostLiteView]], - tours: IO[List[Created]]): Future[Response] = + tours: IO[List[Created]], + filter: IO[FilterConfig]): Future[Response] = myHook.flatMap(_.gameId).fold( gameId ⇒ futureGame(gameId) map { gameOption ⇒ Left(gameOption.fold( @@ -48,12 +50,14 @@ final class Preload( ioToFuture(timeline) zip ioToFuture(posts) zip ioToFuture(tours) zip - featured.one map { - case (((((hooks, messages), entries), posts), tours), feat) ⇒ (Right((Map( + featured.one zip + ioToFuture(filter) map { + case ((((((hooks, messages), entries), posts), tours), feat), filter) ⇒ (Right((Map( "version" -> history.version, "pool" -> renderHooks(hooks, myHook), "chat" -> (messages.reverse map (_.render)), - "timeline" -> (entries.reverse map (_.render)) + "timeline" -> (entries.reverse map (_.render)), + "filter" -> filter.toMap ), posts, tours, feat))): Response } ) diff --git a/app/setup/AnonConfigRepo.scala b/app/setup/AnonConfigRepo.scala index d7d15966ef..368acc8288 100644 --- a/app/setup/AnonConfigRepo.scala +++ b/app/setup/AnonConfigRepo.scala @@ -11,7 +11,7 @@ import com.mongodb.casbah.MongoCollection import com.mongodb.casbah.Imports._ import scalaz.effects._ -final class AnonConfigRepo(collection: MongoCollection) +private[setup] final class AnonConfigRepo(collection: MongoCollection) extends SalatDAO[RawUserConfig, String](collection) { private val sessionKey = "setup" @@ -35,6 +35,15 @@ final class AnonConfigRepo(collection: MongoCollection) private def configOption(req: RequestHeader): IO[Option[UserConfig]] = ~sessionId(req).map(s ⇒ config(s) map (_.some)) + def filter(req: RequestHeader): IO[FilterConfig] = io { + for { + sid ← sessionId(req) + obj ← collection.findOneByID(sid, DBObject("filter" -> true)) + variant ← obj.getAs[Int]("v") + config ← RawFilterConfig(variant).decode + } yield config + } map (_ | FilterConfig.default) + private def save(config: UserConfig): IO[Unit] = io { update( DBObject("_id" -> config.id), diff --git a/app/setup/FilterConfig.scala b/app/setup/FilterConfig.scala index 40df7c5530..6b2aece897 100644 --- a/app/setup/FilterConfig.scala +++ b/app/setup/FilterConfig.scala @@ -9,6 +9,10 @@ case class FilterConfig(variant: Option[Variant]) { def encode = RawFilterConfig( v = ~variant.map(_.id) ) + + def >> = Some((variant map (_.id))) + + def toMap = Map("variant" -> variant.map(_.id)) } object FilterConfig { @@ -17,9 +21,10 @@ object FilterConfig { variant = none) val variants = 0 :: Config.variants - val variantChoices = variants map { id ⇒ - (Config.variantChoices.toMap get id.toString map ("Only " +)) | "All" - } + + def <<(v: Option[Int]) = new FilterConfig( + variant = v flatMap Variant.apply + ) } private[setup] case class RawFilterConfig(v: Int) { diff --git a/app/setup/FormFactory.scala b/app/setup/FormFactory.scala index 7b4c55a901..17a5d26fd1 100644 --- a/app/setup/FormFactory.scala +++ b/app/setup/FormFactory.scala @@ -8,12 +8,23 @@ import play.api.data._ import play.api.data.Forms._ import scalaz.effects._ -final class FormFactory( +private[setup] final class FormFactory( userConfigRepo: UserConfigRepo, anonConfigRepo: AnonConfigRepo) { import Mappings._ + def filterFilled(implicit ctx: Context): IO[Form[FilterConfig]] = + filterConfig map filter(ctx).fill + + def filter(ctx: Context) = Form( + mapping( + "variant" -> optional(variant) + )(FilterConfig.<<)(_.>>) + ) + + def filterConfig(implicit ctx: Context): IO[FilterConfig] = savedConfig map (_.filter) + def aiFilled(implicit ctx: Context): IO[Form[AiConfig]] = aiConfig map ai(ctx).fill diff --git a/app/setup/Processor.scala b/app/setup/Processor.scala index f585c7b638..f3531451a1 100644 --- a/app/setup/Processor.scala +++ b/app/setup/Processor.scala @@ -22,6 +22,9 @@ final class Processor( timelinePush: DbGame ⇒ IO[Unit], ai: () ⇒ Ai) extends core.Futuristic { + def filter(config: FilterConfig)(implicit ctx: Context): IO[Unit] = + saveConfig(_ withFilter config) + def ai(config: AiConfig)(implicit ctx: Context): IO[Pov] = for { _ ← saveConfig(_ withAi config) pov = config.pov diff --git a/app/setup/SetupEnv.scala b/app/setup/SetupEnv.scala index 03938d06f1..f867ee8103 100644 --- a/app/setup/SetupEnv.scala +++ b/app/setup/SetupEnv.scala @@ -64,4 +64,9 @@ final class SetupEnv( userRepo = userRepo, timelinePush = timelinePush, messenger = roundMessenger) + + def filter(implicit ctx: http.Context): IO[FilterConfig] = ctx.me.fold( + userConfigRepo.filter, + anonConfigRepo filter ctx.req + ) } diff --git a/app/setup/UserConfig.scala b/app/setup/UserConfig.scala index e4efe9c8b4..c85be54777 100644 --- a/app/setup/UserConfig.scala +++ b/app/setup/UserConfig.scala @@ -14,6 +14,8 @@ case class UserConfig( hook: HookConfig, filter: FilterConfig) { + def withFilter(c: FilterConfig) = copy(filter = c) + def withAi(c: AiConfig) = copy(ai = c) def withFriend(c: FriendConfig) = copy(friend = c) diff --git a/app/setup/UserConfigRepo.scala b/app/setup/UserConfigRepo.scala index 6a2fa694b4..4b5b37f6cd 100644 --- a/app/setup/UserConfigRepo.scala +++ b/app/setup/UserConfigRepo.scala @@ -9,7 +9,7 @@ import com.mongodb.casbah.MongoCollection import com.mongodb.casbah.Imports._ import scalaz.effects._ -final class UserConfigRepo(collection: MongoCollection) +private[setup] final class UserConfigRepo(collection: MongoCollection) extends SalatDAO[RawUserConfig, String](collection) { def update(user: User)(map: UserConfig ⇒ UserConfig): IO[Unit] = @@ -21,6 +21,14 @@ final class UserConfigRepo(collection: MongoCollection) putStrLn("Can't load config: " + e.getMessage) map (_ ⇒ none[UserConfig]) } map (_ | UserConfig.default(user.id)) + def filter(user: User): IO[FilterConfig] = io { + for { + obj ← collection.findOneByID(user.id, DBObject("filter" -> true)) + variant ← obj.getAs[Int]("v") + config ← RawFilterConfig(variant).decode + } yield config + } map (_ | FilterConfig.default) + private def save(config: UserConfig): IO[Unit] = io { update( DBObject("_id" -> config.id), diff --git a/app/views/setup/filter.scala.html b/app/views/setup/filter.scala.html new file mode 100644 index 0000000000..576d11f886 --- /dev/null +++ b/app/views/setup/filter.scala.html @@ -0,0 +1,13 @@ +@(form: Form[_])(implicit ctx: Context) + +
+

@trans.filterGames()

+
+ @helper.form(action = routes.Setup.filter, 'novalidate -> "novalidate") { +
+ @base.select(form("variant"), translatedVariantChoices, "Any variant".some) +
+ + } +
+
diff --git a/public/stylesheets/opening.css b/public/stylesheets/opening.css index e374093bea..9e5c8a7e23 100644 --- a/public/stylesheets/opening.css +++ b/public/stylesheets/opening.css @@ -15,7 +15,8 @@ div.game_config div.ui-buttonset { #config_level .ui-button { margin-right: -0.6em; } -div.game_config .ui-button-text { +div.game_config .ui-button-text, +div.game_config select { text-transform: capitalize; } div.game_config div.ui-slider {