complete team and teamSearch modules
parent
67d3405cc1
commit
ae33c50fcf
|
@ -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]) {
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -2,3 +2,4 @@ package lila.team
|
|||
package actorApi
|
||||
|
||||
case class InsertTeam(team: Team)
|
||||
case class RemoveTeam(id: String)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue