1package state
2
3import (
4 "log"
5 "net/http"
6 "time"
7
8 comatproto "github.com/bluesky-social/indigo/api/atproto"
9 lexutil "github.com/bluesky-social/indigo/lex/util"
10 "tangled.sh/tangled.sh/core/api/tangled"
11 "tangled.sh/tangled.sh/core/appview/db"
12 "tangled.sh/tangled.sh/core/appview/pages"
13 "tangled.sh/tangled.sh/core/tid"
14)
15
16func (s *State) Follow(w http.ResponseWriter, r *http.Request) {
17 currentUser := s.oauth.GetUser(r)
18
19 subject := r.URL.Query().Get("subject")
20 if subject == "" {
21 log.Println("invalid form")
22 return
23 }
24
25 subjectIdent, err := s.idResolver.ResolveIdent(r.Context(), subject)
26 if err != nil {
27 log.Println("failed to follow, invalid did")
28 }
29
30 if currentUser.Did == subjectIdent.DID.String() {
31 log.Println("cant follow or unfollow yourself")
32 return
33 }
34
35 client, err := s.oauth.AuthorizedClient(r)
36 if err != nil {
37 log.Println("failed to authorize client")
38 return
39 }
40
41 switch r.Method {
42 case http.MethodPost:
43 createdAt := time.Now().Format(time.RFC3339)
44 rkey := tid.TID()
45 resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
46 Collection: tangled.GraphFollowNSID,
47 Repo: currentUser.Did,
48 Rkey: rkey,
49 Record: &lexutil.LexiconTypeDecoder{
50 Val: &tangled.GraphFollow{
51 Subject: subjectIdent.DID.String(),
52 CreatedAt: createdAt,
53 }},
54 })
55 if err != nil {
56 log.Println("failed to create atproto record", err)
57 return
58 }
59
60 log.Println("created atproto record: ", resp.Uri)
61
62 follow := &db.Follow{
63 UserDid: currentUser.Did,
64 SubjectDid: subjectIdent.DID.String(),
65 Rkey: rkey,
66 }
67
68 err = db.AddFollow(s.db, follow)
69 if err != nil {
70 log.Println("failed to follow", err)
71 return
72 }
73
74 s.notifier.NewFollow(r.Context(), follow)
75
76 s.pages.FollowFragment(w, pages.FollowFragmentParams{
77 UserDid: subjectIdent.DID.String(),
78 FollowStatus: db.IsFollowing,
79 })
80
81 return
82 case http.MethodDelete:
83 // find the record in the db
84 follow, err := db.GetFollow(s.db, currentUser.Did, subjectIdent.DID.String())
85 if err != nil {
86 log.Println("failed to get follow relationship")
87 return
88 }
89
90 _, err = client.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
91 Collection: tangled.GraphFollowNSID,
92 Repo: currentUser.Did,
93 Rkey: follow.Rkey,
94 })
95
96 if err != nil {
97 log.Println("failed to unfollow")
98 return
99 }
100
101 err = db.DeleteFollowByRkey(s.db, currentUser.Did, follow.Rkey)
102 if err != nil {
103 log.Println("failed to delete follow from DB")
104 // this is not an issue, the firehose event might have already done this
105 }
106
107 s.pages.FollowFragment(w, pages.FollowFragmentParams{
108 UserDid: subjectIdent.DID.String(),
109 FollowStatus: db.IsNotFollowing,
110 })
111
112 s.notifier.DeleteFollow(r.Context(), follow)
113
114 return
115 }
116
117}