A vibe coded tangled fork which supports pijul.
at f4a09133a636451c495fa96c98b99379b7692497 141 lines 3.7 kB view raw
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 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 currentUser := s.oauth.GetMultiAccountUser(r) 21 22 subject := r.URL.Query().Get("subject") 23 if subject == "" { 24 log.Println("invalid form") 25 return 26 } 27 28 subjectUri, err := syntax.ParseATURI(subject) 29 if err != nil { 30 log.Println("invalid form") 31 return 32 } 33 34 reactionKind, ok := models.ParseReactionKind(r.URL.Query().Get("kind")) 35 if !ok { 36 log.Println("invalid reaction kind") 37 return 38 } 39 40 client, err := s.oauth.AuthorizedClient(r) 41 if err != nil { 42 log.Println("failed to authorize client", err) 43 return 44 } 45 46 switch r.Method { 47 case http.MethodPost: 48 createdAt := time.Now().Format(time.RFC3339) 49 rkey := tid.TID() 50 resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ 51 Collection: tangled.FeedReactionNSID, 52 Repo: currentUser.Active.Did, 53 Rkey: rkey, 54 Record: &lexutil.LexiconTypeDecoder{ 55 Val: &tangled.FeedReaction{ 56 Subject: subjectUri.String(), 57 Reaction: reactionKind.String(), 58 CreatedAt: createdAt, 59 }, 60 }, 61 }) 62 if err != nil { 63 log.Println("failed to create atproto record", err) 64 return 65 } 66 67 err = db.AddReaction(s.db, currentUser.Active.Did, subjectUri, reactionKind, rkey) 68 if err != nil { 69 log.Println("failed to react", err) 70 return 71 } 72 73 reactionMap, err := db.GetReactionMap(s.db, 20, subjectUri) 74 if err != nil { 75 log.Println("failed to get reactions for ", subjectUri) 76 } 77 78 log.Println("created atproto record: ", resp.Uri) 79 80 s.pages.ThreadReactionFragment(w, pages.ThreadReactionFragmentParams{ 81 ThreadAt: subjectUri, 82 Kind: reactionKind, 83 Count: reactionMap[reactionKind].Count, 84 Users: reactionMap[reactionKind].Users, 85 IsReacted: true, 86 }) 87 88 return 89 case http.MethodDelete: 90 tx, err := s.db.BeginTx(r.Context(), nil) 91 if err != nil { 92 s.logger.Error("failed to start transaction", "err", err) 93 } 94 defer tx.Rollback() 95 96 reactions, err := db.DeleteReaction(tx, syntax.DID(currentUser.Active.Did), subjectUri, reactionKind) 97 if err != nil { 98 s.logger.Error("failed to delete reactions from db", "err", err) 99 return 100 } 101 102 var writes []*comatproto.RepoApplyWrites_Input_Writes_Elem 103 for _, reactionAt := range reactions { 104 writes = append(writes, &comatproto.RepoApplyWrites_Input_Writes_Elem{ 105 RepoApplyWrites_Delete: &comatproto.RepoApplyWrites_Delete{ 106 Collection: tangled.FeedReactionNSID, 107 Rkey: reactionAt.RecordKey().String(), 108 }, 109 }) 110 } 111 _, err = comatproto.RepoApplyWrites(r.Context(), client, &comatproto.RepoApplyWrites_Input{ 112 Repo: currentUser.Active.Did, 113 Writes: writes, 114 }) 115 if err != nil { 116 s.logger.Error("failed to delete reactions from PDS", "err", err) 117 return 118 } 119 120 if err := tx.Commit(); err != nil { 121 s.logger.Error("failed to commit transaction", "err", err) 122 // DB op failed but record is created in PDS. Ingester will backfill the missed operation 123 } 124 125 reactionMap, err := db.GetReactionMap(s.db, 20, subjectUri) 126 if err != nil { 127 log.Println("failed to get reactions for ", subjectUri) 128 return 129 } 130 131 s.pages.ThreadReactionFragment(w, pages.ThreadReactionFragmentParams{ 132 ThreadAt: subjectUri, 133 Kind: reactionKind, 134 Count: reactionMap[reactionKind].Count, 135 Users: reactionMap[reactionKind].Users, 136 IsReacted: false, 137 }) 138 139 return 140 } 141}