1package state
2
3import (
4 "log"
5 "net/http"
6 "time"
7
8 comatproto "github.com/bluesky-social/indigo/api/atproto"
9 "github.com/bluesky-social/indigo/atproto/syntax"
10
11 lexutil "github.com/bluesky-social/indigo/lex/util"
12 "tangled.sh/tangled.sh/core/api/tangled"
13 "tangled.sh/tangled.sh/core/appview/db"
14 "tangled.sh/tangled.sh/core/appview/pages"
15 "tangled.sh/tangled.sh/core/tid"
16)
17
18func (s *State) React(w http.ResponseWriter, r *http.Request) {
19 currentUser := s.oauth.GetUser(r)
20
21 subject := r.URL.Query().Get("subject")
22 if subject == "" {
23 log.Println("invalid form")
24 return
25 }
26
27 subjectUri, err := syntax.ParseATURI(subject)
28 if err != nil {
29 log.Println("invalid form")
30 return
31 }
32
33 reactionKind, ok := db.ParseReactionKind(r.URL.Query().Get("kind"))
34 if !ok {
35 log.Println("invalid reaction kind")
36 return
37 }
38
39 client, err := s.oauth.AuthorizedClient(r)
40 if err != nil {
41 log.Println("failed to authorize client", err)
42 return
43 }
44
45 switch r.Method {
46 case http.MethodPost:
47 createdAt := time.Now().Format(time.RFC3339)
48 rkey := tid.TID()
49 resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
50 Collection: tangled.FeedReactionNSID,
51 Repo: currentUser.Did,
52 Rkey: rkey,
53 Record: &lexutil.LexiconTypeDecoder{
54 Val: &tangled.FeedReaction{
55 Subject: subjectUri.String(),
56 Reaction: reactionKind.String(),
57 CreatedAt: createdAt,
58 },
59 },
60 })
61 if err != nil {
62 log.Println("failed to create atproto record", err)
63 return
64 }
65
66 err = db.AddReaction(s.db, currentUser.Did, subjectUri, reactionKind, rkey)
67 if err != nil {
68 log.Println("failed to react", err)
69 return
70 }
71
72 count, err := db.GetReactionCount(s.db, subjectUri, reactionKind)
73 if err != nil {
74 log.Println("failed to get reaction count for ", subjectUri)
75 }
76
77 log.Println("created atproto record: ", resp.Uri)
78
79 s.pages.ThreadReactionFragment(w, pages.ThreadReactionFragmentParams{
80 ThreadAt: subjectUri,
81 Kind: reactionKind,
82 Count: count,
83 IsReacted: true,
84 })
85
86 return
87 case http.MethodDelete:
88 reaction, err := db.GetReaction(s.db, currentUser.Did, subjectUri, reactionKind)
89 if err != nil {
90 log.Println("failed to get reaction relationship for", currentUser.Did, subjectUri)
91 return
92 }
93
94 _, err = client.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
95 Collection: tangled.FeedReactionNSID,
96 Repo: currentUser.Did,
97 Rkey: reaction.Rkey,
98 })
99
100 if err != nil {
101 log.Println("failed to remove reaction")
102 return
103 }
104
105 err = db.DeleteReactionByRkey(s.db, currentUser.Did, reaction.Rkey)
106 if err != nil {
107 log.Println("failed to delete reaction from DB")
108 // this is not an issue, the firehose event might have already done this
109 }
110
111 count, err := db.GetReactionCount(s.db, subjectUri, reactionKind)
112 if err != nil {
113 log.Println("failed to get reaction count for ", subjectUri)
114 return
115 }
116
117 s.pages.ThreadReactionFragment(w, pages.ThreadReactionFragmentParams{
118 ThreadAt: subjectUri,
119 Kind: reactionKind,
120 Count: count,
121 IsReacted: false,
122 })
123
124 return
125 }
126}