This repository has no description
1package models
2
3import (
4 "fmt"
5 "strings"
6 "time"
7
8 comatproto "github.com/bluesky-social/indigo/api/atproto"
9 "github.com/bluesky-social/indigo/atproto/syntax"
10 typegen "github.com/whyrusleeping/cbor-gen"
11 "tangled.org/core/api/tangled"
12)
13
14type Comment struct {
15 Id int64
16
17 Did syntax.DID
18 Collection syntax.NSID
19 Rkey syntax.RecordKey
20 Cid syntax.CID
21
22 // record content
23 Subject comatproto.RepoStrongRef
24 Body tangled.MarkupMarkdown // markup body type. only markdown is supported right now
25 Created time.Time
26 ReplyTo *comatproto.RepoStrongRef // (optional) parent comment
27 PullRoundIdx *int // (optional) pull round number used when subject is sh.tangled.repo.pull
28
29 // store on db, but not on PDS
30 Edited *time.Time
31 Deleted *time.Time
32}
33
34func (c *Comment) AtUri() syntax.ATURI {
35 return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", c.Did, c.Collection, c.Rkey))
36}
37
38func (c *Comment) StrongRef() comatproto.RepoStrongRef {
39 return comatproto.RepoStrongRef{
40 Uri: c.AtUri().String(),
41 Cid: c.Cid.String(),
42 }
43}
44
45func (c *Comment) AsRecord() typegen.CBORMarshaler {
46 // can't convert to record for legacy types
47 if c.Collection != tangled.FeedCommentNSID {
48 return nil
49 }
50 var pullRoundIdx *int64
51 if c.PullRoundIdx != nil {
52 pullRoundIdx = new(int64)
53 *pullRoundIdx = int64(*c.PullRoundIdx)
54 }
55 return &tangled.FeedComment{
56 Subject: &c.Subject,
57 Body: &tangled.FeedComment_Body{MarkupMarkdown: &c.Body},
58 CreatedAt: c.Created.Format(time.RFC3339),
59 ReplyTo: c.ReplyTo,
60 PullRoundIdx: pullRoundIdx,
61 }
62}
63
64func (c *Comment) EditableBody() string {
65 if c.Body.Original != nil {
66 return *c.Body.Original
67 }
68 return c.Body.Text
69}
70
71func (c *Comment) IsLegacy() bool {
72 return c.Collection != tangled.FeedCommentNSID
73}
74
75func (c *Comment) IsTopLevel() bool {
76 return c.ReplyTo == nil
77}
78
79func (c *Comment) IsReply() bool {
80 return c.ReplyTo != nil
81}
82
83func (c *Comment) Validate() error {
84 // TODO: sanitize the body and then trim space
85 if sb := strings.TrimSpace(c.Body.Text); sb == "" {
86 return fmt.Errorf("body is empty after HTML sanitization")
87 }
88
89 // if it's for PR, PullSubmissionId should not be nil
90 subjectAt, err := syntax.ParseATURI(c.Subject.Uri)
91 if err != nil {
92 return fmt.Errorf("subject.uri is not valid at-uri: %w", err)
93 }
94 if subjectAt.Collection().String() == tangled.RepoPullNSID {
95 if c.PullRoundIdx == nil {
96 return fmt.Errorf("pullSubmissionId should not be nil when subject is sh.tangled.repo.pull")
97 }
98 }
99 return nil
100}
101
102func CommentFromRecord(did syntax.DID, rkey syntax.RecordKey, cid syntax.CID, record tangled.FeedComment) (*Comment, error) {
103 created, err := time.Parse(time.RFC3339, record.CreatedAt)
104 if err != nil {
105 created = time.Now()
106 }
107
108 if record.Subject == nil {
109 return nil, fmt.Errorf("subject can't be nil")
110 }
111 subjectAt, err := syntax.ParseATURI(record.Subject.Uri)
112 if err != nil {
113 return nil, fmt.Errorf("invalid subject uri: %w", err)
114 }
115 if _, err = syntax.ParseCID(record.Subject.Cid); err != nil {
116 return nil, fmt.Errorf("invalid subject cid: %w", err)
117 }
118
119 if subjectAt.Collection() == tangled.RepoPullNSID {
120 if record.PullRoundIdx == nil {
121 return nil, fmt.Errorf("pullRoundIdx can't be nil when subject is sh.tangled.repo.pull")
122 }
123 }
124
125 if record.Body == nil {
126 return nil, fmt.Errorf("body can't be nil")
127 }
128 if record.Body.MarkupMarkdown == nil {
129 return nil, fmt.Errorf("body should be markdown type")
130 }
131
132 if record.ReplyTo != nil {
133 if _, err = syntax.ParseATURI(record.ReplyTo.Uri); err != nil {
134 return nil, fmt.Errorf("invalid replyTo uri: %w", err)
135 }
136 if _, err = syntax.ParseCID(record.ReplyTo.Cid); err != nil {
137 return nil, fmt.Errorf("invalid replyTo cid: %w", err)
138 }
139 }
140
141 var pullRoundIdx *int
142 if record.PullRoundIdx != nil {
143 pullRoundIdx = new(int)
144 *pullRoundIdx = int(*record.PullRoundIdx)
145 }
146
147 return &Comment{
148 Did: did,
149 Collection: tangled.FeedCommentNSID,
150 Rkey: rkey,
151 Cid: cid,
152
153 Subject: *record.Subject,
154 Body: *record.Body.MarkupMarkdown,
155 Created: created,
156 ReplyTo: record.ReplyTo,
157 PullRoundIdx: pullRoundIdx,
158 }, nil
159}