This repository has no description
1package models
2
3import (
4 "fmt"
5 "strings"
6 "time"
7
8 "github.com/bluesky-social/indigo/atproto/syntax"
9 lexutil "github.com/bluesky-social/indigo/lex/util"
10 "tangled.org/core/api/tangled"
11 "tangled.org/core/appview/pages/markup/sanitizer"
12)
13
14type Issue struct {
15 Id int64
16 Did string
17 Rkey string
18 RepoDid syntax.DID
19 IssueId int
20 Created time.Time
21 Edited *time.Time
22 Deleted *time.Time
23 Title string
24 Body string
25 Open bool
26 Mentions []syntax.DID
27 References []syntax.ATURI
28 // images embedded in Body; referenced on the record to pin them against GC
29 Blobs []*lexutil.LexBlob
30
31 // optionally, populate this when querying for reverse mappings
32 // like comment counts, parent repo etc.
33 Comments []Comment
34 Labels LabelState
35 Repo *Repo
36}
37
38func (i *Issue) AtUri() syntax.ATURI {
39 return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", i.Did, tangled.RepoIssueNSID, i.Rkey))
40}
41
42func (i *Issue) AsRecord() tangled.RepoIssue {
43 mentions := make([]string, len(i.Mentions))
44 for i, did := range i.Mentions {
45 mentions[i] = string(did)
46 }
47 references := make([]string, len(i.References))
48 for i, uri := range i.References {
49 references[i] = string(uri)
50 }
51 rec := tangled.RepoIssue{
52 Repo: string(i.RepoDid),
53 Title: i.Title,
54 Body: &i.Body,
55 Mentions: mentions,
56 References: references,
57 CreatedAt: i.Created.Format(time.RFC3339),
58 Blobs: i.Blobs,
59 }
60 return rec
61}
62
63func (i *Issue) State() string {
64 if i.Open {
65 return "open"
66 }
67 return "closed"
68}
69
70var _ Validator = new(Issue)
71
72func (i *Issue) Validate() error {
73 if i.Title == "" {
74 return fmt.Errorf("issue title is empty")
75 }
76 if i.Body == "" {
77 return fmt.Errorf("issue body is empty")
78 }
79
80 if st := strings.TrimSpace(sanitizer.SanitizeDescription(i.Title)); st == "" {
81 return fmt.Errorf("title is empty after HTML sanitization")
82 }
83
84 if st := strings.TrimSpace(sanitizer.SanitizeDefault(i.Body)); st == "" {
85 return fmt.Errorf("body is empty after HTML sanitization")
86 }
87 return nil
88}
89
90func (i *Issue) Participants() []syntax.DID {
91 participantSet := make(map[syntax.DID]struct{})
92 participants := []syntax.DID{}
93
94 addParticipant := func(did syntax.DID) {
95 if _, exists := participantSet[did]; !exists {
96 participantSet[did] = struct{}{}
97 participants = append(participants, did)
98 }
99 }
100
101 addParticipant(syntax.DID(i.Did))
102
103 for _, c := range i.Comments {
104 addParticipant(c.Did)
105 }
106
107 return participants
108}
109
110func IssueFromRecord(did, rkey string, record tangled.RepoIssue) Issue {
111 created, err := time.Parse(time.RFC3339, record.CreatedAt)
112 if err != nil {
113 created = time.Now()
114 }
115
116 body := ""
117 if record.Body != nil {
118 body = *record.Body
119 }
120
121 return Issue{
122 RepoDid: syntax.DID(record.Repo),
123 Did: did,
124 Rkey: rkey,
125 Created: created,
126 Title: record.Title,
127 Body: body,
128 Open: true, // new issues are open by default
129 }
130}