This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / appview / models / issue.go
3.8 kB 176 lines
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 RepoDid syntax.DID 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 Mentions []syntax.DID 25 References []syntax.ATURI 26 27 // optionally, populate this when querying for reverse mappings 28 // like comment counts, parent repo etc. 29 Comments []Comment 30 Labels LabelState 31 Repo *Repo 32} 33 34func (i *Issue) AtUri() syntax.ATURI { 35 return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", i.Did, tangled.RepoIssueNSID, i.Rkey)) 36} 37 38func (i *Issue) AsRecord() tangled.RepoIssue { 39 mentions := make([]string, len(i.Mentions)) 40 for i, did := range i.Mentions { 41 mentions[i] = string(did) 42 } 43 references := make([]string, len(i.References)) 44 for i, uri := range i.References { 45 references[i] = string(uri) 46 } 47 rec := tangled.RepoIssue{ 48 Repo: string(i.RepoDid), 49 Title: i.Title, 50 Body: &i.Body, 51 Mentions: mentions, 52 References: references, 53 CreatedAt: i.Created.Format(time.RFC3339), 54 } 55 return rec 56} 57 58func (i *Issue) State() string { 59 if i.Open { 60 return "open" 61 } 62 return "closed" 63} 64 65type CommentListItem struct { 66 Self *Comment 67 Replies []*Comment 68} 69 70func (it *CommentListItem) Participants() []syntax.DID { 71 participantSet := make(map[syntax.DID]struct{}) 72 participants := []syntax.DID{} 73 74 addParticipant := func(did syntax.DID) { 75 if _, exists := participantSet[did]; !exists { 76 participantSet[did] = struct{}{} 77 participants = append(participants, did) 78 } 79 } 80 81 addParticipant(syntax.DID(it.Self.Did)) 82 83 for _, c := range it.Replies { 84 addParticipant(syntax.DID(c.Did)) 85 } 86 87 return participants 88} 89 90func (i *Issue) CommentList() []CommentListItem { 91 // Create a map to quickly find comments by their aturi 92 toplevel := make(map[syntax.ATURI]*CommentListItem) 93 var replies []*Comment 94 95 // collect top level comments into the map 96 for _, comment := range i.Comments { 97 if comment.IsTopLevel() { 98 toplevel[comment.AtUri()] = &CommentListItem{ 99 Self: &comment, 100 } 101 } else { 102 replies = append(replies, &comment) 103 } 104 } 105 106 for _, r := range replies { 107 if r.ReplyTo == nil { 108 continue 109 } 110 if parent, exists := toplevel[syntax.ATURI(r.ReplyTo.Uri)]; exists { 111 parent.Replies = append(parent.Replies, r) 112 } 113 } 114 115 var listing []CommentListItem 116 for _, v := range toplevel { 117 listing = append(listing, *v) 118 } 119 120 // sort everything 121 sortFunc := func(a, b *Comment) bool { 122 return a.Created.Before(b.Created) 123 } 124 sort.Slice(listing, func(i, j int) bool { 125 return sortFunc(listing[i].Self, listing[j].Self) 126 }) 127 for _, r := range listing { 128 sort.Slice(r.Replies, func(i, j int) bool { 129 return sortFunc(r.Replies[i], r.Replies[j]) 130 }) 131 } 132 133 return listing 134} 135 136func (i *Issue) Participants() []syntax.DID { 137 participantSet := make(map[syntax.DID]struct{}) 138 participants := []syntax.DID{} 139 140 addParticipant := func(did syntax.DID) { 141 if _, exists := participantSet[did]; !exists { 142 participantSet[did] = struct{}{} 143 participants = append(participants, did) 144 } 145 } 146 147 addParticipant(syntax.DID(i.Did)) 148 149 for _, c := range i.Comments { 150 addParticipant(c.Did) 151 } 152 153 return participants 154} 155 156func IssueFromRecord(did, rkey string, record tangled.RepoIssue) Issue { 157 created, err := time.Parse(time.RFC3339, record.CreatedAt) 158 if err != nil { 159 created = time.Now() 160 } 161 162 body := "" 163 if record.Body != nil { 164 body = *record.Body 165 } 166 167 return Issue{ 168 RepoDid: syntax.DID(record.Repo), 169 Did: did, 170 Rkey: rkey, 171 Created: created, 172 Title: record.Title, 173 Body: body, 174 Open: true, // new issues are open by default 175 } 176}