Monorepo for Tangled
tangled.org
1package models
2
3import (
4 "fmt"
5 "strings"
6 "time"
7
8 "github.com/bluesky-social/indigo/atproto/syntax"
9 "github.com/whyrusleeping/cbor-gen"
10 "tangled.org/core/api/tangled"
11)
12
13type Comment struct {
14 Id int64
15 Did syntax.DID
16 Collection syntax.NSID
17 Rkey string
18 Subject syntax.ATURI
19 ReplyTo *syntax.ATURI
20 Body string
21 Created time.Time
22 Edited *time.Time
23 Deleted *time.Time
24 Mentions []syntax.DID
25 References []syntax.ATURI
26 PullSubmissionId *int
27}
28
29func (c *Comment) AtUri() syntax.ATURI {
30 return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", c.Did, c.Collection, c.Rkey))
31}
32
33func (c *Comment) AsRecord() typegen.CBORMarshaler {
34 mentions := make([]string, len(c.Mentions))
35 for i, did := range c.Mentions {
36 mentions[i] = string(did)
37 }
38 references := make([]string, len(c.References))
39 for i, uri := range c.References {
40 references[i] = string(uri)
41 }
42 var replyTo *string
43 if c.ReplyTo != nil {
44 replyToStr := c.ReplyTo.String()
45 replyTo = &replyToStr
46 }
47 switch c.Collection {
48 case tangled.RepoIssueCommentNSID:
49 return &tangled.RepoIssueComment{
50 Issue: c.Subject.String(),
51 Body: c.Body,
52 CreatedAt: c.Created.Format(time.RFC3339),
53 ReplyTo: replyTo,
54 Mentions: mentions,
55 References: references,
56 }
57 case tangled.RepoPullCommentNSID:
58 return &tangled.RepoPullComment{
59 Pull: c.Subject.String(),
60 Body: c.Body,
61 CreatedAt: c.Created.Format(time.RFC3339),
62 Mentions: mentions,
63 References: references,
64 }
65 default: // default to CommentNSID
66 return &tangled.Comment{
67 Subject: c.Subject.String(),
68 Body: c.Body,
69 CreatedAt: c.Created.Format(time.RFC3339),
70 ReplyTo: replyTo,
71 Mentions: mentions,
72 References: references,
73 }
74 }
75}
76
77func (c *Comment) IsTopLevel() bool {
78 return c.ReplyTo == nil
79}
80
81func (c *Comment) IsReply() bool {
82 return c.ReplyTo != nil
83}
84
85func (c *Comment) Validate() error {
86 // TODO: sanitize the body and then trim space
87 if sb := strings.TrimSpace(c.Body); sb == "" {
88 return fmt.Errorf("body is empty after HTML sanitization")
89 }
90
91 // if it's for PR, PullSubmissionId should not be nil
92 if c.Subject.Collection().String() == tangled.RepoPullNSID {
93 if c.PullSubmissionId == nil {
94 return fmt.Errorf("PullSubmissionId should not be nil")
95 }
96 }
97 return nil
98}
99
100func CommentFromRecord(did syntax.DID, rkey syntax.RecordKey, record tangled.Comment) (*Comment, error) {
101 created, err := time.Parse(time.RFC3339, record.CreatedAt)
102 if err != nil {
103 created = time.Now()
104 }
105
106 if _, err = syntax.ParseATURI(record.Subject); err != nil {
107 return nil, err
108 }
109
110 i := record
111 mentions := make([]syntax.DID, len(record.Mentions))
112 for i, did := range record.Mentions {
113 mentions[i] = syntax.DID(did)
114 }
115 references := make([]syntax.ATURI, len(record.References))
116 for i, uri := range i.References {
117 references[i] = syntax.ATURI(uri)
118 }
119 var replyTo *syntax.ATURI
120 if record.ReplyTo != nil {
121 replyToAtUri := syntax.ATURI(*record.ReplyTo)
122 replyTo = &replyToAtUri
123 }
124
125 comment := Comment{
126 Did: did,
127 Collection: tangled.CommentNSID,
128 Rkey: rkey.String(),
129 Body: record.Body,
130 Subject: syntax.ATURI(record.Subject),
131 ReplyTo: replyTo,
132 Created: created,
133 Mentions: mentions,
134 References: references,
135 }
136
137 return &comment, nil
138}