-
Notifications
You must be signed in to change notification settings - Fork 0
/
follow.go
251 lines (223 loc) · 5.78 KB
/
follow.go
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
package user
import (
"database/sql"
_ "embed"
"time"
"github.com/allocamelus/allocamelus/internal/data"
"github.com/allocamelus/allocamelus/internal/pkg/compare"
)
var (
//go:embed sql/follow/following.sql
qFollowing string
preFollowing *sql.Stmt
//go:embed sql/follow/listFollowing.sql
qListFollowing string
preListFollowing *sql.Stmt
//go:embed sql/follow/follow.sql
qFollow string
preFollow *sql.Stmt
//go:embed sql/follow/accept.sql
qAccept string
preAccept *sql.Stmt
//go:embed sql/follow/acceptAll.sql
qAcceptAll string
preAcceptAll *sql.Stmt
//go:embed sql/follow/unfollow.sql
qUnfollow string
preUnfollow *sql.Stmt
//go:embed sql/follow/followers.sql
qFollowers string
preFollowers *sql.Stmt
//go:embed sql/follow/followers.sql
qListFollowers string
preListFollowers *sql.Stmt
//go:embed sql/follow/listRequests.sql
qListRequests string
preListRequests *sql.Stmt
)
func init() {
data.PrepareQueuer.Add(&preFollowing, qFollowing)
data.PrepareQueuer.Add(&preListFollowing, qListFollowing)
data.PrepareQueuer.Add(&preFollow, qFollow)
data.PrepareQueuer.Add(&preAccept, qAccept)
data.PrepareQueuer.Add(&preAcceptAll, qAcceptAll)
data.PrepareQueuer.Add(&preUnfollow, qUnfollow)
data.PrepareQueuer.Add(&preFollowers, qFollowers)
data.PrepareQueuer.Add(&preListFollowers, qListFollowers)
data.PrepareQueuer.Add(&preListRequests, qListRequests)
}
// Following is userId following followUserId
func Following(userId, followUserId int64) (follow FollowStruct, err error) {
if compare.EqualInt64(userId, followUserId) {
follow.Following = true
return
}
err = preFollowing.QueryRow(userId, followUserId).Scan(&follow.Following)
if err != sql.ErrNoRows {
if err != nil {
return
}
if !follow.Following {
follow.Requested = true
}
}
return follow, nil
}
// ListFollowing return a slice of userId(s) that userId follows
func ListFollowing(userId int64) ([]int64, error) {
rows, err := preListFollowing.Query(userId)
if err != nil {
return nil, err
}
defer rows.Close()
var (
following []int64
followUserId int64
)
for rows.Next() {
if err = rows.Scan(&followUserId); err != nil {
return nil, err
}
following = append(following, followUserId)
}
return following, nil
}
func FollowExt(userId int64, followUserId int64, accepted bool) error {
following, err := Following(userId, followUserId)
if err != nil || following.Following {
// return if following silently
return err
}
_, err = preFollow.Exec(userId, followUserId, accepted, time.Now().Unix())
return err
}
// Follow userId follow followUserId
func Follow(userId int64, followUserId int64) error {
t, err := GetType(followUserId)
if err != nil {
return err
}
// Only Public Users are auto followed
if t.Public() {
return FollowExt(userId, followUserId, true)
}
// Has the user being followed requested to follow user
follow, err := Following(followUserId, userId)
if err != nil {
return err
}
// if so Accept request
if follow.Requested {
return Accept(userId, followUserId)
}
// else request to follow
return FollowExt(userId, followUserId, false)
}
// Accept userId Accept followerUserId request
func Accept(userId, followerUserId int64) error {
// Is follower following already
follow, err := Following(followerUserId, userId)
if err != nil || follow.Following {
// return if following silently
return err
}
_, err = preAccept.Exec(followerUserId, userId)
if err != nil {
return err
}
t, err := GetType(userId)
if err != nil {
return err
}
// Auto Follow back is like fb friends
if t.Private() {
t, err = GetType(followerUserId)
if err != nil {
return err
}
// Is follower Private? Follow if so
if t.Private() {
return FollowExt(userId, followerUserId, true)
}
}
return nil
}
// Decline userId Decline followerUserId request
func Decline(userId, followerUserId int64) error {
return unfollowDB(followerUserId, userId)
}
// AcceptAll userId Accept all follow request
// Called when accounts goes from private to public
func AcceptAll(userId int64) error {
_, err := preAcceptAll.Exec(userId)
return err
}
// unfollowDB userId unfollow followUserId
func unfollowDB(userId, followUserId int64) error {
follow, err := Following(userId, followUserId)
if err != nil || (!follow.Following && !follow.Requested) {
// return if !following silently
return err
}
_, err = preUnfollow.Exec(userId, followUserId)
return err
}
func Unfollow(userId, unfollowId int64) error {
if err := unfollowDB(userId, unfollowId); err != nil {
return err
}
// Unfriend if unfollowId and userId are private
if t, err := GetType(unfollowId); err != nil || !t.Private() {
return err
}
if t, err := GetType(userId); err != nil || !t.Private() {
return err
}
return unfollowDB(unfollowId, userId)
}
// Followers count userId followers
func Followers(userId int64) (followers int64, err error) {
err = preFollowers.QueryRow(userId).Scan(&followers)
return
}
// ListFollows return a slice of userId(s) that follow userId
func ListFollowers(userId int64) ([]int64, error) {
rows, err := preListFollowing.Query(userId)
if err != nil {
return nil, err
}
defer rows.Close()
var (
followers []int64
follower int64
)
for rows.Next() {
if err = rows.Scan(&follower); err != nil {
return nil, err
}
followers = append(followers, follower)
}
return followers, nil
}
// ListRequests return a ordered map of userId(s) that request to follow userId
// TODO limit
func ListRequests(userId int64) (map[int64]int64, error) {
rows, err := preListRequests.Query(userId)
if err != nil {
return nil, err
}
defer rows.Close()
requests := map[int64]int64{}
var (
i int64
requester int64
)
for rows.Next() {
if err = rows.Scan(&requester); err != nil {
return nil, err
}
requests[i] = requester
i++
}
return requests, nil
}