+1
appview/db/db.go
+1
appview/db/db.go
+44
-3
appview/db/follow.go
+44
-3
appview/db/follow.go
···
1
1
package db
2
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)
3
+
import (
4
+
"log"
5
+
"time"
6
+
)
7
+
8
+
type Follow struct {
9
+
UserDid string
10
+
SubjectDid string
11
+
FollowedAt *time.Time
12
+
AtUri string
13
+
}
14
+
15
+
func (d *DB) AddFollow(userDid, subjectDid, atUri string) error {
16
+
query := `insert into follows (user_did, subject_did, at_uri) values (?, ?, ?)`
17
+
_, err := d.db.Exec(query, userDid, subjectDid, atUri)
18
+
return err
19
+
}
20
+
21
+
// Get a follow record
22
+
func (d *DB) GetFollow(userDid, subjectDid string) (*Follow, error) {
23
+
query := `select user_did, subject_did, followed_at, at_uri from follows where user_did = ? and subject_did = ?`
24
+
row := d.db.QueryRow(query, userDid, subjectDid)
25
+
26
+
var follow Follow
27
+
var followedAt string
28
+
err := row.Scan(&follow.UserDid, &follow.SubjectDid, &followedAt, &follow.AtUri)
29
+
if err != nil {
30
+
return nil, err
31
+
}
32
+
33
+
followedAtTime, err := time.Parse(time.RFC3339, followedAt)
34
+
if err != nil {
35
+
log.Println("unable to determine followed at time")
36
+
follow.FollowedAt = nil
37
+
} else {
38
+
follow.FollowedAt = &followedAtTime
39
+
}
40
+
41
+
return &follow, nil
42
+
}
43
+
44
+
// Get a follow record
45
+
func (d *DB) DeleteFollow(userDid, subjectDid string) error {
46
+
_, err := d.db.Exec(`delete from follows where user_did = ? and subject_did = ?`, userDid, subjectDid)
6
47
return err
7
48
}
+72
-20
appview/state/state.go
+72
-20
appview/state/state.go
···
531
531
}
532
532
533
533
func (s *State) Follow(w http.ResponseWriter, r *http.Request) {
534
-
subject := r.FormValue("subject")
534
+
currentUser := s.auth.GetUser(r)
535
535
536
+
subject := r.URL.Query().Get("subject")
536
537
if subject == "" {
537
538
log.Println("invalid form")
538
539
return
539
540
}
540
541
541
542
subjectIdent, err := s.resolver.ResolveIdent(r.Context(), subject)
542
-
currentUser := s.auth.GetUser(r)
543
+
if err != nil {
544
+
log.Println("failed to follow, invalid did")
545
+
}
546
+
547
+
if currentUser.Did == subjectIdent.DID.String() {
548
+
log.Println("cant follow or unfollow yourself")
549
+
return
550
+
}
543
551
544
552
client, _ := s.auth.AuthorizedClient(r)
545
-
createdAt := time.Now().Format(time.RFC3339)
546
-
resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
547
-
Collection: tangled.GraphFollowNSID,
548
-
Repo: currentUser.Did,
549
-
Rkey: s.TID(),
550
-
Record: &lexutil.LexiconTypeDecoder{
551
-
Val: &tangled.GraphFollow{
552
-
Subject: subjectIdent.DID.String(),
553
-
CreatedAt: createdAt,
554
-
}},
555
-
})
553
+
554
+
switch r.Method {
555
+
case http.MethodPost:
556
+
createdAt := time.Now().Format(time.RFC3339)
557
+
resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
558
+
Collection: tangled.GraphFollowNSID,
559
+
Repo: currentUser.Did,
560
+
Rkey: s.TID(),
561
+
Record: &lexutil.LexiconTypeDecoder{
562
+
Val: &tangled.GraphFollow{
563
+
Subject: subjectIdent.DID.String(),
564
+
CreatedAt: createdAt,
565
+
}},
566
+
})
567
+
if err != nil {
568
+
log.Println("failed to create atproto record", err)
569
+
return
570
+
}
571
+
572
+
err = s.db.AddFollow(currentUser.Did, subjectIdent.DID.String(), resp.Uri)
573
+
if err != nil {
574
+
log.Println("failed to follow", err)
575
+
return
576
+
}
577
+
578
+
log.Println("created atproto record: ", resp.Uri)
579
+
580
+
return
581
+
case http.MethodDelete:
582
+
// find the record in the db
583
+
584
+
follow, err := s.db.GetFollow(currentUser.Did, subjectIdent.DID.String())
585
+
if err != nil {
586
+
log.Println("failed to get follow relationship")
587
+
return
588
+
}
589
+
590
+
existingRecordUri, _ := syntax.ParseATURI(follow.AtUri)
591
+
592
+
resp, err := comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
593
+
Collection: tangled.GraphFollowNSID,
594
+
Repo: currentUser.Did,
595
+
Rkey: existingRecordUri.RecordKey().String(),
596
+
})
597
+
598
+
log.Println(resp.Commit.Cid)
599
+
600
+
if err != nil {
601
+
log.Println("failed to unfollow")
602
+
return
603
+
}
604
+
605
+
err = s.db.DeleteFollow(currentUser.Did, subjectIdent.DID.String())
606
+
if err != nil {
607
+
log.Println("failed to delete follow from DB")
608
+
// this is not an issue, the firehose event might have already done this
609
+
}
556
610
557
-
err = s.db.AddFollow(currentUser.Did, subjectIdent.DID.String())
558
-
if err != nil {
559
-
log.Println("failed to follow", err)
611
+
w.WriteHeader(http.StatusNoContent)
560
612
return
561
613
}
562
614
563
-
log.Println("created atproto record: ", resp.Uri)
564
-
565
-
return
566
615
}
567
616
568
617
func (s *State) Router() http.Handler {
···
655
704
// r.Post("/import", s.ImportRepo)
656
705
})
657
706
658
-
r.With(AuthMiddleware(s)).Put("/follow", s.Follow)
707
+
r.With(AuthMiddleware(s)).Route("/follow", func(r chi.Router) {
708
+
r.Post("/", s.Follow)
709
+
r.Delete("/", s.Follow)
710
+
})
659
711
660
712
r.Route("/settings", func(r chi.Router) {
661
713
r.Use(AuthMiddleware(s))