forked from lichess-org/lila
-
Notifications
You must be signed in to change notification settings - Fork 0
/
RelationApi.scala
146 lines (118 loc) · 4.8 KB
/
RelationApi.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package lila.relation
import akka.actor.ActorSelection
import scala.util.Success
import lila.db.api._
import lila.db.Implicits._
import lila.db.paginator._
import lila.hub.actorApi.timeline.{ Propagate, Follow => FollowUser }
import lila.user.tube.userTube
import lila.user.{ User => UserModel, UserRepo }
import tube.relationTube
import BSONHandlers._
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework._
import reactivemongo.bson._
final class RelationApi(
coll: Coll,
actor: ActorSelection,
bus: lila.common.Bus,
timeline: ActorSelection,
reporter: ActorSelection,
followable: ID => Fu[Boolean],
maxFollow: Int,
maxBlock: Int) {
import RelationRepo.makeId
def fetchRelation(u1: ID, u2: ID): Fu[Option[Relation]] = coll.find(
BSONDocument("u1" -> u1, "u2" -> u2),
BSONDocument("r" -> true, "_id" -> false)
).one[BSONDocument].map {
_.flatMap(_.getAs[Boolean]("r"))
}
def fetchFollowing = RelationRepo following _
def fetchFollowers = RelationRepo followers _
def fetchBlocking = RelationRepo blocking _
def fetchFriends(userId: ID) = coll.aggregate(Match(BSONDocument(
"$or" -> BSONArray(BSONDocument("u1" -> userId), BSONDocument("u2" -> userId)),
"r" -> Follow
)), List(
Group(BSONNull)(
"u1" -> AddToSet("u1"),
"u2" -> AddToSet("u2")),
Project(BSONDocument(
"_id" -> BSONDocument("$setIntersection" -> BSONArray("$u1", "$u2"))
))
)).map {
~_.documents.headOption.flatMap(_.getAs[Set[String]]("_id")) - userId
}
def fetchFollows(u1: ID, u2: ID) =
coll.count(BSONDocument("_id" -> makeId(u1, u2), "r" -> Follow).some).map(0!=)
def fetchBlocks(u1: ID, u2: ID) =
coll.count(BSONDocument("_id" -> makeId(u1, u2), "r" -> Block).some).map(0!=)
def fetchAreFriends(u1: ID, u2: ID) =
fetchFollows(u1, u2) flatMap { _ ?? fetchFollows(u2, u1) }
def countFollowing(userId: ID) =
coll.count(BSONDocument("u1" -> userId, "r" -> Follow).some)
def countFollowers(userId: ID) =
coll.count(BSONDocument("u2" -> userId, "r" -> Follow).some)
def countBlocking(userId: ID) =
coll.count(BSONDocument("u1" -> userId, "r" -> Block).some)
def countBlockers(userId: ID) =
coll.count(BSONDocument("u2" -> userId, "r" -> Block).some)
def followingPaginatorAdapter(userId: ID) = new BSONAdapter[Followed](
collection = coll,
selector = BSONDocument("u1" -> userId, "r" -> Follow),
projection = BSONDocument("u2" -> true, "_id" -> false),
sort = BSONDocument()).map(_.userId)
def followersPaginatorAdapter(userId: ID) = new BSONAdapter[Follower](
collection = coll,
selector = BSONDocument("u2" -> userId, "r" -> Follow),
projection = BSONDocument("u1" -> true, "_id" -> false),
sort = BSONDocument()).map(_.userId)
def blockingPaginatorAdapter(userId: ID) = new BSONAdapter[Blocked](
collection = coll,
selector = BSONDocument("u1" -> userId, "r" -> Block),
projection = BSONDocument("u2" -> true, "_id" -> false),
sort = BSONDocument()).map(_.userId)
def follow(u1: ID, u2: ID): Funit =
if (u1 == u2) funit
else followable(u2) flatMap {
case false => funit
case true => fetchRelation(u1, u2) zip fetchRelation(u2, u1) flatMap {
case (Some(Follow), _) => funit
case (_, Some(Block)) => funit
case _ => RelationRepo.follow(u1, u2) >> limitFollow(u1) >>-
reloadOnlineFriends(u1, u2) >>-
(timeline ! Propagate(FollowUser(u1, u2)).toFriendsOf(u1).toUsers(List(u2)))
}
}
private def limitFollow(u: ID) = countFollowing(u) flatMap { nb =>
(nb >= maxFollow) ?? RelationRepo.drop(u, true, nb - maxFollow + 1)
}
private def limitBlock(u: ID) = countBlocking(u) flatMap { nb =>
(nb >= maxBlock) ?? RelationRepo.drop(u, false, nb - maxBlock + 1)
}
def block(u1: ID, u2: ID): Funit =
if (u1 == u2) funit
else fetchBlocks(u1, u2) flatMap {
case true => funit
case _ => RelationRepo.block(u1, u2) >> limitBlock(u1) >>- reloadOnlineFriends(u1, u2) >>-
bus.publish(lila.hub.actorApi.relation.Block(u1, u2), 'relation)
}
def unfollow(u1: ID, u2: ID): Funit =
if (u1 == u2) funit
else fetchFollows(u1, u2) flatMap {
case true => RelationRepo.unfollow(u1, u2) >>- reloadOnlineFriends(u1, u2)
case _ => funit
}
def unfollowAll(u1: ID): Funit = RelationRepo.unfollowAll(u1)
def unblock(u1: ID, u2: ID): Funit =
if (u1 == u2) funit
else fetchBlocks(u1, u2) flatMap {
case true => RelationRepo.unblock(u1, u2) >>- reloadOnlineFriends(u1, u2) >>-
bus.publish(lila.hub.actorApi.relation.UnBlock(u1, u2), 'relation)
case _ => funit
}
private def reloadOnlineFriends(u1: ID, u2: ID) {
import lila.hub.actorApi.relation.ReloadOnlineFriends
List(u1, u2).foreach(actor ! ReloadOnlineFriends(_))
}
}