diff --git a/app/controllers/User.scala b/app/controllers/User.scala index 401e01a657..8ed284adff 100644 --- a/app/controllers/User.scala +++ b/app/controllers/User.scala @@ -22,6 +22,7 @@ object User extends LilaController { def bookmarkApi = env.bookmark.api def securityStore = env.security.store def firewall = env.security.firewall + def modlogApi = env.modlog.api def show(username: String) = showFilter(username, "all", 1) @@ -93,9 +94,17 @@ object User extends LilaController { } def engine(username: String) = Secure(Permission.MarkEngine) { _ ⇒ - _ ⇒ + me ⇒ IORedirect { - eloUpdater adjust username map { _ ⇒ routes.User show username } + for { + userOption ← userRepo byId username + _ ← userOption.fold( + user ⇒ for { + _ ← eloUpdater adjust user + _ ← modlogApi.engine(me, user, !user.engine) + } yield (), + io()) + } yield routes.User show username } } diff --git a/app/core/CoreEnv.scala b/app/core/CoreEnv.scala index a2b87b2e2e..b916800626 100644 --- a/app/core/CoreEnv.scala +++ b/app/core/CoreEnv.scala @@ -129,10 +129,14 @@ final class CoreEnv private (application: Application, val settings: Settings) { mongodb = mongodb.connection, settings = settings) - lazy val titivate = new core.Titivate( + lazy val titivate = new lila.core.Titivate( gameRepo = game.gameRepo, finisher = round.finisher, bookmarkApi = bookmark.api) + + lazy val modlog = new lila.modlog.ModlogEnv( + settings = settings, + mongodb = mongodb.apply _) } object CoreEnv { diff --git a/app/core/Settings.scala b/app/core/Settings.scala index df3c57e0e4..d3d6a23d39 100644 --- a/app/core/Settings.scala +++ b/app/core/Settings.scala @@ -121,6 +121,8 @@ final class Settings(config: Config) { val ActorLobbyHub = "lobby_hub" val ActorMonitorHub = "monitor_hub" + val ModlogCollectionModlog = getString("modlog.collection.modlog") + private def millis(name: String): Int = getMilliseconds(name).toInt private def seconds(name: String): Int = millis(name) / 1000 diff --git a/app/elo/EloUpdater.scala b/app/elo/EloUpdater.scala index 602877834b..60f7953979 100644 --- a/app/elo/EloUpdater.scala +++ b/app/elo/EloUpdater.scala @@ -20,17 +20,12 @@ final class EloUpdater( val adjustTo = User.STARTING_ELO - def adjust(username: String) = for { - uOption ← userRepo byId username - _ ← uOption.fold( - u ⇒ for { - _ ← userRepo toggleEngine u.id - _ ← (!u.engine && u.elo > adjustTo).fold( - userRepo.setElo(u.id, adjustTo) flatMap { _ ⇒ - historyRepo.addEntry(u.id, adjustTo, entryType = HistoryRepo.TYPE_ADJUST) - }, - io()) - } yield (), + def adjust(u: User) = for { + _ ← userRepo toggleEngine u.id + _ ← (!u.engine && u.elo > adjustTo).fold( + userRepo.setElo(u.id, adjustTo) flatMap { _ ⇒ + historyRepo.addEntry(u.id, adjustTo, entryType = HistoryRepo.TYPE_ADJUST) + }, io()) } yield () } diff --git a/app/modlog/Modlog.scala b/app/modlog/Modlog.scala new file mode 100644 index 0000000000..1b4d57c738 --- /dev/null +++ b/app/modlog/Modlog.scala @@ -0,0 +1,23 @@ +package lila +package modlog + +import user.User + +import org.joda.time.DateTime +import org.scala_tools.time.Imports._ + +case class Modlog( + mod: String, + user: Option[String], + action: String, + date: DateTime = DateTime.now) + +object Modlog { + + val engine = "engine" + val unengine = "un-engine" + val mute = "mute" + val unmute = "un-mute" + val ipban = "ipban" + val deletePost = "remove post" +} diff --git a/app/modlog/ModlogApi.scala b/app/modlog/ModlogApi.scala new file mode 100644 index 0000000000..90112e2241 --- /dev/null +++ b/app/modlog/ModlogApi.scala @@ -0,0 +1,15 @@ +package lila +package modlog + +import user.User + +import scalaz.effects._ + +final class ModlogApi(repo: ModlogRepo) { + + def engine(mod: User, user: User, v: Boolean) = add { + Modlog(mod.id, user.id.some, v.fold(Modlog.engine, Modlog.unengine)).pp + } + + private def add(modLog: Modlog): IO[Unit] = repo saveIO modLog +} diff --git a/app/modlog/ModlogEnv.scala b/app/modlog/ModlogEnv.scala new file mode 100644 index 0000000000..825ed0bc39 --- /dev/null +++ b/app/modlog/ModlogEnv.scala @@ -0,0 +1,18 @@ +package lila +package modlog + +import com.mongodb.casbah.MongoCollection + +import core.Settings + +final class ModlogEnv( + settings: Settings, + mongodb: String ⇒ MongoCollection) { + + import settings._ + + lazy val modlogRepo = new ModlogRepo(mongodb(ModlogCollectionModlog)) + + lazy val api = new ModlogApi( + repo = modlogRepo) +} diff --git a/app/modlog/ModlogRepo.scala b/app/modlog/ModlogRepo.scala new file mode 100644 index 0000000000..8097a69dd8 --- /dev/null +++ b/app/modlog/ModlogRepo.scala @@ -0,0 +1,18 @@ +package lila +package modlog + +import user.User + +import com.novus.salat._ +import com.novus.salat.dao._ +import com.mongodb.casbah.{ MongoCollection, WriteConcern } +import com.mongodb.casbah.Imports._ +import scalaz.effects._ + +class ModlogRepo(collection: MongoCollection) + extends SalatDAO[Modlog, String](collection) { + + def saveIO(modlog: Modlog): IO[Unit] = io { + save(modlog) + } +} diff --git a/app/security/Flood.scala b/app/security/Flood.scala index 068aff2460..306f7a4af0 100644 --- a/app/security/Flood.scala +++ b/app/security/Flood.scala @@ -18,7 +18,6 @@ final class Flood { } type Messages = List[Message] - // uid, [date, message] private val messages = Builder.expiry[String, Messages](ttl) def filterMessage[A](uid: String, text: String)(op: ⇒ Unit) { diff --git a/conf/application.conf b/conf/application.conf index fda84b9b3f..f141bf1118 100644 --- a/conf/application.conf +++ b/conf/application.conf @@ -20,6 +20,9 @@ analyse { security { collection.security = security } +modlog { + collection.modlog = modlog +} firewall { enabled=true block_cookie=fEKHA4zI23ZrZrom diff --git a/todo b/todo index 8cf2b86e5d..0e09c6d158 100644 --- a/todo +++ b/todo @@ -31,11 +31,14 @@ move while disconnected = move lost. should reload the page on ack timeout. finish games per day chart untranslated = https://github.com/ornicar/lila/issues/4 list of adjustments -disable pgn4web onboard features game stats timeline issues http://en.lichess.org/forum/lichess-feedback/move-times propagate IP ban to the user -verify firewall cookie is persistent +forum post IP ban admin ip search interface analyse: show main line for every move http://en.lichess.org/forum/lichess-feedback/about-the-analysis-feature#5 show victory in analysis page + other suggestions http://en.lichess.org/forum/lichess-feedback/a-couple-of-feature-requests#2 only one stockfish instance for moves and analysis. Use a todo with two queues. + +next deploy +----------- +db.createCollection("modlog",{capped:true, size: 1000000})