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