+34
appview/db/follow.go
+34
appview/db/follow.go
···
46
46
_, err := d.db.Exec(`delete from follows where user_did = ? and subject_did = ?`, userDid, subjectDid)
47
47
return err
48
48
}
49
+
50
+
func (d *DB) GetAllFollows() ([]Follow, error) {
51
+
var follows []Follow
52
+
53
+
rows, err := d.db.Query(`select user_did, subject_did, followed_at, at_uri from follows`)
54
+
if err != nil {
55
+
return nil, err
56
+
}
57
+
defer rows.Close()
58
+
59
+
for rows.Next() {
60
+
var follow Follow
61
+
var followedAt string
62
+
if err := rows.Scan(&follow.UserDid, &follow.SubjectDid, &followedAt, &follow.RKey); err != nil {
63
+
return nil, err
64
+
}
65
+
66
+
followedAtTime, err := time.Parse(time.RFC3339, followedAt)
67
+
if err != nil {
68
+
log.Println("unable to determine followed at time")
69
+
follow.FollowedAt = nil
70
+
} else {
71
+
follow.FollowedAt = &followedAtTime
72
+
}
73
+
74
+
follows = append(follows, follow)
75
+
}
76
+
77
+
if err := rows.Err(); err != nil {
78
+
return nil, err
79
+
}
80
+
81
+
return follows, nil
82
+
}
+24
appview/db/repos.go
+24
appview/db/repos.go
···
13
13
Rkey string
14
14
}
15
15
16
+
func (d *DB) GetAllRepos() ([]Repo, error) {
17
+
var repos []Repo
18
+
19
+
rows, err := d.db.Query(`select did, name, knot, created from repos`)
20
+
if err != nil {
21
+
return nil, err
22
+
}
23
+
defer rows.Close()
24
+
25
+
for rows.Next() {
26
+
repo, err := scanRepo(rows)
27
+
if err != nil {
28
+
return nil, err
29
+
}
30
+
repos = append(repos, *repo)
31
+
}
32
+
33
+
if err := rows.Err(); err != nil {
34
+
return nil, err
35
+
}
36
+
37
+
return repos, nil
38
+
}
39
+
16
40
func (d *DB) GetAllReposByDid(did string) ([]Repo, error) {
17
41
var repos []Repo
18
42
+48
appview/db/timeline.go
+48
appview/db/timeline.go
···
1
+
package db
2
+
3
+
import (
4
+
"sort"
5
+
"time"
6
+
)
7
+
8
+
type TimelineEvent struct {
9
+
*Repo
10
+
*Follow
11
+
EventAt *time.Time
12
+
}
13
+
14
+
func (d *DB) MakeTimeline() ([]TimelineEvent, error) {
15
+
var events []TimelineEvent
16
+
17
+
repos, err := d.GetAllRepos()
18
+
if err != nil {
19
+
return nil, err
20
+
}
21
+
22
+
follows, err := d.GetAllFollows()
23
+
if err != nil {
24
+
return nil, err
25
+
}
26
+
27
+
for _, repo := range repos {
28
+
events = append(events, TimelineEvent{
29
+
Repo: &repo,
30
+
Follow: nil,
31
+
EventAt: repo.Created,
32
+
})
33
+
}
34
+
35
+
for _, follow := range follows {
36
+
events = append(events, TimelineEvent{
37
+
Repo: nil,
38
+
Follow: &follow,
39
+
EventAt: follow.FollowedAt,
40
+
})
41
+
}
42
+
43
+
sort.Slice(events, func(i, j int) bool {
44
+
return events[i].EventAt.After(*events[j].EventAt)
45
+
})
46
+
47
+
return events, nil
48
+
}
+1
appview/pages/pages.go
+1
appview/pages/pages.go
+37
-4
appview/pages/templates/timeline.html
+37
-4
appview/pages/templates/timeline.html
···
1
-
{{define "title"}}timeline{{end}}
1
+
{{ define "title" }}timeline{{ end }}
2
+
3
+
{{ define "content" }}
4
+
<h1>Timeline</h1>
5
+
6
+
{{ range .Timeline }}
7
+
{{ if .Repo }}
8
+
<div class="border border-black p-4 m-2 bg-white w-1/2">
9
+
<div class="flex items-center">
10
+
<div class="text-sm text-gray-600">
11
+
{{ .Repo.Did }} created
12
+
</div>
13
+
<div class="px-3">{{ .Repo.Name }}</div>
14
+
</div>
15
+
16
+
<time class="text-sm text-gray-700"
17
+
>{{ .Repo.Created | timeFmt }}</time
18
+
>
19
+
</div>
20
+
{{ else if .Follow }}
21
+
<div class="border border-black p-4 m-2 bg-white w-1/2">
22
+
<div class="flex items-center">
23
+
<div class="text-sm text-gray-600">
24
+
{{ .Follow.UserDid }} followed
25
+
</div>
26
+
<div class="text-sm text-gray-800">
27
+
{{ .Follow.SubjectDid }}
28
+
</div>
29
+
</div>
2
30
3
-
{{define "content"}}
4
-
<h1>timeline</h1>
5
-
{{end}}
31
+
<time class="text-sm text-gray-700"
32
+
>{{ .Follow.FollowedAt | timeFmt }}</time
33
+
>
34
+
</div>
35
+
{{ end }}
36
+
{{ end }}
37
+
38
+
{{ end }}
+9
appview/state/state.go
+9
appview/state/state.go
···
157
157
158
158
func (s *State) Timeline(w http.ResponseWriter, r *http.Request) {
159
159
user := s.auth.GetUser(r)
160
+
161
+
timeline, err := s.db.MakeTimeline()
162
+
if err != nil {
163
+
log.Println(err)
164
+
s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.")
165
+
}
166
+
160
167
s.pages.Timeline(w, pages.TimelineParams{
161
168
LoggedInUser: user,
169
+
Timeline: timeline,
162
170
})
171
+
163
172
return
164
173
}
165
174