Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Blame · server/web/activity_query.go

Line attribution on main · 105 line(s)

73a732b1
Keenan Nemetz
9d ago
1 package web
2
bca9ec24
Keenan Nemetz
9d ago
3 // The activity feed as a page of events.
73a732b1
Keenan Nemetz
9d ago
4 //
bca9ec24
Keenan Nemetz
9d ago
5 // The rows come from forge/index (`Events` and `EventCount`), which keeps a row
6 // per feed event with a (repository, time) index: a page is an index range read,
7 // and an unfiltered page total is a stored count. Releases are rows there too, so
8 // nothing is fetched from git to render a page.
73a732b1
Keenan Nemetz
9d ago
9
10 import (
11 "strings"
12 "time"
13
d37d301f
Keenan Nemetz
15h ago
14 "rodent.software/vole/forge/index"
73a732b1
Keenan Nemetz
9d ago
15 )
16
bca9ec24
Keenan Nemetz
9d ago
17 // activityEventFromRow maps one indexed event to the event a template renders.
18 func (w *Web) activityEventFromRow(row index.EventRow, repoName string, withRepo bool) activityEvent {
73a732b1
Keenan Nemetz
9d ago
19 ev := activityEvent{
bca9ec24
Keenan Nemetz
9d ago
20 Time: time.Unix(row.At, 0).UTC(), ActorName: row.Actor,
73a732b1
Keenan Nemetz
9d ago
21 Title: row.Title, Assignees: splitAssignees(row.Assignees),
22 }
23 if withRepo {
24 ev.Repo = repoName
25 }
ed03b3d1
Keenan Nemetz
2h ago
26 base := "/" + repoName
bca9ec24
Keenan Nemetz
9d ago
27 switch row.Kind {
28 case "release":
29 ev.Kind, ev.Icon, ev.Detail = "release", "tag", "released"
30 ev.Actor = row.Actor // the tagger identity, as the tag records it
a6b42433
Keenan Nemetz
7d ago
31 // A tag's tagger is a Git identity, not the credential that proves an
32 // account, so it is shown as text and never linked to a profile.
33 ev.ActorName = ""
bca9ec24
Keenan Nemetz
9d ago
34 ev.URL = base + "/releases/" + row.EntityID
35 return ev
36 case "issue":
37 ev.Kind, ev.Icon = "issue", "circle-dot"
38 case "change":
39 ev.Kind, ev.Icon = "change", "git-pull-request"
40 }
41 ev.Actor = w.who(row.Actor)
42 switch row.Type {
43 case "open":
44 if row.Kind == "issue" {
45 ev.Detail = "opened issue"
46 ev.URL = base + "/issues/" + row.EntityID
47 } else {
48 ev.Detail = "opened change"
8fb7aabf
Keenan Nemetz
3d ago
49 ev.URL = base + "/changes/" + row.EntityID
bca9ec24
Keenan Nemetz
9d ago
50 }
51 case "comment":
52 ev.Icon = "message-square"
53 if row.Kind == "issue" {
54 ev.Detail = "commented on issue"
55 ev.URL = base + "/issues/" + row.ParentID + "#c-" + row.CommentID
56 } else {
57 ev.Detail = "commented on change"
8fb7aabf
Keenan Nemetz
3d ago
58 ev.URL = base + "/changes/" + row.ParentID + "#c-" + row.CommentID
bca9ec24
Keenan Nemetz
9d ago
59 }
73a732b1
Keenan Nemetz
9d ago
60 case "approval":
bca9ec24
Keenan Nemetz
9d ago
61 ev.Icon, ev.Detail = "check", "approved change"
8fb7aabf
Keenan Nemetz
3d ago
62 ev.URL = base + "/changes/" + row.EntityID
bca9ec24
Keenan Nemetz
9d ago
63 case "state":
64 if row.Kind == "issue" {
65 ev.Detail = issueStateDetail(row.State)
66 ev.URL = base + "/issues/" + row.EntityID
67 } else {
68 ev.Detail = requestStateDetail(row.State)
8fb7aabf
Keenan Nemetz
3d ago
69 ev.URL = base + "/changes/" + row.EntityID
bca9ec24
Keenan Nemetz
9d ago
70 }
73a732b1
Keenan Nemetz
9d ago
71 }
72 return ev
73 }
74
bca9ec24
Keenan Nemetz
9d ago
75 // activityPage returns one page of the feed and the pager that describes it.
76 func (w *Web) activityPage(repoIDs []string, names map[string]string,
73a732b1
Keenan Nemetz
9d ago
77 kind, actor, assignee string, withRepo bool, number, perPage int,
78 urlFor func(int) string, label string) ([]activityEvent, pager, error) {
bca9ec24
Keenan Nemetz
9d ago
79 count, err := w.Index.EventCount(repoIDs, kind, actor, assignee)
73a732b1
Keenan Nemetz
9d ago
80 if err != nil {
81 return nil, pager{}, err
82 }
bca9ec24
Keenan Nemetz
9d ago
83 p := newPager(count, perPage, number, urlFor)
73a732b1
Keenan Nemetz
9d ago
84 p.Label = label
85 if p.Total == 0 {
86 return nil, p, nil
87 }
bca9ec24
Keenan Nemetz
9d ago
88 from, _ := p.rows()
89 rows, err := w.Index.Events(repoIDs, kind, actor, assignee, perPage, from)
73a732b1
Keenan Nemetz
9d ago
90 if err != nil {
91 return nil, p, err
92 }
bca9ec24
Keenan Nemetz
9d ago
93 events := make([]activityEvent, 0, len(rows))
73a732b1
Keenan Nemetz
9d ago
94 for _, row := range rows {
95 events = append(events, w.activityEventFromRow(row, names[row.RepoID], withRepo))
96 }
bca9ec24
Keenan Nemetz
9d ago
97 return events, p, nil
73a732b1
Keenan Nemetz
9d ago
98 }
99
100 func splitAssignees(s string) []string {
101 if s == "" {
102 return nil
103 }
104 return strings.Split(s, "\x1f")
105 }