forked from tangled.org/core
this repo has no description
1package models 2 3import ( 4 "fmt" 5 "sort" 6 "time" 7 8 "github.com/bluesky-social/indigo/atproto/syntax" 9 "tangled.org/core/api/tangled" 10) 11 12type Issue struct { 13 Id int64 14 Did string 15 Rkey string 16 RepoAt syntax.ATURI 17 IssueId int 18 Created time.Time 19 Edited *time.Time 20 Deleted *time.Time 21 Title string 22 Body string 23 Open bool 24 25 // optionally, populate this when querying for reverse mappings 26 // like comment counts, parent repo etc. 27 Comments []IssueComment 28 Labels LabelState 29 Repo *Repo 30} 31 32func (i *Issue) AtUri() syntax.ATURI { 33 return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", i.Did, tangled.RepoIssueNSID, i.Rkey)) 34} 35 36func (i *Issue) AsRecord() tangled.RepoIssue { 37 return tangled.RepoIssue{ 38 Repo: i.RepoAt.String(), 39 Title: i.Title, 40 Body: &i.Body, 41 CreatedAt: i.Created.Format(time.RFC3339), 42 } 43} 44 45func (i *Issue) State() string { 46 if i.Open { 47 return "open" 48 } 49 return "closed" 50} 51 52type CommentListItem struct { 53 Self *IssueComment 54 Replies []*IssueComment 55} 56 57func (i *Issue) CommentList() []CommentListItem { 58 // Create a map to quickly find comments by their aturi 59 toplevel := make(map[string]*CommentListItem) 60 var replies []*IssueComment 61 62 // collect top level comments into the map 63 for _, comment := range i.Comments { 64 if comment.IsTopLevel() { 65 toplevel[comment.AtUri().String()] = &CommentListItem{ 66 Self: &comment, 67 } 68 } else { 69 replies = append(replies, &comment) 70 } 71 } 72 73 for _, r := range replies { 74 parentAt := *r.ReplyTo 75 if parent, exists := toplevel[parentAt]; exists { 76 parent.Replies = append(parent.Replies, r) 77 } 78 } 79 80 var listing []CommentListItem 81 for _, v := range toplevel { 82 listing = append(listing, *v) 83 } 84 85 // sort everything 86 sortFunc := func(a, b *IssueComment) bool { 87 return a.Created.Before(b.Created) 88 } 89 sort.Slice(listing, func(i, j int) bool { 90 return sortFunc(listing[i].Self, listing[j].Self) 91 }) 92 for _, r := range listing { 93 sort.Slice(r.Replies, func(i, j int) bool { 94 return sortFunc(r.Replies[i], r.Replies[j]) 95 }) 96 } 97 98 return listing 99} 100 101func (i *Issue) Participants() []string { 102 participantSet := make(map[string]struct{}) 103 participants := []string{} 104 105 addParticipant := func(did string) { 106 if _, exists := participantSet[did]; !exists { 107 participantSet[did] = struct{}{} 108 participants = append(participants, did) 109 } 110 } 111 112 addParticipant(i.Did) 113 114 for _, c := range i.Comments { 115 addParticipant(c.Did) 116 } 117 118 return participants 119} 120 121func IssueFromRecord(did, rkey string, record tangled.RepoIssue) Issue { 122 created, err := time.Parse(time.RFC3339, record.CreatedAt) 123 if err != nil { 124 created = time.Now() 125 } 126 127 body := "" 128 if record.Body != nil { 129 body = *record.Body 130 } 131 132 return Issue{ 133 RepoAt: syntax.ATURI(record.Repo), 134 Did: did, 135 Rkey: rkey, 136 Created: created, 137 Title: record.Title, 138 Body: body, 139 Open: true, // new issues are open by default 140 } 141} 142 143type IssueComment struct { 144 Id int64 145 Did string 146 Rkey string 147 IssueAt string 148 ReplyTo *string 149 Body string 150 Created time.Time 151 Edited *time.Time 152 Deleted *time.Time 153} 154 155func (i *IssueComment) AtUri() syntax.ATURI { 156 return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", i.Did, tangled.RepoIssueCommentNSID, i.Rkey)) 157} 158 159func (i *IssueComment) AsRecord() tangled.RepoIssueComment { 160 return tangled.RepoIssueComment{ 161 Body: i.Body, 162 Issue: i.IssueAt, 163 CreatedAt: i.Created.Format(time.RFC3339), 164 ReplyTo: i.ReplyTo, 165 } 166} 167 168func (i *IssueComment) IsTopLevel() bool { 169 return i.ReplyTo == nil 170} 171 172func IssueCommentFromRecord(did, rkey string, record tangled.RepoIssueComment) (*IssueComment, error) { 173 created, err := time.Parse(time.RFC3339, record.CreatedAt) 174 if err != nil { 175 created = time.Now() 176 } 177 178 ownerDid := did 179 180 if _, err = syntax.ParseATURI(record.Issue); err != nil { 181 return nil, err 182 } 183 184 comment := IssueComment{ 185 Did: ownerDid, 186 Rkey: rkey, 187 Body: record.Body, 188 IssueAt: record.Issue, 189 ReplyTo: record.ReplyTo, 190 Created: created, 191 } 192 193 return &comment, nil 194}