forked from tangled.org/core
this repo has no description

add unfollow bits

Changed files
+117 -23
appview
+1
appview/db/db.go
···
create table if not exists follows (
user_did text not null,
subject_did text not null,
+
at_uri text not null,
followed_at text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
primary key (user_did, subject_did),
check (user_did <> subject_did)
+44 -3
appview/db/follow.go
···
package db
-
func (d *DB) AddFollow(userDid, subjectDid string) error {
-
query := `insert into follows (user_did, subject_did) values (?, ?)`
-
_, err := d.db.Exec(query, userDid, subjectDid)
+
import (
+
"log"
+
"time"
+
)
+
+
type Follow struct {
+
UserDid string
+
SubjectDid string
+
FollowedAt *time.Time
+
AtUri string
+
}
+
+
func (d *DB) AddFollow(userDid, subjectDid, atUri string) error {
+
query := `insert into follows (user_did, subject_did, at_uri) values (?, ?, ?)`
+
_, err := d.db.Exec(query, userDid, subjectDid, atUri)
+
return err
+
}
+
+
// Get a follow record
+
func (d *DB) GetFollow(userDid, subjectDid string) (*Follow, error) {
+
query := `select user_did, subject_did, followed_at, at_uri from follows where user_did = ? and subject_did = ?`
+
row := d.db.QueryRow(query, userDid, subjectDid)
+
+
var follow Follow
+
var followedAt string
+
err := row.Scan(&follow.UserDid, &follow.SubjectDid, &followedAt, &follow.AtUri)
+
if err != nil {
+
return nil, err
+
}
+
+
followedAtTime, err := time.Parse(time.RFC3339, followedAt)
+
if err != nil {
+
log.Println("unable to determine followed at time")
+
follow.FollowedAt = nil
+
} else {
+
follow.FollowedAt = &followedAtTime
+
}
+
+
return &follow, nil
+
}
+
+
// Get a follow record
+
func (d *DB) DeleteFollow(userDid, subjectDid string) error {
+
_, err := d.db.Exec(`delete from follows where user_did = ? and subject_did = ?`, userDid, subjectDid)
return err
}
+72 -20
appview/state/state.go
···
}
func (s *State) Follow(w http.ResponseWriter, r *http.Request) {
-
subject := r.FormValue("subject")
+
currentUser := s.auth.GetUser(r)
+
subject := r.URL.Query().Get("subject")
if subject == "" {
log.Println("invalid form")
return
}
subjectIdent, err := s.resolver.ResolveIdent(r.Context(), subject)
-
currentUser := s.auth.GetUser(r)
+
if err != nil {
+
log.Println("failed to follow, invalid did")
+
}
+
+
if currentUser.Did == subjectIdent.DID.String() {
+
log.Println("cant follow or unfollow yourself")
+
return
+
}
client, _ := s.auth.AuthorizedClient(r)
-
createdAt := time.Now().Format(time.RFC3339)
-
resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
-
Collection: tangled.GraphFollowNSID,
-
Repo: currentUser.Did,
-
Rkey: s.TID(),
-
Record: &lexutil.LexiconTypeDecoder{
-
Val: &tangled.GraphFollow{
-
Subject: subjectIdent.DID.String(),
-
CreatedAt: createdAt,
-
}},
-
})
+
+
switch r.Method {
+
case http.MethodPost:
+
createdAt := time.Now().Format(time.RFC3339)
+
resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+
Collection: tangled.GraphFollowNSID,
+
Repo: currentUser.Did,
+
Rkey: s.TID(),
+
Record: &lexutil.LexiconTypeDecoder{
+
Val: &tangled.GraphFollow{
+
Subject: subjectIdent.DID.String(),
+
CreatedAt: createdAt,
+
}},
+
})
+
if err != nil {
+
log.Println("failed to create atproto record", err)
+
return
+
}
+
+
err = s.db.AddFollow(currentUser.Did, subjectIdent.DID.String(), resp.Uri)
+
if err != nil {
+
log.Println("failed to follow", err)
+
return
+
}
+
+
log.Println("created atproto record: ", resp.Uri)
+
+
return
+
case http.MethodDelete:
+
// find the record in the db
+
+
follow, err := s.db.GetFollow(currentUser.Did, subjectIdent.DID.String())
+
if err != nil {
+
log.Println("failed to get follow relationship")
+
return
+
}
+
+
existingRecordUri, _ := syntax.ParseATURI(follow.AtUri)
+
+
resp, err := comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
+
Collection: tangled.GraphFollowNSID,
+
Repo: currentUser.Did,
+
Rkey: existingRecordUri.RecordKey().String(),
+
})
+
+
log.Println(resp.Commit.Cid)
+
+
if err != nil {
+
log.Println("failed to unfollow")
+
return
+
}
+
+
err = s.db.DeleteFollow(currentUser.Did, subjectIdent.DID.String())
+
if err != nil {
+
log.Println("failed to delete follow from DB")
+
// this is not an issue, the firehose event might have already done this
+
}
-
err = s.db.AddFollow(currentUser.Did, subjectIdent.DID.String())
-
if err != nil {
-
log.Println("failed to follow", err)
+
w.WriteHeader(http.StatusNoContent)
return
}
-
log.Println("created atproto record: ", resp.Uri)
-
-
return
}
func (s *State) Router() http.Handler {
···
// r.Post("/import", s.ImportRepo)
})
-
r.With(AuthMiddleware(s)).Put("/follow", s.Follow)
+
r.With(AuthMiddleware(s)).Route("/follow", func(r chi.Router) {
+
r.Post("/", s.Follow)
+
r.Delete("/", s.Follow)
+
})
r.Route("/settings", func(r chi.Router) {
r.Use(AuthMiddleware(s))