tiny 88x31 lexicon for atproto

lets see if this is any good

+95 -1
+7
db/lexicon.go
··· 236 236 `, uri) 237 237 return err 238 238 } 239 + 240 + func (s *Store) DeleteButton(uri string, ctx context.Context) error { 241 + _, err := s.pool.Exec(ctx, ` 242 + DELETE FROM buttons WHERE uri = $1 243 + `, uri) 244 + return err 245 + }
+1
handler/handler.go
··· 45 45 mux.HandleFunc("POST /logout", h.oauthMiddleware(h.logout)) 46 46 mux.HandleFunc("GET /upload", h.oauthMiddleware(getupload)) 47 47 mux.HandleFunc("POST /upload", h.oauthMiddleware(h.upload)) 48 + mux.HandleFunc("POST /delete", h.oauthMiddleware(h.delete)) 48 49 mux.HandleFunc("POST /like", h.oauthMiddleware(h.like)) 49 50 mux.HandleFunc("POST /unlike", h.oauthMiddleware(h.unlike)) 50 51 mux.HandleFunc("GET /button", h.oauthMiddleware(h.getbutton))
+69
handler/upload.go
··· 118 118 http.Redirect(w, r, fmt.Sprintf("/button?uri=%s", uri), http.StatusSeeOther) 119 119 } 120 120 121 + func (h *Handler) delete(cs *oauth.ClientSession, w http.ResponseWriter, r *http.Request) { 122 + if cs == nil { 123 + http.Error(w, "deletion requires auth", http.StatusUnauthorized) 124 + return 125 + } 126 + err := r.ParseForm() 127 + if err != nil { 128 + http.Error(w, "form failed to parse", http.StatusBadRequest) 129 + return 130 + } 131 + uri := r.FormValue("uri") 132 + if uri == "" { 133 + http.Error(w, "must provide uri, don't tamper with form", http.StatusBadRequest) 134 + return 135 + } 136 + aturi, err := syntax.ParseATURI(uri) 137 + if err != nil { 138 + http.Error(w, "uri should parse", http.StatusBadRequest) 139 + return 140 + } 141 + cid := r.FormValue("cid") 142 + if cid == "" { 143 + http.Error(w, "must provide a cid, don't tamper with form", http.StatusBadRequest) 144 + return 145 + } 146 + ll, err := h.db.GetMyLikesFor(uri, cid, cs.Data.AccountDID.String(), r.Context()) 147 + if err == nil { 148 + for _, likeuricid := range ll { 149 + arr := strings.Split(likeuricid, " ") 150 + if len(arr) != 2 { 151 + http.Error(w, "invalid likeuricid", http.StatusInternalServerError) 152 + return 153 + } 154 + likeuri := arr[0] 155 + likecid := arr[1] 156 + aturi, err := syntax.ParseATURI(likeuri) 157 + if err != nil { 158 + http.Error(w, "uri doesn't parse, don't tamper with form", http.StatusBadRequest) 159 + return 160 + } 161 + err = myoauth.DeleteLike(cs, aturi.RecordKey().String(), likecid, r.Context()) 162 + if err != nil { 163 + log.Println(err) 164 + http.Error(w, "error deleting like", http.StatusInternalServerError) 165 + return 166 + } 167 + err = h.db.DeleteLike(likeuri, r.Context()) 168 + if err != nil { 169 + log.Println(err) 170 + http.Error(w, "error deleting cached like", http.StatusInternalServerError) 171 + return 172 + } 173 + } 174 + } 175 + err = myoauth.DeleteButton(cs, aturi.RecordKey().String(), cid, r.Context()) 176 + if err != nil { 177 + log.Println(err) 178 + http.Error(w, "failed to delete button", http.StatusInternalServerError) 179 + return 180 + } 181 + err = h.db.DeleteButton(uri, r.Context()) 182 + if err != nil { 183 + log.Println(err) 184 + http.Error(w, "error deleting cached button", http.StatusInternalServerError) 185 + return 186 + } 187 + http.Redirect(w, r, "/", http.StatusSeeOther) 188 + } 189 + 121 190 func (h *Handler) upload(cs *oauth.ClientSession, w http.ResponseWriter, r *http.Request) { 122 191 if cs == nil { 123 192 http.Error(w, "upload requires auth", http.StatusUnauthorized)
+17
oauth/client.go
··· 67 67 return 68 68 } 69 69 70 + func DeleteButton(cs *oauth.ClientSession, rkey string, cid string, ctx context.Context) error { 71 + c := cs.APIClient() 72 + body := map[string]any{ 73 + "collection": "store.88x31.button", 74 + "repo": *c.AccountDID, 75 + "rkey": rkey, 76 + "swapRecord": cid, 77 + } 78 + var out atproto.RepoDeleteRecord_Output 79 + err := c.Post(ctx, "com.atproto.repo.deleteRecord", body, &out) 80 + if err != nil { 81 + err = errors.New("oops! failed to delete a button: " + err.Error()) 82 + return err 83 + } 84 + return nil 85 + } 86 + 70 87 func CreateLike(cs *oauth.ClientSession, like *lex.LikeRecord, ctx context.Context) (uri string, cid string, err error) { 71 88 c := cs.APIClient() 72 89 body := map[string]any{
+1 -1
tmpl/button.html
··· 15 15 </form> 16 16 {{end}} 17 17 {{if eq .Button.DID (deref .DID)}} 18 - <form action="/unlike" method="POST"> 18 + <form action="/delete" method="POST"> 19 19 <input type="text" name="uri" value="{{.Button.URI}}" hidden /> 20 20 <input type="text" name="cid" value="{{.Button.CID}}" hidden /> 21 21 <input type="submit" value='delete (permanent, one click)'/>