diff --git a/app/Env.scala b/app/Env.scala index 983e89be8f..3469288d4d 100644 --- a/app/Env.scala +++ b/app/Env.scala @@ -29,6 +29,7 @@ final class Env( bookmarkApi = Env.bookmark.api, eloCalculator = Env.round.eloCalculator, relationApi = Env.relation.api, + gameCached = Env.game.cached, postApi = Env.forum.postApi, getRank = Env.user.ranking.get) _ diff --git a/app/Global.scala b/app/Global.scala index e6928191e4..13c9108921 100644 --- a/app/Global.scala +++ b/app/Global.scala @@ -18,9 +18,8 @@ object Global extends GlobalSettings { else Action(NotFound("I am an AI server")).some } else { - // if (!Env.api.isProd) println(req) Env.monitor.reporting ! AddRequest - Env.security.wiretap(req) + // Env.security.wiretap(req) Env.security.firewall.requestHandler(req).await orElse Env.i18n.requestHandler(req) orElse super.onRouteRequest(req) diff --git a/app/controllers/Setup.scala b/app/controllers/Setup.scala index 421cb24f2e..ec11ed4932 100644 --- a/app/controllers/Setup.scala +++ b/app/controllers/Setup.scala @@ -63,7 +63,7 @@ object Setup extends LilaController with TheftPrevention { def hook(uid: String) = OpenBody { implicit ctx ⇒ implicit val req = ctx.body env.forms.hook(ctx).bindFromRequest.value ?? { config ⇒ - env.processor.hook(config, uid, lila.common.HTTPRequest sid req) + env.processor.hook(config, uid, lila.common.HTTPRequest sid req, ctx.me) } } diff --git a/app/controllers/Tv.scala b/app/controllers/Tv.scala index f120b22006..82fcaf1c5b 100644 --- a/app/controllers/Tv.scala +++ b/app/controllers/Tv.scala @@ -36,7 +36,7 @@ object Tv extends LilaController { private def confrontation(game: GameModel): Fu[Option[Confrontation]] = ~{ (game.creator.userId |@| game.invited.userId) apply { case (id1, id2) ⇒ (UserRepo byId id1) zip (UserRepo byId id2) flatMap { - case (Some(user1), Some(user2)) ⇒ GameRepo.confrontation(user1, user2) map (_.some) + case (Some(user1), Some(user2)) ⇒ Env.game.cached.confrontation(user1, user2) map (_.some) case _ ⇒ fuccess(none) } } diff --git a/app/mashup/UserInfo.scala b/app/mashup/UserInfo.scala index 6b8af6c953..26e072ab26 100644 --- a/app/mashup/UserInfo.scala +++ b/app/mashup/UserInfo.scala @@ -36,16 +36,17 @@ object UserInfo { bookmarkApi: BookmarkApi, eloCalculator: EloCalculator, relationApi: RelationApi, + gameCached: lila.game.Cached, postApi: PostApi, getRank: String ⇒ Fu[Option[Int]])(user: User, ctx: Context): Fu[UserInfo] = (getRank(user.id) flatMap { _ ?? { rank ⇒ countUsers() map { nb ⇒ (rank -> nb).some } } }) zip ((ctx is user) ?? { - GameRepo count (_ notFinished user.id) map (_.some) + gameCached nbPlaying user.id map (_.some) }) zip (ctx.me.filter(user!=) ?? { me ⇒ - GameRepo.confrontation(me, user) map (_.some filterNot (_.empty)) + gameCached.confrontation(me, user) map (_.some filterNot (_.empty)) }) zip (bookmarkApi countByUser user) zip EloChart(user) zip diff --git a/app/views/user/confrontation.scala.html b/app/views/user/confrontation.scala.html index 6b4aa2c93b..8de55e1dda 100644 --- a/app/views/user/confrontation.scala.html +++ b/app/views/user/confrontation.scala.html @@ -1,7 +1,7 @@ @(c: lila.user.Confrontation)(implicit ctx: Context)
-
@userLink(c.user1, withElo = false, withOnline = false) vs @userLink(c.user2, withElo = false, withOnline = false)
+
@userIdLink(c.user1.some, withOnline = false) vs @userIdLink(c.user2.some, withOnline = false)
@trans.nbWins(""+c.wins+""), @trans.nbDraws(""+c.draws+""), @trans.nbLosses(""+c.losses+"") diff --git a/conf/messages.bs b/conf/messages.bs index ce5aed6e35..1c5784ffbd 100644 --- a/conf/messages.bs +++ b/conf/messages.bs @@ -1,87 +1,100 @@ -playWithAFriend=Igraj s prijateljem +playWithAFriend=Igraj protiv prijatelja inviteAFriendToPlayWithYou=Pozovi prijatelja playWithTheMachine=Igraj protiv računara challengeTheArtificialIntelligence=Izazovi vještačku inteligenciju -toInviteSomeoneToPlayGiveThisUrl=Kako bi pozvao nekoga, pošalji slijedeći link: -gameOver=Kraj igre -waitingForOpponent=Čekaj protivnika -waiting=Čekamo -yourTurn=Ti si na potezu -aiNameLevelAiLevel=%s Nivo %s -level=Nivo -toggleTheChat=Aktiviraj/deaktiviraj chat -toggleSound=Uključi/Isključi zvuk -chat=Chat -resign=Predaj +toInviteSomeoneToPlayGiveThisUrl=Za poziv u igru, posalji ovu adresu +gameOver=Igra je završila +waitingForOpponent=Čekanje protivnika +waiting=% na potezu +yourTurn=Vi ste na potezu +aiNameLevelAiLevel=%s Razina %s +level=Razina +toggleTheChat=Uključi/isključi dopisivanje +toggleSound=Uključi/ isključi zvuk +chat=Dopisivanje +resign=Predati igru checkmate=Šah-mat stalemate=Pat white=Bijeli black=Crni -createAGame=Kreiraj partiju -noGameAvailableRightNowCreateOne=Trenutno nema raspoložive partije, kreiraj je! -whiteIsVictorious=Bijeli pobjeđuje -blackIsVictorious=Crni pobjeđuje -playWithTheSameOpponentAgain=Igraj opet sa istim protivnikom +createAGame=Stvoriti igru +noGameAvailableRightNowCreateOne=Nema dostupnih igara +whiteIsVictorious=Bijeli je pobjednik +blackIsVictorious=Crni je pobjednik +playWithTheSameOpponentAgain=Igrati ponovo sa istim protivnikom newOpponent=Novi protivnik -playWithAnotherOpponent=Igraj protiv nekog drugog -yourOpponentWantsToPlayANewGameWithYou=Tvoj protivnik želi opet ograti s tobom -joinTheGame=Uključi se u igru +playWithAnotherOpponent=Igrati sa drugim protivnikom +yourOpponentWantsToPlayANewGameWithYou=Vaš protivnik želi novu igru +joinTheGame=Pridruži se igri whitePlays=Bijeli je na potezu blackPlays=Crni je na potezu -theOtherPlayerHasLeftTheGameYouCanForceResignationOrWaitForHim=Protivnički igrač je napustio igru. Možete tražiti da preda partiju ili čekati. -makeYourOpponentResign=Tražite da preda igru. -forceResignation=Tražite da preda igru. -talkInChat=Chat -theFirstPersonToComeOnThisUrlWillPlayWithYou=Prva osoba koja iskoristi ovaj link će igrati s vama -whiteCreatesTheGame=Bijeli kreira igru -blackCreatesTheGame=Crni kreira igru -whiteJoinsTheGame=Bijeli se pridružio -blackJoinsTheGame=Crni se pridružio +theOtherPlayerHasLeftTheGameYouCanForceResignationOrWaitForHim=Vaš protivnik je napustio igru. Možete ga prisiliti na predaju ili čekati. +makeYourOpponentResign=Tražite da protivnik preda igru +forceResignation=Prisilite protivnika na predaju +talkInChat=Dopisivati se +theFirstPersonToComeOnThisUrlWillPlayWithYou=Prva osoba koja se pojavi, na ovoj adresi,će igrati protiv vas +whiteCreatesTheGame=Bijeli stvara igru +blackCreatesTheGame=Crni stvara igru +whiteJoinsTheGame=Bijeli se pridružuje igri +blackJoinsTheGame=Crni se pridružuje igri whiteResigned=Bijeli je predao blackResigned=Crni je predao whiteLeftTheGame=Bijeli je napustio igru blackLeftTheGame=Crni je napustio igru -shareThisUrlToLetSpectatorsSeeTheGame=Podijeli ovaj link kako bi posmatrači mogli vidjeti igru -youAreViewingThisGameAsASpectator=Gledate ovu igru kao promatrač -replayAndAnalyse=Repriza i analiza -viewGameStats=Pogledaj statistiku igre -flipBoard=Zamijeni strane -threefoldRepetition=Pozicija tri puta ponovljena -claimADraw=Zatraži neriješeno -offerDraw=Ponudi remi -draw=neriješeno -nbConnectedPlayers=%s spojenih igrača -talkAboutChessAndDiscussLichessFeaturesInTheForum=Razgovaraj o šahu i raspravljaj lichess značajke na forumu -seeTheGamesBeingPlayedInRealTime=Pogledaj trenutne igre +shareThisUrlToLetSpectatorsSeeTheGame=Podijeliti ovaj link kako bi drugi mogli vidjeti igru +youAreViewingThisGameAsASpectator=Ovdje ste kao promatrač +replayAndAnalyse=Ponovi i analiziraj +computerAnalysisInProgress=Računarska analiza u tijeku +theComputerAnalysisYouRequestedIsNowAvailable=Računarska analiza koju ste trazili je sada dostupna +theComputerAnalysisHasFailed=Raćunarska analiza nije uspjela +viewTheComputerAnalysis=Pogledati računarsku analizu +requestAComputerAnalysis=Zahtijevaj računarsku analizu +blunders=Zabuna +mistakes=Greški +inaccuracies=Nepravilnosti +viewGameStats=Pogledati statistiku igre +flipBoard=Okrenuti ploču +threefoldRepetition=Trostruko ponavljanje +claimADraw=Zahtijevati remi +offerDraw=Ponuditi remi +draw=Remi +nbConnectedPlayers=%s prisutnih igrača +talkAboutChessAndDiscussLichessFeaturesInTheForum=Razgovarati o šahu i diskutovati o lichess svojstvima na forumu +seeTheGamesBeingPlayedInRealTime=Pogledati trenutne igre gamesBeingPlayedRightNow=Trenutne igre -viewAllNbGames=Pogledaj sve %s igre -viewNbCheckmates=Pogledaj %s matova -nbBookmarks=%s Favoriti +viewAllNbGames=%s igre +viewNbCheckmates=%s Šah - matovi +nbBookmarks=%s Označeno nbPopularGames=%s Popularne Igre nbAnalysedGames=%s Analizirane Igre -bookmarkedByNbPlayers=Dodano u favorite od strane %s igraca -viewInFullSize=Pogledaj u punoj veličini +bookmarkedByNbPlayers=Igra je označena od strane %s protivnika +viewInFullSize=Pogledati u punoj veličini logOut=Odjava signIn=Prijava -signUp=Registracija -people=Ljudi +newToLichess=Novi u lichess-u? +youNeedAnAccountToDoThat=Trebate račun da bi to napravili +signUp=Registrovati se +people=Prijatelji games=Igre forum=Forum +xPostedInForumY=%s objavio u forumu %s chessPlayers=Igrači -minutesPerSide=Minuta po strani +minutesPerSide=Minuta po igraču variant=Varijanta -timeControl=Upravljanje vremenom +timeControl=Vremenska kontrola +time=Vrijeme start=Početak username=Korisničko ime password=Lozinka -haveAnAccount=Imate li račun? +haveAnAccount=Već imate raćun? allYouNeedIsAUsernameAndAPassword=Sve što trebate je korisničko ime i lozinka. -learnMoreAboutLichess=Nauči više o Lichess-u -rank=Rank -gamesPlayed=Igara odigrano -declineInvitation=Odbi pozivnicu -cancel=Odgodi -timeOut=Vrijeme za partiju isteklo +learnMoreAboutLichess=Naučiti više o Lichess-u +rank=Poredak +gamesPlayed=Broj odigranih igara +nbGamesWithYou=%s odigranih igara protiv vas +declineInvitation=Odbiti pozivnicu +cancel=Otkazati +timeOut=Vrijeme je isteklo drawOfferSent=Ponuda za remi poslana drawOfferDeclined=Punuda za remi odbijena drawOfferAccepted=Ponuda za remi prihvaćena @@ -90,6 +103,7 @@ yourOpponentOffersADraw=Protivnik nudi remi accept=Prihvati decline=Odbij playingRightNow=Upravo igra +finished=Završeno abortGame=Prekini partiju gameAborted=Partija prekinuta standard=Standardan @@ -111,6 +125,10 @@ chatRoom=Razgovaranje spectatorRoom=Soba za posmatrače composeMessage=Skladaj poruku sentMessages=Poslane pruke +noNewMessages=Nema novih poruka +subject=Subjekt +recipient=Primalac +send=Pošalji incrementInSeconds=Dodatnih sekundi po potezu freeOnlineChess=Besplatni internet šah spectators=Posmatrača @@ -135,8 +153,10 @@ takebackPropositionCanceled=Prijedlog za povlačenje poteza otkazan yourOpponentProposesATakeback=Vaš protivnik predlaže da povučete potez bookmarkThisGame=Dodaj ovu igru u favorite toggleBackground=Izmijeni boju pozadine +search=Traži advancedSearch=Napredna pretraga tournament=Turnir +tournaments=Turniri tournamentPoints=Bodovi na turniru viewTournament=Pogledaj turnir freeOnlineChessGamePlayChessNowInACleanInterfaceNoRegistrationNoAdsNoPluginRequiredPlayChessWithComputerFriendsOrRandomOpponents=Besplatni internet šah. Igrajte šah sa čistim interface-om. Registracija nije neophodna, nema reklama, ne zahtijeva browser plugins. Igrajte protiv računara, prijatelja ili slučajnih protivnika. diff --git a/modules/bookmark/src/main/BookmarkRepo.scala b/modules/bookmark/src/main/BookmarkRepo.scala index fadb3d87ec..74f6c19b03 100644 --- a/modules/bookmark/src/main/BookmarkRepo.scala +++ b/modules/bookmark/src/main/BookmarkRepo.scala @@ -10,9 +10,6 @@ import tube.bookmarkTube case class Bookmark(game: lila.game.Game, user: lila.user.User) -// db.bookmark.ensureIndex({g:1}) -// db.bookmark.ensureIndex({u:1}) -// db.bookmark.ensureIndex({d: -1}) private[bookmark] object BookmarkRepo { def toggle(gameId: String, userId: String): Fu[Boolean] = diff --git a/modules/game/src/main/Cached.scala b/modules/game/src/main/Cached.scala index dbabb96eff..f7a2bb09d1 100644 --- a/modules/game/src/main/Cached.scala +++ b/modules/game/src/main/Cached.scala @@ -6,14 +6,29 @@ import play.api.libs.json.JsObject import lila.db.api.$count import lila.memo.AsyncCache +import lila.user.{ User, Confrontation } import tube.gameTube -private[game] final class Cached(ttl: Duration) { +final class Cached(ttl: Duration) { def nbGames: Fu[Int] = count(Query.all) def nbMates: Fu[Int] = count(Query.mate) def nbPopular: Fu[Int] = count(Query.popular) def nbImported: Fu[Int] = count(Query.imported) + def nbPlaying(userId: String): Fu[Int] = count(Query notFinished userId) + + def confrontation(user1: User, user2: User): Fu[Confrontation] = { + def idGame(user: User) = (user.id, user.count.game) + confrontationCache { + (user1 < user2).fold( + idGame(user1) -> idGame(user2), + idGame(user2) -> idGame(user1)) + } + } + + private val confrontationCache = + AsyncCache(GameRepo.confrontation, timeToLive = 1.minute) + private val count = AsyncCache((o: JsObject) ⇒ $count(o), timeToLive = ttl) } diff --git a/modules/game/src/main/GameRepo.scala b/modules/game/src/main/GameRepo.scala index d0bf8152de..49e3725530 100644 --- a/modules/game/src/main/GameRepo.scala +++ b/modules/game/src/main/GameRepo.scala @@ -226,32 +226,37 @@ object GameRepo { _ sort Query.sortCreated skip (Random nextInt 1000) ) - // user1 wins, draws, losses - def confrontation(user1: User, user2: User): Fu[Confrontation] = { - import reactivemongo.bson._ - import reactivemongo.core.commands._ - val userIds = List(user1, user2).sortBy(_.count.game).map(_.id) - val command = Aggregate(gameTube.coll.name, Seq( - Match(BSONDocument( - "uids" -> BSONDocument("$all" -> userIds), - "s" -> BSONDocument("$gte" -> chess.Status.Mate.id) - )), - GroupField("wid")("nb" -> SumValue(1)) - )) - gameTube.coll.db.command(command) map { stream ⇒ - val res = (stream.toList map { obj ⇒ - toJSON(obj).asOpt[JsObject] flatMap { o ⇒ - o int "nb" map { nb ⇒ - ~(o str "_id") -> nb + // gets 2 users (id, nbGames) + // returns user1 wins, draws, losses + // the 2 userIds SHOULD be sorted by game count desc + // this method is cached in lila.game.Cached + private[game] def confrontation(users: ((String, Int), (String, Int))): Fu[Confrontation] = users match { + case (user1, user2) ⇒ { + import reactivemongo.bson._ + import reactivemongo.core.commands._ + val userIds = List(user1, user2).sortBy(_._2).map(_._1) + val command = Aggregate(gameTube.coll.name, Seq( + Match(BSONDocument( + "uids" -> BSONDocument("$all" -> userIds), + "s" -> BSONDocument("$gte" -> chess.Status.Mate.id) + )), + GroupField("wid")("nb" -> SumValue(1)) + )) + gameTube.coll.db.command(command) map { stream ⇒ + val res = (stream.toList map { obj ⇒ + toJSON(obj).asOpt[JsObject] flatMap { o ⇒ + o int "nb" map { nb ⇒ + ~(o str "_id") -> nb + } } - } - }).flatten.toMap - Confrontation( - user1, user2, - ~(res get user1.id), - ~(res get ""), - ~(res get user2.id) - ) + }).flatten.toMap + Confrontation( + user1._1, user2._1, + ~(res get user1._1), + ~(res get ""), + ~(res get user2._1) + ) + } } } } diff --git a/modules/game/src/main/PgnDump.scala b/modules/game/src/main/PgnDump.scala index ed088400e9..11ae80a573 100644 --- a/modules/game/src/main/PgnDump.scala +++ b/modules/game/src/main/PgnDump.scala @@ -28,7 +28,7 @@ final class PgnDump( player(game.blackPlayer, blackUser), game.id) - private val dateFormat = DateTimeFormat forPattern "yyyy-MM-dd"; + private val dateFormat = DateTimeFormat forPattern "yyyy.MM.dd"; private def elo(p: Player) = p.elo.fold("?")(_.toString) diff --git a/modules/lobby/src/main/Biter.scala b/modules/lobby/src/main/Biter.scala index d47a70be8b..6d4fbce7b3 100644 --- a/modules/lobby/src/main/Biter.scala +++ b/modules/lobby/src/main/Biter.scala @@ -49,13 +49,13 @@ private[lobby] final class Biter( source = lila.game.Source.Lobby, pgnImport = None) - private def canJoin(hook: Hook, userOption: Option[User]) = + def canJoin(hook: Hook, user: Option[User]) = hook.open && hook.realMode.casual.fold( - userOption.isDefined || hook.allowAnon, - userOption ?? { u ⇒ hook.realEloRange.fold(true)(_ contains u.elo) } + user.isDefined || hook.allowAnon, + user ?? { u ⇒ hook.realEloRange.fold(true)(_ contains u.elo) } ) && !{ - userOption ?? { u ⇒ + user ?? { u ⇒ hook.userId ?? { blocks(_, u.id).await } } } diff --git a/modules/lobby/src/main/Color.scala b/modules/lobby/src/main/Color.scala index 72510945f8..01df21d4d9 100644 --- a/modules/lobby/src/main/Color.scala +++ b/modules/lobby/src/main/Color.scala @@ -5,6 +5,8 @@ import scala.util.Random.nextBoolean sealed abstract class Color(val name: String) { def resolve: chess.Color + + def compatibleWith(c: Color) = (c == this).fold(c == Color.Random, true) } object Color { diff --git a/modules/lobby/src/main/Hook.scala b/modules/lobby/src/main/Hook.scala index 6137f1da16..e01dc7893a 100644 --- a/modules/lobby/src/main/Hook.scala +++ b/modules/lobby/src/main/Hook.scala @@ -1,10 +1,10 @@ package lila.lobby +import chess.{ Variant, Mode, Clock } import org.joda.time.DateTime import ornicar.scalalib.Random import play.api.libs.json._ -import chess.{ Variant, Mode, Clock } import lila.common.EloRange import lila.user.User @@ -19,11 +19,8 @@ case class Hook( mode: Int, allowAnon: Boolean, color: String, - userId: Option[String], - username: String, - elo: Option[Int], + user: Option[User], eloRange: String, - engine: Boolean, gameId: Option[String] = None, createdAt: DateTime) { @@ -36,8 +33,23 @@ case class Hook( def realMode = Mode orDefault mode + def memberOnly = !allowAnon + + def compatibleWith(h: Hook) = + compatibilityProperties == h.compatibilityProperties && + (realColor compatibleWith h.realColor) && + (memberOnly || h.memberOnly).fold(isMember && h.isMember, true) + + private def compatibilityProperties = (variant, time, increment, mode) + lazy val realEloRange: Option[EloRange] = EloRange noneIfDefault eloRange + def userId = user map (_.id) + def isMember = user.nonEmpty + def username = user.fold(User.anonymous)(_.username) + def elo = user map (_.elo) + def engine = user ?? (_.engine) + def render: JsObject = Json.obj( "id" -> id, "uid" -> uid, @@ -82,11 +94,8 @@ object Hook { mode = mode.id, allowAnon = allowAnon || user.isEmpty, color = color, - userId = user map (_.id), - username = user.fold(User.anonymous)(_.username), + user = user, sid = sid, - elo = user map (_.elo), eloRange = eloRange.toString, - engine = user.??(_.engine), createdAt = DateTime.now) } diff --git a/modules/lobby/src/main/HookRepo.scala b/modules/lobby/src/main/HookRepo.scala index 7d1f1f6ef6..4f2cc62c8f 100644 --- a/modules/lobby/src/main/HookRepo.scala +++ b/modules/lobby/src/main/HookRepo.scala @@ -7,6 +7,8 @@ object HookRepo { private var hooks = Vector[Hook]() + def findCompatible(hook: Hook): List[Hook] = allOpen filter (_ compatibleWith hook) + def list = hooks.toList def byId(id: String) = hooks find (_.id == id) diff --git a/modules/lobby/src/main/Lobby.scala b/modules/lobby/src/main/Lobby.scala index 859ec4ef75..8d4f3b5241 100644 --- a/modules/lobby/src/main/Lobby.scala +++ b/modules/lobby/src/main/Lobby.scala @@ -5,11 +5,12 @@ import scala.concurrent.duration._ import actorApi._ import akka.actor._ import akka.pattern.{ ask, pipe } +import makeTimeout.short + import lila.db.api._ import lila.hub.actorApi.GetUids import lila.memo.ExpireSetMemo import lila.socket.actorApi.Broom -import makeTimeout.short private[lobby] final class Lobby( biter: Biter, @@ -19,11 +20,16 @@ private[lobby] final class Lobby( case GetOpen ⇒ sender ! HookRepo.allOpen - case msg @ AddHook(hook) ⇒ { + case msg @ AddHook(hook, user) ⇒ { HookRepo byUid hook.uid foreach remove hook.sid ?? { sid ⇒ HookRepo bySid sid foreach remove } - HookRepo save hook - socket ! msg + HookRepo findCompatible hook find { biter.canJoin(_, user) } match { + case Some(h) ⇒ self ! BiteHook(h.id, hook.uid, user map (_.id)) + case None ⇒ { + HookRepo save hook + socket ! msg + } + } } case CancelHook(uid) ⇒ { diff --git a/modules/lobby/src/main/Socket.scala b/modules/lobby/src/main/Socket.scala index 7e289cb13d..aa08f84d14 100644 --- a/modules/lobby/src/main/Socket.scala +++ b/modules/lobby/src/main/Socket.scala @@ -5,16 +5,17 @@ import scala.concurrent.duration._ import actorApi._ import akka.actor._ import akka.pattern.ask +import makeTimeout.short +import play.api.libs.iteratee._ +import play.api.libs.json._ +import play.api.templates.Html + import lila.game.actorApi._ import lila.hub.actorApi.lobby._ import lila.hub.actorApi.router.{ Homepage, Player } import lila.hub.actorApi.timeline._ import lila.socket.actorApi.{ Connected ⇒ _, _ } import lila.socket.{ SocketActor, History, Historical } -import makeTimeout.short -import play.api.libs.iteratee._ -import play.api.libs.json._ -import play.api.templates.Html private[lobby] final class Socket( val history: History, @@ -43,7 +44,7 @@ private[lobby] final class Socket( case ReloadTimeline(user) ⇒ sendTo(user, makeMessage("reload_timeline", JsNull)) - case AddHook(hook) ⇒ notifyVersion("hook_add", hook.render) + case AddHook(hook, _) ⇒ notifyVersion("hook_add", hook.render) case RemoveHook(hookId) ⇒ notifyVersion("hook_remove", hookId) diff --git a/modules/lobby/src/main/actorApi.scala b/modules/lobby/src/main/actorApi.scala index e046c925d8..d6717f0540 100644 --- a/modules/lobby/src/main/actorApi.scala +++ b/modules/lobby/src/main/actorApi.scala @@ -20,7 +20,7 @@ object Member { case class Connected(enumerator: JsEnumerator, member: Member) case class WithHooks(op: Iterable[String] ⇒ Unit) -case class AddHook(hook: Hook) +case class AddHook(hook: Hook, user: Option[User]) case class RemoveHook(hookId: String) case class CancelHook(uid: String) case class BiteHook(hookId: String, uid: String, userId: Option[String]) diff --git a/modules/setup/src/main/Processor.scala b/modules/setup/src/main/Processor.scala index 0e0a21bad0..dce014b58f 100644 --- a/modules/setup/src/main/Processor.scala +++ b/modules/setup/src/main/Processor.scala @@ -1,9 +1,10 @@ package lila.setup import akka.pattern.ask +import chess.{ Game ⇒ ChessGame, Board, Color ⇒ ChessColor } +import makeTimeout.short import play.api.libs.json.{ Json, JsObject } -import chess.{ Game ⇒ ChessGame, Board, Color ⇒ ChessColor } import lila.ai.Ai import lila.db.api._ import lila.game.tube.gameTube @@ -13,7 +14,6 @@ import lila.i18n.I18nDomain import lila.lobby.actorApi.AddHook import lila.lobby.Hook import lila.user.{ User, Context } -import makeTimeout.short import tube.{ userConfigTube, anonConfigTube } private[setup] final class Processor( @@ -50,12 +50,14 @@ private[setup] final class Processor( friendConfigMemo.set(pov.game.id, config) inject pov } - def hook(config: HookConfig, uid: String, sid: Option[String])(implicit ctx: Context): Funit = { - val hook = config.hook(uid, ctx.me, sid) + def hook( + config: HookConfig, + uid: String, + sid: Option[String], + user: Option[User])(implicit ctx: Context): Funit = saveConfig(_ withHook config) >>- { - lobby ! AddHook(hook) + lobby ! AddHook(config.hook(uid, ctx.me, sid), user) } - } def api(implicit ctx: Context): Fu[JsObject] = { val config = ApiConfig diff --git a/modules/team/src/main/MemberRepo.scala b/modules/team/src/main/MemberRepo.scala index 72794931e9..9e68b2f938 100644 --- a/modules/team/src/main/MemberRepo.scala +++ b/modules/team/src/main/MemberRepo.scala @@ -6,9 +6,6 @@ import reactivemongo.api._ import lila.db.api._ import tube.memberTube -// db.team_member.ensureIndex({team:1}) -// db.team_member.ensureIndex({user:1}) -// db.team_member.ensureIndex({date: -1}) object MemberRepo { type ID = String diff --git a/modules/team/src/main/RequestRepo.scala b/modules/team/src/main/RequestRepo.scala index 6d7f8002dc..a60025a584 100644 --- a/modules/team/src/main/RequestRepo.scala +++ b/modules/team/src/main/RequestRepo.scala @@ -6,8 +6,6 @@ import reactivemongo.api._ import lila.db.api._ import tube.requestTube -// db.team_request.ensureIndex({team:1}) -// db.team_request.ensureIndex({date: -1}) object RequestRepo { type ID = String diff --git a/modules/user/src/main/Confrontation.scala b/modules/user/src/main/Confrontation.scala index 6c991eb4f7..99baef2407 100644 --- a/modules/user/src/main/Confrontation.scala +++ b/modules/user/src/main/Confrontation.scala @@ -1,8 +1,8 @@ package lila.user case class Confrontation( - user1: User, - user2: User, + user1: String, + user2: String, wins: Int, draws: Int, losses: Int) { diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 6113929065..8970fa504a 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -43,15 +43,15 @@ object Dependencies { val jodaTime = "joda-time" % "joda-time" % "2.2" val jodaConvert = "org.joda" % "joda-convert" % "1.3.1" val scalastic = "scalastic" %% "scalastic" % "0.90.0-thib" - val reactivemongo = "org.reactivemongo" %% "reactivemongo" % "0.10.0" - val playReactivemongo = "org.reactivemongo" %% "play2-reactivemongo" % "0.10-THIB" + val reactivemongo = "org.reactivemongo" %% "reactivemongo" % "0.10.5-THIB" + val playReactivemongo = "org.reactivemongo" %% "play2-reactivemongo" % "0.10.5-THIB" object play { - val version = "2.2.0-RC1" + val version = "2.2.0-RC2" val api = "com.typesafe.play" %% "play" % version val test = "com.typesafe.play" %% "play-test" % version } object akka { - val version = "2.1.0" + val version = "2.2.0" val agent = "com.typesafe.akka" %% "akka-agent" % version } object spray { diff --git a/public/javascripts/deps.min.js b/public/javascripts/deps.min.js index 816fbb951f..e0431addc2 100644 --- a/public/javascripts/deps.min.js +++ b/public/javascripts/deps.min.js @@ -20,5 +20,5 @@ // jquery.timeago 1.2.0 https://github.com/rmm5t/jquery-timeago (function(d){"function"===typeof define&&define.amd?define(["jquery"],d):d(jQuery)})(function(d){function l(){var a;a=d(this);if(!a.data("timeago")){a.data("timeago",{datetime:e.datetime(a)});var b=d.trim(a.text());e.settings.localeTitle?a.attr("title",a.data("timeago").datetime.toLocaleString()):0a&&(e=c.prefixFromNow,f=c.suffixFromNow);var h=Math.abs(a)/1E3,g=h/60,m=g/60,k=m/24,l=k/365,h=45>h&&b(c.seconds,Math.round(h))||90>h&&b(c.minute,1)||45>g&&b(c.minutes,Math.round(g))||90>g&&b(c.hour,1)||24>m&&b(c.hours,Math.round(m))||42>m&&b(c.day,1)||30>k&&b(c.days,Math.round(k))||45>k&&b(c.month,1)||365>k&&b(c.months,Math.round(k/30))||1.5>l&&b(c.year,1)||b(c.years,Math.round(l)),g=c.wordSeparator||"";void 0===c.wordSeparator&&(g=" ");return d.trim([e,h,f].join(g))},parse:function(a){a=d.trim(a);a=a.replace(/\.\d+/,"");a=a.replace(/-/,"/").replace(/-/,"/");a=a.replace(/T/," ").replace(/Z/," UTC");a=a.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2");return new Date(a)},datetime:function(a){a=e.isTime(a)?d(a).attr("datetime"):d(a).attr("title");return e.parse(a)},isTime:function(a){return"time"===d(a).get(0).tagName.toLowerCase()}});var n={init:function(){var a=d.proxy(l,this);a();var b=e.settings;0a)return l.idle=!1,clearTimeout(e.idleTimer.tId),d.enabled&&(e.idleTimer.tId=setTimeout(o,d.timeout)),void 0;var m=e.Event(e.data(i,"idleTimer",l.idle?"idle":"active")+".idleTimer");e(i).trigger(m)},m=function(e){var t=e.data("idleTimerObj")||{};t.enabled=!1,clearTimeout(t.tId),e.off(".idleTimer")};if(a.olddate=a.olddate||+new Date,"number"==typeof t)d.timeout=t;else{if("destroy"===t)return m(l),this;if("getElapsedTime"===t)return+new Date-a.olddate}l.on(e.trim((d.events+" ").split(" ").join(".idleTimer ")),function(){var t=e.data(this,"idleTimerObj");clearTimeout(t.tId),t.enabled&&(t.idle&&o(this),t.tId=setTimeout(o,t.timeout))}),a.idle=d.idle,a.enabled=d.enabled,a.timeout=d.timeout,d.startImmediately&&(a.tId=setTimeout(o,a.timeout)),l.data("idleTimer","active"),l.data("idleTimerObj",a)},e.fn.idleTimer=function(t,i){return i||(i={}),this[0]&&e.idleTimer(t,this[0],i),this}})(jQuery); +// Idle Timer - v0.9.3 - 2013-08-04 https://github.com/mikesherov/jquery-idletimer +(function(e){e.idleTimer=function(t,i,d){d=e.extend({startImmediately:!0,idle:!1,enabled:!0,timeout:3e4,events:"mousemove keydown DOMMouseScroll mousewheel mousedown touchstart touchmove"},d),i=i||document;var l=e(i),a=l.data("idleTimerObj")||{},o=function(t){"number"==typeof t&&(t=void 0);var l=e.data(t||i,"idleTimerObj");l.idle=!l.idle;var a=+new Date-l.olddate;if(l.olddate=+new Date,l.idle&&d.timeout>a)return l.idle=!1,clearTimeout(e.idleTimer.tId),d.enabled&&(e.idleTimer.tId=setTimeout(o,d.timeout)),void 0;var m=e.Event(e.data(i,"idleTimer",l.idle?"idle":"active")+".idleTimer");e(i).trigger(m)},m=function(e){var t=e.data("idleTimerObj")||{};t.enabled=!1,clearTimeout(t.tId),e.off(".idleTimer")};if(a.olddate=a.olddate||+new Date,"number"==typeof t)d.timeout=t;else{if("destroy"===t)return m(l),this;if("getElapsedTime"===t)return+new Date-a.olddate}l.on(e.trim((d.events+" ").split(" ").join(".idleTimer ")),function(){var t=e.data(this,"idleTimerObj");clearTimeout(t.tId),t.enabled&&(t.idle&&o(this),t.tId=setTimeout(o,t.timeout))}),a.idle=d.idle,a.enabled=d.enabled,a.timeout=d.timeout,d.startImmediately&&(a.tId=setTimeout(o,a.timeout)),l.data("idleTimer","active"),l.data("idleTimerObj",a)},e.fn.idleTimer=function(t,i){return i||(i={}),this[0]?e.idleTimer(t,this[0],i):this}})(jQuery); diff --git a/todo b/todo index f5003a990e..8f498c88c9 100644 --- a/todo +++ b/todo @@ -42,7 +42,6 @@ the forum search user:mephostophilis returns no result players world map account closed accounts in team counts IE10 no sound toggle http://en.lichess.org/forum/lichess-feedback/notification-of-game-creation#3 -show friend games in homepage board replace plot with watch plot when game starts team search is broken liquid UI for large screens http://fr.lichess.org/forum/lichess-feedback/hi-res#5 @@ -61,5 +60,6 @@ separate games in spectator chat real board editor save clickable mistakes list in analysis FEN/editor castle/enpassant https://github.com/ornicar/lila/issues/42 white/black to play -stupid team forum slug http://ru.lichess.org/forum/team-4epa250h user notes, shared among friends +detect cheat using lichess AI +fix AI protocol