2013-04-02 09:45:45 -06:00
|
|
|
package lila.team
|
|
|
|
|
2013-04-04 08:28:52 -06:00
|
|
|
import actorApi._
|
2013-09-19 13:27:19 -06:00
|
|
|
import akka.actor.ActorSelection
|
2016-04-01 11:50:57 -06:00
|
|
|
import lila.db.dsl._
|
2017-08-06 01:40:37 -06:00
|
|
|
import lila.hub.actorApi.team.{ CreateTeam, JoinTeam }
|
2013-05-24 14:37:27 -06:00
|
|
|
import lila.hub.actorApi.timeline.{ Propagate, TeamJoin, TeamCreate }
|
2018-07-05 14:39:57 -06:00
|
|
|
import lila.mod.ModlogApi
|
2016-04-01 22:57:54 -06:00
|
|
|
import lila.user.{ User, UserRepo, UserContext }
|
2015-12-06 09:09:16 -07:00
|
|
|
import org.joda.time.Period
|
2018-07-21 03:05:05 -06:00
|
|
|
import reactivemongo.api.{ Cursor, ReadPreference }
|
2013-04-02 09:45:45 -06:00
|
|
|
|
2013-04-03 11:12:38 -06:00
|
|
|
final class TeamApi(
|
2016-04-01 22:57:54 -06:00
|
|
|
coll: Colls,
|
2013-04-03 11:12:38 -06:00
|
|
|
cached: Cached,
|
|
|
|
notifier: Notifier,
|
2017-08-06 01:40:37 -06:00
|
|
|
bus: lila.common.Bus,
|
2013-09-19 13:27:19 -06:00
|
|
|
indexer: ActorSelection,
|
2018-07-05 14:39:57 -06:00
|
|
|
timeline: ActorSelection,
|
|
|
|
modLog: ModlogApi
|
2017-02-14 08:34:07 -07:00
|
|
|
) {
|
2013-04-02 09:45:45 -06:00
|
|
|
|
2016-04-01 22:57:54 -06:00
|
|
|
import BSONHandlers._
|
|
|
|
|
2014-11-15 06:53:01 -07:00
|
|
|
val creationPeriod = Period weeks 1
|
2013-04-02 09:45:45 -06:00
|
|
|
|
2019-07-08 11:59:39 -06:00
|
|
|
def team(id: Team.ID) = coll.team.byId[Team](id)
|
2013-05-06 14:49:12 -06:00
|
|
|
|
2019-07-08 11:59:39 -06:00
|
|
|
def request(id: Team.ID) = coll.request.byId[Request](id)
|
2013-05-06 14:49:12 -06:00
|
|
|
|
2013-04-04 08:28:52 -06:00
|
|
|
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,
|
2017-02-14 08:34:07 -07:00
|
|
|
createdBy = me
|
|
|
|
)
|
2016-04-01 22:57:54 -06:00
|
|
|
coll.team.insert(team) >>
|
2014-04-18 03:51:19 -06:00
|
|
|
MemberRepo.add(team.id, me.id) >>- {
|
2017-08-06 01:40:37 -06:00
|
|
|
cached invalidateTeamIds me.id
|
|
|
|
indexer ! InsertTeam(team)
|
|
|
|
timeline ! Propagate(
|
2014-04-18 03:51:19 -06:00
|
|
|
TeamCreate(me.id, team.id)
|
2017-08-06 01:40:37 -06:00
|
|
|
).toFollowersOf(me.id)
|
|
|
|
bus.publish(CreateTeam(id = team.id, name = team.name, userId = me.id), 'team)
|
2014-04-18 03:51:19 -06:00
|
|
|
} inject team
|
2013-04-04 08:28:52 -06:00
|
|
|
}
|
|
|
|
|
2014-02-17 02:12:19 -07:00
|
|
|
def update(team: Team, edit: TeamEdit, me: User): Funit = edit.trim |> { e =>
|
2013-04-04 08:28:52 -06:00
|
|
|
team.copy(
|
|
|
|
location = e.location,
|
|
|
|
description = e.description,
|
2017-02-14 08:34:07 -07:00
|
|
|
open = e.isOpen
|
|
|
|
) |> { team =>
|
2018-07-05 14:39:57 -06:00
|
|
|
coll.team.update($id(team.id), team).void >>
|
|
|
|
!team.isCreator(me.id) ?? {
|
|
|
|
modLog.teamEdit(me.id, team.createdBy, team.name)
|
|
|
|
} >>-
|
|
|
|
(indexer ! InsertTeam(team))
|
2017-01-25 03:41:08 -07:00
|
|
|
}
|
2013-04-04 08:28:52 -06:00
|
|
|
}
|
|
|
|
|
2017-01-25 03:41:08 -07:00
|
|
|
def mine(me: User): Fu[List[Team]] =
|
2017-03-25 05:17:03 -06:00
|
|
|
cached teamIds me.id flatMap { ids => coll.team.byIds[Team](ids.toArray) }
|
2013-04-04 08:28:52 -06:00
|
|
|
|
2017-02-05 04:11:03 -07:00
|
|
|
def hasTeams(me: User): Fu[Boolean] = cached.teamIds(me.id).map(_.value.nonEmpty)
|
2015-09-09 09:32:49 -06:00
|
|
|
|
2013-04-04 08:28:52 -06:00
|
|
|
def hasCreatedRecently(me: User): Fu[Boolean] =
|
|
|
|
TeamRepo.userHasCreatedSince(me.id, creationPeriod)
|
|
|
|
|
|
|
|
def requestsWithUsers(team: Team): Fu[List[RequestWithUser]] = for {
|
|
|
|
requests ← RequestRepo findByTeam team.id
|
2017-03-25 05:23:01 -06:00
|
|
|
users ← UserRepo usersFromSecondary requests.map(_.user)
|
2013-04-04 08:28:52 -06:00
|
|
|
} yield requests zip users map {
|
2014-02-17 02:12:19 -07:00
|
|
|
case (request, user) => RequestWithUser(request, user)
|
2013-04-04 08:28:52 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
def requestsWithUsers(user: User): Fu[List[RequestWithUser]] = for {
|
|
|
|
teamIds ← TeamRepo teamIdsByCreator user.id
|
|
|
|
requests ← RequestRepo findByTeams teamIds
|
2017-03-25 05:23:01 -06:00
|
|
|
users ← UserRepo usersFromSecondary requests.map(_.user)
|
2013-04-04 08:28:52 -06:00
|
|
|
} yield requests zip users map {
|
2014-02-17 02:12:19 -07:00
|
|
|
case (request, user) => RequestWithUser(request, user)
|
2013-04-04 08:28:52 -06:00
|
|
|
}
|
|
|
|
|
2019-07-16 12:03:10 -06:00
|
|
|
def join(teamId: Team.ID, me: User): Fu[Option[Requesting]] =
|
|
|
|
coll.team.byId[Team](teamId) flatMap {
|
|
|
|
_ ?? { team =>
|
|
|
|
if (team.open) doJoin(team, me) inject Joined(team).some
|
|
|
|
else fuccess(Motivate(team).some)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
def joinApi(teamId: Team.ID, me: User, oAuthAppOwner: User.ID): Fu[Option[Requesting]] =
|
|
|
|
coll.team.byId[Team](teamId) flatMap {
|
|
|
|
_ ?? { team =>
|
|
|
|
if (team.open || team.createdBy == oAuthAppOwner) doJoin(team, me) inject Joined(team).some
|
|
|
|
else fuccess(Motivate(team).some)
|
|
|
|
}
|
|
|
|
}
|
2013-04-04 08:28:52 -06:00
|
|
|
|
2019-07-08 11:59:39 -06:00
|
|
|
def requestable(teamId: Team.ID, user: User): Fu[Option[Team]] = for {
|
2016-04-01 22:57:54 -06:00
|
|
|
teamOption ← coll.team.byId[Team](teamId)
|
2013-05-17 18:09:35 -06:00
|
|
|
able ← teamOption.??(requestable(_, user))
|
2014-02-17 02:12:19 -07:00
|
|
|
} yield teamOption filter (_ => able)
|
2013-04-04 08:28:52 -06:00
|
|
|
|
2017-01-25 03:41:08 -07:00
|
|
|
def requestable(team: Team, user: User): Fu[Boolean] = for {
|
|
|
|
belongs <- belongsTo(team.id, user.id)
|
|
|
|
requested <- RequestRepo.exists(team.id, user.id)
|
|
|
|
} yield !belongs && !requested
|
2013-04-04 08:28:52 -06:00
|
|
|
|
|
|
|
def createRequest(team: Team, setup: RequestSetup, user: User): Funit =
|
2013-05-11 15:45:39 -06:00
|
|
|
requestable(team, user) flatMap {
|
|
|
|
_ ?? {
|
|
|
|
val request = Request.make(team = team.id, user = user.id, message = setup.message)
|
2017-01-26 16:23:43 -07:00
|
|
|
coll.request.insert(request).void >>- (cached.nbRequests invalidate team.createdBy)
|
2013-05-11 15:45:39 -06:00
|
|
|
}
|
2013-04-04 08:28:52 -06:00
|
|
|
}
|
|
|
|
|
2013-05-11 15:45:39 -06:00
|
|
|
def processRequest(team: Team, request: Request, accept: Boolean): Funit = for {
|
2016-04-01 22:57:54 -06:00
|
|
|
_ ← coll.request.remove(request)
|
2017-01-26 16:23:43 -07:00
|
|
|
_ = cached.nbRequests invalidate team.createdBy
|
2016-04-01 22:57:54 -06:00
|
|
|
userOption ← UserRepo byId request.user
|
2014-02-17 02:12:19 -07:00
|
|
|
_ ← userOption.filter(_ => accept).??(user =>
|
2019-07-16 12:03:10 -06:00
|
|
|
doJoin(team, user) >>- notifier.acceptRequest(team, request))
|
2013-05-11 15:45:39 -06:00
|
|
|
} yield ()
|
2013-04-04 08:28:52 -06:00
|
|
|
|
2017-10-30 09:31:27 -06:00
|
|
|
def deleteRequestsByUserId(userId: lila.user.User.ID) =
|
|
|
|
RequestRepo.getByUserId(userId) flatMap {
|
|
|
|
_.map { request =>
|
|
|
|
RequestRepo.remove(request.id) >>
|
|
|
|
TeamRepo.creatorOf(request.team).map { _ ?? cached.nbRequests.invalidate }
|
|
|
|
}.sequenceFu
|
|
|
|
}
|
|
|
|
|
2019-07-16 12:03:10 -06:00
|
|
|
def doJoin(team: Team, user: User): Funit = !belongsTo(team.id, user.id) flatMap {
|
2017-01-25 03:41:08 -07:00
|
|
|
_ ?? {
|
2019-07-16 12:03:10 -06:00
|
|
|
MemberRepo.add(team.id, user.id) >>
|
2017-01-25 03:41:08 -07:00
|
|
|
TeamRepo.incMembers(team.id, +1) >>- {
|
2019-07-16 12:03:10 -06:00
|
|
|
cached invalidateTeamIds user.id
|
|
|
|
timeline ! Propagate(TeamJoin(user.id, team.id)).toFollowersOf(user.id)
|
|
|
|
bus.publish(JoinTeam(id = team.id, userId = user.id), 'team)
|
2017-01-25 03:41:08 -07:00
|
|
|
}
|
2017-02-01 05:56:47 -07:00
|
|
|
} recover lila.db.recoverDuplicateKey(_ => ())
|
2017-01-25 03:41:08 -07:00
|
|
|
}
|
2013-04-04 08:28:52 -06:00
|
|
|
|
2019-07-08 11:59:39 -06:00
|
|
|
def quit(teamId: Team.ID)(implicit ctx: UserContext): Fu[Option[Team]] = for {
|
2016-04-01 22:57:54 -06:00
|
|
|
teamOption ← coll.team.byId[Team](teamId)
|
2013-04-04 08:28:52 -06:00
|
|
|
result ← ~(teamOption |@| ctx.me)({
|
2014-02-17 02:12:19 -07:00
|
|
|
case (team, user) => doQuit(team, user.id) inject team.some
|
2013-04-04 08:28:52 -06:00
|
|
|
})
|
|
|
|
} yield result
|
|
|
|
|
2019-07-08 11:59:39 -06:00
|
|
|
def doQuit(team: Team, userId: User.ID): Funit = belongsTo(team.id, userId) flatMap {
|
2017-01-25 03:41:08 -07:00
|
|
|
_ ?? {
|
|
|
|
MemberRepo.remove(team.id, userId) >>
|
|
|
|
TeamRepo.incMembers(team.id, -1) >>-
|
|
|
|
(cached invalidateTeamIds userId)
|
|
|
|
}
|
2014-04-18 03:51:19 -06:00
|
|
|
}
|
2013-04-04 08:28:52 -06:00
|
|
|
|
2019-07-08 11:59:39 -06:00
|
|
|
def quitAll(userId: User.ID): Funit = MemberRepo.removeByUser(userId)
|
2013-04-04 08:28:52 -06:00
|
|
|
|
2019-07-08 11:59:39 -06:00
|
|
|
def kick(team: Team, userId: User.ID, me: User): Funit =
|
2018-07-05 14:39:57 -06:00
|
|
|
doQuit(team, userId) >>
|
|
|
|
!team.isCreator(me.id) ?? {
|
|
|
|
modLog.teamKick(me.id, userId, team.name)
|
|
|
|
}
|
2013-04-04 08:28:52 -06:00
|
|
|
|
2019-07-08 11:59:39 -06:00
|
|
|
def changeOwner(team: Team, userId: User.ID, me: User): Funit =
|
2018-07-06 08:55:11 -06:00
|
|
|
MemberRepo.exists(team.id, userId) flatMap { e =>
|
|
|
|
e ?? {
|
|
|
|
TeamRepo.changeOwner(team.id, userId) >>
|
|
|
|
modLog.teamMadeOwner(me.id, userId, team.name) >>-
|
|
|
|
notifier.madeOwner(team, userId)
|
|
|
|
}
|
|
|
|
}
|
2018-07-03 15:00:32 -06:00
|
|
|
|
2013-04-04 08:28:52 -06:00
|
|
|
def enable(team: Team): Funit =
|
2016-04-01 22:57:54 -06:00
|
|
|
TeamRepo.enable(team).void >>- (indexer ! InsertTeam(team))
|
2013-04-04 08:28:52 -06:00
|
|
|
|
|
|
|
def disable(team: Team): Funit =
|
2016-04-01 22:57:54 -06:00
|
|
|
TeamRepo.disable(team).void >>- (indexer ! RemoveTeam(team.id))
|
2013-04-04 08:28:52 -06:00
|
|
|
|
2013-05-28 07:53:32 -06:00
|
|
|
// delete for ever, with members but not forums
|
2013-04-04 08:28:52 -06:00
|
|
|
def delete(team: Team): Funit =
|
2016-04-01 22:57:54 -06:00
|
|
|
coll.team.remove($id(team.id)) >>
|
2013-05-06 07:48:05 -06:00
|
|
|
MemberRepo.removeByteam(team.id) >>-
|
2013-04-04 08:28:52 -06:00
|
|
|
(indexer ! RemoveTeam(team.id))
|
|
|
|
|
2019-07-08 11:59:39 -06:00
|
|
|
def syncBelongsTo(teamId: Team.ID, userId: User.ID): Boolean =
|
2017-01-25 03:41:08 -07:00
|
|
|
cached.syncTeamIds(userId) contains teamId
|
|
|
|
|
2019-07-08 11:59:39 -06:00
|
|
|
def belongsTo(teamId: Team.ID, userId: User.ID): Fu[Boolean] =
|
2017-01-25 03:41:08 -07:00
|
|
|
cached.teamIds(userId) map (_ contains teamId)
|
2013-04-09 12:58:34 -06:00
|
|
|
|
2019-07-08 11:59:39 -06:00
|
|
|
def owns(teamId: Team.ID, userId: User.ID): Fu[Boolean] =
|
2013-05-28 07:53:32 -06:00
|
|
|
TeamRepo ownerOf teamId map (Some(userId) ==)
|
|
|
|
|
2019-07-08 11:59:39 -06:00
|
|
|
def teamName(teamId: Team.ID): Option[String] = cached.name(teamId)
|
2013-04-09 12:58:34 -06:00
|
|
|
|
2019-07-08 11:59:39 -06:00
|
|
|
def nbRequests(teamId: Team.ID) = cached.nbRequests get teamId
|
2015-04-12 00:18:47 -06:00
|
|
|
|
|
|
|
def recomputeNbMembers =
|
2018-07-21 03:05:05 -06:00
|
|
|
coll.team.find($empty).cursor[Team](ReadPreference.secondaryPreferred).foldWhileM({}) { (_, team) =>
|
2016-07-21 06:41:34 -06:00
|
|
|
for {
|
|
|
|
nb <- MemberRepo.countByTeam(team.id)
|
|
|
|
_ <- coll.team.updateField($id(team.id), "nbMembers", nb)
|
|
|
|
} yield Cursor.Cont({})
|
|
|
|
}
|
2013-04-03 11:12:38 -06:00
|
|
|
}
|