diff --git a/app/controllers/User.scala b/app/controllers/User.scala
index 878f275036..ac37961a1e 100644
--- a/app/controllers/User.scala
+++ b/app/controllers/User.scala
@@ -22,7 +22,7 @@ object User extends LilaController {
def show(username: String) = showFilter(username, "all", 1)
def showFilter(username: String, filterName: String, page: Int) = Open { implicit ctx ⇒
- IOptionIOk(userRepo byUsername username) { u ⇒
+ IOptionIOk(userRepo byId username) { u ⇒
u.enabled.fold(
env.user.userInfo(u, ctx) map { info ⇒
val filters = user.GameFilterMenu(info, ctx.me, filterName)
@@ -79,7 +79,7 @@ object User extends LilaController {
_ ⇒
IORedirect {
for {
- uOption ← userRepo byUsername username
+ uOption ← userRepo byId username
_ ← uOption.filter(_.elo > UserModel.STARTING_ELO).fold(
u ⇒ eloUpdater.adjust(u, UserModel.STARTING_ELO) flatMap { _ ⇒
userRepo setEngine u
@@ -101,5 +101,5 @@ object User extends LilaController {
def export(username: String) = TODO
private val onlineUsers: IO[List[UserModel]] =
- userRepo byUsernames env.user.usernameMemo.keys
+ userRepo byIds env.user.usernameMemo.keys
}
diff --git a/app/core/CoreEnv.scala b/app/core/CoreEnv.scala
index 912e509165..2f32a550eb 100644
--- a/app/core/CoreEnv.scala
+++ b/app/core/CoreEnv.scala
@@ -2,7 +2,7 @@ package lila
package core
import com.mongodb.casbah.MongoConnection
-import com.mongodb.{ DBRef, Mongo, MongoOptions, ServerAddress ⇒ MongoServer }
+import com.mongodb.{ Mongo, MongoOptions, ServerAddress ⇒ MongoServer }
import akka.actor._
@@ -26,8 +26,7 @@ final class CoreEnv private (application: Application, val settings: Settings) {
lazy val user = new lila.user.UserEnv(
settings = settings,
mongodb = mongodb.apply _,
- gameRepo = game.gameRepo,
- dbRef = namespace ⇒ id ⇒ mongodb.ref(namespace, id))
+ gameRepo = game.gameRepo)
lazy val forum = new lila.forum.ForumEnv(
settings = settings,
@@ -57,14 +56,13 @@ final class CoreEnv private (application: Application, val settings: Settings) {
userRepo = user.userRepo,
timelinePush = timeline.push.apply,
roundMessenger = round.messenger,
- ai = ai.ai,
- userDbRef = user.userRepo.dbRef)
+ ai = ai.ai)
lazy val timeline = new lila.timeline.TimelineEnv(
settings = settings,
mongodb = mongodb.apply _,
lobbyNotify = lobby.socket.addEntry,
- getUsername = user.cached.username)
+ getUsername = user.cached.usernameOrAnonymous)
lazy val ai = new lila.ai.AiEnv(
settings = settings)
diff --git a/app/forum/CategRepo.scala b/app/forum/CategRepo.scala
index 2ce01133e7..e372ca66b8 100644
--- a/app/forum/CategRepo.scala
+++ b/app/forum/CategRepo.scala
@@ -3,7 +3,6 @@ package forum
import com.novus.salat._
import com.novus.salat.dao._
-import com.mongodb.DBRef
import com.mongodb.casbah.MongoCollection
import com.mongodb.casbah.Imports._
import scalaz.effects._
diff --git a/app/forum/ForumHelper.scala b/app/forum/ForumHelper.scala
index 4ece565bb8..dfd3147d76 100644
--- a/app/forum/ForumHelper.scala
+++ b/app/forum/ForumHelper.scala
@@ -8,10 +8,10 @@ import play.api.templates.Html
trait ForumHelper { self: UserHelper ⇒
def authorName(post: Post) =
- post.userIdString.fold(userIdToUsername, post.showAuthor)
+ post.userId.fold(userIdToUsername, post.showAuthor)
def authorLink(post: Post, cssClass: Option[String] = None) =
- post.userIdString.fold(
+ post.userId.fold(
userId ⇒ userIdLink(userId.some, cssClass),
Html("""%s"""
.format(cssClass | "", authorName(post)))
diff --git a/app/forum/Post.scala b/app/forum/Post.scala
index de28e4034f..9fd6cc9f46 100644
--- a/app/forum/Post.scala
+++ b/app/forum/Post.scala
@@ -3,7 +3,6 @@ package forum
import org.joda.time.DateTime
import com.novus.salat.annotations.Key
-import com.mongodb.casbah.Imports.ObjectId
import ornicar.scalalib.OrnicarRandom
import user.User
@@ -12,14 +11,12 @@ case class Post(
@Key("_id") id: String,
topicId: String,
author: Option[String],
- userId: Option[ObjectId],
+ userId: Option[String],
text: String,
number: Int,
createdAt: DateTime) {
def showAuthor = (author map (_.trim) filter ("" !=)) | User.anonymous
-
- def userIdString: Option[String] = userId map (_.toString)
}
object Post {
@@ -29,7 +26,7 @@ object Post {
def apply(
topicId: String,
author: Option[String],
- userId: Option[ObjectId],
+ userId: Option[String],
text: String,
number: Int): Post = Post(
id = OrnicarRandom nextAsciiString idSize,
diff --git a/app/forum/PostRepo.scala b/app/forum/PostRepo.scala
index 4ac5c491db..30d9bac421 100644
--- a/app/forum/PostRepo.scala
+++ b/app/forum/PostRepo.scala
@@ -3,7 +3,6 @@ package forum
import com.novus.salat._
import com.novus.salat.dao._
-import com.mongodb.DBRef
import com.mongodb.casbah.MongoCollection
import com.mongodb.casbah.Imports._
import scalaz.effects._
diff --git a/app/game/DbPlayer.scala b/app/game/DbPlayer.scala
index 465c5beb39..c8e10c0ee0 100644
--- a/app/game/DbPlayer.scala
+++ b/app/game/DbPlayer.scala
@@ -4,8 +4,6 @@ package game
import chess._
import user.User
-import com.mongodb.DBRef
-
case class DbPlayer(
id: String,
color: Color,
@@ -16,7 +14,7 @@ case class DbPlayer(
isOfferingRematch: Boolean = false,
lastDrawOffer: Option[Int] = None,
isProposingTakeback: Boolean = false,
- user: Option[DBRef] = None,
+ userId: Option[String] = None,
elo: Option[Int] = None,
eloDiff: Option[Int] = None,
moveTimes: String = "",
@@ -34,23 +32,17 @@ case class DbPlayer(
ps = encodePieces(allPieces)
)
- def withUser(user: User)(dbRef: User ⇒ DBRef): DbPlayer = copy(
- user = dbRef(user).some,
+ def withUser(user: User): DbPlayer = copy(
+ userId = user.id.some,
elo = user.elo.some)
def isAi = aiLevel.isDefined
def isHuman = !isAi
- def userId: Option[String] = user map (_.getId.toString)
+ def hasUser = userId.isDefined
- def hasUser = user.isDefined
-
- def isUser(u: User) = user.fold(_.getId == u.id, false)
-
- def withUser(u: User, ref: DBRef) = copy(
- elo = u.elo.some,
- user = ref.some)
+ def isUser(u: User) = userId.fold(_ == u.id, false)
def wins = isWinner getOrElse false
@@ -82,12 +74,12 @@ case class DbPlayer(
aiLevel = aiLevel,
w = isWinner,
elo = elo,
- eloDiff = eloDiff,
+ ed = eloDiff,
isOfferingDraw = if (isOfferingDraw) Some(true) else None,
isOfferingRematch = if (isOfferingRematch) Some(true) else None,
lastDrawOffer = lastDrawOffer,
isProposingTakeback = if (isProposingTakeback) Some(true) else None,
- user = user,
+ userId = userId,
mts = Some(moveTimes) filter ("" !=),
blurs = Some(blurs) filter (0 !=)
)
@@ -114,12 +106,12 @@ case class RawDbPlayer(
aiLevel: Option[Int],
w: Option[Boolean],
elo: Option[Int],
- eloDiff: Option[Int],
+ ed: Option[Int],
isOfferingDraw: Option[Boolean],
isOfferingRematch: Option[Boolean],
lastDrawOffer: Option[Int],
isProposingTakeback: Option[Boolean],
- user: Option[DBRef],
+ userId: Option[String],
mts: Option[String],
blurs: Option[Int]) {
@@ -132,12 +124,12 @@ case class RawDbPlayer(
aiLevel = aiLevel,
isWinner = w,
elo = elo,
- eloDiff = eloDiff,
+ eloDiff = ed,
isOfferingDraw = isOfferingDraw | false,
isOfferingRematch = isOfferingRematch | false,
lastDrawOffer = lastDrawOffer,
isProposingTakeback = isProposingTakeback | false,
- user = user,
+ userId = userId,
moveTimes = mts | "",
blurs = blurs | 0
)
diff --git a/app/game/GameRepo.scala b/app/game/GameRepo.scala
index 30ec56a3ee..a215a35491 100644
--- a/app/game/GameRepo.scala
+++ b/app/game/GameRepo.scala
@@ -71,16 +71,16 @@ class GameRepo(collection: MongoCollection)
update(idSelector(id), $set("players.0.eloDiff" -> white, "players.1.eloDiff" -> black))
}
- def setUser(id: String, color: Color, dbRef: DBRef, elo: Int) = io {
+ def setUser(id: String, color: Color, user: User) = io {
val pn = "players.%d".format(color.fold(0, 1))
- update(idSelector(id), $set(pn + ".user" -> dbRef, pn + ".elo" -> elo))
+ update(idSelector(id), $set(pn + ".userId" -> user.id, pn + ".elo" -> user.elo))
}
def finish(id: String, winnerId: Option[String]) = io {
update(
idSelector(id),
winnerId.fold(userId ⇒
- $set("positionHashes" -> "", "winnerUserId" -> userId),
+ $set("positionHashes" -> "", "winId" -> userId),
$set("positionHashes" -> ""))
++ $unset(
"players.0.previousMoveTs",
@@ -157,22 +157,6 @@ class GameRepo(collection: MongoCollection)
find("_id" $in ids).toList.map(_.decode).flatten sortBy (_.id)
}
- def ensureIndexes: IO[Unit] = io {
- collection.underlying |> { coll ⇒
- coll.ensureIndex(DBObject("status" -> 1))
- coll.ensureIndex(DBObject("userIds" -> 1))
- coll.ensureIndex(DBObject("winnerUserId" -> 1))
- coll.ensureIndex(DBObject("turns" -> 1))
- coll.ensureIndex(DBObject("updatedAt" -> -1))
- coll.ensureIndex(DBObject("createdAt" -> -1))
- coll.ensureIndex(DBObject("createdAt" -> -1, "userIds" -> 1))
- }
- }
-
- def dropIndexes: IO[Unit] = io {
- collection.dropIndexes()
- }
-
private def idSelector(game: DbGame): DBObject = idSelector(game.id)
private def idSelector(id: String): DBObject = DBObject("_id" -> id)
}
diff --git a/app/game/Query.scala b/app/game/Query.scala
index 755c24b964..154e8bd8fb 100644
--- a/app/game/Query.scala
+++ b/app/game/Query.scala
@@ -29,19 +29,19 @@ object Query {
def clock(c: Boolean): DBObject = "clock.l" $exists c
- def user(u: User): DBObject = DBObject("userIds" -> u.idString)
+ def user(u: User): DBObject = DBObject("userIds" -> u.id)
def started(u: User): DBObject = user(u) ++ started
def rated(u: User): DBObject = user(u) ++ rated
- def win(u: User): DBObject = DBObject("winnerUserId" -> u.idString)
+ def win(u: User): DBObject = DBObject("winId" -> u.id)
def draw(u: User): DBObject = user(u) ++ draw
- def loss(u: User): DBObject = user(u) ++ finished ++ ("winnerUserId" $ne u.idString)
+ def loss(u: User): DBObject = user(u) ++ finished ++ ("winId" $ne u.id)
def playing(u: User): DBObject = user(u) ++ playing
- def opponents(u1: User, u2: User) = "userIds" $all List(u1.idString, u2.idString)
+ def opponents(u1: User, u2: User) = "userIds" $all List(u1.id, u2.id)
}
diff --git a/app/lobby/Hook.scala b/app/lobby/Hook.scala
index a725b8985f..5813944cda 100644
--- a/app/lobby/Hook.scala
+++ b/app/lobby/Hook.scala
@@ -72,7 +72,7 @@ object Hook {
increment = clock map (_.increment),
mode = mode.id,
color = color,
- userId = user map (_.idString),
+ userId = user map (_.id),
username = user.fold(_.username, User.anonymous),
elo = user map (_.elo),
eloRange = eloRange.toString,
diff --git a/app/lobby/LobbyEnv.scala b/app/lobby/LobbyEnv.scala
index f2432081a6..94c9508153 100644
--- a/app/lobby/LobbyEnv.scala
+++ b/app/lobby/LobbyEnv.scala
@@ -8,7 +8,6 @@ import play.api.i18n.Lang
import play.api.i18n.MessagesPlugin
import scalaz.effects._
import com.mongodb.casbah.MongoCollection
-import com.mongodb.DBRef
import user.{ User, UserRepo }
import game.{ GameRepo, DbGame }
diff --git a/app/lobby/Messenger.scala b/app/lobby/Messenger.scala
index ae4a0c743f..bf30816ce1 100644
--- a/app/lobby/Messenger.scala
+++ b/app/lobby/Messenger.scala
@@ -13,7 +13,7 @@ final class Messenger(
private val urlRegex = """lichess\.org/([\w-]{8})[\w-]{4}""".r
def apply(text: String, username: String): IO[Valid[Message]] = for {
- userOption ← userRepo byUsername username
+ userOption ← userRepo byId username
message = for {
user ← userOption toValid "Unknown user"
msg ← createMessage(text, user)
@@ -35,7 +35,7 @@ final class Messenger(
}
def ban(username: String): IO[Unit] = for {
- userOption ← userRepo byUsername username
+ userOption ← userRepo byId username
_ ← userOption.fold(
user ⇒ for {
_ ← userRepo toggleChatBan user
diff --git a/app/message/DataForm.scala b/app/message/DataForm.scala
index 57d392d209..0432466dcb 100644
--- a/app/message/DataForm.scala
+++ b/app/message/DataForm.scala
@@ -26,7 +26,7 @@ final class DataForm(userRepo: UserRepo) {
))
private def fetchUser(username: String) =
- (userRepo byUsername username).unsafePerformIO
+ (userRepo byId username).unsafePerformIO
private def usernameExists(username: String) =
fetchUser(username).isDefined
diff --git a/app/message/Post.scala b/app/message/Post.scala
index ec78f65ede..5e9169baad 100644
--- a/app/message/Post.scala
+++ b/app/message/Post.scala
@@ -2,7 +2,6 @@ package lila
package message
import org.joda.time.DateTime
-import com.mongodb.casbah.Imports.ObjectId
import ornicar.scalalib.OrnicarRandom
case class Post(
diff --git a/app/message/Thread.scala b/app/message/Thread.scala
index f595d8a94f..8508cadef3 100644
--- a/app/message/Thread.scala
+++ b/app/message/Thread.scala
@@ -5,7 +5,6 @@ import user.User
import org.joda.time.DateTime
import com.novus.salat.annotations.Key
-import com.mongodb.casbah.Imports.ObjectId
import ornicar.scalalib.OrnicarRandom
case class Thread(
@@ -14,9 +13,9 @@ case class Thread(
createdAt: DateTime,
updatedAt: DateTime,
posts: List[Post],
- creatorId: ObjectId,
- invitedId: ObjectId,
- visibleByUserIds: List[ObjectId]) {
+ creatorId: String,
+ invitedId: String,
+ visibleByUserIds: List[String]) {
def +(post: Post) = copy(
posts = posts :+ post,
diff --git a/app/message/ThreadRepo.scala b/app/message/ThreadRepo.scala
index 7cca45b9c2..6f402b47b9 100644
--- a/app/message/ThreadRepo.scala
+++ b/app/message/ThreadRepo.scala
@@ -26,19 +26,19 @@ final class ThreadRepo(
def userNbUnread(user: User): IO[Int] = userNbUnread(user.id)
- def userNbUnread(userId: ObjectId): IO[Int] = io {
+ def userNbUnread(userId: String): IO[Int] = io {
val result = collection.mapReduce(
mapFunction = """function() {
var thread = this, nb = 0;
thread.posts.forEach(function(p) {
if (!p.isRead) {
- if (thread.creatorId.equals(ObjectId("%s"))) {
+ if (thread.creatorId == "%s") {
if (!p.isByCreator) nb++;
} else if (p.isByCreator) nb++;
}
});
if (nb > 0) emit("n", nb);
-}""" format userId.toString,
+}""" format userId,
reduceFunction = """function(key, values) {
var sum = 0;
for(var i in values) { sum += values[i]; }
@@ -81,7 +81,7 @@ final class ThreadRepo(
def visibleByUserQuery(user: User): DBObject =
visibleByUserQuery(user.id)
- def visibleByUserQuery(userId: ObjectId): DBObject =
+ def visibleByUserQuery(userId: String): DBObject =
DBObject("visibleByUserIds" -> userId)
def selectId(id: String) = DBObject("_id" -> id)
diff --git a/app/message/UnreadCache.scala b/app/message/UnreadCache.scala
index 6b94b8fb65..7e78d02630 100644
--- a/app/message/UnreadCache.scala
+++ b/app/message/UnreadCache.scala
@@ -12,12 +12,12 @@ final class UnreadCache(threadRepo: ThreadRepo) {
def get(user: User): Int = get(user.id)
- def get(userId: ObjectId): Int =
+ def get(username: String): Int =
cache.getOrElseUpdate(username.toLowerCase, {
- (threadRepo userNbUnread user).unsafePerformIO
+ (threadRepo userNbUnread username).unsafePerformIO
})
def invalidate(user: User) {
- cache -= user.usernameCanonical
+ cache -= user.id
}
}
diff --git a/app/mongodb/MongoDbEnv.scala b/app/mongodb/MongoDbEnv.scala
index c74ff9e296..4c948097d9 100644
--- a/app/mongodb/MongoDbEnv.scala
+++ b/app/mongodb/MongoDbEnv.scala
@@ -2,8 +2,7 @@ package lila
package mongodb
import com.mongodb.casbah.MongoConnection
-import com.mongodb.casbah.Imports.ObjectId
-import com.mongodb.{ DBRef, Mongo, MongoOptions, ServerAddress ⇒ MongoServer }
+import com.mongodb.{ Mongo, MongoOptions, ServerAddress ⇒ MongoServer }
import core.Settings
@@ -14,9 +13,6 @@ final class MongoDbEnv(
def apply(coll: String) = connection(coll)
- def ref(namespace: String, id: ObjectId): DBRef =
- new DBRef(connection.underlying, namespace, id)
-
lazy val cache = new Cache(connection(MongoCollectionCache))
lazy val connection = MongoConnection(server, options)(MongoDbName)
diff --git a/app/security/AuthImpl.scala b/app/security/AuthImpl.scala
index 3db7ca6bf6..1f4d08a4e1 100644
--- a/app/security/AuthImpl.scala
+++ b/app/security/AuthImpl.scala
@@ -85,6 +85,6 @@ trait AuthImpl {
def restoreUser(req: RequestHeader): Option[User] = for {
sessionId ← req.session.get("sessionId")
username ← env.securityStore.getUsername(sessionId)
- user ← (env.user.userRepo byUsername username).unsafePerformIO
+ user ← (env.user.userRepo byId username).unsafePerformIO
} yield user
}
diff --git a/app/setup/FriendJoiner.scala b/app/setup/FriendJoiner.scala
index db8e2a3580..83e6a68d00 100644
--- a/app/setup/FriendJoiner.scala
+++ b/app/setup/FriendJoiner.scala
@@ -7,22 +7,20 @@ import user.User
import round.{ Event, Progress, Messenger }
import controllers.routes
-import com.mongodb.DBRef
import scalaz.effects._
final class FriendJoiner(
gameRepo: GameRepo,
messenger: Messenger,
- timelinePush: DbGame ⇒ IO[Unit],
- userDbRef: User ⇒ DBRef) {
+ timelinePush: DbGame ⇒ IO[Unit]) {
def apply(game: DbGame, user: Option[User]): Valid[IO[(Pov, List[Event])]] =
game.notStarted option {
val color = game.invitedColor
for {
p1 ← user.fold(
- u ⇒ gameRepo.setUser(game.id, color, userDbRef(u), u.elo) map { _ ⇒
- Progress(game, game.updatePlayer(color, _.withUser(u, userDbRef(u))))
+ u ⇒ gameRepo.setUser(game.id, color, u) map { _ ⇒
+ Progress(game, game.updatePlayer(color, _ withUser u))
},
io(Progress(game)))
p2 = p1 withGame game.start
diff --git a/app/setup/HookJoiner.scala b/app/setup/HookJoiner.scala
index db51287b4c..1571a54967 100644
--- a/app/setup/HookJoiner.scala
+++ b/app/setup/HookJoiner.scala
@@ -8,14 +8,12 @@ import game.{ GameRepo, DbGame, DbPlayer, Pov }
import round.{ Messenger, Progress }
import scalaz.effects._
-import com.mongodb.DBRef
final class HookJoiner(
hookRepo: HookRepo,
fisherman: Fisherman,
gameRepo: GameRepo,
userRepo: UserRepo,
- userDbRef: User ⇒ DBRef,
timelinePush: DbGame ⇒ IO[Unit],
messenger: Messenger) {
@@ -51,7 +49,7 @@ final class HookJoiner(
def blame(color: DbGame ⇒ ChessColor, userOption: Option[User], game: DbGame) =
userOption.fold(
- user ⇒ game.updatePlayer(color(game), _.withUser(user, userDbRef(user))),
+ user ⇒ game.updatePlayer(color(game), _ withUser user),
game)
def makeGame(hook: Hook) = DbGame(
diff --git a/app/setup/Processor.scala b/app/setup/Processor.scala
index 36703882ce..333f99a286 100644
--- a/app/setup/Processor.scala
+++ b/app/setup/Processor.scala
@@ -8,7 +8,6 @@ import chess.{ Game, Board }
import ai.Ai
import lobby.{ Hook, Fisherman }
-import com.mongodb.DBRef
import scalaz.effects._
final class Processor(
@@ -17,8 +16,7 @@ final class Processor(
gameRepo: GameRepo,
fisherman: Fisherman,
timelinePush: DbGame ⇒ IO[Unit],
- ai: () ⇒ Ai,
- userDbRef: User ⇒ DBRef) {
+ ai: () ⇒ Ai) {
def ai(config: AiConfig)(implicit ctx: Context): IO[Pov] = for {
_ ← ctx.me.fold(
@@ -27,7 +25,7 @@ final class Processor(
)
pov = config.pov
game = ctx.me.fold(
- user ⇒ pov.game.updatePlayer(pov.color, _.withUser(user, userDbRef(user))),
+ user ⇒ pov.game.updatePlayer(pov.color, _ withUser user),
pov.game)
_ ← gameRepo insert game
_ ← gameRepo denormalizeStarted game
@@ -50,7 +48,7 @@ final class Processor(
)
pov = config.pov
game = ctx.me.fold(
- user ⇒ pov.game.updatePlayer(pov.color, _.withUser(user, userDbRef(user))),
+ user ⇒ pov.game.updatePlayer(pov.color, _ withUser user),
pov.game)
_ ← gameRepo insert game
_ ← timelinePush(game)
diff --git a/app/setup/Rematcher.scala b/app/setup/Rematcher.scala
index 6b730ff300..e65b3c506c 100644
--- a/app/setup/Rematcher.scala
+++ b/app/setup/Rematcher.scala
@@ -89,7 +89,7 @@ final class Rematcher(
game.player(color).userId.fold(
userId ⇒ userRepo byId userId map { userOption ⇒
userOption.fold(
- user ⇒ player.withUser(user)(userRepo.dbRef),
+ user ⇒ player withUser user,
player)
},
io(player))
diff --git a/app/setup/SetupEnv.scala b/app/setup/SetupEnv.scala
index 7f14428cd4..77e285b7ec 100644
--- a/app/setup/SetupEnv.scala
+++ b/app/setup/SetupEnv.scala
@@ -10,7 +10,6 @@ import user.{ User, UserRepo }
import com.mongodb.casbah.MongoCollection
import scalaz.effects._
-import com.mongodb.DBRef
final class SetupEnv(
settings: Settings,
@@ -21,8 +20,7 @@ final class SetupEnv(
userRepo: UserRepo,
timelinePush: DbGame ⇒ IO[Unit],
roundMessenger: Messenger,
- ai: () ⇒ Ai,
- userDbRef: User ⇒ DBRef) {
+ ai: () ⇒ Ai) {
import settings._
@@ -37,8 +35,7 @@ final class SetupEnv(
gameRepo = gameRepo,
fisherman = fisherman,
timelinePush = timelinePush,
- ai = ai,
- userDbRef = userDbRef)
+ ai = ai)
lazy val friendConfigMemo = new FriendConfigMemo(
ttl = SetupFriendConfigMemoTtl)
@@ -52,15 +49,13 @@ final class SetupEnv(
lazy val friendJoiner = new FriendJoiner(
gameRepo = gameRepo,
messenger = roundMessenger,
- timelinePush = timelinePush,
- userDbRef = userDbRef)
+ timelinePush = timelinePush)
lazy val hookJoiner = new HookJoiner(
hookRepo = hookRepo,
fisherman = fisherman,
gameRepo = gameRepo,
userRepo = userRepo,
- userDbRef = userDbRef,
timelinePush = timelinePush,
messenger = roundMessenger)
}
diff --git a/app/setup/UserConfig.scala b/app/setup/UserConfig.scala
index 4ff9b94c9e..cf6a1db9b4 100644
--- a/app/setup/UserConfig.scala
+++ b/app/setup/UserConfig.scala
@@ -27,7 +27,7 @@ case class UserConfig(
object UserConfig {
def default(user: User) = UserConfig(
- id = user.usernameCanonical,
+ id = user.id,
ai = AiConfig.default,
friend = FriendConfig.default,
hook = HookConfig.default)
diff --git a/app/setup/UserConfigRepo.scala b/app/setup/UserConfigRepo.scala
index 9a4bf12127..24e14f97f2 100644
--- a/app/setup/UserConfigRepo.scala
+++ b/app/setup/UserConfigRepo.scala
@@ -19,7 +19,7 @@ class UserConfigRepo(collection: MongoCollection)
} yield ()
def config(user: User): IO[UserConfig] = io {
- findOneByID(user.usernameCanonical) flatMap (_.decode)
+ findOneByID(user.id) flatMap (_.decode)
} except { e ⇒
putStrLn("Can't load config: " + e.getMessage) map (_ ⇒ none[UserConfig])
} map (_ | UserConfig.default(user))
diff --git a/app/socket/HubActor.scala b/app/socket/HubActor.scala
index 33e1a84159..f7857ec649 100644
--- a/app/socket/HubActor.scala
+++ b/app/socket/HubActor.scala
@@ -48,7 +48,7 @@ abstract class HubActor[M <: SocketMember](uidTimeout: Int) extends Actor {
setAlive(uid)
member(uid) foreach { m ⇒
m.channel push m.username.fold(
- u ⇒ pong ++ JsObject(Seq("m" -> env.message.unreadCache.get(u))),
+ u ⇒ pong ++ JsObject(Seq("m" -> JsNumber(unreadMessages(u)))),
pong)
}
}
@@ -83,4 +83,7 @@ abstract class HubActor[M <: SocketMember](uidTimeout: Int) extends Actor {
def member(uid: String): Option[M] = members get uid
def usernames: Iterable[String] = members.values.map(_.username).flatten
+
+ private def unreadMessages(username: String): Int =
+ env.message.unreadCache get username
}
diff --git a/app/user/Cached.scala b/app/user/Cached.scala
index d3d4addd6a..1f006b64ea 100644
--- a/app/user/Cached.scala
+++ b/app/user/Cached.scala
@@ -2,25 +2,17 @@ package lila
package user
import scala.collection.mutable
-import com.mongodb.casbah.Imports.ObjectId
final class Cached(userRepo: UserRepo) {
- // idString => username|Anonymous
- val usernameCache = mutable.Map[String, String]()
-
- // username => Option[ObjectId]
- val idCache = mutable.Map[String, Option[ObjectId]]()
+ // id => username
+ val usernameCache = mutable.Map[String, Option[String]]()
def username(userId: String) =
usernameCache.getOrElseUpdate(
- userId,
- (userRepo username userId).unsafePerformIO | "Anonymous"
+ userId.toLowerCase,
+ (userRepo username userId).unsafePerformIO
)
- def id(username: String): Option[ObjectId] =
- idCache.getOrElseUpdate(
- username.toLowerCase,
- (userRepo id username).unsafePerformIO
- )
+ def usernameOrAnonymous(userId: String) = username(userId) | User.anonymous
}
diff --git a/app/user/EloUpdater.scala b/app/user/EloUpdater.scala
index 0ed70e1870..ff8b0ea398 100644
--- a/app/user/EloUpdater.scala
+++ b/app/user/EloUpdater.scala
@@ -12,12 +12,12 @@ final class EloUpdater(
def game(user: User, elo: Int, gameId: String): IO[Unit] = {
val newElo = max(elo, floor)
userRepo.setElo(user.id, newElo) flatMap { _ ⇒
- historyRepo.addEntry(user.usernameCanonical, newElo, Some(gameId))
+ historyRepo.addEntry(user.id, newElo, Some(gameId))
}
}
def adjust(user: User, elo: Int): IO[Unit] =
userRepo.setElo(user.id, elo) flatMap { _ ⇒
- historyRepo.addEntry(user.usernameCanonical, elo, entryType = HistoryRepo.TYPE_ADJUST)
+ historyRepo.addEntry(user.id, elo, entryType = HistoryRepo.TYPE_ADJUST)
}
}
diff --git a/app/user/User.scala b/app/user/User.scala
index ebab8ccb3c..f89e3b0ea7 100644
--- a/app/user/User.scala
+++ b/app/user/User.scala
@@ -2,11 +2,10 @@ package lila
package user
import com.novus.salat.annotations.Key
-import com.mongodb.casbah.Imports.ObjectId
import org.joda.time.DateTime
case class User(
- @Key("_id") id: ObjectId,
+ id: String,
username: String,
elo: Int,
nbGames: Int,
@@ -18,8 +17,6 @@ case class User(
bio: Option[String] = None,
engine: Boolean = false) {
- def usernameCanonical = username.toLowerCase
-
def disabled = !enabled
def usernameWithElo = "%s (%d)".format(username, elo)
@@ -29,8 +26,6 @@ case class User(
def nonEmptyBio = bio filter ("" !=)
def hasGames = nbGames > 0
-
- def idString = id.toString
}
object User {
@@ -41,7 +36,7 @@ object User {
// the password is hashed
def apply(username: String): User = User(
- id = new ObjectId,
+ id = username.toLowerCase,
username = username,
elo = STARTING_ELO,
nbGames = 0,
diff --git a/app/user/UserEnv.scala b/app/user/UserEnv.scala
index f1611f2202..10dc5ad446 100644
--- a/app/user/UserEnv.scala
+++ b/app/user/UserEnv.scala
@@ -2,8 +2,6 @@ package lila
package user
import com.mongodb.casbah.MongoCollection
-import com.mongodb.casbah.Imports.ObjectId
-import com.mongodb.DBRef
import chess.EloCalculator
import game.GameRepo
@@ -12,16 +10,14 @@ import core.Settings
final class UserEnv(
settings: Settings,
mongodb: String ⇒ MongoCollection,
- gameRepo: GameRepo,
- dbRef: String ⇒ ObjectId ⇒ DBRef) {
+ gameRepo: GameRepo) {
import settings._
lazy val historyRepo = new HistoryRepo(mongodb(MongoCollectionHistory))
lazy val userRepo = new UserRepo(
- collection = mongodb(MongoCollectionUser),
- dbRef = user ⇒ dbRef(MongoCollectionUser)(user.id))
+ collection = mongodb(MongoCollectionUser))
lazy val paginator = new PaginatorBuilder(
userRepo = userRepo,
diff --git a/app/user/UserHelper.scala b/app/user/UserHelper.scala
index 09d62537c0..ffcf945a06 100644
--- a/app/user/UserHelper.scala
+++ b/app/user/UserHelper.scala
@@ -4,7 +4,6 @@ package user
import core.CoreEnv
import controllers.routes
-import com.mongodb.casbah.Imports.ObjectId
import play.api.templates.Html
trait UserHelper {
@@ -14,20 +13,18 @@ trait UserHelper {
private def cached = env.user.cached
private def usernameMemo = env.user.usernameMemo
- def userIdToUsername(userId: String): String = cached username userId
+ def userIdToUsername(userId: String): String =
+ cached usernameOrAnonymous userId
def userIdToUsername(userId: Option[String]): String =
userId.fold(userIdToUsername, User.anonymous)
def isUsernameOnline(username: String) = usernameMemo get username
- def isUserIdOnline(userId: String) =
- usernameMemo get userIdToUsername(userId)
-
def userIdLink(
userId: Option[String],
cssClass: Option[String]): Html = Html {
- (userId map userIdToUsername).fold(
+ (userId flatMap cached.username).fold(
username ⇒ """%s""".format(
isUsernameOnline(username).fold(" online", ""),
cssClass.fold(" " + _, ""),
@@ -38,8 +35,8 @@ trait UserHelper {
}
def userIdLink(
- userId: ObjectId,
- cssClass: Option[String]): Html = userIdLink(userId.toString.some, cssClass)
+ userId: String,
+ cssClass: Option[String]): Html = userIdLink(userId.some, cssClass)
def userLink(
user: User,
diff --git a/app/user/UserRepo.scala b/app/user/UserRepo.scala
index 378d68649d..a6e44c6e3d 100644
--- a/app/user/UserRepo.scala
+++ b/app/user/UserRepo.scala
@@ -3,7 +3,6 @@ package user
import com.novus.salat._
import com.novus.salat.dao._
-import com.mongodb.DBRef
import com.mongodb.casbah.{ MongoCollection, WriteConcern }
import com.mongodb.casbah.Imports._
import scalaz.effects._
@@ -11,51 +10,38 @@ import com.roundeights.hasher.Implicits._
import ornicar.scalalib.OrnicarRandom
class UserRepo(
- collection: MongoCollection,
- val dbRef: User ⇒ DBRef) extends SalatDAO[User, ObjectId](collection) {
+ collection: MongoCollection
+ ) extends SalatDAO[User, String](collection) {
- private val enabledQuery = DBObject("enabled" -> true)
+ val enabledQuery = DBObject("enabled" -> true)
+ def byIdQuery(id: String): DBObject = DBObject("_id" -> normalize(id))
+ def byIdQuery(user: User): DBObject = byIdQuery(user.id)
- private def byUsernameQuery(username: String) =
- DBObject("usernameCanonical" -> username.toLowerCase)
+ def normalize(id: String) = id.toLowerCase
- private def byIdQuery(id: String) = DBObject("_id" -> new ObjectId(id))
+ def byId(id: String): IO[Option[User]] = io {
+ findOneByID(normalize(id))
+ }
- def byId(userId: String): IO[Option[User]] = byId(new ObjectId(userId))
-
- def byId(userId: ObjectId): IO[Option[User]] = io {
- findOneByID(userId)
+ def byIds(ids: Iterable[String]): IO[List[User]] = io {
+ find("_id" $in ids.map(normalize)).toList
}
def username(userId: String): IO[Option[String]] = io {
primitiveProjection[String](byIdQuery(userId), "username")
}
- def id(username: String): IO[Option[ObjectId]] = io {
- primitiveProjection[ObjectId](byUsernameQuery(username), "_id")
- }
-
- def byUsername(username: String): IO[Option[User]] = io {
- findOne(byUsernameQuery(username))
- }
-
- def byUsernames(usernames: Iterable[String]): IO[List[User]] = io {
- find("usernameCanonical" $in usernames).toList
- }
-
def rank(user: User): IO[Int] = io {
count("elo" $gt user.elo).toInt + 1
}
- def setElo(userId: ObjectId, elo: Int): IO[Unit] = io {
- collection.update(
- idSelector(userId),
- $set("elo" -> elo))
+ def setElo(id: String, elo: Int): IO[Unit] = io {
+ collection.update(byIdQuery(id), $set("elo" -> elo))
}
- def incNbGames(userId: String, rated: Boolean): IO[Unit] = io {
+ def incNbGames(id: String, rated: Boolean): IO[Unit] = io {
collection.update(
- DBObject("_id" -> new ObjectId(userId)),
+ byIdQuery(id),
if (rated) $inc("nbGames" -> 1, "nbRatedGames" -> 1)
else $inc("nbGames" -> 1))
}
@@ -66,30 +52,26 @@ class UserRepo(
}
def toggleChatBan(user: User): IO[Unit] = io {
- collection.update(
- idSelector(user),
- $set("isChatBan" -> !user.isChatBan))
+ collection.update(byIdQuery(user), $set("isChatBan" -> !user.isChatBan))
}
def saveSetting(user: User, key: String, value: String) = io {
- collection.update(
- idSelector(user),
- $set(("settings." + key) -> value))
+ collection.update(byIdQuery(user), $set(("settings." + key) -> value))
}
def exists(username: String): IO[Boolean] = io {
- count(byUsernameQuery(username)) != 0
+ count(byIdQuery(username)) != 0
}
def authenticate(username: String, password: String): IO[Option[User]] = for {
- userOption ← byUsername(username)
+ userOption ← byId(username)
greenLight ← authenticable(username, password)
} yield userOption filter (_ ⇒ greenLight)
private def authenticable(username: String, password: String): IO[Boolean] = io {
for {
data ← collection.findOne(
- byUsernameQuery(username),
+ byIdQuery(username),
DBObject("password" -> true, "salt" -> true, "enabled" -> true)
)
hashed ← data.getAs[String]("password")
@@ -105,8 +87,8 @@ class UserRepo(
io {
val salt = OrnicarRandom nextAsciiString 32
val obj = DBObject(
+ "_id" -> normalize(username),
"username" -> username,
- "usernameCanonical" -> username.toLowerCase,
"password" -> hash(password, salt),
"salt" -> salt,
"elo" -> User.STARTING_ELO,
@@ -115,18 +97,18 @@ class UserRepo(
"enabled" -> true,
"roles" -> Nil)
collection.insert(obj, WriteConcern.Safe)
- } flatMap { _ ⇒ byUsername(username) }
+ } flatMap { _ ⇒ byId(username) }
)
} yield userOption
val countEnabled: IO[Int] = io { count(enabledQuery).toInt }
def usernamesLike(username: String): IO[List[String]] = io {
- val regex = "^" + username.toLowerCase + ".*$"
+ val regex = "^" + normalize(username) + ".*$"
collection.find(
- DBObject("usernameCanonical" -> regex.r),
+ DBObject("_id" -> regex.r),
DBObject("username" -> 1))
- .sort(DBObject("usernameCanonical" -> 1))
+ .sort(DBObject("_id" -> 1))
.limit(10)
.toList
.map(_.expand[String]("username"))
@@ -150,18 +132,14 @@ class UserRepo(
def disable(user: User) = updateIO(user)($set("enabled" -> false))
def updateIO(username: String)(op: User ⇒ DBObject): IO[Unit] = for {
- userOption ← byUsername(username)
+ userOption ← byId(username)
_ ← userOption.fold(user ⇒ updateIO(user)(op(user)), io())
} yield ()
def updateIO(user: User)(obj: DBObject): IO[Unit] = io {
- update(idSelector(user), obj)
+ update(byIdQuery(user), obj)
}
- private def idSelector(user: User) = DBObject("_id" -> user.id)
-
- private def idSelector(id: ObjectId) = DBObject("_id" -> id)
-
private def hash(pass: String, salt: String): String =
"%s{%s}".format(pass, salt).sha1
}
diff --git a/bin/migrate b/bin/migrate
new file mode 100755
index 0000000000..a4cc6bb5b6
--- /dev/null
+++ b/bin/migrate
@@ -0,0 +1,7 @@
+#!/bin/sh
+mongo lichess mongo_migration_user.js
+mongo lichess mongo_migration_forum.js
+mongo lichess mongo_migration_message.js
+mongo lichess mongo_migration_rest.js
+mongo lichess mongo_migration_game.js
+bin/cli forum-denormalize
diff --git a/cli/src/main/scala/Games.scala b/cli/src/main/scala/Games.scala
index f198f2d695..81f8bf8a63 100644
--- a/cli/src/main/scala/Games.scala
+++ b/cli/src/main/scala/Games.scala
@@ -5,10 +5,4 @@ import scalaz.effects._
case class Games(gameRepo: GameRepo) {
- def index: IO[Unit] = for {
- _ ← putStrLn("- Drop indexes")
- _ ← gameRepo.dropIndexes
- _ ← putStrLn("- Ensure indexes")
- _ ← gameRepo.ensureIndexes
- } yield ()
}
diff --git a/cli/src/main/scala/Main.scala b/cli/src/main/scala/Main.scala
index e1131e559e..125e6176d8 100644
--- a/cli/src/main/scala/Main.scala
+++ b/cli/src/main/scala/Main.scala
@@ -25,7 +25,6 @@ object Main {
val op: IO[Unit] = args.toList match {
case "average-elo" :: Nil ⇒ infos.averageElo
- case "game-index" :: Nil ⇒ games.index
case "trans-js-dump" :: Nil ⇒ TransJsDump(
path = new File(env.app.path.getCanonicalPath + "/public/trans"),
pool = env.i18n.pool,
diff --git a/cli/src/main/scala/Users.scala b/cli/src/main/scala/Users.scala
index dcc2773aeb..9bdf938d28 100644
--- a/cli/src/main/scala/Users.scala
+++ b/cli/src/main/scala/Users.scala
@@ -18,7 +18,7 @@ case class Users(userRepo: UserRepo, securityStore: Store) {
def perform(username: String, action: String, op: User ⇒ IO[Unit]) = for {
_ ← putStrLn(action + " " + username)
- userOption ← userRepo byUsername username
+ userOption ← userRepo byId username
_ ← userOption.fold(
u ⇒ op(u) flatMap { _ ⇒ putStrLn("Success") },
putStrLn("Not found")
diff --git a/conf/application.conf b/conf/application.conf
index 937b6a8704..1133c09c8d 100644
--- a/conf/application.conf
+++ b/conf/application.conf
@@ -3,8 +3,8 @@ mongo {
port = 27017
dbName = lichess
collection {
- game = game
- user = user
+ game = game2
+ user = user2
hook = hook
entry = lobby_entry
message = lobby_room
diff --git a/mongo_migration_forum.js b/mongo_migration_forum.js
index f241f9c860..a3a9778d65 100644
--- a/mongo_migration_forum.js
+++ b/mongo_migration_forum.js
@@ -1,8 +1,12 @@
print("Hashing users")
-var users = {};
+var userHash = {};
db.user2.find({},{oid:1}).forEach(function(user) {
- users[user.oid.toString()] = user._id;
+ userHash[user.oid.toString()] = user._id;
});
+function user(oid) {
+ if(userHash[oid]) return userHash[oid];
+ throw "Missing user " + oid;
+}
var categSlugs = {};
var topicIds = {};
@@ -73,7 +77,7 @@ var topicIds = {};
number: obj.number
};
if (obj.author) {
- post.userId = users[obj.author['$id'].toString()];
+ post.userId = user(obj.author['$id'].toString());
}
coll.insert(post);
}
diff --git a/mongo_migration_game.js b/mongo_migration_game.js
index 4c20a43b72..87f6c75f6c 100644
--- a/mongo_migration_game.js
+++ b/mongo_migration_game.js
@@ -10,11 +10,12 @@ function user(oid) {
print("Games");
var batch = 10000;
+var max = 100000;
var oGames = db.game;
var nGames = db.game2;
var it = 0, totalNb = oGames.count();
nGames.drop();
-oGames.find().batchSize(batch).limit(100000).forEach(function(game) {
+oGames.find().batchSize(batch).limit(max).forEach(function(game) {
delete game["positionHashes"];
delete game["players.0.previousMoveTs"];
delete game["players.1.previousMoveTs"];
@@ -45,5 +46,15 @@ oGames.find().batchSize(batch).limit(100000).forEach(function(game) {
}
nGames.insert(game);
++it;
- if (0 == it % batch) print(it + "/" + totalNb);
+ if (0 == it % batch)
+ print(it + "/" + totalNb + " " + Math.round(100*it/totalNb) + "%");
});
+
+print("Indexes");
+nGames.ensureIndex({status:1});
+nGames.ensureIndex({userIds:1});
+nGames.ensureIndex({winId:1});
+nGames.ensureIndex({turns:1});
+nGames.ensureIndex({updatedAt:-1});
+nGames.ensureIndex({createdAt:-1});
+nGames.ensureIndex({userIds:1, createdAt:-1});
diff --git a/mongo_migration_message.js b/mongo_migration_message.js
index eef7417ecb..db259b1f3e 100644
--- a/mongo_migration_message.js
+++ b/mongo_migration_message.js
@@ -1,8 +1,12 @@
print("Hashing users")
-var users = {};
+var userHash = {};
db.user2.find({},{oid:1}).forEach(function(user) {
- users[user.oid.toString()] = user._id;
+ userHash[user.oid.toString()] = user._id;
});
+function user(oid) {
+ if(userHash[oid]) return userHash[oid];
+ throw "Missing user " + oid;
+}
print("Threads and messages");
var oThreads = db.message_thread;
@@ -16,7 +20,7 @@ oThreads.find().forEach(function(oThread) {
name: oThread.subject,
createdAt: oThread.createdAt,
creatorId: creatorId(oThread),
- invitedId: users[invOid],
+ invitedId: user(invOid),
visibleByUserIds: visibleByUserIds(oThread)
};
var posts = [];
@@ -57,7 +61,7 @@ function invitedOid(oThread) {
}
function userIds(oThread) {
- return [creatorId(oThread), users[invitedOid(oThread)]];
+ return [creatorId(oThread), user(invitedOid(oThread))];
}
function visibleByUserIds(oThread) {
@@ -69,8 +73,8 @@ function visibleByUserIds(oThread) {
}
function username(obj) {
- if (typeof obj == "object") return users[objId(obj)];
- return users[obj];
+ if (typeof obj == "object") return user(objId(obj));
+ return user(obj);
}
function objId(obj) {
diff --git a/mongo_migration_rest.js b/mongo_migration_rest.js
new file mode 100644
index 0000000000..16f3976765
--- /dev/null
+++ b/mongo_migration_rest.js
@@ -0,0 +1,13 @@
+print("Other collections");
+
+db.lobby_room.drop();
+db.createCollection("lobby_room", {capped:true, max:1000})
+
+db.lobby_entry.drop();
+db.createCollection("lobby_entry", {capped:true, max:50})
+
+db.hook.drop();
+db.hook.ensureIndex({ownerId: 1});
+db.hook.ensureIndex({mode: 1});
+db.hook.ensureIndex({createdAt: -1});
+db.hook.ensureIndex({match: 1});
diff --git a/todo b/todo
index 4f87dcdb07..ae968d6c87 100644
--- a/todo
+++ b/todo
@@ -22,12 +22,10 @@ http://codetunes.com/2012/05/09/scala-dsl-tutorial-writing-web-framework-router
use POST instead of GET where it makes sense
endgame sound http://en.lichess.org/forum/lichess-feedback/checkmate-sound-feature?page=1#1
cached username option app/user/Cached.scala
+game.next dbref => string
next deploy:
-mongo lichess mongo_migration_user.js
-mongo lichess mongo_migration_forum.js
-mongo lichess mongo_migration_message.js
-bin/cli forum-denormalize
+bin/migrate
new translations:
-rematchOfferCanceled=Rematch offer canceled
-rematchOfferDeclined=Rematch offer declined