This repository has no description
0

Configure Feed

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

core / appview / state / vouch.go
4.6 kB 181 lines
1package state 2 3import ( 4 "net/http" 5 "time" 6 7 comatproto "github.com/bluesky-social/indigo/api/atproto" 8 "github.com/bluesky-social/indigo/atproto/syntax" 9 lexutil "github.com/bluesky-social/indigo/lex/util" 10 "github.com/ipfs/go-cid" 11 "tangled.org/core/api/tangled" 12 "tangled.org/core/appview/db" 13 "tangled.org/core/appview/models" 14 "tangled.org/core/log" 15) 16 17func (s *State) Vouch(w http.ResponseWriter, r *http.Request) { 18 l := log.SubLogger(s.logger, "vouch") 19 l = s.logger.With("handler", "Vouch") 20 currentUser := s.oauth.GetMultiAccountUser(r) 21 22 var subject string 23 24 subject = r.FormValue("subject") 25 26 if subject == "" { 27 l.Warn("invalid form: missing subject") 28 s.pages.Notice(w, "error", "Missing subject user.") 29 return 30 } 31 32 subjectIdent, err := s.idResolver.ResolveIdent(r.Context(), subject) 33 if err != nil { 34 l.Error("failed to vouch, invalid did", "subject", subject, "err", err) 35 s.pages.Notice(w, "error", "Could not find that user.") 36 return 37 } 38 39 if currentUser.Did == subjectIdent.DID.String() { 40 l.Warn("cant vouch or denounce yourself") 41 s.pages.Notice(w, "error", "You cannot vouch for yourself.") 42 return 43 } 44 45 client, err := s.oauth.AuthorizedClient(r) 46 if err != nil { 47 l.Error("failed to authorize client", "err", err) 48 s.pages.Notice(w, "error", "Authentication required.") 49 return 50 } 51 52 if err := r.ParseForm(); err != nil { 53 l.Warn("failed to parse form", "err", err) 54 s.pages.Notice(w, "error", "Invalid form data.") 55 return 56 } 57 58 subjectDid := subjectIdent.DID.String() 59 60 // handle "none" by deleting any existing vouch 61 if r.FormValue("kind") == "none" { 62 _, err := db.GetVouch(s.db, currentUser.Did, subjectDid) 63 if err != nil { 64 l.Info("no existing vouch to delete") 65 s.pages.HxRefresh(w) 66 return 67 } 68 69 _, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{ 70 Collection: tangled.GraphVouchNSID, 71 Repo: currentUser.Did, 72 Rkey: subjectDid, 73 }) 74 75 if err != nil { 76 l.Error("failed to delete vouch record", "err", err) 77 s.pages.Notice(w, "error", "Failed to delete vouch record.") 78 return 79 } 80 81 err = db.DeleteVouch(s.db, currentUser.Did, subjectDid) 82 if err != nil { 83 l.Warn("failed to delete vouch from DB", "err", err) 84 } 85 86 l.Info("deleted vouch record") 87 s.pages.HxRefresh(w) 88 return 89 } 90 91 kind, err := models.ParseVouchKind(r.FormValue("kind")) 92 if err != nil { 93 l.Warn("failed to parse vouch kind", "err", err) 94 s.pages.Notice(w, "error", "Invalid action type.") 95 return 96 } 97 98 reason := r.FormValue("reason") 99 createdAt := time.Now().Format(time.RFC3339) 100 101 var reasonPtr *string 102 if reason != "" { 103 reasonPtr = &reason 104 } 105 106 var evidences []string 107 for _, raw := range r.Form["evidences"] { 108 if _, err := syntax.ParseATURI(raw); err != nil { 109 l.Warn("invalid evidence AT-URI, skipping", "uri", raw, "err", err) 110 continue 111 } 112 evidences = append(evidences, raw) 113 } 114 115 var swapCid *string 116 existingVouch, err := db.GetVouch(s.db, currentUser.Did, subjectDid) 117 if err == nil { 118 cidStr := existingVouch.Cid.String() 119 swapCid = &cidStr 120 } 121 122 resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ 123 Collection: tangled.GraphVouchNSID, 124 Repo: currentUser.Did, 125 Rkey: subjectDid, 126 SwapRecord: swapCid, 127 Record: &lexutil.LexiconTypeDecoder{ 128 Val: &tangled.GraphVouch{ 129 Kind: string(kind), 130 Reason: reasonPtr, 131 CreatedAt: createdAt, 132 Evidences: evidences, 133 }}, 134 }) 135 if err != nil { 136 l.Error("failed to create atproto record", "err", err) 137 s.pages.Notice(w, "error", "Failed to create vouch record.") 138 return 139 } 140 141 l.Info("created atproto record", "uri", resp.Uri, "kind", kind) 142 143 newCid, err := cid.Parse(resp.Cid) 144 if err != nil { 145 l.Error("failed to parse returned cid", "err", err) 146 s.pages.Notice(w, "error", "Failed to save vouch.") 147 return 148 } 149 150 vouch := &models.Vouch{ 151 Did: syntax.DID(currentUser.Did), 152 SubjectDid: subjectIdent.DID, 153 Cid: newCid, 154 Kind: kind, 155 Reason: reasonPtr, 156 Evidences: evidences, 157 } 158 159 tx, err := s.db.Begin() 160 if err != nil { 161 l.Error("failed to start transaction", "err", err) 162 s.pages.Notice(w, "error", "Failed to save vouch.") 163 return 164 } 165 defer tx.Rollback() 166 167 err = db.AddVouch(tx, vouch) 168 if err != nil { 169 l.Error("failed to add vouch to db", "err", err) 170 s.pages.Notice(w, "error", "Failed to save vouch.") 171 return 172 } 173 174 if err = tx.Commit(); err != nil { 175 l.Error("failed to commit vouch transaction", "err", err) 176 s.pages.Notice(w, "error", "Failed to save vouch.") 177 return 178 } 179 180 s.pages.HxRefresh(w) 181}