Monorepo for Tangled forked from tangled.org/core
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265package models
import ( "fmt" "sort" "time"
"github.com/bluesky-social/indigo/atproto/syntax" "tangled.org/core/api/tangled")
type Issue struct { Id int64 Did string Rkey string RepoAt syntax.ATURI IssueId int Created time.Time Edited *time.Time Deleted *time.Time Title string Body string Open bool Mentions []syntax.DID References []syntax.ATURI
// optionally, populate this when querying for reverse mappings // like comment counts, parent repo etc. Comments []IssueComment Labels LabelState Repo *Repo}
func (i *Issue) AtUri() syntax.ATURI { return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", i.Did, tangled.RepoIssueNSID, i.Rkey))}
func (i *Issue) AsRecord() tangled.RepoIssue { mentions := make([]string, len(i.Mentions)) for i, did := range i.Mentions { mentions[i] = string(did) } references := make([]string, len(i.References)) for i, uri := range i.References { references[i] = string(uri) } repoAtStr := i.RepoAt.String() rec := tangled.RepoIssue{ Repo: &repoAtStr, Title: i.Title, Body: &i.Body, Mentions: mentions, References: references, CreatedAt: i.Created.Format(time.RFC3339), } if i.Repo != nil && i.Repo.RepoDid != "" { rec.RepoDid = &i.Repo.RepoDid } return rec}
func (i *Issue) State() string { if i.Open { return "open" } return "closed"}
type CommentListItem struct { Self *IssueComment Replies []*IssueComment}
func (it *CommentListItem) Participants() []syntax.DID { participantSet := make(map[syntax.DID]struct{}) participants := []syntax.DID{}
addParticipant := func(did syntax.DID) { if _, exists := participantSet[did]; !exists { participantSet[did] = struct{}{} participants = append(participants, did) } }
addParticipant(syntax.DID(it.Self.Did))
for _, c := range it.Replies { addParticipant(syntax.DID(c.Did)) }
return participants}
func (i *Issue) CommentList() []CommentListItem { // Create a map to quickly find comments by their aturi toplevel := make(map[string]*CommentListItem) var replies []*IssueComment
// collect top level comments into the map for _, comment := range i.Comments { if comment.IsTopLevel() { toplevel[comment.AtUri().String()] = &CommentListItem{ Self: &comment, } } else { replies = append(replies, &comment) } }
for _, r := range replies { parentAt := *r.ReplyTo if parent, exists := toplevel[parentAt]; exists { parent.Replies = append(parent.Replies, r) } }
var listing []CommentListItem for _, v := range toplevel { listing = append(listing, *v) }
// sort everything sortFunc := func(a, b *IssueComment) bool { return a.Created.Before(b.Created) } sort.Slice(listing, func(i, j int) bool { return sortFunc(listing[i].Self, listing[j].Self) }) for _, r := range listing { sort.Slice(r.Replies, func(i, j int) bool { return sortFunc(r.Replies[i], r.Replies[j]) }) }
return listing}
func (i *Issue) Participants() []syntax.DID { participantSet := make(map[syntax.DID]struct{}) participants := []syntax.DID{}
addParticipant := func(did syntax.DID) { if _, exists := participantSet[did]; !exists { participantSet[did] = struct{}{} participants = append(participants, did) } }
addParticipant(syntax.DID(i.Did))
for _, c := range i.Comments { addParticipant(syntax.DID(c.Did)) }
return participants}
func IssueFromRecord(did, rkey string, record tangled.RepoIssue) Issue { created, err := time.Parse(time.RFC3339, record.CreatedAt) if err != nil { created = time.Now() }
body := "" if record.Body != nil { body = *record.Body }
var repoAt syntax.ATURI if record.Repo != nil { repoAt = syntax.ATURI(*record.Repo) }
return Issue{ RepoAt: repoAt, Did: did, Rkey: rkey, Created: created, Title: record.Title, Body: body, Open: true, // new issues are open by default }}
type IssueComment struct { Id int64 Did string Rkey string IssueAt string ReplyTo *string Body string Created time.Time Edited *time.Time Deleted *time.Time Mentions []syntax.DID References []syntax.ATURI}
func (i *IssueComment) AtUri() syntax.ATURI { return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", i.Did, tangled.RepoIssueCommentNSID, i.Rkey))}
func (i *IssueComment) AsRecord() tangled.RepoIssueComment { mentions := make([]string, len(i.Mentions)) for i, did := range i.Mentions { mentions[i] = string(did) } references := make([]string, len(i.References)) for i, uri := range i.References { references[i] = string(uri) } return tangled.RepoIssueComment{ Body: i.Body, Issue: i.IssueAt, CreatedAt: i.Created.Format(time.RFC3339), ReplyTo: i.ReplyTo, Mentions: mentions, References: references, }}
func (i *IssueComment) IsTopLevel() bool { return i.ReplyTo == nil}
func (i *IssueComment) IsReply() bool { return i.ReplyTo != nil}
func IssueCommentFromRecord(did, rkey string, record tangled.RepoIssueComment) (*IssueComment, error) { created, err := time.Parse(time.RFC3339, record.CreatedAt) if err != nil { created = time.Now() }
ownerDid := did
if _, err = syntax.ParseATURI(record.Issue); err != nil { return nil, err }
i := record mentions := make([]syntax.DID, len(record.Mentions)) for i, did := range record.Mentions { mentions[i] = syntax.DID(did) } references := make([]syntax.ATURI, len(record.References)) for i, uri := range i.References { references[i] = syntax.ATURI(uri) }
comment := IssueComment{ Did: ownerDid, Rkey: rkey, Body: record.Body, IssueAt: record.Issue, ReplyTo: record.ReplyTo, Created: created, Mentions: mentions, References: references, }
return &comment, nil}