refactor and cache bookmarks
This commit is contained in:
parent
a56e459df8
commit
b1ec3ca07e
|
@ -1,12 +1,12 @@
|
|||
package lila
|
||||
package star
|
||||
package bookmark
|
||||
|
||||
import game.DbGame
|
||||
import user.User
|
||||
|
||||
import org.joda.time.DateTime
|
||||
|
||||
case class Star(
|
||||
case class Bookmark(
|
||||
game: DbGame,
|
||||
user: User,
|
||||
date: DateTime) {
|
|
@ -1,13 +1,14 @@
|
|||
package lila
|
||||
package star
|
||||
package bookmark
|
||||
|
||||
import game.{ DbGame, GameRepo }
|
||||
import user.{ User, UserRepo }
|
||||
|
||||
import scalaz.effects._
|
||||
|
||||
final class StarApi(
|
||||
starRepo: StarRepo,
|
||||
final class BookmarkApi(
|
||||
bookmarkRepo: BookmarkRepo,
|
||||
cached: Cached,
|
||||
gameRepo: GameRepo,
|
||||
userRepo: UserRepo,
|
||||
paginator: PaginatorBuilder) {
|
||||
|
@ -16,28 +17,29 @@ final class StarApi(
|
|||
gameOption ← gameRepo game gameId
|
||||
_ ← gameOption.fold(
|
||||
game ⇒ for {
|
||||
bookmarked ← starRepo.toggle(game.id, user.id)
|
||||
bookmarked ← bookmarkRepo.toggle(game.id, user.id)
|
||||
_ ← gameRepo.incBookmarks(game.id, bookmarked.fold(1, -1))
|
||||
_ ← io(cached invalidateUserId user.id)
|
||||
} yield (),
|
||||
io())
|
||||
} yield ()
|
||||
|
||||
def starred(game: DbGame, user: User): IO[Boolean] =
|
||||
starRepo.exists(game.id, user.id)
|
||||
def bookmarked(game: DbGame, user: User): Boolean =
|
||||
cached.bookmarked(game.id, user.id)
|
||||
|
||||
def countByUser(user: User): IO[Int] =
|
||||
starRepo countByUserId user.id
|
||||
def countByUser(user: User): Int =
|
||||
cached.count(user.id)
|
||||
|
||||
def usersByGame(game: DbGame): IO[List[User]] = for {
|
||||
userIds ← starRepo userIdsByGameId game.id
|
||||
userIds ← bookmarkRepo userIdsByGameId game.id
|
||||
users ← (userIds map userRepo.byId).sequence
|
||||
} yield users.flatten
|
||||
|
||||
def removeByGame(game: DbGame): IO[Unit] =
|
||||
starRepo removeByGameId game.id
|
||||
bookmarkRepo removeByGameId game.id
|
||||
|
||||
def removeByGameIds(ids: List[String]): IO[Unit] =
|
||||
starRepo removeByGameIds ids
|
||||
bookmarkRepo removeByGameIds ids
|
||||
|
||||
def gamePaginatorByUser(user: User, page: Int) =
|
||||
paginator.byUser(user: User, page: Int) map (_.game)
|
|
@ -1,5 +1,5 @@
|
|||
package lila
|
||||
package star
|
||||
package bookmark
|
||||
|
||||
import com.mongodb.casbah.MongoCollection
|
||||
|
||||
|
@ -7,7 +7,7 @@ import game.GameRepo
|
|||
import user.UserRepo
|
||||
import core.Settings
|
||||
|
||||
final class StarEnv(
|
||||
final class BookmarkEnv(
|
||||
settings: Settings,
|
||||
gameRepo: GameRepo,
|
||||
userRepo: UserRepo,
|
||||
|
@ -15,16 +15,20 @@ final class StarEnv(
|
|||
|
||||
import settings._
|
||||
|
||||
lazy val starRepo = new StarRepo(mongodb(MongoCollectionStar))
|
||||
lazy val bookmarkRepo = new BookmarkRepo(mongodb(MongoCollectionBookmark))
|
||||
|
||||
lazy val paginator = new PaginatorBuilder(
|
||||
starRepo = starRepo,
|
||||
bookmarkRepo = bookmarkRepo,
|
||||
gameRepo = gameRepo,
|
||||
userRepo = userRepo,
|
||||
maxPerPage = GamePaginatorMaxPerPage)
|
||||
|
||||
lazy val api = new StarApi(
|
||||
starRepo = starRepo,
|
||||
lazy val cached = new Cached(
|
||||
bookmarkRepo = bookmarkRepo)
|
||||
|
||||
lazy val api = new BookmarkApi(
|
||||
bookmarkRepo = bookmarkRepo,
|
||||
cached = cached,
|
||||
gameRepo = gameRepo,
|
||||
userRepo = userRepo,
|
||||
paginator = paginator)
|
16
app/bookmark/BookmarkHelper.scala
Normal file
16
app/bookmark/BookmarkHelper.scala
Normal file
|
@ -0,0 +1,16 @@
|
|||
package lila
|
||||
package bookmark
|
||||
|
||||
import core.CoreEnv
|
||||
|
||||
import game.DbGame
|
||||
import user.User
|
||||
|
||||
trait BookmarkHelper {
|
||||
|
||||
protected def env: CoreEnv
|
||||
private def api = env.bookmark.api
|
||||
|
||||
def bookmarked(game: DbGame, user: User): Boolean =
|
||||
api.bookmarked(game, user)
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
package lila
|
||||
package star
|
||||
package bookmark
|
||||
|
||||
import com.mongodb.casbah.MongoCollection
|
||||
import com.mongodb.casbah.Imports._
|
||||
|
@ -8,12 +8,12 @@ import com.mongodb.MongoException.DuplicateKey
|
|||
import scalaz.effects._
|
||||
import org.joda.time.DateTime
|
||||
|
||||
// db.star.ensureIndex({g:1})
|
||||
// db.star.ensureIndex({u:1})
|
||||
// db.star.ensureIndex({d: -1})
|
||||
final class StarRepo(val collection: MongoCollection) {
|
||||
// db.bookmark.ensureIndex({g:1})
|
||||
// db.bookmark.ensureIndex({u:1})
|
||||
// db.bookmark.ensureIndex({d: -1})
|
||||
final class BookmarkRepo(val collection: MongoCollection) {
|
||||
|
||||
private[star] def toggle(gameId: String, userId: String): IO[Boolean] = io {
|
||||
private[bookmark] def toggle(gameId: String, userId: String): IO[Boolean] = io {
|
||||
try {
|
||||
add(gameId, userId, DateTime.now)
|
||||
true
|
||||
|
@ -26,18 +26,16 @@ final class StarRepo(val collection: MongoCollection) {
|
|||
}
|
||||
}
|
||||
|
||||
def exists(gameId: String, userId: String) = io {
|
||||
(collection count idQuery(gameId, userId)) > 0
|
||||
}
|
||||
|
||||
def countByUserId(userId: String) = io {
|
||||
collection count userIdQuery(userId) toInt
|
||||
}
|
||||
|
||||
def userIdsByGameId(gameId: String): IO[List[String]] = io {
|
||||
(collection find gameIdQuery(gameId) sort sortQuery(1) map { obj ⇒
|
||||
obj.getAs[String]("u")
|
||||
}).toList.flatten
|
||||
}).flatten.toList
|
||||
}
|
||||
|
||||
def gameIdsByUserId(userId: String): IO[Set[String]] = io {
|
||||
(collection find userIdQuery(userId) map { obj ⇒
|
||||
obj.getAs[String]("g")
|
||||
}).flatten.toSet
|
||||
}
|
||||
|
||||
def removeByGameId(gameId: String): IO[Unit] = io {
|
25
app/bookmark/Cached.scala
Normal file
25
app/bookmark/Cached.scala
Normal file
|
@ -0,0 +1,25 @@
|
|||
package lila
|
||||
package bookmark
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
final class Cached(bookmarkRepo: BookmarkRepo) {
|
||||
|
||||
private val gameIdsCache = mutable.Map[String, Set[String]]()
|
||||
|
||||
def bookmarked(gameId: String, userId: String) =
|
||||
userGameIds(userId)(gameId)
|
||||
|
||||
def count(userId: String) =
|
||||
userGameIds(userId).size
|
||||
|
||||
def invalidateUserId(userId: String) = {
|
||||
gameIdsCache -= userId
|
||||
}
|
||||
|
||||
private def userGameIds(userId: String): Set[String] =
|
||||
gameIdsCache.getOrElseUpdate(
|
||||
userId,
|
||||
(bookmarkRepo gameIdsByUserId userId).unsafePerformIO
|
||||
)
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
package lila
|
||||
package star
|
||||
package bookmark
|
||||
|
||||
import game.{ DbGame, GameRepo }
|
||||
import user.{ User, UserRepo }
|
||||
|
@ -9,27 +9,27 @@ import com.mongodb.casbah.Imports._
|
|||
import org.joda.time.DateTime
|
||||
|
||||
final class PaginatorBuilder(
|
||||
starRepo: StarRepo,
|
||||
bookmarkRepo: BookmarkRepo,
|
||||
gameRepo: GameRepo,
|
||||
userRepo: UserRepo,
|
||||
maxPerPage: Int) {
|
||||
|
||||
def byUser(user: User, page: Int): Paginator[Star] =
|
||||
def byUser(user: User, page: Int): Paginator[Bookmark] =
|
||||
paginator(new UserAdapter(user), page)
|
||||
|
||||
private def paginator(adapter: Adapter[Star], page: Int): Paginator[Star] =
|
||||
private def paginator(adapter: Adapter[Bookmark], page: Int): Paginator[Bookmark] =
|
||||
Paginator(
|
||||
adapter,
|
||||
currentPage = page,
|
||||
maxPerPage = maxPerPage
|
||||
).fold(_ ⇒ paginator(adapter, 0), identity)
|
||||
|
||||
final class UserAdapter(user: User) extends Adapter[Star] {
|
||||
final class UserAdapter(user: User) extends Adapter[Bookmark] {
|
||||
|
||||
def nbResults: Int = starRepo.collection count query toInt
|
||||
def nbResults: Int = bookmarkRepo.collection count query toInt
|
||||
|
||||
def slice(offset: Int, length: Int): Seq[Star] = {
|
||||
val objs = ((starRepo.collection find query sort sort skip offset limit length).toList map { obj ⇒
|
||||
def slice(offset: Int, length: Int): Seq[Bookmark] = {
|
||||
val objs = ((bookmarkRepo.collection find query sort sort skip offset limit length).toList map { obj ⇒
|
||||
for {
|
||||
gameId ← obj.getAs[String]("g")
|
||||
date ← obj.getAs[DateTime]("d")
|
||||
|
@ -38,12 +38,12 @@ final class PaginatorBuilder(
|
|||
val games = (gameRepo games objs.map(_._1)).unsafePerformIO
|
||||
objs map { obj ⇒
|
||||
games find (_.id == obj._1) map { game ⇒
|
||||
Star(game, user, obj._2)
|
||||
Bookmark(game, user, obj._2)
|
||||
}
|
||||
}
|
||||
} flatten
|
||||
|
||||
private def query = starRepo userIdQuery user.id
|
||||
private def sort = starRepo sortQuery -1
|
||||
private def query = bookmarkRepo userIdQuery user.id
|
||||
private def sort = bookmarkRepo sortQuery -1
|
||||
}
|
||||
}
|
|
@ -13,11 +13,11 @@ object Analyse extends LilaController {
|
|||
def gameRepo = env.game.gameRepo
|
||||
def pgnDump = env.analyse.pgnDump
|
||||
def openingExplorer = chess.OpeningExplorer
|
||||
def starApi = env.star.api
|
||||
def bookmarkApi = env.bookmark.api
|
||||
|
||||
def replay(id: String, color: String) = Open { implicit ctx ⇒
|
||||
IOptionIOk(gameRepo.pov(id, color)) { pov ⇒
|
||||
starApi usersByGame pov.game map { bookmarkers ⇒
|
||||
bookmarkApi usersByGame pov.game map { bookmarkers ⇒
|
||||
html.analyse.replay(
|
||||
pov,
|
||||
bookmarkers,
|
||||
|
|
|
@ -11,16 +11,15 @@ object Game extends LilaController {
|
|||
val gameRepo = env.game.gameRepo
|
||||
val paginator = env.game.paginator
|
||||
val cached = env.game.cached
|
||||
val starApi = env.star.api
|
||||
val bookmarkApi = env.bookmark.api
|
||||
val listMenu = env.game.listMenu
|
||||
|
||||
val maxPage = 40
|
||||
|
||||
val realtime = Open { implicit ctx ⇒
|
||||
IOk(for {
|
||||
games ← gameRepo recentGames 9
|
||||
menu ← makeListMenu
|
||||
} yield html.game.realtime(games, menu))
|
||||
IOk(gameRepo recentGames 9 map { games ⇒
|
||||
html.game.realtime(games, makeListMenu)
|
||||
})
|
||||
}
|
||||
|
||||
def realtimeInner(ids: String) = Open { implicit ctx ⇒
|
||||
|
@ -31,34 +30,26 @@ object Game extends LilaController {
|
|||
|
||||
def all(page: Int) = Open { implicit ctx ⇒
|
||||
reasonable(page) {
|
||||
IOk(makeListMenu map { menu ⇒
|
||||
html.game.all(paginator recent page, menu)
|
||||
})
|
||||
Ok(html.game.all(paginator recent page, makeListMenu))
|
||||
}
|
||||
}
|
||||
|
||||
def checkmate(page: Int) = Open { implicit ctx ⇒
|
||||
reasonable(page) {
|
||||
IOk(makeListMenu map { menu ⇒
|
||||
html.game.checkmate(paginator checkmate page, menu)
|
||||
})
|
||||
Ok(html.game.checkmate(paginator checkmate page, makeListMenu))
|
||||
}
|
||||
}
|
||||
|
||||
def star(page: Int) = Auth { implicit ctx ⇒
|
||||
def bookmark(page: Int) = Auth { implicit ctx ⇒
|
||||
me ⇒
|
||||
reasonable(page) {
|
||||
IOk(makeListMenu map { menu ⇒
|
||||
html.game.star(starApi.gamePaginatorByUser(me, page), menu)
|
||||
})
|
||||
Ok(html.game.bookmarked(bookmarkApi.gamePaginatorByUser(me, page), makeListMenu))
|
||||
}
|
||||
}
|
||||
|
||||
def popular(page: Int) = Open { implicit ctx ⇒
|
||||
reasonable(page) {
|
||||
IOk(makeListMenu map { menu ⇒
|
||||
html.game.popular(paginator popular page, menu)
|
||||
})
|
||||
Ok(html.game.popular(paginator popular page, makeListMenu))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,5 +57,5 @@ object Game extends LilaController {
|
|||
(page < maxPage).fold(result, BadRequest("too old"))
|
||||
|
||||
private def makeListMenu(implicit ctx: Context) =
|
||||
listMenu(starApi.countByUser, ctx.me)
|
||||
listMenu(bookmarkApi.countByUser, ctx.me)
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ object Round extends LilaController {
|
|||
def messenger = env.round.messenger
|
||||
def rematcher = env.setup.rematcher
|
||||
def joiner = env.setup.friendJoiner
|
||||
def starApi = env.star.api
|
||||
def bookmarkApi = env.bookmark.api
|
||||
|
||||
def websocketWatcher(gameId: String, color: String) = WebSocket.async[JsValue] { req ⇒
|
||||
implicit val ctx = reqToCtx(req)
|
||||
|
@ -59,7 +59,7 @@ object Round extends LilaController {
|
|||
|
||||
private def watch(pov: Pov)(implicit ctx: Context): IO[Result] =
|
||||
pov.game.hasBookmarks.fold(
|
||||
starApi usersByGame pov.game,
|
||||
bookmarkApi usersByGame pov.game,
|
||||
io(Nil)
|
||||
) map { bookmarkers ⇒
|
||||
Ok(html.round.watcher(pov, version(pov.gameId), bookmarkers))
|
||||
|
|
|
@ -16,7 +16,7 @@ object Setup extends LilaController {
|
|||
def processor = env.setup.processor
|
||||
def friendConfigMemo = env.setup.friendConfigMemo
|
||||
def gameRepo = env.game.gameRepo
|
||||
def starApi = env.star.api
|
||||
def bookmarkApi = env.bookmark.api
|
||||
|
||||
val aiForm = Open { implicit ctx ⇒
|
||||
IOk(forms.aiFilled map { html.setup.ai(_) })
|
||||
|
@ -69,7 +69,7 @@ object Setup extends LilaController {
|
|||
io(routes.Round.player(pov.fullId)),
|
||||
for {
|
||||
_ ← gameRepo remove pov.game.id
|
||||
_ ← starApi removeByGame pov.game
|
||||
_ ← bookmarkApi removeByGame pov.game
|
||||
} yield routes.Lobby.home
|
||||
)
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ import views._
|
|||
import play.api.mvc._
|
||||
import scalaz.effects._
|
||||
|
||||
object Star extends LilaController {
|
||||
object Bookmark extends LilaController {
|
||||
|
||||
val api = env.star.api
|
||||
val api = env.bookmark.api
|
||||
val gameRepo = env.game.gameRepo
|
||||
|
||||
def toggle(gameId: String) = Auth { implicit ctx ⇒
|
||||
|
|
|
@ -19,18 +19,18 @@ object User extends LilaController {
|
|||
def forms = user.DataForm
|
||||
def eloUpdater = env.user.eloUpdater
|
||||
def lobbyMessenger = env.lobby.messenger
|
||||
def starApi = env.star.api
|
||||
def bookmarkApi = env.bookmark.api
|
||||
|
||||
def show(username: String) = showFilter(username, "all", 1)
|
||||
|
||||
def showFilter(username: String, filterName: String, page: Int) = Open { implicit ctx ⇒
|
||||
IOptionIOk(userRepo byId username) { u ⇒
|
||||
u.enabled.fold(
|
||||
env.user.userInfo(u, starApi, ctx) map { info ⇒
|
||||
env.user.userInfo(u, bookmarkApi, ctx) map { info ⇒
|
||||
val filters = user.GameFilterMenu(info, ctx.me, filterName)
|
||||
val paginator = filters.query.fold(
|
||||
query ⇒ gamePaginator.recentlyCreated(query)(page),
|
||||
starApi.gamePaginatorByUser(u, page))
|
||||
bookmarkApi.gamePaginatorByUser(u, page))
|
||||
html.user.show(u, info, paginator, filters)
|
||||
},
|
||||
io(html.user.disabled(u)))
|
||||
|
|
|
@ -92,7 +92,7 @@ final class CoreEnv private (application: Application, val settings: Settings) {
|
|||
gameRepo = game.gameRepo,
|
||||
userRepo = user.userRepo)
|
||||
|
||||
lazy val star = new lila.star.StarEnv(
|
||||
lazy val bookmark = new lila.bookmark.BookmarkEnv(
|
||||
settings = settings,
|
||||
gameRepo = game.gameRepo,
|
||||
userRepo = user.userRepo,
|
||||
|
@ -120,7 +120,7 @@ final class CoreEnv private (application: Application, val settings: Settings) {
|
|||
lazy val titivate = new core.Titivate(
|
||||
gameRepo = game.gameRepo,
|
||||
finisher = round.finisher,
|
||||
starApi = star.api)
|
||||
bookmarkApi = bookmark.api)
|
||||
}
|
||||
|
||||
object CoreEnv {
|
||||
|
|
|
@ -73,7 +73,7 @@ final class Settings(config: Config) {
|
|||
val MongoCollectionMessageThread = getString("mongo.collection.message_thread")
|
||||
val MongoCollectionWikiPage = getString("mongo.collection.wiki_page")
|
||||
val MongoCollectionFirewall = getString("mongo.collection.firewall")
|
||||
val MongoCollectionStar = getString("mongo.collection.star")
|
||||
val MongoCollectionBookmark = getString("mongo.collection.bookmark")
|
||||
|
||||
val FirewallCacheTtl = millis("firewall.cache_ttl")
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ package core
|
|||
|
||||
import game.GameRepo
|
||||
import round.Finisher
|
||||
import star.StarApi
|
||||
import bookmark.BookmarkApi
|
||||
|
||||
import com.mongodb.casbah.Imports._
|
||||
import org.joda.time.DateTime
|
||||
|
@ -13,7 +13,7 @@ import scalaz.effects._
|
|||
final class Titivate(
|
||||
gameRepo: GameRepo,
|
||||
finisher: Finisher,
|
||||
starApi: StarApi) {
|
||||
bookmarkApi: BookmarkApi) {
|
||||
|
||||
val finishByClock: IO[Unit] =
|
||||
for {
|
||||
|
@ -24,7 +24,7 @@ final class Titivate(
|
|||
val cleanupUnplayed = for {
|
||||
ids ← gameRepo.unplayedIds
|
||||
_ ← gameRepo removeIds ids
|
||||
_ ← starApi removeByGameIds ids
|
||||
_ ← bookmarkApi removeByGameIds ids
|
||||
} yield ()
|
||||
|
||||
val cleanupNext: IO[Unit] = {
|
||||
|
|
|
@ -1,17 +1,7 @@
|
|||
package lila
|
||||
package game
|
||||
|
||||
import akka.actor._
|
||||
import akka.pattern.ask
|
||||
import akka.util.duration._
|
||||
import akka.util.Timeout
|
||||
import akka.dispatch.{ Future, Await }
|
||||
import akka.pattern.ask
|
||||
import akka.util.duration._
|
||||
import akka.util.Timeout
|
||||
|
||||
import play.api.Play.current
|
||||
import play.api.libs.concurrent._
|
||||
|
||||
import memo.ActorMemo
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ trait GameHelper { self: I18nHelper with UserHelper with StringHelper ⇒
|
|||
isUsernameOnline(username).fold(" online", " offline"),
|
||||
""),
|
||||
routes.User.show(username),
|
||||
usernameWithElo(player) + player.eloDiff.filter(_ ⇒ withDiff.pp).fold(
|
||||
usernameWithElo(player) + player.eloDiff.filter(_ ⇒ withDiff).fold(
|
||||
diff ⇒ " (%s)".format(showNumber(diff)),
|
||||
"")
|
||||
)
|
||||
|
|
|
@ -140,7 +140,7 @@ class GameRepo(collection: MongoCollection)
|
|||
)
|
||||
}
|
||||
|
||||
// stars should also be removed
|
||||
// bookmarks should also be removed
|
||||
def remove(id: String): IO[Unit] = io {
|
||||
remove(idSelector(id))
|
||||
}
|
||||
|
|
|
@ -9,21 +9,16 @@ case class ListMenu(
|
|||
nbGames: Int,
|
||||
nbMates: Int,
|
||||
nbPopular: Int,
|
||||
nbStars: Option[Int])
|
||||
nbBookmarks: Option[Int])
|
||||
|
||||
object ListMenu {
|
||||
|
||||
type CountStars = User ⇒ IO[Int]
|
||||
type CountBookmarks = User ⇒ Int
|
||||
|
||||
def apply(cached: Cached)(countStars: CountStars, me: Option[User]): IO[ListMenu] =
|
||||
me.fold(
|
||||
m ⇒ countStars(m) map (_.some),
|
||||
io(none)
|
||||
) map { nbStars ⇒
|
||||
new ListMenu(
|
||||
nbGames = cached.nbGames,
|
||||
nbMates = cached.nbMates,
|
||||
nbPopular = cached.nbPopular,
|
||||
nbStars = nbStars)
|
||||
}
|
||||
def apply(cached: Cached)(countBookmarks: CountBookmarks, me: Option[User]): ListMenu =
|
||||
new ListMenu(
|
||||
nbGames = cached.nbGames,
|
||||
nbMates = cached.nbMates,
|
||||
nbPopular = cached.nbPopular,
|
||||
nbBookmarks = me map countBookmarks)
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
package lila
|
||||
package star
|
||||
|
||||
import core.CoreEnv
|
||||
|
||||
import game.DbGame
|
||||
import user.User
|
||||
|
||||
trait StarHelper {
|
||||
|
||||
protected def env: CoreEnv
|
||||
private def api = env.star.api
|
||||
|
||||
def starred(game: DbGame, user: User): Boolean =
|
||||
api.starred(game, user).unsafePerformIO
|
||||
}
|
|
@ -27,7 +27,7 @@ object Environment
|
|||
with forum.ForumHelper
|
||||
with security.SecurityHelper
|
||||
with i18n.I18nHelper
|
||||
with star.StarHelper {
|
||||
with bookmark.BookmarkHelper {
|
||||
|
||||
protected def env = coreEnv
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import scala.collection.mutable
|
|||
final class Cached(userRepo: UserRepo) {
|
||||
|
||||
// id => username
|
||||
val usernameCache = mutable.Map[String, Option[String]]()
|
||||
private val usernameCache = mutable.Map[String, Option[String]]()
|
||||
|
||||
def username(userId: String) =
|
||||
usernameCache.getOrElseUpdate(
|
||||
|
|
|
@ -4,7 +4,7 @@ package user
|
|||
import chess.{ EloCalculator, Color }
|
||||
import game.{ GameRepo, DbGame }
|
||||
import http.Context
|
||||
import star.StarApi
|
||||
import bookmark.BookmarkApi
|
||||
|
||||
import scalaz.effects._
|
||||
|
||||
|
@ -34,7 +34,7 @@ object UserInfo {
|
|||
eloCalculator: EloCalculator,
|
||||
eloChartBuilder: User ⇒ IO[Option[EloChart]])(
|
||||
user: User,
|
||||
starApi: StarApi,
|
||||
bookmarkApi: BookmarkApi,
|
||||
ctx: Context): IO[UserInfo] = for {
|
||||
rank ← (user.elo >= 1500).fold(
|
||||
userRepo rank user flatMap { rank ⇒
|
||||
|
@ -54,7 +54,7 @@ object UserInfo {
|
|||
me ⇒ gameRepo count (_.opponents(user, me)) map (_.some),
|
||||
io(none)
|
||||
)
|
||||
nbBookmark ← starApi countByUser user
|
||||
nbBookmark = bookmarkApi countByUser user
|
||||
eloChart ← eloChartBuilder(user)
|
||||
winChart = (user.nbRatedGames > 0) option {
|
||||
new WinChart(nbWin, nbDraw, nbLoss)
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
@(g: DbGame)(implicit ctx: Context)
|
||||
|
||||
<span class="star_game">
|
||||
<span class="bookmark">
|
||||
@ctx.me.map { m =>
|
||||
<a
|
||||
href="@routes.Star.toggle(g.id)"
|
||||
href="@routes.Bookmark.toggle(g.id)"
|
||||
class="icon
|
||||
@starred(g, m).fold("starred", "")"
|
||||
@bookmarked(g, m).fold("bookmarked", "")"
|
||||
title="@trans.bookmarkThisGame()">@g.showBookmarks</a>
|
||||
}.getOrElse {
|
||||
<span class="icon">@g.showBookmarks</span>
|
7
app/views/game/bookmarked.scala.html
Normal file
7
app/views/game/bookmarked.scala.html
Normal file
|
@ -0,0 +1,7 @@
|
|||
@(paginator: Paginator[DbGame], listMenu: lila.game.ListMenu)(implicit ctx: Context)
|
||||
|
||||
@game.list(
|
||||
name = trans.nbBookmarks.str(listMenu.nbBookmarks.fold(_.localize, 0)),
|
||||
paginator = paginator,
|
||||
next = paginator.nextPage map { n => routes.Game.bookmark(n) },
|
||||
menu = sideMenu(listMenu, "bookmark"))
|
|
@ -9,8 +9,8 @@
|
|||
<a class="@active.active("checkmate")" href="@routes.Game.checkmate()">
|
||||
@trans.viewNbCheckmates(listMenu.nbMates.localize)
|
||||
</a>
|
||||
@listMenu.nbStars.map { nb =>
|
||||
<a class="@active.active("star")" href="@routes.Game.star()">
|
||||
@listMenu.nbBookmarks.map { nb =>
|
||||
<a class="@active.active("bookmark")" href="@routes.Game.bookmark()">
|
||||
@trans.nbBookmarks(nb.localize)
|
||||
</a>
|
||||
<a class="@active.active("popular")" href="@routes.Game.popular()">
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
@(paginator: Paginator[DbGame], listMenu: lila.game.ListMenu)(implicit ctx: Context)
|
||||
|
||||
@game.list(
|
||||
name = trans.nbBookmarks.str(listMenu.nbStars.fold(_.localize, 0)),
|
||||
paginator = paginator,
|
||||
next = paginator.nextPage map { n => routes.Game.star(n) },
|
||||
menu = sideMenu(listMenu, "star"))
|
|
@ -6,7 +6,7 @@
|
|||
@defining(fromPlayer | g.creator ) { firstPlayer =>
|
||||
@gameFen(g, firstPlayer.color.some)
|
||||
<div class="infos">
|
||||
@game.bookmark(g)
|
||||
@bookmark.toggle(g)
|
||||
<b>
|
||||
@if(g.isBeingPlayed) {
|
||||
<a class="link" href="@routes.Round.watcher(g.id, firstPlayer.color.name)">@trans.playingRightNow()</a>,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
@defining("http://lichess.org" + routes.Round.watcher(g.id, "white")) { url =>
|
||||
<div class="game_share clearfix">
|
||||
@game.bookmark(g)
|
||||
@bookmark.toggle(g)
|
||||
<a
|
||||
title="@trans.shareThisUrlToLetSpectatorsSeeTheGame()"
|
||||
class="game_permalink blank_if_play"
|
||||
|
|
|
@ -19,7 +19,7 @@ mongo {
|
|||
message_thread = m_thread
|
||||
wiki_page = wiki
|
||||
firewall = firewall
|
||||
star = star
|
||||
bookmark = bookmark
|
||||
}
|
||||
connectionsPerHost = 100
|
||||
autoConnectRetry = true
|
||||
|
|
|
@ -6,7 +6,7 @@ GET /games controllers.Game.realtime
|
|||
GET /games/refresh/:ids controllers.Game.realtimeInner(ids: String)
|
||||
GET /games/all controllers.Game.all(page: Int ?= 1)
|
||||
GET /games/checkmate controllers.Game.checkmate(page: Int ?= 1)
|
||||
GET /games/bookmark controllers.Game.star(page: Int ?= 1)
|
||||
GET /games/bookmark controllers.Game.bookmark(page: Int ?= 1)
|
||||
GET /games/popular controllers.Game.popular(page: Int ?= 1)
|
||||
|
||||
# Round
|
||||
|
@ -94,8 +94,8 @@ GET /new/$hookId<[\w\-]{8}>/join controllers.Lobby.join(hookId: String)
|
|||
GET /lobby/socket controllers.Lobby.socket
|
||||
GET /lobby/log controllers.Lobby.log
|
||||
|
||||
# Star
|
||||
POST /star/$gameId<[\w\-]{8}> controllers.Star.toggle(gameId: String)
|
||||
# Bookmark
|
||||
POST /bookmark/$gameId<[\w\-]{8}> controllers.Bookmark.toggle(gameId: String)
|
||||
|
||||
# Forum
|
||||
GET /forum controllers.ForumCateg.index
|
||||
|
|
|
@ -162,20 +162,20 @@ $(function() {
|
|||
return confirm('Confirm this action?');
|
||||
});
|
||||
|
||||
function stars() {
|
||||
$('span.star_game a.icon:not(.jsed)').each(function() {
|
||||
function bookmarks() {
|
||||
$('span.bookmark a.icon:not(.jsed)').each(function() {
|
||||
var t = $(this).addClass("jsed");
|
||||
t.click(function() {
|
||||
t.toggleClass("starred");
|
||||
t.toggleClass("bookmarked");
|
||||
$.post(t.attr("href"));
|
||||
var count = (parseInt(t.html()) || 0) + (t.hasClass("starred") ? 1 : -1);
|
||||
var count = (parseInt(t.html()) || 0) + (t.hasClass("bookmarked") ? 1 : -1);
|
||||
t.html(count > 0 ? count : "");
|
||||
return false;
|
||||
});
|
||||
});
|
||||
}
|
||||
stars();
|
||||
$('body').on('lichess.content_loaded', stars);
|
||||
bookmarks();
|
||||
$('body').on('lichess.content_loaded', bookmarks);
|
||||
|
||||
var elem = document.createElement('audio');
|
||||
var canPlayAudio = !! elem.canPlayType && elem.canPlayType('audio/ogg; codecs="vorbis"');
|
||||
|
|
|
@ -590,12 +590,12 @@ div.game_share a.game_permalink {
|
|||
margin-top: 3px;
|
||||
}
|
||||
|
||||
span.star_game {
|
||||
span.bookmark {
|
||||
position: relative;
|
||||
float: right;
|
||||
margin-right: 40px;
|
||||
}
|
||||
span.star_game .icon {
|
||||
span.bookmark .icon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
@ -607,6 +607,6 @@ span.star_game .icon {
|
|||
text-decoration: none;
|
||||
color: #a0a0a0;
|
||||
}
|
||||
span.star_game .icon.starred {
|
||||
span.bookmark .icon.bookmarked {
|
||||
background-position: 0 -24px;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue