Monorepo for Tangled tangled.org
3

Configure Feed

Select the types of activity you want to include in your feed.

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