complete team and teamSearch modules

pull/83/head
Thibault Duplessis 2013-04-04 11:28:52 -03:00
parent 67d3405cc1
commit ae33c50fcf
8 changed files with 134 additions and 184 deletions

View File

@ -22,8 +22,6 @@ trait PackageObject
with scalaz.Options
with scalaz.OptionTs {
val toVoid = (_: Any) ()
def !![A](msg: String): Valid[A] = msg.failNel[A]
def nowMillis: Double = System.currentTimeMillis
@ -83,7 +81,7 @@ trait WithFuture extends scalaz.Zeros {
def fuccess[A](a: A) = Future successful a
def fufail[A <: Throwable, B](a: A): Fu[B] = Future failed a
def fufail[B](a: String): Fu[B] = Future failed (new RuntimeException(a))
def funit = fuccess(())
val funit = fuccess(())
implicit def LilaFuZero[A: Zero] = new Zero[Fu[A]] { val zero = fuccess([A]) }
@ -104,14 +102,14 @@ trait WithPlay { self: PackageObject ⇒
type SocketFuture = Fu[(Iteratee[JsValue, _], JsEnumerator)]
// Typeclasses
implicit def LilaFutureFunctor = new Functor[Fu] {
implicit val LilaFutureFunctor = new Functor[Fu] {
def fmap[A, B](r: Fu[A], f: A B) = r map f
}
implicit def LilaFutureMonad = new Monad[Fu] {
implicit val LilaFutureMonad = new Monad[Fu] {
def pure[A](a: A) = fuccess(a)
def bind[A, B](r: Fu[A], f: A Fu[B]) = r flatMap f
}
implicit def LilaJsObjectZero = new Zero[JsObject] { val zero = JsObject(Seq.empty) }
implicit val LilaJsObjectZero = new Zero[JsObject] { val zero = JsObject(Seq.empty) }
implicit final class LilaPimpedFuture[A](fua: Fu[A]) {

View File

@ -17,6 +17,7 @@ final class Env(config: Config, system: ActorSystem) {
val messenger = actorFor(config getString "actor.messenger.name")
val router = actorFor(config getString "actor.router.name")
val forum = actorFor(config getString "actor.forum.name")
val teamIndexer = actorFor(config getString "actor.team_indexer.name")
}
val sockets = system.actorOf(Props(new Broadcast(List(

View File

@ -1,72 +0,0 @@
package lila.app
package team
import core.Settings
import site.Captcha
import user.UserRepo
import message.LichessThread
import forum.{ Categ, PostLiteView }
import com.mongodb.casbah.MongoCollection
import scalastic.elasticsearch.{ Indexer EsIndexer }
import scalaz.effects._
final class TeamEnv(
settings: Settings,
esIndexer: EsIndexer,
captcha: Captcha,
userRepo: UserRepo,
sendMessage: LichessThread IO[Unit],
makeForum: (String, String) IO[Unit],
getForumNbPosts: String IO[Int],
getForumPosts: String IO[List[PostLiteView]],
mongodb: String MongoCollection) {
import settings._
lazy val indexer = new SearchIndexer(es = esIndexer, teamRepo = teamRepo)
lazy val teamRepo = new TeamRepo(mongodb(TeamCollectionTeam))
lazy val memberRepo = new MemberRepo(mongodb(TeamCollectionMember))
lazy val requestRepo = new RequestRepo(mongodb(TeamCollectionRequest))
private lazy val messenger = new TeamMessenger(
send = sendMessage,
netBaseUrl = NetBaseUrl)
lazy val paginator = new PaginatorBuilder(
memberRepo = memberRepo,
teamRepo = teamRepo,
userRepo = userRepo,
maxPerPage = TeamPaginatorMaxPerPage,
maxUserPerPage = TeamPaginatorMaxUserPerPage)
lazy val searchPaginator = new SearchPaginatorBuilder(
indexer = indexer,
maxPerPage = TeamPaginatorMaxPerPage)
lazy val api = new TeamApi(
teamRepo = teamRepo,
memberRepo = memberRepo,
requestRepo = requestRepo,
cached = cached,
userRepo = userRepo,
messenger = messenger,
makeForum = makeForum,
paginator = paginator,
indexer = indexer)
lazy val teamInfo = TeamInfo(
api = api,
memberRepo = memberRepo,
requestRepo = requestRepo,
userRepo = userRepo,
getForumNbPosts = getForumNbPosts,
getForumPosts = getForumPosts) _
lazy val forms = new DataForm(teamRepo, captcha)
lazy val cached = new Cached(teamRepo, memberRepo, requestRepo)
}

View File

@ -10,6 +10,7 @@ final class Env(
messenger: ActorRef,
router: ActorRef,
forum: ActorRef,
indexer: ActorRef,
db: lila.db.Env) {
private val settings = new {
@ -24,11 +25,21 @@ final class Env(
lazy val forms = new DataForm(captcher)
lazy val api = new TeamApi(
cached = cached,
notifier = notifier,
forum = forum,
paginator = paginator,
indexer = indexer)
private[team] lazy val teamColl = db(CollectionTeam)
private[team] lazy val requestColl = db(CollectionRequest)
private[team] lazy val memberColl = db(CollectionMember)
private[team] lazy val cached = new Cached(CacheCapacity)
private[team] lazy val paginator = new PaginatorBuilder(
maxPerPage = PaginatorMaxPerPage,
maxUserPerPage = PaginatorMaxUserPerPage)
private lazy val notifier = new Notifier(
messenger = messenger,
@ -45,5 +56,6 @@ object Env {
messenger = actors.messenger,
router = actors.router,
forum = actors.forum,
indexer = actors.teamIndexer,
db = lila.db.Env.current)
}

View File

@ -30,6 +30,12 @@ private[team] object MemberRepo {
def exists(teamId: ID, userId: ID): Fu[Boolean] =
$count.exists(selectId(teamId, userId))
def add(teamId: String, userId: String): Funit =
$insert(Member.make(team = teamId, user = userId))
def remove(teamId: String, userId: String): Funit =
$remove(selectId(teamId, userId))
def selectId(teamId: ID, userId: ID) = $select(Member.makeId(teamId, userId))
def teamQuery(teamId: ID) = Json.obj("team" -> teamId)
def userQuery(userId: ID) = Json.obj("user" -> userId)

View File

@ -2,139 +2,142 @@ package lila.team
import org.scala_tools.time.Imports._
import akka.actor.ActorRef
import play.api.libs.concurrent.Execution.Implicits._
import lila.user.{ User, Context }
import lila.user.tube.userTube
import tube._
import actorApi._
import lila.hub.actorApi.forum.MakeTeam
import lila.db.api._
final class TeamApi(
cached: Cached,
notifier: Notifier,
forum: ActorRef,
paginator: PaginatorBuilder) { //, indexer: SearchIndexer) {
paginator: PaginatorBuilder,
indexer: ActorRef) {
val creationPeriod = 1.week
// def create(setup: TeamSetup, me: User): Option[IO[Team]] = me.canTeam option {
// val s = setup.trim
// val team = Team(
// name = s.name,
// location = s.location,
// description = s.description,
// open = s.isOpen,
// createdBy = me)
// (teamRepo saveIO team) >>
// memberRepo.add(team.id, me.id) >>
// io(cached invalidateTeamIds me.id) >>
// makeForum(team.id, team.name) >>
// (indexer insertOne team) inject team
// }
def create(setup: TeamSetup, me: User): Option[Fu[Team]] = me.canTeam option {
val s = setup.trim
val team = Team.make(
name = s.name,
location = s.location,
description = s.description,
open = s.isOpen,
createdBy = me)
$insert(team) >>
MemberRepo.add(team.id, me.id) >>
(cached.teamIds invalidate me.id) >>
(forum ! MakeTeam(team.id, team.name)) >>
(indexer ! InsertTeam(team)) inject team
}
// def update(team: Team, edit: TeamEdit, me: User): IO[Unit] = edit.trim |> { e
// team.copy(
// location = e.location,
// description = e.description,
// open = e.isOpen
// ) |> { team teamRepo.saveIO(team) >> indexer.insertOne(team) }
// }
def update(team: Team, edit: TeamEdit, me: User): Funit = edit.trim |> { e
team.copy(
location = e.location,
description = e.description,
open = e.isOpen
) |> { team $update(team) >> (indexer ! InsertTeam(team)) }
}
// def mine(me: User): IO[List[Team]] = for {
// teamIds memberRepo teamIdsByUserId me.id
// teams teamRepo byOrderedIds teamIds
// } yield teams
def mine(me: User): Fu[List[Team]] =
cached teamIds me.id flatMap $find.byOrderedIds[Team]
// def hasCreatedRecently(me: User): IO[Boolean] =
// teamRepo.userHasCreatedSince(me.id, creationPeriod)
def hasCreatedRecently(me: User): Fu[Boolean] =
TeamRepo.userHasCreatedSince(me.id, creationPeriod)
// def requestsWithUsers(team: Team): IO[List[RequestWithUser]] = for {
// requests requestRepo findByTeamId team.id
// users userRepo byOrderedIds requests.map(_.user)
// } yield requests zip users map {
// case (request, user) RequestWithUser(request, user)
// }
def requestsWithUsers(team: Team): Fu[List[RequestWithUser]] = for {
requests RequestRepo findByTeam team.id
users $find.byOrderedIds[User](requests map (_.user))
} yield requests zip users map {
case (request, user) RequestWithUser(request, user)
}
// def requestsWithUsers(user: User): IO[List[RequestWithUser]] = for {
// teamIds teamRepo teamIdsByCreator user.id
// requests requestRepo findByTeamIds teamIds
// users userRepo byOrderedIds requests.map(_.user)
// } yield requests zip users map {
// case (request, user) RequestWithUser(request, user)
// }
def requestsWithUsers(user: User): Fu[List[RequestWithUser]] = for {
teamIds TeamRepo teamIdsByCreator user.id
requests RequestRepo findByTeams teamIds
users $find.byOrderedIds[User](requests map (_.user))
} yield requests zip users map {
case (request, user) RequestWithUser(request, user)
}
// def join(teamId: String)(implicit ctx: Context): IO[Option[Requesting]] = for {
// teamOption teamRepo byId teamId
// result ~(teamOption |@| ctx.me.filter(_.canTeam))({
// case (team, user) if team.open
// (doJoin(team, user.id) inject Joined(team).some): IO[Option[Requesting]]
// case (team, user)
// io(Motivate(team).some: Option[Requesting])
// })
// } yield result
def join(teamId: String)(implicit ctx: Context): Fu[Option[Requesting]] = for {
teamOption $find.byId[Team](teamId)
result ~(teamOption |@| ctx.me.filter(_.canTeam))({
case (team, user) if team.open
(doJoin(team, user.id) inject Joined(team).some): Fu[Option[Requesting]]
case (team, user)
fuccess(Motivate(team).some: Option[Requesting])
})
} yield result
// def requestable(teamId: String, user: User): IO[Option[Team]] = for {
// teamOption teamRepo byId teamId
// able ~teamOption.map(requestable(_, user))
// } yield teamOption filter (_ able)
def requestable(teamId: String, user: User): Fu[Option[Team]] = for {
teamOption $find.byId[Team](teamId)
able teamOption.zmap(requestable(_, user))
} yield teamOption filter (_ able)
// def requestable(team: Team, user: User): IO[Boolean] =
// requestRepo.exists(team.id, user.id) map { exists
// !exists && !belongsTo(team.id, user.id)
// }
def requestable(team: Team, user: User): Fu[Boolean] =
RequestRepo.exists(team.id, user.id) zip belongsTo(team.id, user.id) map {
case (false, false) true
case _ false
}
// def createRequest(team: Team, setup: RequestSetup, user: User): IO[Unit] = for {
// able requestable(team, user)
// request = Request(team = team.id, user = user.id, message = setup.message)
// rwu = RequestWithUser(request, user)
// _ {
// requestRepo.add(request) >>
// io(cached invalidateNbRequests team.createdBy)
// } doIf able
// } yield ()
def createRequest(team: Team, setup: RequestSetup, user: User): Funit =
requestable(team, user) flatMap { able
val request = Request.make(team = team.id, user = user.id, message = setup.message)
val rwu = RequestWithUser(request, user)
$insert(request) >> (cached.nbRequests invalidate team.createdBy) doIf able
}
// def processRequest(team: Team, request: Request, accept: Boolean): IO[Unit] = for {
// _ requestRepo remove request.id
// _ io(cached invalidateNbRequests team.createdBy)
// userOption userRepo byId request.user
// _ ~userOption.map(user
// (doJoin(team, user.id) >> messenger.acceptRequest(team, request)) doIf accept
// )
// } yield ()
def processRequest(team: Team, request: Request, accept: Boolean): Funit = for {
_ $remove(request)
_ cached.nbRequests invalidate team.createdBy
userOption $find.byId[User](request.user)
_ userOption.zmap(user
doJoin(team, user.id) >> notifier.acceptRequest(team, request) doIf accept
)
} yield ()
// def doJoin(team: Team, userId: String): IO[Unit] = {
// memberRepo.add(team.id, userId) >>
// teamRepo.incMembers(team.id, +1) >>
// io(cached invalidateTeamIds userId)
// } doUnless belongsTo(team.id, userId)
def doJoin(team: Team, userId: String): Funit =
belongsTo(team.id, userId) flatMap { belongs
MemberRepo.add(team.id, userId) >>
TeamRepo.incMembers(team.id, +1) >>
(cached.teamIds invalidate userId) doUnless belongs
}
// def quit(teamId: String)(implicit ctx: Context): IO[Option[Team]] = for {
// teamOption teamRepo byId teamId
// result ~(teamOption |@| ctx.me)({
// case (team, user) doQuit(team, user.id) inject team.some
// })
// } yield result
def quit(teamId: String)(implicit ctx: Context): Fu[Option[Team]] = for {
teamOption $find.byId[Team](teamId)
result ~(teamOption |@| ctx.me)({
case (team, user) doQuit(team, user.id) inject team.some
})
} yield result
// def doQuit(team: Team, userId: String): IO[Unit] = {
// memberRepo.remove(team.id, userId) >>
// teamRepo.incMembers(team.id, -1) >>
// io(cached invalidateTeamIds userId)
// } doIf belongsTo(team.id, userId)
def doQuit(team: Team, userId: String): Funit =
belongsTo(team.id, userId) flatMap { belongs
MemberRepo.remove(team.id, userId) >>
TeamRepo.incMembers(team.id, -1) >>
(cached.teamIds invalidate userId) doIf belongs
}
// def quitAll(userId: String): IO[Unit] = memberRepo.removeByUserId(userId)
def quitAll(userId: String): Funit = MemberRepo.removeByUser(userId)
// def kick(team: Team, userId: String): IO[Unit] = doQuit(team, userId)
def kick(team: Team, userId: String): Funit = doQuit(team, userId)
// def enable(team: Team): IO[Unit] =
// teamRepo.enable(team) >> indexer.insertOne(team)
def enable(team: Team): Funit =
TeamRepo.enable(team) >> (indexer ! InsertTeam(team))
// def disable(team: Team): IO[Unit] =
// teamRepo.disable(team) >> indexer.removeOne(team)
def disable(team: Team): Funit =
TeamRepo.disable(team) >> (indexer ! RemoveTeam(team.id))
// // delete for ever, with members but not forums
// def delete(team: Team): IO[Unit] =
// teamRepo.removeIO(team) >>
// memberRepo.removeByteamId(team.id) >>
// indexer.removeOne(team)
// // delete for ever, with members but not forums
def delete(team: Team): Funit =
$remove(team) >>
MemberRepo.removeByteam(team.id) >>
(indexer ! RemoveTeam(team.id))
// def belongsTo(teamId: String, userId: String): Boolean =
// cached teamIds userId contains teamId
def belongsTo(teamId: String, userId: String): Fu[Boolean] =
cached teamIds userId map (_ contains teamId)
}

View File

@ -2,3 +2,4 @@ package lila.team
package actorApi
case class InsertTeam(team: Team)
case class RemoveTeam(id: String)

View File

@ -11,7 +11,8 @@ private[teamSearch] final class Indexer(lowLevel: ActorRef) extends Actor {
def receive = {
case InsertTeam(team)
lowLevel ! S.InsertOne(team.id, Team from team)
case InsertTeam(team) lowLevel ! S.InsertOne(team.id, Team from team)
case RemoveTeam(id) lowLevel ! S.RemoveOne(id)
}
}