Federated via graft
3.0 kB
104 lines
1package activitypub
2
3import (
4 "strconv"
5 "time"
6
7 "graft/internal/state"
8)
9
10// OrderedCollection wraps a series' outbox: every mirrored event as a
11// Create{Note} activity, newest first.
12type OrderedCollection struct {
13 Context string `json:"@context"`
14 ID string `json:"id"`
15 Type string `json:"type"`
16 TotalItems int `json:"totalItems"`
17 OrderedItems []Create `json:"orderedItems"`
18}
19
20type Create struct {
21 Context string `json:"@context,omitempty"`
22 ID string `json:"id"`
23 Type string `json:"type"`
24 Actor string `json:"actor"`
25 Published string `json:"published"`
26 To []string `json:"to,omitempty"`
27 Object Note `json:"object"`
28}
29
30// Note is one mirrored event, addressable on its own
31// (/actors/{series}/notes/{id}) so a reply's inReplyTo can point back at
32// the specific commit/issue/patch it's about.
33type Note struct {
34 Context string `json:"@context,omitempty"`
35 ID string `json:"id"`
36 Type string `json:"type"`
37 AttributedTo string `json:"attributedTo"`
38 Content string `json:"content"`
39 URL string `json:"url,omitempty"`
40 Published string `json:"published"`
41 To []string `json:"to,omitempty"`
42}
43
44const publicAudience = "https://www.w3.org/ns/activitystreams#Public"
45
46// NoteURI returns the stable object URI for one activity_log entry's Note.
47func NoteURI(host, series string, entryID int64) string {
48 return ActorURI(host, series) + "/notes/" + strconv.FormatInt(entryID, 10)
49}
50
51// BuildNote turns one mirrored event into its Note representation.
52func BuildNote(host, series string, e state.ActivityEntry) Note {
53 actor := ActorURI(host, series)
54 content := kindLabel(e.Kind) + ": " + e.Summary
55 return Note{
56 ID: NoteURI(host, series, e.ID),
57 Type: "Note",
58 AttributedTo: actor,
59 Content: content,
60 URL: e.URL,
61 Published: e.OccurredAt.Format(time.RFC3339),
62 To: []string{publicAudience},
63 }
64}
65
66// BuildOutbox wraps a series' recent activity entries (newest first, as
67// returned by state.Store.ActivityForSeries) into an OrderedCollection of
68// Create activities.
69func BuildOutbox(host, series string, entries []state.ActivityEntry) OrderedCollection {
70 base := ActorURI(host, series)
71 actor := base
72 items := make([]Create, 0, len(entries))
73 for _, e := range entries {
74 note := BuildNote(host, series, e)
75 items = append(items, Create{
76 ID: note.ID + "/activity",
77 Type: "Create",
78 Actor: actor,
79 Published: note.Published,
80 To: []string{publicAudience},
81 Object: note,
82 })
83 }
84 return OrderedCollection{
85 Context: "https://www.w3.org/ns/activitystreams",
86 ID: base + "/outbox",
87 Type: "OrderedCollection",
88 TotalItems: len(items),
89 OrderedItems: items,
90 }
91}
92
93func kindLabel(kind string) string {
94 switch kind {
95 case "git":
96 return "Commit"
97 case "issue":
98 return "Issue"
99 case "patch":
100 return "Patch"
101 default:
102 return kind
103 }
104}