Merge branch 'master' into play22
* master: cache more game collection queries cache confrontation count complete autopairing implementation bs "bosanski jezik" translation #4246. Author: MirhadS. improve autopairing wip implement hook auto pairing disable global wiretap upgrade mongodb driver fix pgn export date format remove index comments upgrade js vendors upgrade reactivemongo Conflicts: project/Dependencies.scalapull/83/head
commit
3894e4fb02
|
@ -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) _
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
@(c: lila.user.Confrontation)(implicit ctx: Context)
|
||||
|
||||
<div class="confrontation boxed_data">
|
||||
<div class="vs">@userLink(c.user1, withElo = false, withOnline = false) vs @userLink(c.user2, withElo = false, withOnline = false)</div>
|
||||
<div class="vs">@userIdLink(c.user1.some, withOnline = false) vs @userIdLink(c.user2.some, withOnline = false)</div>
|
||||
@trans.nbWins("<strong>"+c.wins+"</strong>"),
|
||||
@trans.nbDraws("<strong>"+c.draws+"</strong>"),
|
||||
@trans.nbLosses("<strong>"+c.losses+"</strong>")
|
||||
|
|
134
conf/messages.bs
134
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.
|
||||
|
|
|
@ -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] =
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) ⇒ {
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package lila.user
|
||||
|
||||
case class Confrontation(
|
||||
user1: User,
|
||||
user2: User,
|
||||
user1: String,
|
||||
user2: String,
|
||||
wins: Int,
|
||||
draws: Int,
|
||||
losses: Int) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()):0<b.length&&(!e.isTime(a)||!a.attr("title"))&&a.attr("title",b)}a=a.data("timeago");b=e.settings;isNaN(a.datetime)||(0==b.cutoff||(new Date).getTime()-a.datetime.getTime()<b.cutoff)&&d(this).text(f(a.datetime));return this}function f(a){return e.inWords((new Date).getTime()-a.getTime())}d.timeago=function(a){return a instanceof Date?f(a):"string"===typeof a?f(d.timeago.parse(a)):"number"===typeof a?f(new Date(a)):f(d.timeago.datetime(a))};var e=d.timeago;d.extend(d.timeago,{settings:{refreshMillis:6E4,allowFuture:!1,localeTitle:!1,cutoff:0,strings:{prefixAgo:null,prefixFromNow:null,suffixAgo:"ago",suffixFromNow:"from now",seconds:"less than a minute",minute:"about a minute",minutes:"%d minutes",hour:"about an hour",hours:"about %d hours",day:"a day",days:"%d days",month:"about a month",months:"%d months",year:"about a year",years:"%d years",wordSeparator:" ",numbers:[]}},inWords:function(a){function b(b,e){return(d.isFunction(b)?b(e,a):b).replace(/%d/i,c.numbers&&c.numbers[e]||e)}var c=this.settings.strings,e=c.prefixAgo,f=c.suffixAgo;this.settings.allowFuture&&0>a&&(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;0<b.refreshMillis&&setInterval(a,b.refreshMillis)},update:function(a){d(this).data("timeago",{datetime:e.parse(a)});l.apply(this)}};d.fn.timeago=function(a,b){var c=a?n[a]:n.init;if(!c)throw Error("Unknown function name '"+a+"' for timeago");this.each(function(){c.call(this,b)});return this};document.createElement("abbr");document.createElement("time")});
|
||||
|
||||
// Idle Timer - v0.9.2 - 2013-01-06 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);
|
||||
// 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);
|
||||
|
|
4
todo
4
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
|
||||
|
|
Loading…
Reference in New Issue