From 663ade5a9367d1311953943463b50193356f5abf Mon Sep 17 00:00:00 2001 From: cchantep Date: Thu, 21 Jul 2016 14:41:34 +0200 Subject: [PATCH 001/161] Upgrade to ReactiveMongo 0.12 (Release Candidate 0) --- .travis.yml | 1 + bin/build-deps.sh | 6 --- modules/bookmark/src/main/BookmarkRepo.scala | 2 +- .../challenge/src/main/ChallengeRepo.scala | 4 +- modules/db/src/main/BSON.scala | 19 +--------- modules/db/src/main/Env.scala | 37 ++++++++++++------- modules/forum/src/main/PostRepo.scala | 4 +- .../forumSearch/src/main/ForumSearchApi.scala | 17 +++++---- modules/game/src/main/GameRepo.scala | 8 ++-- modules/game/src/main/PlayTime.scala | 18 ++++----- .../src/main/AggregationClusters.scala | 4 +- modules/insight/src/main/Storage.scala | 4 +- modules/mod/src/main/Gamify.scala | 4 +- modules/opening/src/main/OpeningApi.scala | 4 +- .../perfStat/src/main/PerfStatIndexer.scala | 6 +-- modules/plan/src/main/MonthlyGoal.scala | 2 +- modules/plan/src/main/PlanApi.scala | 2 +- modules/pref/src/main/PrefApi.scala | 4 +- modules/puzzle/src/main/PuzzleApi.scala | 4 +- modules/qa/src/main/QaApi.scala | 2 +- modules/relation/src/main/RelationApi.scala | 2 +- modules/relation/src/main/RelationRepo.scala | 8 ++-- modules/security/src/main/Api.scala | 10 ++--- modules/security/src/main/Firewall.scala | 4 +- modules/security/src/main/UserSpy.scala | 4 +- modules/study/src/main/StudyRepo.scala | 27 ++++++-------- modules/team/src/main/MemberRepo.scala | 4 +- modules/team/src/main/TeamApi.scala | 15 ++++---- modules/team/src/main/TeamRepo.scala | 2 +- .../teamSearch/src/main/TeamSearchApi.scala | 15 ++++---- modules/timeline/src/main/UnsubApi.scala | 4 +- .../tournament/src/main/LeaderboardApi.scala | 2 +- modules/tournament/src/main/PairingRepo.scala | 10 ++--- modules/tournament/src/main/PlayerRepo.scala | 7 ++-- modules/user/src/main/RankingApi.scala | 26 ++++++------- modules/user/src/main/UserRepo.scala | 6 +-- modules/video/src/main/VideoApi.scala | 10 ++--- project/Dependencies.scala | 2 +- 38 files changed, 145 insertions(+), 165 deletions(-) diff --git a/.travis.yml b/.travis.yml index beb63fac68..9074cf7a40 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +sudo: false language: scala # https://docs.travis-ci.com/user/notifications/#IRC-notification diff --git a/bin/build-deps.sh b/bin/build-deps.sh index 6d2cf82a5c..f7cb169088 100755 --- a/bin/build-deps.sh +++ b/bin/build-deps.sh @@ -10,12 +10,6 @@ cd gfc-semver sbt publish-local cd .. -git clone https://github.com/ornicar/ReactiveMongo --branch lichess -cd ReactiveMongo -git checkout b3e895f1c723d7cb518763f31fba62dc74311eab -sbt publish-local -cd .. - git clone https://github.com/ornicar/scalalib cd scalalib sbt publish-local diff --git a/modules/bookmark/src/main/BookmarkRepo.scala b/modules/bookmark/src/main/BookmarkRepo.scala index 989c860c6c..6c146dc78a 100644 --- a/modules/bookmark/src/main/BookmarkRepo.scala +++ b/modules/bookmark/src/main/BookmarkRepo.scala @@ -21,7 +21,7 @@ private[bookmark] object BookmarkRepo { } def gameIdsByUserId(userId: String): Fu[Set[String]] = - coll.distinct("g", $doc("u" -> userId).some) map lila.db.BSON.asStringSet + coll.distinct[String, Set]("g", $doc("u" -> userId).some) def removeByGameId(gameId: String): Funit = coll.remove($doc("g" -> gameId)).void diff --git a/modules/challenge/src/main/ChallengeRepo.scala b/modules/challenge/src/main/ChallengeRepo.scala index ffa5e08ef4..fde2818038 100644 --- a/modules/challenge/src/main/ChallengeRepo.scala +++ b/modules/challenge/src/main/ChallengeRepo.scala @@ -56,10 +56,10 @@ private final class ChallengeRepo(coll: Coll, maxPerUser: Int) { )).cursor[Challenge]().gather[List](max) private[challenge] def expiredIds(max: Int): Fu[List[Challenge.ID]] = - coll.distinct( + coll.distinct[String, List]( "_id", $doc("expiresAt" -> $doc("$lt" -> DateTime.now)).some - ) map lila.db.BSON.asStrings + ) def setSeenAgain(id: Challenge.ID) = coll.update( $id(id), diff --git a/modules/db/src/main/BSON.scala b/modules/db/src/main/BSON.scala index 61e58fe6ae..c55cbbefcc 100644 --- a/modules/db/src/main/BSON.scala +++ b/modules/db/src/main/BSON.scala @@ -199,23 +199,6 @@ object BSON extends Handlers { def debugDoc(doc: Bdoc): String = (doc.elements.toList map { case (k, v) => s"$k: ${debug(v)}" }).mkString("{", ", ", "}") + def hashDoc(doc: Bdoc): String = debugDoc(doc).replace(" ", "") - - def asStrings(vs: List[BSONValue]): List[String] = { - val b = new scala.collection.mutable.ListBuffer[String] - vs foreach { - case BSONString(s) => b += s - case _ => - } - b.toList - } - - def asStringSet(vs: List[BSONValue]): Set[String] = { - val b = Set.newBuilder[String] - vs foreach { - case BSONString(s) => b += s - case _ => - } - b.result - } } diff --git a/modules/db/src/main/Env.scala b/modules/db/src/main/Env.scala index c0b66b57df..dd7ab6c735 100644 --- a/modules/db/src/main/Env.scala +++ b/modules/db/src/main/Env.scala @@ -3,8 +3,8 @@ package lila.db import com.typesafe.config.Config import reactivemongo.api._ import scala.concurrent.duration._ -import scala.concurrent.Future -import scala.util.{ Success, Failure } +import scala.concurrent.{ Await, Future } +import scala.util.{ Failure, Success, Try } import dsl._ final class Env( @@ -12,20 +12,29 @@ final class Env( lifecycle: play.api.inject.ApplicationLifecycle) { lazy val db = { - val parsedUri: MongoConnection.ParsedURI = - MongoConnection.parseURI(config.getString("uri")) match { - case Success(parsedURI) => parsedURI - case Failure(e) => sys error s"Invalid mongodb.uri" - } val driver = new MongoDriver(Some(config)) - val connection = driver.connection(parsedUri) - parsedUri.db.fold[DefaultDB](sys error s"cannot resolve database from URI: $parsedUri") { dbUri => - val db = DB(dbUri, connection) - registerDriverShutdownHook(driver) - logger.info(s"""ReactiveMongoApi successfully started with DB '$dbUri'! Servers: ${parsedUri.hosts.map { s => s"[${s._1}:${s._2}]" }.mkString("\n\t\t")}""") - db - } + registerDriverShutdownHook(driver) + + (for { + parsedUri <- MongoConnection.parseURI(config getString "uri") + con <- driver.connection(parsedUri, true) + db <- parsedUri.db match { + case Some(name) => { + def resolvedDB = con.database(name).andThen { + case _ => + logger.info(s"""ReactiveMongoApi successfully started with DB '$name'! Servers: ${parsedUri.hosts.map { s => s"[${s._1}:${s._2}]" }.mkString("\n\t\t")}""") + } + + Try(Await.result(resolvedDB, 10.seconds)) + } + + case _ => { + Failure[DefaultDB](new IllegalArgumentException( + s"cannot resolve database from URI: $parsedUri")) + } + } + } yield db).get } def apply(name: String): Coll = db(name) diff --git a/modules/forum/src/main/PostRepo.scala b/modules/forum/src/main/PostRepo.scala index 52ef03915f..844e0f3101 100644 --- a/modules/forum/src/main/PostRepo.scala +++ b/modules/forum/src/main/PostRepo.scala @@ -68,10 +68,10 @@ sealed abstract class PostRepo(troll: Boolean) { def sortQuery = $sort.createdAsc def userIdsByTopicId(topicId: String): Fu[List[String]] = - coll.distinct("userId", $doc("topicId" -> topicId).some) map lila.db.BSON.asStrings + coll.distinct[String, List]("userId", $doc("topicId" -> topicId).some) def idsByTopicId(topicId: String): Fu[List[String]] = - coll.distinct("_id", $doc("topicId" -> topicId).some) map lila.db.BSON.asStrings + coll.distinct[String, List]("_id", $doc("topicId" -> topicId).some) import reactivemongo.api.ReadPreference def cursor( diff --git a/modules/forumSearch/src/main/ForumSearchApi.scala b/modules/forumSearch/src/main/ForumSearchApi.scala index 47571ed57f..90a7d96f80 100644 --- a/modules/forumSearch/src/main/ForumSearchApi.scala +++ b/modules/forumSearch/src/main/ForumSearchApi.scala @@ -1,5 +1,7 @@ package lila.forumSearch +import reactivemongo.api.Cursor + import lila.forum.actorApi._ import lila.forum.{ Post, PostView, PostLiteView, PostApi, PostRepo } import lila.search._ @@ -37,14 +39,15 @@ final class ForumSearchApi( case c: ESClientHttp => c.putMapping >> { lila.log("forumSearch").info(s"Index to ${c.index.name}") import lila.db.dsl._ - import play.api.libs.iteratee._ - PostRepo.cursor($empty).enumerateBulks(Int.MaxValue) |>>> - Iteratee.foldM[Iterator[Post], Unit](()) { - case (_, posts) => (postApi liteViews posts.toList) flatMap { views => - c.storeBulk(views map (v => Id(v.post.id) -> toDoc(v))) - } - } + + PostRepo.cursor($empty).foldBulksM({}) { (_, posts) => + for { + views <- postApi liteViews posts.toList + _ <- c.storeBulk(views map (v => Id(v.post.id) -> toDoc(v))) + } yield Cursor.Cont({}) + } } + case _ => funit } } diff --git a/modules/game/src/main/GameRepo.scala b/modules/game/src/main/GameRepo.scala index 6db902a0f7..613ba3ca65 100644 --- a/modules/game/src/main/GameRepo.scala +++ b/modules/game/src/main/GameRepo.scala @@ -187,9 +187,9 @@ object GameRepo { coll.exists($id(id) ++ Query.analysed(true)) def filterAnalysed(ids: Seq[String]): Fu[Set[String]] = - coll.distinct("_id", ($inIds(ids) ++ $doc( + coll.distinct[String, Set]("_id", ($inIds(ids) ++ $doc( F.analysed -> true - )).some) map lila.db.BSON.asStringSet + )).some) def exists(id: String) = coll.exists($id(id)) @@ -342,7 +342,7 @@ object GameRepo { Match($doc(F.playerUids -> $doc("$ne" -> userId))), GroupField(F.playerUids)("gs" -> SumValue(1)), Sort(Descending("gs")), - Limit(limit))).map(_.documents.flatMap { obj => + Limit(limit))).map(_.firstBatch.flatMap { obj => obj.getAs[String]("_id") flatMap { id => obj.getAs[Int]("gs") map { id -> _ } } @@ -420,7 +420,7 @@ object GameRepo { )), GroupField(F.playerUids)("nb" -> SumValue(1)), Sort(Descending("nb")), - Limit(max))).map(_.documents.flatMap { obj => + Limit(max))).map(_.firstBatch.flatMap { obj => obj.getAs[Int]("nb") map { nb => UidNb(~obj.getAs[String]("_id"), nb) } diff --git a/modules/game/src/main/PlayTime.scala b/modules/game/src/main/PlayTime.scala index 88c8b3e94a..64369ad828 100644 --- a/modules/game/src/main/PlayTime.scala +++ b/modules/game/src/main/PlayTime.scala @@ -15,7 +15,7 @@ final class PlayTime(gameColl: Coll) { def apply(user: User): Fu[User.PlayTime] = user.playTime match { case Some(pt) => fuccess(pt) - case None => { + case _ => { gameColl .find($doc( Game.BSONFields.playerUids -> user.id, @@ -25,15 +25,13 @@ final class PlayTime(gameColl: Coll) { moveTimeField -> true, tvField -> true )) - .cursor[Bdoc]() - .enumerate() |>>> (Iteratee.fold(User.PlayTime(0, 0)) { - case (pt, doc) => - val t = doc.getAs[ByteArray](moveTimeField) ?? { times => - BinaryFormat.moveTime.read(times).sum - } / 10 - val isTv = doc.get(tvField).isDefined - User.PlayTime(pt.total + t, pt.tv + isTv.fold(t, 0)) - }) + .cursor[Bdoc]().fold(User.PlayTime(0, 0)) { (pt, doc) => + val t = doc.getAs[ByteArray](moveTimeField) ?? { times => + BinaryFormat.moveTime.read(times).sum + } / 10 + val isTv = doc.get(tvField).isDefined + User.PlayTime(pt.total + t, pt.tv + isTv.fold(t, 0)) + } }.addEffect { UserRepo.setPlayTime(user, _) } } } diff --git a/modules/insight/src/main/AggregationClusters.scala b/modules/insight/src/main/AggregationClusters.scala index d1b46efd32..7c96af2cb1 100644 --- a/modules/insight/src/main/AggregationClusters.scala +++ b/modules/insight/src/main/AggregationClusters.scala @@ -12,7 +12,7 @@ object AggregationClusters { } private def single[X](question: Question[X], res: AggregationResult): List[Cluster[X]] = - res.documents.flatMap { doc => + res.firstBatch.flatMap { doc => for { x <- doc.getAs[X]("_id")(question.dimension.bson) value <- doc.getAs[BSONNumberLike]("v") @@ -25,7 +25,7 @@ object AggregationClusters { private implicit val StackEntryBSONReader = Macros.reader[StackEntry] private def stacked[X](question: Question[X], res: AggregationResult): List[Cluster[X]] = - res.documents.flatMap { doc => + res.firstBatch.flatMap { doc => val metricValues = Metric valuesOf question.metric // println(lila.db.BSON debug doc) for { diff --git a/modules/insight/src/main/Storage.scala b/modules/insight/src/main/Storage.scala index 9a503c5841..a97e5724b6 100644 --- a/modules/insight/src/main/Storage.scala +++ b/modules/insight/src/main/Storage.scala @@ -44,13 +44,13 @@ private final class Storage(coll: Coll) { def find(id: String) = coll.find(selectId(id)).uno[Entry] def ecos(userId: String): Fu[Set[String]] = - coll.distinct(F.eco, selectUserId(userId).some) map lila.db.BSON.asStringSet + coll.distinct[String, Set](F.eco, selectUserId(userId).some) def nbByPerf(userId: String): Fu[Map[PerfType, Int]] = coll.aggregate( Match(BSONDocument(F.userId -> userId)), List(GroupField(F.perf)("nb" -> SumValue(1))) ).map { - _.documents.flatMap { doc => + _.firstBatch.flatMap { doc => for { perfType <- doc.getAs[PerfType]("_id") nb <- doc.getAs[Int]("nb") diff --git a/modules/mod/src/main/Gamify.scala b/modules/mod/src/main/Gamify.scala index 1364004ae6..143a9baf1c 100644 --- a/modules/mod/src/main/Gamify.scala +++ b/modules/mod/src/main/Gamify.scala @@ -84,7 +84,7 @@ final class Gamify( )), List( GroupField("mod")("nb" -> SumValue(1)), Sort(Descending("nb")))).map { - _.documents.flatMap { obj => + _.firstBatch.flatMap { obj => obj.getAs[String]("_id") |@| obj.getAs[Int]("nb") apply ModCount.apply } } @@ -97,7 +97,7 @@ final class Gamify( )), List( GroupField("processedBy")("nb" -> SumValue(1)), Sort(Descending("nb")))).map { - _.documents.flatMap { obj => + _.firstBatch.flatMap { obj => obj.getAs[String]("_id") |@| obj.getAs[Int]("nb") apply ModCount.apply } } diff --git a/modules/opening/src/main/OpeningApi.scala b/modules/opening/src/main/OpeningApi.scala index 099d9a3967..e921d30f76 100644 --- a/modules/opening/src/main/OpeningApi.scala +++ b/modules/opening/src/main/OpeningApi.scala @@ -3,7 +3,7 @@ package lila.opening import scala.util.{ Try, Success, Failure } import org.joda.time.DateTime -import reactivemongo.bson.BSONArray +import reactivemongo.bson.{ BSONArray, BSONValue } import reactivemongo.core.commands._ import lila.db.dsl._ @@ -38,7 +38,7 @@ private[opening] final class OpeningApi( )) def playedIds(user: User): Fu[BSONArray] = - attemptColl.distinct(Attempt.BSONFields.openingId, + attemptColl.distinct[BSONValue, List](Attempt.BSONFields.openingId, $doc(Attempt.BSONFields.userId -> user.id).some ) map BSONArray.apply } diff --git a/modules/perfStat/src/main/PerfStatIndexer.scala b/modules/perfStat/src/main/PerfStatIndexer.scala index d523e84252..c70af2af69 100644 --- a/modules/perfStat/src/main/PerfStatIndexer.scala +++ b/modules/perfStat/src/main/PerfStatIndexer.scala @@ -25,13 +25,11 @@ final class PerfStatIndexer(storage: PerfStatStorage, sequencer: ActorRef) { Query.finished ++ Query.turnsMoreThan(2) ++ Query.variant(PerfType variantOf perfType), - Query.sortChronological) - .enumerate(Int.MaxValue, stopOnError = true) |>>> - Iteratee.fold[Game, PerfStat](PerfStat.init(user.id, perfType)) { + Query.sortChronological).fold(PerfStat.init(user.id, perfType)) { case (perfStat, game) if game.perfType.contains(perfType) => Pov.ofUserId(game, user.id).fold(perfStat)(perfStat.agg) case (perfStat, _) => perfStat - } + } } flatMap storage.insert def addGame(game: Game): Funit = game.players.flatMap { player => diff --git a/modules/plan/src/main/MonthlyGoal.scala b/modules/plan/src/main/MonthlyGoal.scala index 04658887fd..1bd55ac0d4 100644 --- a/modules/plan/src/main/MonthlyGoal.scala +++ b/modules/plan/src/main/MonthlyGoal.scala @@ -17,7 +17,7 @@ private final class MonthlyGoalApi(goal: Cents, chargeColl: Coll) { Match($doc("date" $gt DateTime.now.withDayOfMonth(1).withTimeAtStartOfDay)), List( Group(BSONNull)("cents" -> SumField("cents")) )).map { - ~_.documents.headOption.flatMap { _.getAs[Int]("cents") } + ~_.firstBatch.headOption.flatMap { _.getAs[Int]("cents") } } map Cents.apply } diff --git a/modules/plan/src/main/PlanApi.scala b/modules/plan/src/main/PlanApi.scala index 2c69681e95..68c2e83d59 100644 --- a/modules/plan/src/main/PlanApi.scala +++ b/modules/plan/src/main/PlanApi.scala @@ -219,7 +219,7 @@ final class PlanApi( GroupField("userId")("total" -> SumField("cents")), Sort(Descending("total")), Limit(nb))).map { - _.documents.flatMap { _.getAs[User.ID]("_id") } + _.firstBatch.flatMap { _.getAs[User.ID]("_id") } } flatMap filterUserIds, timeToLive = 1 hour) diff --git a/modules/pref/src/main/PrefApi.scala b/modules/pref/src/main/PrefApi.scala index 9a6b3c3acc..df07424ae7 100644 --- a/modules/pref/src/main/PrefApi.scala +++ b/modules/pref/src/main/PrefApi.scala @@ -115,9 +115,9 @@ final class PrefApi( } def unfollowableIds(userIds: List[String]): Fu[Set[String]] = - coll.distinct("_id", ($inIds(userIds) ++ $doc( + coll.distinct[String, Set]("_id", ($inIds(userIds) ++ $doc( "follow" -> false - )).some) map lila.db.BSON.asStringSet + )).some) def followableIds(userIds: List[String]): Fu[Set[String]] = unfollowableIds(userIds) map userIds.toSet.diff diff --git a/modules/puzzle/src/main/PuzzleApi.scala b/modules/puzzle/src/main/PuzzleApi.scala index c9dc355882..fd5a97ef2b 100644 --- a/modules/puzzle/src/main/PuzzleApi.scala +++ b/modules/puzzle/src/main/PuzzleApi.scala @@ -5,7 +5,7 @@ import scala.util.{ Try, Success, Failure } import org.joda.time.DateTime import play.api.libs.json.JsValue import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework._ -import reactivemongo.bson. BSONArray +import reactivemongo.bson.{ BSONArray, BSONValue } import lila.db.dsl._ import lila.user.{ User, UserRepo } @@ -100,7 +100,7 @@ private[puzzle] final class PuzzleApi( )) def playedIds(user: User): Fu[BSONArray] = - attemptColl.distinct(Attempt.BSONFields.puzzleId, + attemptColl.distinct[BSONValue, List](Attempt.BSONFields.puzzleId, $doc(Attempt.BSONFields.userId -> user.id).some ) map BSONArray.apply diff --git a/modules/qa/src/main/QaApi.scala b/modules/qa/src/main/QaApi.scala index 78ab287642..4673f32b2f 100644 --- a/modules/qa/src/main/QaApi.scala +++ b/modules/qa/src/main/QaApi.scala @@ -293,7 +293,7 @@ final class QaApi( col.aggregate(Project($doc("tags" -> BSONBoolean(true))), List( Unwind("tags"), Group(BSONBoolean(true))("tags" -> AddToSet("tags")))). - map(_.documents.headOption.flatMap(_.getAs[List[String]]("tags")). + map(_.firstBatch.headOption.flatMap(_.getAs[List[String]]("tags")). getOrElse(List.empty[String]).map(_.toLowerCase).distinct) } } diff --git a/modules/relation/src/main/RelationApi.scala b/modules/relation/src/main/RelationApi.scala index d0cbf55c6d..7e33ad475c 100644 --- a/modules/relation/src/main/RelationApi.scala +++ b/modules/relation/src/main/RelationApi.scala @@ -44,7 +44,7 @@ final class RelationApi( "u2" -> AddToSet("u2")), Project($id($doc("$setIntersection" -> $arr("$u1", "$u2")))) )).map { - ~_.documents.headOption.flatMap(_.getAs[Set[String]]("_id")) - userId + ~_.firstBatch.headOption.flatMap(_.getAs[Set[String]]("_id")) - userId } def fetchFollows(u1: ID, u2: ID) = diff --git a/modules/relation/src/main/RelationRepo.scala b/modules/relation/src/main/RelationRepo.scala index 32e83c18f6..30038cb44e 100644 --- a/modules/relation/src/main/RelationRepo.scala +++ b/modules/relation/src/main/RelationRepo.scala @@ -16,16 +16,16 @@ private[relation] object RelationRepo { def blocking(userId: ID) = relating(userId, Block) private def relaters(userId: ID, relation: Relation): Fu[Set[ID]] = - coll.distinct("u1", $doc( + coll.distinct[String, Set]("u1", $doc( "u2" -> userId, "r" -> relation - ).some) map lila.db.BSON.asStringSet + ).some) private def relating(userId: ID, relation: Relation): Fu[Set[ID]] = - coll.distinct("u2", $doc( + coll.distinct[String, Set]("u2", $doc( "u1" -> userId, "r" -> relation - ).some) map lila.db.BSON.asStringSet + ).some) def follow(u1: ID, u2: ID): Funit = save(u1, u2, Follow) def unfollow(u1: ID, u2: ID): Funit = remove(u1, u2) diff --git a/modules/security/src/main/Api.scala b/modules/security/src/main/Api.scala index 1ed96898f8..a3252328dc 100644 --- a/modules/security/src/main/Api.scala +++ b/modules/security/src/main/Api.scala @@ -92,18 +92,18 @@ final class Api( def userIdsSharingFingerprint = userIdsSharingField("fp") _ private def userIdsSharingField(field: String)(userId: String): Fu[List[String]] = - coll.distinct( + coll.distinct[String, List]( field, $doc("user" -> userId, field -> $doc("$exists" -> true)).some ).flatMap { case Nil => fuccess(Nil) - case values => coll.distinct( + case values => coll.distinct[String, List]( "user", $doc( field $in values, "user" $ne userId ).some - ) map lila.db.BSON.asStrings + ) } def recentUserIdsByFingerprint = recentUserIdsByField("fp") _ @@ -111,13 +111,13 @@ final class Api( def recentUserIdsByIp = recentUserIdsByField("ip") _ private def recentUserIdsByField(field: String)(value: String): Fu[List[String]] = - coll.distinct( + coll.distinct[String, List]( "user", $doc( field -> value, "date" $gt DateTime.now.minusYears(1) ).some - ) map lila.db.BSON.asStrings + ) } object Api { diff --git a/modules/security/src/main/Firewall.scala b/modules/security/src/main/Firewall.scala index 961f421384..3864a64a0c 100644 --- a/modules/security/src/main/Firewall.scala +++ b/modules/security/src/main/Firewall.scala @@ -75,9 +75,7 @@ final class Firewall( def clear { cache.clear } def contains(ip: String) = apply map (_ contains strToIp(ip)) def fetch: Fu[Set[IP]] = - coll.distinct("_id") map { res => - lila.db.BSON.asStringSet(res) map strToIp - } addEffect { ips => + coll.distinct[String, Set]("_id").map(_.map(strToIp)).addEffect { ips => lila.mon.security.firewall.ip(ips.size) } } diff --git a/modules/security/src/main/UserSpy.scala b/modules/security/src/main/UserSpy.scala index 90dd94f307..f7a7ffdf9e 100644 --- a/modules/security/src/main/UserSpy.scala +++ b/modules/security/src/main/UserSpy.scala @@ -72,12 +72,12 @@ object UserSpy { private def nextUsers(field: String)(values: Set[Value], user: User)(implicit coll: Coll): Fu[Set[User]] = values.nonEmpty ?? { - coll.distinct("user", + coll.distinct[String, Set]("user", $doc( field $in values, "user" $ne user.id ).some - ) map lila.db.BSON.asStrings flatMap { userIds => + ) flatMap { userIds => userIds.nonEmpty ?? (UserRepo byIds userIds) map (_.toSet) } } diff --git a/modules/study/src/main/StudyRepo.scala b/modules/study/src/main/StudyRepo.scala index 46c32cfd72..0dbdb39f6a 100644 --- a/modules/study/src/main/StudyRepo.scala +++ b/modules/study/src/main/StudyRepo.scala @@ -1,6 +1,7 @@ package lila.study import org.joda.time.DateTime +import reactivemongo.api.Cursor import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework.{ Project, Match } import scala.concurrent.duration._ @@ -101,20 +102,16 @@ final class StudyRepo(private[study] val coll: Coll) { def filterLiked(user: User, studyIds: Seq[Study.ID]): Fu[Set[Study.ID]] = coll.primitive[Study.ID]($inIds(studyIds) ++ selectLiker(user.id), "_id").map(_.toSet) - def resetAllRanks: Fu[Int] = { - import play.api.libs.iteratee._ - coll.find( - $empty, $doc("likes" -> true, "createdAt" -> true) - ).cursor[Bdoc]().enumerate() |>>> - Iteratee.foldM[Bdoc, Int](0) { - case (count, doc) => ~(for { - id <- doc.getAs[Study.ID]("_id") - likes <- doc.getAs[Study.Likes]("likes") - createdAt <- doc.getAs[DateTime]("createdAt") - } yield coll.update( - $id(id), $set("rank" -> Study.Rank.compute(likes, createdAt)) - ).void) inject (count + 1) - } + def resetAllRanks: Fu[Int] = coll.find( + $empty, $doc("likes" -> true, "createdAt" -> true) + ).cursor[Bdoc]().foldWhileM(0) { (count, doc) => + ~(for { + id <- doc.getAs[Study.ID]("_id") + likes <- doc.getAs[Study.Likes]("likes") + createdAt <- doc.getAs[DateTime]("createdAt") + } yield coll.update( + $id(id), $set("rank" -> Study.Rank.compute(likes, createdAt)) + ).void) inject Cursor.Cont(count + 1) } private def doLike(studyId: Study.ID, userId: User.ID, v: Boolean): Funit = @@ -134,7 +131,7 @@ final class StudyRepo(private[study] val coll: Coll) { ))) ).map { res => for { - doc <- res.documents.headOption + doc <- res.firstBatch.headOption likes <- doc.getAs[Study.Likes]("likes") createdAt <- doc.getAs[DateTime]("createdAt") } yield likes -> createdAt diff --git a/modules/team/src/main/MemberRepo.scala b/modules/team/src/main/MemberRepo.scala index a8ec7b30df..809f33a572 100644 --- a/modules/team/src/main/MemberRepo.scala +++ b/modules/team/src/main/MemberRepo.scala @@ -15,10 +15,10 @@ object MemberRepo { type ID = String def userIdsByTeam(teamId: ID): Fu[Set[ID]] = - coll.distinct("user", $doc("team" -> teamId).some) map lila.db.BSON.asStringSet + coll.distinct[String, Set]("user", $doc("team" -> teamId).some) def teamIdsByUser(userId: ID): Fu[Set[ID]] = - coll.distinct("team", $doc("user" -> userId).some) map lila.db.BSON.asStringSet + coll.distinct[String, Set]("team", $doc("user" -> userId).some) def removeByteam(teamId: ID): Funit = coll.remove(teamQuery(teamId)).void diff --git a/modules/team/src/main/TeamApi.scala b/modules/team/src/main/TeamApi.scala index 9f6b2c5bf2..b1e8cb540f 100644 --- a/modules/team/src/main/TeamApi.scala +++ b/modules/team/src/main/TeamApi.scala @@ -7,6 +7,7 @@ import lila.hub.actorApi.forum.MakeTeam import lila.hub.actorApi.timeline.{ Propagate, TeamJoin, TeamCreate } import lila.user.{ User, UserRepo, UserContext } import org.joda.time.Period +import reactivemongo.api.Cursor final class TeamApi( coll: Colls, @@ -162,13 +163,11 @@ final class TeamApi( def nbRequests(teamId: String) = cached nbRequests teamId - import play.api.libs.iteratee._ def recomputeNbMembers = - coll.team.find($empty).cursor[Team]() - .enumerate(Int.MaxValue, stopOnError = true) |>>> - Iteratee.foldM[Team, Unit](()) { - case (_, team) => MemberRepo.countByTeam(team.id) flatMap { nb => - coll.team.updateField($id(team.id), "nbMembers", nb).void - } - } + coll.team.find($empty).cursor[Team]().foldWhileM({}) { (_, team) => + for { + nb <- MemberRepo.countByTeam(team.id) + _ <- coll.team.updateField($id(team.id), "nbMembers", nb) + } yield Cursor.Cont({}) + } } diff --git a/modules/team/src/main/TeamRepo.scala b/modules/team/src/main/TeamRepo.scala index 2cfa2c939b..a2378ef0e8 100644 --- a/modules/team/src/main/TeamRepo.scala +++ b/modules/team/src/main/TeamRepo.scala @@ -24,7 +24,7 @@ object TeamRepo { coll.uno[Team]($id(id) ++ $doc("createdBy" -> createdBy)) def teamIdsByCreator(userId: String): Fu[List[String]] = - coll.distinct("_id", BSONDocument("createdBy" -> userId).some) map lila.db.BSON.asStrings + coll.distinct[String, List]("_id", BSONDocument("createdBy" -> userId).some) def name(id: String): Fu[Option[String]] = coll.primitiveOne[String]($id(id), "name") diff --git a/modules/teamSearch/src/main/TeamSearchApi.scala b/modules/teamSearch/src/main/TeamSearchApi.scala index 9f7fe5becc..f970aa28f5 100644 --- a/modules/teamSearch/src/main/TeamSearchApi.scala +++ b/modules/teamSearch/src/main/TeamSearchApi.scala @@ -1,11 +1,12 @@ package lila.teamSearch +import reactivemongo.api.Cursor + import lila.search._ import lila.team.actorApi._ import lila.team.{ Team, TeamRepo } import play.api.libs.json._ -import play.api.libs.iteratee._ final class TeamSearchApi(client: ESClient) extends SearchReadApi[Team, Query] { @@ -28,13 +29,13 @@ final class TeamSearchApi(client: ESClient) extends SearchReadApi[Team, Query] { case c: ESClientHttp => c.putMapping >> { lila.log("teamSearch").info(s"Index to ${c.index.name}") import lila.db.dsl._ - TeamRepo.cursor($doc("enabled" -> true)) - .enumerateBulks(Int.MaxValue) |>>> - Iteratee.foldM[Iterator[Team], Unit](()) { - case (_, teams) => - c.storeBulk(teams.toList map (t => Id(t.id) -> toDoc(t))) - } + + TeamRepo.cursor($doc("enabled" -> true)).foldBulksM({}) { (_, teams) => + c.storeBulk(teams.toList map (t => Id(t.id) -> toDoc(t))). + map(Cursor.Cont(_)) + } } + case _ => funit } } diff --git a/modules/timeline/src/main/UnsubApi.scala b/modules/timeline/src/main/UnsubApi.scala index 91177ca934..2bdb3973ad 100644 --- a/modules/timeline/src/main/UnsubApi.scala +++ b/modules/timeline/src/main/UnsubApi.scala @@ -21,8 +21,8 @@ private[timeline] final class UnsubApi(coll: Coll) { coll.count(select(channel, userId).some) map (0 !=) def filterUnsub(channel: String, userIds: List[String]): Fu[List[String]] = - coll.distinct("_id", $inIds(userIds.map { makeId(channel, _) }).some) map - lila.db.BSON.asStrings map { unsubs => + coll.distinct[String, List]( + "_id", $inIds(userIds.map { makeId(channel, _) }).some) map { unsubs => userIds diff unsubs.map(_ takeWhile ('@' !=)) } } diff --git a/modules/tournament/src/main/LeaderboardApi.scala b/modules/tournament/src/main/LeaderboardApi.scala index 18c0d9cc59..a891dff73f 100644 --- a/modules/tournament/src/main/LeaderboardApi.scala +++ b/modules/tournament/src/main/LeaderboardApi.scala @@ -31,7 +31,7 @@ final class LeaderboardApi( Match($doc("u" -> user.id)), List(GroupField("v")("nb" -> SumValue(1), "points" -> Push("s"), "ratios" -> Push("w"))) ).map { - _.documents map leaderboardAggregationResultBSONHandler.read + _.firstBatch map leaderboardAggregationResultBSONHandler.read }.map { aggs => ChartData { aggs.flatMap { agg => diff --git a/modules/tournament/src/main/PairingRepo.scala b/modules/tournament/src/main/PairingRepo.scala index 4f264fde62..bd88526bff 100644 --- a/modules/tournament/src/main/PairingRepo.scala +++ b/modules/tournament/src/main/PairingRepo.scala @@ -32,8 +32,8 @@ object PairingRepo { coll.find( selectTour(tourId) ++ $doc("u" $in userIds), $doc("_id" -> false, "u" -> true) - ).sort(recentSort).cursor[Bdoc]().enumerate(nb) |>>> - Iteratee.fold(scala.collection.immutable.Map.empty[String, String]) { (acc, doc) => + ).sort(recentSort).cursor[Bdoc]().fold( + scala.collection.immutable.Map.empty[String, String], nb) { (acc, doc) => ~doc.getAs[List[String]]("u") match { case List(u1, u2) => val acc1 = acc.contains(u1).fold(acc, acc.updated(u1, u2)) @@ -81,7 +81,7 @@ object PairingRepo { Unwind("u"), GroupField("u")("nb" -> SumValue(1)) )).map { - _.documents.flatMap { doc => + _.firstBatch.flatMap { doc => doc.getAs[String]("_id") flatMap { uid => doc.getAs[Int]("nb") map { uid -> _ } } @@ -132,12 +132,12 @@ object PairingRepo { Project($doc( "u" -> BSONBoolean(true), "_id" -> BSONBoolean(false))), Unwind("u"), Group(BSONBoolean(true))("ids" -> AddToSet("u")))).map( - _.documents.headOption.flatMap(_.getAs[Set[String]]("ids")). + _.firstBatch.headOption.flatMap(_.getAs[Set[String]]("ids")). getOrElse(Set.empty[String])) def playingGameIds(tourId: String): Fu[List[String]] = coll.aggregate(Match(selectTour(tourId) ++ selectPlaying), List( Group(BSONBoolean(true))("ids" -> Push("_id")))).map( - _.documents.headOption.flatMap(_.getAs[List[String]]("ids")). + _.firstBatch.headOption.flatMap(_.getAs[List[String]]("ids")). getOrElse(List.empty[String])) } diff --git a/modules/tournament/src/main/PlayerRepo.scala b/modules/tournament/src/main/PlayerRepo.scala index de1819c87b..3731263c51 100644 --- a/modules/tournament/src/main/PlayerRepo.scala +++ b/modules/tournament/src/main/PlayerRepo.scala @@ -102,10 +102,11 @@ object PlayerRepo { import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework.{ Descending, Group, Match, Push, Sort } def userIds(tourId: String): Fu[List[String]] = - coll.distinct("uid", selectTour(tourId).some) map lila.db.BSON.asStrings + coll.distinct[String, List]("uid", selectTour(tourId).some) def activeUserIds(tourId: String): Fu[List[String]] = - coll.distinct("uid", (selectTour(tourId) ++ selectActive).some) map lila.db.BSON.asStrings + coll.distinct[String, List]( + "uid", (selectTour(tourId) ++ selectActive).some) def winner(tourId: String): Fu[Option[Player]] = coll.find(selectTour(tourId)).sort(bestSort).uno[Player] @@ -114,7 +115,7 @@ object PlayerRepo { private[tournament] def computeRanking(tourId: String): Fu[Ranking] = coll.aggregate(Match(selectTour(tourId)), List(Sort(Descending("m")), Group(BSONNull)("uids" -> Push("uid")))) map { - _.documents.headOption.fold(Map.empty: Ranking) { + _.firstBatch.headOption.fold(Map.empty: Ranking) { _ get "uids" match { case Some(BSONArray(uids)) => // mutable optimized implementation diff --git a/modules/user/src/main/RankingApi.scala b/modules/user/src/main/RankingApi.scala index a46132fb1d..4738402c16 100644 --- a/modules/user/src/main/RankingApi.scala +++ b/modules/user/src/main/RankingApi.scala @@ -2,6 +2,7 @@ package lila.user import org.joda.time.DateTime import play.api.libs.iteratee._ +import reactivemongo.api.Cursor import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework.{ Match, Project, Group, GroupField, SumField, SumValue } import reactivemongo.bson._ import scala.concurrent.duration._ @@ -77,21 +78,18 @@ final class RankingApi( f = compute, timeToLive = 15 minutes) - private def compute(perfId: Perf.ID): Fu[Map[User.ID, Rank]] = { - val enumerator = coll.find( + private def compute(perfId: Perf.ID): Fu[Map[User.ID, Rank]] = + coll.find( $doc("perf" -> perfId, "stable" -> true), $doc("user" -> true, "_id" -> false) - ).sort($doc("rating" -> -1)).cursor[Bdoc]().enumerate() - var rank = 1 - val b = Map.newBuilder[User.ID, Rank] - val mapBuilder: Iteratee[Bdoc, Unit] = Iteratee.foreach { doc => - doc.getAs[User.ID]("user") foreach { user => - b += (user -> rank) - rank = rank + 1 - } - } - enumerator.run(mapBuilder) inject b.result - } + ).sort($doc("rating" -> -1)).cursor[Bdoc](). + fold(1 -> Map.newBuilder[User.ID, Rank]) { + case (state @ (rank, b), doc) => + doc.getAs[User.ID]("user").fold(state) { user => + b += (user -> rank) + (rank + 1) -> b + } + }.map(_._2.result()) } object weeklyRatingDistribution { @@ -122,7 +120,7 @@ final class RankingApi( )), GroupField("r")("nb" -> SumValue(1)) )).map { res => - val hash = res.documents.flatMap { obj => + val hash = res.firstBatch.flatMap { obj => for { rating <- obj.getAs[Int]("_id") nb <- obj.getAs[NbUsers]("nb") diff --git a/modules/user/src/main/UserRepo.scala b/modules/user/src/main/UserRepo.scala index a50f9979f2..bbd7c367b8 100644 --- a/modules/user/src/main/UserRepo.scala +++ b/modules/user/src/main/UserRepo.scala @@ -81,7 +81,7 @@ object UserRepo { coll.primitiveOne[String]($id(id), F.username) def usernamesByIds(ids: List[ID]) = - coll.distinct(F.username, $inIds(ids).some) map lila.db.BSON.asStrings + coll.distinct[String, List](F.username, $inIds(ids).some) def orderByGameCount(u1: String, u2: String): Fu[Option[(String, String)]] = { coll.find( @@ -242,7 +242,7 @@ object UserRepo { coll.primitive[String]($inIds(usernames.map(normalize)), "_id") def engineIds: Fu[Set[String]] = - coll.distinct("_id", $doc("engine" -> true).some) map lila.db.BSON.asStringSet + coll.distinct[String, Set]("_id", $doc("engine" -> true).some) private val userIdPattern = """^[\w-]{3,20}$""".r.pattern @@ -339,7 +339,7 @@ object UserRepo { def idsSumToints(ids: Iterable[String]): Fu[Int] = ids.nonEmpty ?? coll.aggregate(Match($inIds(ids)), List(Group(BSONNull)(F.toints -> SumField(F.toints)))).map( - _.documents.headOption flatMap { _.getAs[Int](F.toints) } + _.firstBatch.headOption flatMap { _.getAs[Int](F.toints) } ).map(~_) def filterByEngine(userIds: List[String]): Fu[List[String]] = diff --git a/modules/video/src/main/VideoApi.scala b/modules/video/src/main/VideoApi.scala index e829a34ba7..2ddd1057cf 100644 --- a/modules/video/src/main/VideoApi.scala +++ b/modules/video/src/main/VideoApi.scala @@ -76,7 +76,7 @@ private[video] final class VideoApi( ).void def allIds: Fu[List[Video.ID]] = - videoColl.distinct("_id", none) map lila.db.BSON.asStrings + videoColl.distinct[String, List]("_id", none) def popular(user: Option[User], page: Int): Fu[Paginator[VideoView]] = Paginator( adapter = new Adapter[Video]( @@ -149,10 +149,10 @@ private[video] final class VideoApi( ).some) map (0!=) def seenVideoIds(user: User, videos: Seq[Video]): Fu[Set[Video.ID]] = - viewColl.distinct(View.BSONFields.videoId, + viewColl.distinct[String, Set](View.BSONFields.videoId, $inIds(videos.map { v => View.makeId(v.id, user.id) - }).some) map lila.db.BSON.asStringSet + }).some) } object tag { @@ -177,7 +177,7 @@ private[video] final class VideoApi( Match($doc("tags" $all filterTags)), List(Project($doc("tags" -> true)), Unwind("tags"), GroupField("tags")("nb" -> SumValue(1)))).map( - _.documents.flatMap(_.asOpt[TagNb])) + _.firstBatch.flatMap(_.asOpt[TagNb])) allPopular zip allPaths map { case (all, paths) => @@ -203,7 +203,7 @@ private[video] final class VideoApi( Project($doc("tags" -> true)), List( Unwind("tags"), GroupField("tags")("nb" -> SumValue(1)), Sort(Descending("nb")))).map( - _.documents.flatMap(_.asOpt[TagNb])), + _.firstBatch.flatMap(_.asOpt[TagNb])), timeToLive = 1.day) } } diff --git a/project/Dependencies.scala b/project/Dependencies.scala index a6822159a4..af1f00243e 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -34,7 +34,7 @@ object Dependencies { val hasher = "com.roundeights" %% "hasher" % "1.2.0" val jgit = "org.eclipse.jgit" % "org.eclipse.jgit" % "3.2.0.201312181205-r" val jodaTime = "joda-time" % "joda-time" % "2.9.2" - val RM = "org.reactivemongo" % "reactivemongo_2.11" % "0.11.9.1-LILA" + val RM = "org.reactivemongo" %% "reactivemongo" % "0.12-RC0" val maxmind = "com.sanoma.cda" %% "maxmind-geoip2-scala" % "1.2.3-THIB" val prismic = "io.prismic" %% "scala-kit" % "1.2.11-THIB" val java8compat = "org.scala-lang.modules" %% "scala-java8-compat" % "0.7.0" From 2c9e4eb7efbc4cee7491eafbf756bbab9635beb7 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Tue, 26 Jul 2016 23:54:30 +0200 Subject: [PATCH 002/161] analysis variation fork WIP --- public/stylesheets/analyse.css | 23 +++++++ ui/analyse/src/tree/treeView.js | 105 +++++++++++++++++--------------- ui/analyse/src/view.js | 12 +++- 3 files changed, 90 insertions(+), 50 deletions(-) diff --git a/public/stylesheets/analyse.css b/public/stylesheets/analyse.css index f92784ca0c..f41ba7717d 100644 --- a/public/stylesheets/analyse.css +++ b/public/stylesheets/analyse.css @@ -134,6 +134,7 @@ div.game_control .jumps button:nth-child(3) { padding: 0 14px 0 10px; } div.lichess_game div.lichess_ground { + position: relative; transition: padding-left 0.3s; } div.eval_gauge { @@ -239,6 +240,28 @@ div.gauge_displayed div.lichess_game div.lichess_ground { background: #759900; transition: 1s; } + +.fork { + position: absolute; + bottom: 36px; + left: 15px; + right: 0; + background: #fff; + box-shadow: 0px 8px 17px 0px rgba(0, 0, 0, 0.2), 0px 6px 20px 0px rgba(0, 0, 0, 0.19); + padding: 15px 0; + z-index: 1; +} +.fork move { + font-family: 'ChessSansPiratf', sans-serif; + font-size: 16px; + line-height: 30px; + display: block; + cursor: pointer; + padding: 0 10px; + display: flex; + /* justify-content: */ +} + .explorer_box { position: relative; flex: 2.5 1 0px; diff --git a/ui/analyse/src/tree/treeView.js b/ui/analyse/src/tree/treeView.js index c4e7247aed..62ec6e5603 100644 --- a/ui/analyse/src/tree/treeView.js +++ b/ui/analyse/src/tree/treeView.js @@ -124,20 +124,24 @@ function renderMainlineMoveOf(ctx, node, opts) { var attrs = { p: path }; - var eval = node.eval || node.ceval || {}; var classes = []; if (path === ctx.ctrl.vm.path) classes.push('active'); if (path === ctx.ctrl.vm.contextMenuPath) classes.push('context_menu'); if (path === ctx.ctrl.vm.initialPath && game.playable(ctx.ctrl.data)) classes.push('current'); if (opts.conceal) classes.push(opts.conceal); if (classes.length) attrs.class = classes.join(' '); - return moveTag(attrs, [ + return moveTag(attrs, renderMove(node)); +} + +function renderMove(node, eval) { + var eval = node.eval || node.ceval || {}; + return [ util.fixCrazySan(node.san), node.glyphs ? renderGlyphs(node.glyphs) : null, defined(eval.cp) ? renderEval(util.renderEval(eval.cp)) : ( defined(eval.mate) ? renderEval('#' + eval.mate) : null ), - ]); + ]; } function renderVariationMoveOf(ctx, node, opts) { @@ -255,51 +259,54 @@ function eventPath(e, ctrl) { return e.target.getAttribute('p') || e.target.parentNode.getAttribute('p'); } -module.exports = function(ctrl, conceal) { - var root = ctrl.tree.root; - var ctx = { - ctrl: ctrl, - concealOf: function(isMainline) { - return function(path, node) { - if (!conceal || (isMainline && conceal.ply >= node.ply)) return null; - if (treePath.contains(ctrl.vm.path, path)) return null; - return conceal.owner ? 'conceal' : 'hide' - }; - } - }; - var commentTags = renderMainlineCommentsOf(ctx, root, { - withColor: false, - conceal: false - }); - return m('div.tview2', { - onmousedown: function(e) { - if (e.button !== undefined && e.button !== 0) return; // only touch or left click - var path = eventPath(e, ctrl); - if (path) ctrl.userJump(path); - }, - config: function(el, isUpdate) { - if (ctrl.vm.autoScrollRequested || !isUpdate) { - autoScroll(ctrl, el); - ctrl.vm.autoScrollRequested = false; +module.exports = { + render: function(ctrl, conceal) { + var root = ctrl.tree.root; + var ctx = { + ctrl: ctrl, + concealOf: function(isMainline) { + return function(path, node) { + if (!conceal || (isMainline && conceal.ply >= node.ply)) return null; + if (treePath.contains(ctrl.vm.path, path)) return null; + return conceal.owner ? 'conceal' : 'hide' + }; } - }, - oncontextmenu: function(e) { - var path = eventPath(e, ctrl); - contextMenu.open(e, { - path: path, - root: ctrl - }); - return false; - }, - }, [ - commentTags ? m('interrupt', commentTags) : null, - root.ply % 2 === 1 ? [ - renderIndex(root.ply, false), - emptyMove({}) - ] : null, - renderChildrenOf(ctx, root, { - parentPath: '', - isMainline: true - }) - ]); + }; + var commentTags = renderMainlineCommentsOf(ctx, root, { + withColor: false, + conceal: false + }); + return m('div.tview2', { + onmousedown: function(e) { + if (e.button !== undefined && e.button !== 0) return; // only touch or left click + var path = eventPath(e, ctrl); + if (path) ctrl.userJump(path); + }, + config: function(el, isUpdate) { + if (ctrl.vm.autoScrollRequested || !isUpdate) { + autoScroll(ctrl, el); + ctrl.vm.autoScrollRequested = false; + } + }, + oncontextmenu: function(e) { + var path = eventPath(e, ctrl); + contextMenu.open(e, { + path: path, + root: ctrl + }); + return false; + }, + }, [ + commentTags ? m('interrupt', commentTags) : null, + root.ply % 2 === 1 ? [ + renderIndex(root.ply, false), + emptyMove({}) + ] : null, + renderChildrenOf(ctx, root, { + parentPath: '', + isMainline: true + }) + ]); + }, + renderMove: renderMove }; diff --git a/ui/analyse/src/view.js b/ui/analyse/src/view.js index df4695559a..b7abfc77e3 100644 --- a/ui/analyse/src/view.js +++ b/ui/analyse/src/view.js @@ -46,7 +46,7 @@ function renderAnalyse(ctrl) { ply: ctrl.study.data.chapter.conceal } : null; return m('div.areplay', [ - treeView(ctrl, conceal), + treeView.render(ctrl, conceal), renderResult(ctrl) ]); } @@ -198,6 +198,15 @@ function renderOpeningBox(ctrl) { ]); } +function renderFork(ctrl) { + if (!true) return; + return m('div.fork', + ctrl.vm.node.children.map(function(node) { + return m('move', treeView.renderMove(node)); + }) + ); +} + var firstRender = true; module.exports = function(ctrl) { @@ -222,6 +231,7 @@ module.exports = function(ctrl) { cevalView.renderCeval(ctrl), renderOpeningBox(ctrl), renderAnalyse(ctrl), + renderFork(ctrl), explorerView.renderExplorer(ctrl) ], ctrl.actionMenu.open ? null : crazyView.pocket(ctrl, ctrl.bottomColor(), 'bottom'), From a0d7543485a0fe3615da12f72cb5890339b40bcd Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Wed, 27 Jul 2016 12:41:20 +0200 Subject: [PATCH 003/161] [master] fix chat presets --- public/stylesheets/chat.css | 1 + 1 file changed, 1 insertion(+) diff --git a/public/stylesheets/chat.css b/public/stylesheets/chat.css index 43cd7a2e95..620c25fa5b 100644 --- a/public/stylesheets/chat.css +++ b/public/stylesheets/chat.css @@ -112,6 +112,7 @@ div.mchat .messages a:not(.user_link) { } div.mchat .presets { display: flex; + flex: 0 0 auto; align-items: center; flex-flow: row nowrap; } From 8db798374d542ce8a1dae03b9bac96e4b1645d48 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Wed, 27 Jul 2016 12:47:33 +0200 Subject: [PATCH 004/161] [master] fix homepage alignment --- public/stylesheets/home.css | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/public/stylesheets/home.css b/public/stylesheets/home.css index 687d8e2209..f22662f8a0 100644 --- a/public/stylesheets/home.css +++ b/public/stylesheets/home.css @@ -355,8 +355,7 @@ body.dark #hooks_wrap { flex-flow: column nowrap; } #featured_game { - position: absolute; - top: 529px; + margin-top: 16px; } div.undertable { width: 512px; @@ -478,7 +477,7 @@ div.new_posts li span.extract { #daily_puzzle { width: 224px; position: absolute; - top: 527px; + top: 531px; left: 527px; } #daily_puzzle > div.vstext { From 923f18c14fe395b17c94d4564361dd9852f89ce0 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Wed, 27 Jul 2016 16:03:37 +0200 Subject: [PATCH 005/161] faster crosstable display --- app/views/analyse/replayBot.scala.html | 4 ++-- app/views/round/player.scala.html | 2 +- app/views/round/watcher.scala.html | 2 +- app/views/tv/index.scala.html | 2 +- public/javascripts/main.js | 4 +--- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/app/views/analyse/replayBot.scala.html b/app/views/analyse/replayBot.scala.html index f0f1f291d8..0da4ae6f31 100644 --- a/app/views/analyse/replayBot.scala.html +++ b/app/views/analyse/replayBot.scala.html @@ -62,7 +62,7 @@ chessground = true) { -