package forge import ( "net/http" "time" ) const followSchema = ` create table if not exists follows ( follower integer not null references users(id) on delete cascade, followee integer not null references users(id) on delete cascade, created integer not null, primary key (follower, followee) ); create index if not exists follows_followee on follows(followee, created); ` func (s *Store) Follow(follower, followee int64, on bool) { if on { s.db.Exec(`insert or ignore into follows(follower, followee, created) values (?, ?, ?)`, follower, followee, time.Now().Unix()) } else { s.db.Exec(`delete from follows where follower = ? and followee = ?`, follower, followee) } } func (s *Store) Follows(follower, followee int64) bool { var n int s.db.QueryRow(`select count(*) from follows where follower = ? and followee = ?`, follower, followee).Scan(&n) return n > 0 } func (s *Store) FollowCounts(id int64) (followers, following int) { s.db.QueryRow(`select (select count(*) from follows f join users u on u.id = f.follower where f.followee = ?1 and u.banned = 0), (select count(*) from follows f join users u on u.id = f.followee where f.follower = ?1 and u.banned = 0)`, id).Scan(&followers, &following) return } func (s *Store) Followers(id int64) []User { return s.userList(`select u.id, u.name, u.created from follows f join users u on u.id = f.follower where f.followee = ? and u.banned = 0 order by f.created desc`, id) } func (s *Store) Following(id int64) []User { return s.userList(`select u.id, u.name, u.created from follows f join users u on u.id = f.followee where f.follower = ? and u.banned = 0 order by f.created desc`, id) } func (s *Server) follow(w http.ResponseWriter, r *http.Request, owner User) { u := s.require(w, r) if u == nil { return } if u.ID != owner.ID && !s.store.IsOrg(u.ID) { s.store.Follow(u.ID, owner.ID, !s.store.Follows(u.ID, owner.ID)) } http.Redirect(w, r, "/~"+owner.Name, http.StatusSeeOther) } func (s *Server) follows(w http.ResponseWriter, r *http.Request, owner User, viewer *User, kind string) { list := s.store.Followers(owner.ID) if kind == "following" { list = s.store.Following(owner.ID) } people := make([]userHit, 0, len(list)) for _, p := range list { people = append(people, userHit{User: p, Profile: s.store.Profile(p.ID)}) } followers, following := s.store.FollowCounts(owner.ID) s.render(w, r, "follows", page{Title: "~" + owner.Name + " " + kind, User: viewer, Data: map[string]any{"Owner": owner, "Kind": kind, "People": people, "Followers": followers, "Following": following, "Org": s.store.IsOrg(owner.ID)}}) }