+2
-7
appview/db/profile.go
+2
-7
appview/db/profile.go
···
348
348
return tx.Commit()
349
349
}
350
350
351
-
func GetProfiles(e Execer, filters ...filter) ([]Profile, error) {
351
+
func GetProfiles(e Execer, filters ...filter) (map[string]*Profile, error) {
352
352
var conditions []string
353
353
var args []any
354
354
for _, filter := range filters {
···
448
448
idxs[did] = idx + 1
449
449
}
450
450
451
-
var profiles []Profile
452
-
for _, p := range profileMap {
453
-
profiles = append(profiles, *p)
454
-
}
455
-
456
-
return profiles, nil
451
+
return profileMap, nil
457
452
}
458
453
459
454
func GetProfile(e Execer, did string) (*Profile, error) {
+2
-6
appview/db/timeline.go
+2
-6
appview/db/timeline.go
···
151
151
return nil, nil
152
152
}
153
153
154
-
profileMap := make(map[string]Profile)
155
154
profiles, err := GetProfiles(e, FilterIn("did", subjects))
156
155
if err != nil {
157
156
return nil, err
158
-
}
159
-
for _, p := range profiles {
160
-
profileMap[p.Did] = p
161
157
}
162
158
163
159
followStatMap := make(map[string]FollowStats)
···
174
170
175
171
var events []TimelineEvent
176
172
for _, f := range follows {
177
-
profile, _ := profileMap[f.SubjectDid]
173
+
profile, _ := profiles[f.SubjectDid]
178
174
followStatMap, _ := followStatMap[f.SubjectDid]
179
175
180
176
events = append(events, TimelineEvent{
181
177
Follow: &f,
182
-
Profile: &profile,
178
+
Profile: profile,
183
179
FollowStats: &followStatMap,
184
180
EventAt: f.FollowedAt,
185
181
})
+5
appview/pages/funcmap.go
+5
appview/pages/funcmap.go
···
277
277
"layoutCenter": func() string {
278
278
return "col-span-1 md:col-span-8 lg:col-span-6"
279
279
},
280
+
281
+
"normalizeForHtmlId": func(s string) string {
282
+
// TODO: extend this to handle other cases?
283
+
return strings.ReplaceAll(s, ":", "_")
284
+
},
280
285
}
281
286
}
282
287
+33
-5
appview/pages/pages.go
+33
-5
appview/pages/pages.go
···
418
418
}
419
419
420
420
type ProfileCard struct {
421
-
UserDid string
422
-
UserHandle string
423
-
FollowStatus db.FollowStatus
424
-
Followers int
425
-
Following int
421
+
UserDid string
422
+
UserHandle string
423
+
FollowStatus db.FollowStatus
424
+
FollowersCount int
425
+
FollowingCount int
426
426
427
427
Profile *db.Profile
428
428
}
···
439
439
440
440
func (p *Pages) ReposPage(w io.Writer, params ReposPageParams) error {
441
441
return p.execute("user/repos", w, params)
442
+
}
443
+
444
+
type FollowCard struct {
445
+
UserDid string
446
+
FollowStatus db.FollowStatus
447
+
FollowersCount int
448
+
FollowingCount int
449
+
Profile *db.Profile
450
+
}
451
+
452
+
type FollowersPageParams struct {
453
+
LoggedInUser *oauth.User
454
+
Followers []FollowCard
455
+
Card ProfileCard
456
+
}
457
+
458
+
func (p *Pages) FollowersPage(w io.Writer, params FollowersPageParams) error {
459
+
return p.execute("user/followers", w, params)
460
+
}
461
+
462
+
type FollowingPageParams struct {
463
+
LoggedInUser *oauth.User
464
+
Following []FollowCard
465
+
Card ProfileCard
466
+
}
467
+
468
+
func (p *Pages) FollowingPage(w io.Writer, params FollowingPageParams) error {
469
+
return p.execute("user/following", w, params)
442
470
}
443
471
444
472
type FollowFragmentParams struct {
+3
-3
appview/pages/templates/timeline/timeline.html
+3
-3
appview/pages/templates/timeline/timeline.html
···
171
171
{{ end }}
172
172
{{ end }}
173
173
{{ with $stat }}
174
-
<div class="text-sm flex items-center gap-2 my-2 overflow-hidden text-ellipsis whitespace-nowrap max-w-full text-sm">
174
+
<div class="text-sm flex items-center gap-2 my-2 overflow-hidden text-ellipsis whitespace-nowrap max-w-full">
175
175
<span class="flex-shrink-0">{{ i "users" "size-4" }}</span>
176
-
<span id="followers">{{ .Followers }} followers</span>
176
+
<span id="followers"><a href="/{{ $subjectHandle }}?tab=followers">{{ .Followers }} followers</a></span>
177
177
<span class="select-none after:content-['·']"></span>
178
-
<span id="following">{{ .Following }} following</span>
178
+
<span id="following"><a href="/{{ $subjectHandle }}?tab=following">{{ .Following }} following</a></span>
179
179
</div>
180
180
{{ end }}
181
181
</div>
+30
appview/pages/templates/user/followers.html
+30
appview/pages/templates/user/followers.html
···
1
+
{{ define "title" }}{{ or .Card.UserHandle .Card.UserDid }} · followers {{ end }}
2
+
3
+
{{ define "extrameta" }}
4
+
<meta property="og:title" content="{{ or .Card.UserHandle .Card.UserDid }}'s followers" />
5
+
<meta property="og:type" content="object" />
6
+
<meta property="og:url" content="https://tangled.sh/{{ or .Card.UserHandle .Card.UserDid }}?tab=followers" />
7
+
<meta property="og:description" content="{{ or .Card.Profile.Description .Card.UserHandle .Card.UserDid }}" />
8
+
{{ end }}
9
+
10
+
{{ define "content" }}
11
+
<div class="grid grid-cols-1 md:grid-cols-11 gap-4">
12
+
<div class="md:col-span-3 order-1 md:order-1">
13
+
{{ template "user/fragments/profileCard" .Card }}
14
+
</div>
15
+
<div id="all-followers" class="md:col-span-8 order-2 md:order-2">
16
+
{{ block "followers" . }}{{ end }}
17
+
</div>
18
+
</div>
19
+
{{ end }}
20
+
21
+
{{ define "followers" }}
22
+
<p class="text-sm font-bold p-2 dark:text-white">ALL FOLLOWERS</p>
23
+
<div id="followers" class="grid grid-cols-1 gap-4 mb-6">
24
+
{{ range .Followers }}
25
+
{{ template "user/fragments/followCard" . }}
26
+
{{ else }}
27
+
<p class="px-6 dark:text-white">This user does not have any followers yet.</p>
28
+
{{ end }}
29
+
</div>
30
+
{{ end }}
+30
appview/pages/templates/user/following.html
+30
appview/pages/templates/user/following.html
···
1
+
{{ define "title" }}{{ or .Card.UserHandle .Card.UserDid }} · following {{ end }}
2
+
3
+
{{ define "extrameta" }}
4
+
<meta property="og:title" content="{{ or .Card.UserHandle .Card.UserDid }}'s following" />
5
+
<meta property="og:type" content="object" />
6
+
<meta property="og:url" content="https://tangled.sh/{{ or .Card.UserHandle .Card.UserDid }}?tab=following" />
7
+
<meta property="og:description" content="{{ or .Card.Profile.Description .Card.UserHandle .Card.UserDid }}" />
8
+
{{ end }}
9
+
10
+
{{ define "content" }}
11
+
<div class="grid grid-cols-1 md:grid-cols-11 gap-4">
12
+
<div class="md:col-span-3 order-1 md:order-1">
13
+
{{ template "user/fragments/profileCard" .Card }}
14
+
</div>
15
+
<div id="all-following" class="md:col-span-8 order-2 md:order-2">
16
+
{{ block "following" . }}{{ end }}
17
+
</div>
18
+
</div>
19
+
{{ end }}
20
+
21
+
{{ define "following" }}
22
+
<p class="text-sm font-bold p-2 dark:text-white">ALL FOLLOWING</p>
23
+
<div id="following" class="grid grid-cols-1 gap-4 mb-6">
24
+
{{ range .Following }}
25
+
{{ template "user/fragments/followCard" . }}
26
+
{{ else }}
27
+
<p class="px-6 dark:text-white">This user does not follow anyone yet.</p>
28
+
{{ end }}
29
+
</div>
30
+
{{ end }}
+2
-2
appview/pages/templates/user/fragments/follow.html
+2
-2
appview/pages/templates/user/fragments/follow.html
···
1
1
{{ define "user/fragments/follow" }}
2
-
<button id="followBtn"
2
+
<button id="{{ normalizeForHtmlId .UserDid }}"
3
3
class="btn mt-2 w-full flex gap-2 items-center group"
4
4
5
5
{{ if eq .FollowStatus.String "IsNotFollowing" }}
···
9
9
{{ end }}
10
10
11
11
hx-trigger="click"
12
-
hx-target="#followBtn"
12
+
hx-target="#{{ normalizeForHtmlId .UserDid }}"
13
13
hx-swap="outerHTML"
14
14
>
15
15
{{ if eq .FollowStatus.String "IsNotFollowing" }}Follow{{ else }}Unfollow{{ end }}
+29
appview/pages/templates/user/fragments/followCard.html
+29
appview/pages/templates/user/fragments/followCard.html
···
1
+
{{ define "user/fragments/followCard" }}
2
+
{{ $userIdent := resolve .UserDid }}
3
+
<div class="flex flex-col divide-y divide-gray-200 dark:divide-gray-700 border border-gray-200 dark:border-gray-700 rounded-sm">
4
+
<div class="py-4 px-6 drop-shadow-sm rounded bg-white dark:bg-gray-800 flex items-center gap-4">
5
+
<div class="flex-shrink-0 max-h-full w-24 h-24">
6
+
<img class="object-cover rounded-full p-2" src="{{ fullAvatar $userIdent }}" />
7
+
</div>
8
+
9
+
<div class="flex-1 min-h-0 justify-around flex flex-col">
10
+
<a href="/{{ $userIdent }}">
11
+
<span class="font-bold dark:text-white overflow-hidden text-ellipsis whitespace-nowrap max-w-full">{{ $userIdent | truncateAt30 }}</span>
12
+
</a>
13
+
<p class="text-sm pb-2 md:pb-2">{{.Profile.Description}}</p>
14
+
<div class="text-sm flex items-center gap-2 my-2 overflow-hidden text-ellipsis whitespace-nowrap max-w-full">
15
+
<span class="flex-shrink-0">{{ i "users" "size-4" }}</span>
16
+
<span id="followers"><a href="/{{ $userIdent }}?tab=followers">{{ .FollowersCount }} followers</a></span>
17
+
<span class="select-none after:content-['·']"></span>
18
+
<span id="following"><a href="/{{ $userIdent }}?tab=following">{{ .FollowingCount }} following</a></span>
19
+
</div>
20
+
</div>
21
+
22
+
{{ if ne .FollowStatus.String "IsSelf" }}
23
+
<div class="max-w-24">
24
+
{{ template "user/fragments/follow" . }}
25
+
</div>
26
+
{{ end }}
27
+
</div>
28
+
</div>
29
+
{{ end }}
+17
-14
appview/pages/templates/user/fragments/profileCard.html
+17
-14
appview/pages/templates/user/fragments/profileCard.html
···
1
1
{{ define "user/fragments/profileCard" }}
2
+
{{ $userIdent := didOrHandle .UserDid .UserHandle }}
2
3
<div class="bg-white dark:bg-gray-800 px-6 py-4 rounded drop-shadow-sm max-h-fit">
3
4
<div class="grid grid-cols-3 md:grid-cols-1 gap-1 items-center">
4
5
<div id="avatar" class="col-span-1 flex justify-center items-center">
···
8
9
</div>
9
10
<div class="col-span-2">
10
11
<div class="flex items-center flex-row flex-nowrap gap-2">
11
-
<p title="{{ didOrHandle .UserDid .UserHandle }}"
12
+
<p title="{{ $userIdent }}"
12
13
class="text-lg font-bold dark:text-white overflow-hidden text-ellipsis whitespace-nowrap">
13
-
{{ didOrHandle .UserDid .UserHandle }}
14
+
{{ $userIdent }}
14
15
</p>
15
-
<a href="/{{ didOrHandle .UserDid .UserHandle }}/feed.atom">{{ i "rss" "size-4" }}</a>
16
+
<a href="/{{ $userIdent }}/feed.atom">{{ i "rss" "size-4" }}</a>
16
17
</div>
17
18
18
19
<div class="md:hidden">
19
-
{{ block "followerFollowing" (list .Followers .Following) }} {{ end }}
20
+
{{ block "followerFollowing" (list . $userIdent) }} {{ end }}
20
21
</div>
21
22
</div>
22
23
<div class="col-span-3 md:col-span-full">
···
29
30
{{ end }}
30
31
31
32
<div class="hidden md:block">
32
-
{{ block "followerFollowing" (list $.Followers $.Following) }} {{ end }}
33
+
{{ block "followerFollowing" (list $ $userIdent) }} {{ end }}
33
34
</div>
34
35
35
36
<div class="flex flex-col gap-2 mb-2 overflow-hidden text-ellipsis whitespace-nowrap max-w-full">
···
42
43
{{ if .IncludeBluesky }}
43
44
<div class="flex items-center gap-2">
44
45
<span class="flex-shrink-0">{{ template "user/fragments/bluesky" "w-4 h-4 text-black dark:text-white" }}</span>
45
-
<a id="bluesky-link" href="https://bsky.app/profile/{{ $.UserDid }}">{{ didOrHandle $.UserDid $.UserHandle }}</a>
46
+
<a id="bluesky-link" href="https://bsky.app/profile/{{ $.UserDid }}">{{ $userIdent }}</a>
46
47
</div>
47
48
{{ end }}
48
49
{{ range $link := .Links }}
···
88
89
{{ end }}
89
90
90
91
{{ define "followerFollowing" }}
91
-
{{ $followers := index . 0 }}
92
-
{{ $following := index . 1 }}
93
-
<div class="flex items-center gap-2 my-2 overflow-hidden text-ellipsis whitespace-nowrap max-w-full text-sm">
94
-
<span class="flex-shrink-0">{{ i "users" "size-4" }}</span>
95
-
<span id="followers">{{ $followers }} followers</span>
96
-
<span class="select-none after:content-['·']"></span>
97
-
<span id="following">{{ $following }} following</span>
98
-
</div>
92
+
{{ $root := index . 0 }}
93
+
{{ $userIdent := index . 1 }}
94
+
{{ with $root }}
95
+
<div class="flex items-center gap-2 my-2 overflow-hidden text-ellipsis whitespace-nowrap max-w-full text-sm">
96
+
<span class="flex-shrink-0">{{ i "users" "size-4" }}</span>
97
+
<span id="followers"><a href="/{{ $userIdent }}?tab=followers">{{ .FollowersCount }} followers</a></span>
98
+
<span class="select-none after:content-['·']"></span>
99
+
<span id="following"><a href="/{{ $userIdent }}?tab=following">{{ .FollowingCount }} following</a></span>
100
+
</div>
101
+
{{ end }}
99
102
{{ end }}
100
103
+1
-1
appview/pages/templates/user/repos.html
+1
-1
appview/pages/templates/user/repos.html
···
3
3
{{ define "extrameta" }}
4
4
<meta property="og:title" content="{{ or .Card.UserHandle .Card.UserDid }}'s repos" />
5
5
<meta property="og:type" content="object" />
6
-
<meta property="og:url" content="https://tangled.sh/{{ or .Card.UserHandle .Card.UserDid }}/repos" />
6
+
<meta property="og:url" content="https://tangled.sh/{{ or .Card.UserHandle .Card.UserDid }}?tab=repos" />
7
7
<meta property="og:description" content="{{ or .Card.Profile.Description .Card.UserHandle .Card.UserDid }}" />
8
8
{{ end }}
9
9
+169
-12
appview/state/profile.go
+169
-12
appview/state/profile.go
···
2
2
3
3
import (
4
4
"context"
5
+
"errors"
5
6
"fmt"
6
7
"log"
7
8
"net/http"
···
17
18
"github.com/gorilla/feeds"
18
19
"tangled.sh/tangled.sh/core/api/tangled"
19
20
"tangled.sh/tangled.sh/core/appview/db"
21
+
"tangled.sh/tangled.sh/core/appview/oauth"
20
22
"tangled.sh/tangled.sh/core/appview/pages"
21
23
)
22
24
···
27
29
s.profilePage(w, r)
28
30
case "repos":
29
31
s.reposPage(w, r)
32
+
case "followers":
33
+
s.followersPage(w, r)
34
+
case "following":
35
+
s.followingPage(w, r)
30
36
}
31
37
}
32
38
···
117
123
Repos: pinnedRepos,
118
124
CollaboratingRepos: pinnedCollaboratingRepos,
119
125
Card: pages.ProfileCard{
120
-
UserDid: ident.DID.String(),
121
-
UserHandle: ident.Handle.String(),
122
-
Profile: profile,
123
-
FollowStatus: followStatus,
124
-
Followers: followers,
125
-
Following: following,
126
+
UserDid: ident.DID.String(),
127
+
UserHandle: ident.Handle.String(),
128
+
Profile: profile,
129
+
FollowStatus: followStatus,
130
+
FollowersCount: followers,
131
+
FollowingCount: following,
126
132
},
127
133
Punchcard: punchcard,
128
134
ProfileTimeline: timeline,
···
165
171
LoggedInUser: loggedInUser,
166
172
Repos: repos,
167
173
Card: pages.ProfileCard{
168
-
UserDid: ident.DID.String(),
169
-
UserHandle: ident.Handle.String(),
170
-
Profile: profile,
171
-
FollowStatus: followStatus,
172
-
Followers: followers,
173
-
Following: following,
174
+
UserDid: ident.DID.String(),
175
+
UserHandle: ident.Handle.String(),
176
+
Profile: profile,
177
+
FollowStatus: followStatus,
178
+
FollowersCount: followers,
179
+
FollowingCount: following,
180
+
},
181
+
})
182
+
}
183
+
184
+
type FollowsPageParams struct {
185
+
LoggedInUser *oauth.User
186
+
Follows []pages.FollowCard
187
+
Card pages.ProfileCard
188
+
}
189
+
190
+
func (s *State) followPage(w http.ResponseWriter, r *http.Request, fetchFollows func(db.Execer, string) ([]db.Follow, error), extractDid func(db.Follow) string) (FollowsPageParams, error) {
191
+
ident, ok := r.Context().Value("resolvedId").(identity.Identity)
192
+
if !ok {
193
+
s.pages.Error404(w)
194
+
return FollowsPageParams{}, errors.New("identity not found")
195
+
}
196
+
did := ident.DID.String()
197
+
198
+
profile, err := db.GetProfile(s.db, did)
199
+
if err != nil {
200
+
log.Printf("getting profile data for %s: %s", did, err)
201
+
return FollowsPageParams{}, err
202
+
}
203
+
204
+
loggedInUser := s.oauth.GetUser(r)
205
+
206
+
follows, err := fetchFollows(s.db, did)
207
+
if err != nil {
208
+
log.Printf("getting followers for %s: %s", did, err)
209
+
return FollowsPageParams{}, err
210
+
}
211
+
212
+
var loggedInUserFollowing map[string]struct{}
213
+
if loggedInUser != nil {
214
+
following, err := db.GetFollowing(s.db, loggedInUser.Did)
215
+
if err != nil {
216
+
return FollowsPageParams{}, err
217
+
}
218
+
if len(following) > 0 {
219
+
loggedInUserFollowing = make(map[string]struct{}, len(following))
220
+
for _, follow := range following {
221
+
loggedInUserFollowing[follow.SubjectDid] = struct{}{}
222
+
}
223
+
}
224
+
}
225
+
226
+
followStatus := db.IsNotFollowing
227
+
if loggedInUser != nil {
228
+
followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, did)
229
+
}
230
+
231
+
followersCount, followingCount, err := db.GetFollowerFollowingCount(s.db, did)
232
+
if err != nil {
233
+
log.Printf("getting follow stats followers for %s: %s", did, err)
234
+
return FollowsPageParams{}, err
235
+
}
236
+
237
+
if len(follows) == 0 {
238
+
return FollowsPageParams{
239
+
LoggedInUser: loggedInUser,
240
+
Follows: []pages.FollowCard{},
241
+
Card: pages.ProfileCard{
242
+
UserDid: did,
243
+
UserHandle: ident.Handle.String(),
244
+
Profile: profile,
245
+
FollowStatus: followStatus,
246
+
FollowersCount: followersCount,
247
+
FollowingCount: followingCount,
248
+
},
249
+
}, nil
250
+
}
251
+
252
+
followDids := make([]string, 0, len(follows))
253
+
for _, follow := range follows {
254
+
followDids = append(followDids, extractDid(follow))
255
+
}
256
+
257
+
profiles, err := db.GetProfiles(s.db, db.FilterIn("did", followDids))
258
+
if err != nil {
259
+
log.Printf("getting profile for %s: %s", followDids, err)
260
+
return FollowsPageParams{}, err
261
+
}
262
+
263
+
followCards := make([]pages.FollowCard, 0, len(follows))
264
+
for _, did := range followDids {
265
+
followersCount, followingCount, err := db.GetFollowerFollowingCount(s.db, did)
266
+
if err != nil {
267
+
log.Printf("getting follow stats for %s: %s", did, err)
268
+
}
269
+
followStatus := db.IsNotFollowing
270
+
if loggedInUserFollowing != nil {
271
+
if _, exists := loggedInUserFollowing[did]; exists {
272
+
followStatus = db.IsFollowing
273
+
} else if loggedInUser.Did == did {
274
+
followStatus = db.IsSelf
275
+
}
276
+
}
277
+
var profile *db.Profile
278
+
if p, exists := profiles[did]; exists {
279
+
profile = p
280
+
} else {
281
+
profile = &db.Profile{}
282
+
profile.Did = did
283
+
}
284
+
followCards = append(followCards, pages.FollowCard{
285
+
UserDid: did,
286
+
FollowStatus: followStatus,
287
+
FollowersCount: followersCount,
288
+
FollowingCount: followingCount,
289
+
Profile: profile,
290
+
})
291
+
}
292
+
293
+
return FollowsPageParams{
294
+
LoggedInUser: loggedInUser,
295
+
Follows: followCards,
296
+
Card: pages.ProfileCard{
297
+
UserDid: did,
298
+
UserHandle: ident.Handle.String(),
299
+
Profile: profile,
300
+
FollowStatus: followStatus,
301
+
FollowersCount: followersCount,
302
+
FollowingCount: followingCount,
174
303
},
304
+
}, nil
305
+
}
306
+
307
+
func (s *State) followersPage(w http.ResponseWriter, r *http.Request) {
308
+
followPage, err := s.followPage(w, r, db.GetFollowers, func(f db.Follow) string { return f.UserDid })
309
+
if err != nil {
310
+
s.pages.Notice(w, "all-followers", "Failed to load followers")
311
+
return
312
+
}
313
+
314
+
s.pages.FollowersPage(w, pages.FollowersPageParams{
315
+
LoggedInUser: followPage.LoggedInUser,
316
+
Followers: followPage.Follows,
317
+
Card: followPage.Card,
318
+
})
319
+
}
320
+
321
+
func (s *State) followingPage(w http.ResponseWriter, r *http.Request) {
322
+
followPage, err := s.followPage(w, r, db.GetFollowing, func(f db.Follow) string { return f.SubjectDid })
323
+
if err != nil {
324
+
s.pages.Notice(w, "all-following", "Failed to load following")
325
+
return
326
+
}
327
+
328
+
s.pages.FollowingPage(w, pages.FollowingPageParams{
329
+
LoggedInUser: followPage.LoggedInUser,
330
+
Following: followPage.Follows,
331
+
Card: followPage.Card,
175
332
})
176
333
}
177
334
+7
-7
appview/strings/strings.go
+7
-7
appview/strings/strings.go
···
202
202
followStatus = db.GetFollowStatus(s.Db, loggedInUser.Did, id.DID.String())
203
203
}
204
204
205
-
followers, following, err := db.GetFollowerFollowingCount(s.Db, id.DID.String())
205
+
followersCount, followingCount, err := db.GetFollowerFollowingCount(s.Db, id.DID.String())
206
206
if err != nil {
207
207
l.Error("failed to get follow stats", "err", err)
208
208
}
···
210
210
s.Pages.StringsDashboard(w, pages.StringsDashboardParams{
211
211
LoggedInUser: s.OAuth.GetUser(r),
212
212
Card: pages.ProfileCard{
213
-
UserDid: id.DID.String(),
214
-
UserHandle: id.Handle.String(),
215
-
Profile: profile,
216
-
FollowStatus: followStatus,
217
-
Followers: followers,
218
-
Following: following,
213
+
UserDid: id.DID.String(),
214
+
UserHandle: id.Handle.String(),
215
+
Profile: profile,
216
+
FollowStatus: followStatus,
217
+
FollowersCount: followersCount,
218
+
FollowingCount: followingCount,
219
219
},
220
220
Strings: all,
221
221
})