tavern/web/view_object.go

190 lines
3.8 KiB
Go

package web
import (
"sort"
"time"
"github.com/gofrs/uuid"
"github.com/ngerakines/tavern/storage"
)
type viewObjectSorter struct {
viewObjects []*viewObject
by func(v1, v2 *viewObject) bool
}
func (s *viewObjectSorter) Len() int {
return len(s.viewObjects)
}
func (s *viewObjectSorter) Swap(i, j int) {
s.viewObjects[i], s.viewObjects[j] = s.viewObjects[j], s.viewObjects[i]
}
func (s *viewObjectSorter) Less(i, j int) bool {
return s.by(s.viewObjects[i], s.viewObjects[j])
}
type viewObject struct {
ObjectRowID uuid.UUID
Raw storage.Payload
ViewContext *viewObjectContext
Parent *viewObject
Children []*viewObject
}
type viewObjectContext struct {
Focus bool
Public bool
ObjectID string
Icon string
LinkView bool
LinkViewURL string
LinkReply bool
LinkReplyURL string
LinkAnnounce bool
LinkLike bool
LinkDelete bool
AttributedTo string
AttributedToLink string
HasParent bool
ParentAttributedTo string
ParentAttributedToLink string
ParentObjectLink string
HasAnnouncer bool
AnnounceActivityID string
Announcer string
AnnouncerLink string
HasAnnouncers bool
Announcers map[string]string
Content string
HasPublishedAt bool
PublishedAt time.Time
Tags []string
Mentions []string
Media []viewContentAttachment
ViewerAnnounced bool
TotalAnnounces int
TotalReplies int
TotalLikes int
Error string
Tombstone bool
TombstoneFormerType string
TombstoneHasDeletedAt bool
TombstoneDeletedAt time.Time
Sensitive bool
ContentWarning string
ShortHash string
}
type viewContentAttachment struct {
Thumbnail string
URL string
}
type viewObjectMapper func(uuid.UUID, storage.Payload, *viewObjectContext) *viewObjectContext
func addViewObject(root *viewObject, parentObjectRowID, objectRowID uuid.UUID, payload storage.Payload) *viewObject {
if root != nil {
parent := root.searchObjectRowID(parentObjectRowID)
if parent != nil {
parent.addChild(objectRowID, payload)
return root
}
}
newRoot := createViewObject(objectRowID, payload, nil)
if root != nil {
newRoot.Children = append(newRoot.Children, root)
}
return newRoot
}
func (v *viewObject) populate(depth int, allChildren map[uuid.UUID][]uuid.UUID, refs map[uuid.UUID]storage.Payload) {
if depth > 100 {
return
}
childRowIDs, hasChildRowIDs := allChildren[v.ObjectRowID]
if !hasChildRowIDs {
return
}
for _, childRowID := range childRowIDs {
payload, hasPayload := refs[childRowID]
if !hasPayload {
continue
}
v.addChild(childRowID, payload)
}
for _, child := range v.Children {
child.populate(depth+1, allChildren, refs)
}
}
func (v *viewObject) searchObjectRowID(parentObjectRowID uuid.UUID) *viewObject {
if v.ObjectRowID == parentObjectRowID {
return v
}
for _, child := range v.Children {
if f := child.searchObjectRowID(parentObjectRowID); f != nil {
return f
}
}
return nil
}
func (v *viewObject) addChild(objectRowID uuid.UUID, payload storage.Payload) {
child := createViewObject(objectRowID, payload, v)
v.Children = append(v.Children, child)
}
func (v *viewObject) applyView(mapper viewObjectMapper) {
v.ViewContext = mapper(v.ObjectRowID, v.Raw, v.ViewContext)
for _, child := range v.Children {
child.applyView(mapper)
}
}
func (v *viewObject) sort(by func(v1, v2 *viewObject) bool) {
if len(v.Children) > 0 {
vos := &viewObjectSorter{
viewObjects: v.Children,
by: by,
}
sort.Sort(vos)
for _, child := range v.Children {
child.sort(by)
}
}
}
func createViewObject(objectRowID uuid.UUID, payload storage.Payload, parent *viewObject) *viewObject {
return &viewObject{
ObjectRowID: objectRowID,
Raw: payload,
ViewContext: &viewObjectContext{},
Parent: parent,
Children: make([]*viewObject, 0),
}
}