Mirror of @tangled.org/core. Running on a Raspberry Pi Zero 2 (Please be gentle).
0
fork

Configure Feed

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

add /follow endpoint

Akshay 3990d9a3 4b3dd514

+163 -63
api/tangled/cbor_gen.go

This is a binary file and will not be displayed.

api/tangled/graphfollow.go

This is a binary file and will not be displayed.

+7
appview/db/db.go
··· 40 40 created text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')), 41 41 unique(did, name, knot) 42 42 ); 43 + create table if not exists follows ( 44 + user_did text not null, 45 + subject_did text not null, 46 + followed_at text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')), 47 + primary key (user_did, subject_did), 48 + check (user_did <> subject_did) 49 + ); 43 50 `) 44 51 if err != nil { 45 52 return nil, err
+7
appview/db/follow.go
··· 1 + package db 2 + 3 + func (d *DB) AddFollow(userDid, subjectDid string) error { 4 + query := `insert into follows (user_did, subject_did) values (?, ?)` 5 + _, err := d.db.Exec(query, userDid, subjectDid) 6 + return err 7 + }
+76
appview/state/settings.go
··· 1 + package state 2 + 3 + import ( 4 + "log" 5 + "net/http" 6 + "strings" 7 + "time" 8 + 9 + comatproto "github.com/bluesky-social/indigo/api/atproto" 10 + lexutil "github.com/bluesky-social/indigo/lex/util" 11 + "github.com/gliderlabs/ssh" 12 + "github.com/sotangled/tangled/api/tangled" 13 + "github.com/sotangled/tangled/appview/pages" 14 + ) 15 + 16 + func (s *State) Settings(w http.ResponseWriter, r *http.Request) { 17 + // for now, this is just pubkeys 18 + user := s.auth.GetUser(r) 19 + pubKeys, err := s.db.GetPublicKeys(user.Did) 20 + if err != nil { 21 + log.Println(err) 22 + } 23 + 24 + s.pages.Settings(w, pages.SettingsParams{ 25 + LoggedInUser: user, 26 + PubKeys: pubKeys, 27 + }) 28 + } 29 + 30 + func (s *State) SettingsKeys(w http.ResponseWriter, r *http.Request) { 31 + switch r.Method { 32 + case http.MethodGet: 33 + w.Write([]byte("unimplemented")) 34 + log.Println("unimplemented") 35 + return 36 + case http.MethodPut: 37 + did := s.auth.GetDid(r) 38 + key := r.FormValue("key") 39 + key = strings.TrimSpace(key) 40 + name := r.FormValue("name") 41 + client, _ := s.auth.AuthorizedClient(r) 42 + 43 + _, _, _, _, err := ssh.ParseAuthorizedKey([]byte(key)) 44 + if err != nil { 45 + log.Printf("parsing public key: %s", err) 46 + return 47 + } 48 + 49 + if err := s.db.AddPublicKey(did, name, key); err != nil { 50 + log.Printf("adding public key: %s", err) 51 + return 52 + } 53 + 54 + // store in pds too 55 + resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ 56 + Collection: tangled.PublicKeyNSID, 57 + Repo: did, 58 + Rkey: s.TID(), 59 + Record: &lexutil.LexiconTypeDecoder{ 60 + Val: &tangled.PublicKey{ 61 + Created: time.Now().Format(time.RFC3339), 62 + Key: key, 63 + Name: name, 64 + }}, 65 + }) 66 + // invalid record 67 + if err != nil { 68 + log.Printf("failed to create record: %s", err) 69 + return 70 + } 71 + 72 + log.Println("created atproto record: ", resp.Uri) 73 + 74 + return 75 + } 76 + }
+42 -63
appview/state/state.go
··· 14 14 comatproto "github.com/bluesky-social/indigo/api/atproto" 15 15 "github.com/bluesky-social/indigo/atproto/syntax" 16 16 lexutil "github.com/bluesky-social/indigo/lex/util" 17 - "github.com/gliderlabs/ssh" 18 17 "github.com/go-chi/chi/v5" 19 18 tangled "github.com/sotangled/tangled/api/tangled" 20 19 "github.com/sotangled/tangled/appview" ··· 153 154 } 154 155 } 155 156 156 - func (s *State) Settings(w http.ResponseWriter, r *http.Request) { 157 - // for now, this is just pubkeys 158 - user := s.auth.GetUser(r) 159 - pubKeys, err := s.db.GetPublicKeys(user.Did) 160 - if err != nil { 161 - log.Println(err) 162 - } 163 - 164 - s.pages.Settings(w, pages.SettingsParams{ 165 - LoggedInUser: user, 166 - PubKeys: pubKeys, 167 - }) 168 - } 169 - 170 157 func (s *State) Keys(w http.ResponseWriter, r *http.Request) { 171 158 user := chi.URLParam(r, "user") 172 159 user = strings.TrimPrefix(user, "@") ··· 182 197 for _, k := range pubKeys { 183 198 key := strings.TrimRight(k.Key, "\n") 184 199 w.Write([]byte(fmt.Sprintln(key))) 185 - } 186 - } 187 - 188 - func (s *State) SettingsKeys(w http.ResponseWriter, r *http.Request) { 189 - switch r.Method { 190 - case http.MethodGet: 191 - w.Write([]byte("unimplemented")) 192 - log.Println("unimplemented") 193 - return 194 - case http.MethodPut: 195 - did := s.auth.GetDid(r) 196 - key := r.FormValue("key") 197 - key = strings.TrimSpace(key) 198 - name := r.FormValue("name") 199 - client, _ := s.auth.AuthorizedClient(r) 200 - 201 - _, _, _, _, err := ssh.ParseAuthorizedKey([]byte(key)) 202 - if err != nil { 203 - log.Printf("parsing public key: %s", err) 204 - return 205 - } 206 - 207 - if err := s.db.AddPublicKey(did, name, key); err != nil { 208 - log.Printf("adding public key: %s", err) 209 - return 210 - } 211 - 212 - // store in pds too 213 - resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ 214 - Collection: tangled.PublicKeyNSID, 215 - Repo: did, 216 - Rkey: s.TID(), 217 - Record: &lexutil.LexiconTypeDecoder{ 218 - Val: &tangled.PublicKey{ 219 - Created: time.Now().Format(time.RFC3339), 220 - Key: key, 221 - Name: name, 222 - }}, 223 - }) 224 - // invalid record 225 - if err != nil { 226 - log.Printf("failed to create record: %s", err) 227 - return 228 - } 229 - 230 - log.Println("created atproto record: ", resp.Uri) 231 - 232 - return 233 200 } 234 201 } 235 202 ··· 531 594 }) 532 595 } 533 596 597 + func (s *State) Follow(w http.ResponseWriter, r *http.Request) { 598 + subject := r.FormValue("subject") 599 + 600 + if subject == "" { 601 + log.Println("invalid form") 602 + return 603 + } 604 + 605 + subjectIdent, err := s.resolver.ResolveIdent(r.Context(), subject) 606 + currentUser := s.auth.GetUser(r) 607 + 608 + client, _ := s.auth.AuthorizedClient(r) 609 + createdAt := time.Now().Format(time.RFC3339) 610 + resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ 611 + Collection: tangled.GraphFollowNSID, 612 + Repo: currentUser.Did, 613 + Rkey: s.TID(), 614 + Record: &lexutil.LexiconTypeDecoder{ 615 + Val: &tangled.GraphFollow{ 616 + Subject: subjectIdent.DID.String(), 617 + CreatedAt: createdAt, 618 + }}, 619 + }) 620 + 621 + err = s.db.AddFollow(currentUser.Did, subjectIdent.DID.String()) 622 + if err != nil { 623 + log.Println("failed to follow", err) 624 + return 625 + } 626 + 627 + // invalid record 628 + if err != nil { 629 + log.Printf("failed to create record: %s", err) 630 + return 631 + } 632 + log.Println("created atproto record: ", resp.Uri) 633 + 634 + return 635 + } 636 + 534 637 func (s *State) Router() http.Handler { 535 638 router := chi.NewRouter() 536 639 ··· 647 670 }) 648 671 // r.Post("/import", s.ImportRepo) 649 672 }) 673 + 674 + r.With(AuthMiddleware(s)).Put("/follow", s.Follow) 650 675 651 676 r.Route("/settings", func(r chi.Router) { 652 677 r.Use(AuthMiddleware(s))
+1
cmd/gen.go
··· 16 16 "tangled", 17 17 shtangled.PublicKey{}, 18 18 shtangled.KnotMember{}, 19 + shtangled.GraphFollow{}, 19 20 ); err != nil { 20 21 panic(err) 21 22 }
+30
lexicons/follow.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "sh.tangled.graph.follow", 4 + "needsCbor": true, 5 + "needsType": true, 6 + "defs": { 7 + "main": { 8 + "type": "record", 9 + "key": "tid", 10 + "record": { 11 + "type": "object", 12 + "required": [ 13 + "createdAt", 14 + "subject" 15 + ], 16 + "properties": { 17 + "createdAt": { 18 + "type": "string", 19 + "format": "datetime" 20 + }, 21 + "subject": { 22 + "type": "string", 23 + "format": "did" 24 + } 25 + } 26 + } 27 + } 28 + } 29 + } 30 +