Monorepo for Tangled tangled.org
2

Configure Feed

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

at icy/sntnrt 5.7 kB View raw
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) SkipVouchSuggestion(w http.ResponseWriter, r *http.Request) { 18 l := log.SubLogger(s.logger, "skipVouchSuggestion") 19 currentUser := s.oauth.GetMultiAccountUser(r) 20 21 subject := r.FormValue("subject") 22 if subject == "" { 23 l.Warn("missing subject") 24 s.pages.Notice(w, "error", "Missing subject user.") 25 return 26 } 27 28 subjectIdent, err := s.idResolver.ResolveIdent(r.Context(), subject) 29 if err != nil { 30 l.Error("failed to resolve subject", "subject", subject, "err", err) 31 s.pages.Notice(w, "error", "Could not find that user.") 32 return 33 } 34 35 if currentUser.Did == subjectIdent.DID.String() { 36 l.Warn("cannot skip yourself") 37 s.pages.Notice(w, "error", "You cannot skip yourself.") 38 return 39 } 40 41 if err := db.SkipVouchSuggestion(s.db, currentUser.Did, subjectIdent.DID.String()); err != nil { 42 l.Error("failed to skip vouch suggestion", "err", err) 43 s.pages.Notice(w, "error", "Failed to skip suggestion.") 44 return 45 } 46 47 s.pages.HxRefresh(w) 48} 49 50func (s *State) Vouch(w http.ResponseWriter, r *http.Request) { 51 l := log.SubLogger(s.logger, "vouch") 52 l = s.logger.With("handler", "Vouch") 53 currentUser := s.oauth.GetMultiAccountUser(r) 54 55 var subject string 56 57 subject = r.FormValue("subject") 58 59 if subject == "" { 60 l.Warn("invalid form: missing subject") 61 s.pages.Notice(w, "error", "Missing subject user.") 62 return 63 } 64 65 subjectIdent, err := s.idResolver.ResolveIdent(r.Context(), subject) 66 if err != nil { 67 l.Error("failed to vouch, invalid did", "subject", subject, "err", err) 68 s.pages.Notice(w, "error", "Could not find that user.") 69 return 70 } 71 72 if currentUser.Did == subjectIdent.DID.String() { 73 l.Warn("cant vouch or denounce yourself") 74 s.pages.Notice(w, "error", "You cannot vouch for yourself.") 75 return 76 } 77 78 client, err := s.oauth.AuthorizedClient(r) 79 if err != nil { 80 l.Error("failed to authorize client", "err", err) 81 s.pages.Notice(w, "error", "Authentication required.") 82 return 83 } 84 85 if err := r.ParseForm(); err != nil { 86 l.Warn("failed to parse form", "err", err) 87 s.pages.Notice(w, "error", "Invalid form data.") 88 return 89 } 90 91 subjectDid := subjectIdent.DID.String() 92 93 // handle "none" by deleting any existing vouch 94 if r.FormValue("kind") == "none" { 95 _, err := db.GetVouch(s.db, currentUser.Did, subjectDid) 96 if err != nil { 97 l.Info("no existing vouch to delete") 98 s.pages.HxRefresh(w) 99 return 100 } 101 102 _, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{ 103 Collection: tangled.GraphVouchNSID, 104 Repo: currentUser.Did, 105 Rkey: subjectDid, 106 }) 107 108 if err != nil { 109 l.Error("failed to delete vouch record", "err", err) 110 s.pages.Notice(w, "error", "Failed to delete vouch record.") 111 return 112 } 113 114 err = db.DeleteVouch(s.db, currentUser.Did, subjectDid) 115 if err != nil { 116 l.Warn("failed to delete vouch from DB", "err", err) 117 } 118 119 l.Info("deleted vouch record") 120 s.pages.HxRefresh(w) 121 return 122 } 123 124 kind, err := models.ParseVouchKind(r.FormValue("kind")) 125 if err != nil { 126 l.Warn("failed to parse vouch kind", "err", err) 127 s.pages.Notice(w, "error", "Invalid action type.") 128 return 129 } 130 131 reason := r.FormValue("reason") 132 createdAt := time.Now().Format(time.RFC3339) 133 134 var reasonPtr *string 135 if reason != "" { 136 reasonPtr = &reason 137 } 138 139 var evidences []syntax.ATURI 140 for _, raw := range r.Form["evidences"] { 141 uri, err := syntax.ParseATURI(raw) 142 if err != nil { 143 l.Warn("invalid evidence AT-URI, skipping", "uri", raw, "err", err) 144 continue 145 } 146 evidences = append(evidences, uri) 147 } 148 149 var swapCid *string 150 existingVouch, err := db.GetVouch(s.db, currentUser.Did, subjectDid) 151 if err == nil { 152 cidStr := existingVouch.Cid.String() 153 swapCid = &cidStr 154 } 155 156 resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ 157 Collection: tangled.GraphVouchNSID, 158 Repo: currentUser.Did, 159 Rkey: subjectDid, 160 SwapRecord: swapCid, 161 Record: &lexutil.LexiconTypeDecoder{ 162 Val: &tangled.GraphVouch{ 163 Kind: string(kind), 164 Reason: reasonPtr, 165 CreatedAt: createdAt, 166 Evidences: func() []string { 167 ss := make([]string, len(evidences)) 168 for i, e := range evidences { 169 ss[i] = e.String() 170 } 171 return ss 172 }(), 173 }}, 174 }) 175 if err != nil { 176 l.Error("failed to create atproto record", "err", err) 177 s.pages.Notice(w, "error", "Failed to create vouch record.") 178 return 179 } 180 181 l.Info("created atproto record", "uri", resp.Uri, "kind", kind) 182 183 newCid, err := cid.Parse(resp.Cid) 184 if err != nil { 185 l.Error("failed to parse returned cid", "err", err) 186 s.pages.Notice(w, "error", "Failed to save vouch.") 187 return 188 } 189 190 vouch := &models.Vouch{ 191 Did: syntax.DID(currentUser.Did), 192 SubjectDid: subjectIdent.DID, 193 Cid: newCid, 194 Kind: kind, 195 Reason: reasonPtr, 196 Evidences: evidences, 197 } 198 199 tx, err := s.db.Begin() 200 if err != nil { 201 l.Error("failed to start transaction", "err", err) 202 s.pages.Notice(w, "error", "Failed to save vouch.") 203 return 204 } 205 defer tx.Rollback() 206 207 err = db.AddVouch(tx, vouch) 208 if err != nil { 209 l.Error("failed to add vouch to db", "err", err) 210 s.pages.Notice(w, "error", "Failed to save vouch.") 211 return 212 } 213 214 if err = tx.Commit(); err != nil { 215 l.Error("failed to commit vouch transaction", "err", err) 216 s.pages.Notice(w, "error", "Failed to save vouch.") 217 return 218 } 219 220 s.pages.HxRefresh(w) 221}